Commit df7dc2b3 authored by Sebastian Rettenberger's avatar Sebastian Rettenberger

Merge branch 'master' of github.com:TUM-I5/SWE

parents b4de84cf 3af18e4a
...@@ -65,7 +65,7 @@ vars.AddVariables( ...@@ -65,7 +65,7 @@ vars.AddVariables(
PathVariable( 'buildDir', 'where to build the code', 'build', PathVariable.PathIsDirCreate ), PathVariable( 'buildDir', 'where to build the code', 'build', PathVariable.PathIsDirCreate ),
EnumVariable( 'compiler', 'used compiler', 'gnu', EnumVariable( 'compiler', 'used compiler', 'gnu',
allowed_values=('gnu', 'intel') allowed_values=('gnu', 'intel', 'cray')
), ),
EnumVariable( 'compileMode', 'mode of the compilation', 'release', EnumVariable( 'compileMode', 'mode of the compilation', 'release',
...@@ -78,7 +78,8 @@ vars.AddVariables( ...@@ -78,7 +78,8 @@ vars.AddVariables(
EnumVariable( 'computeCapability', 'optional architecture/compute capability of the CUDA card', 'sm_20', EnumVariable( 'computeCapability', 'optional architecture/compute capability of the CUDA card', 'sm_20',
allowed_values=('sm_10', 'sm_11', 'sm_12','sm_13', allowed_values=('sm_10', 'sm_11', 'sm_12','sm_13',
'sm_20', 'sm_21', 'sm_22', 'sm_23' ) 'sm_20', 'sm_21', 'sm_22', 'sm_23',
'sm_30', 'sm_35' )
), ),
BoolVariable( 'openGL', 'compile with OpenGL visualization', False), BoolVariable( 'openGL', 'compile with OpenGL visualization', False),
...@@ -103,7 +104,9 @@ vars.AddVariables( ...@@ -103,7 +104,9 @@ vars.AddVariables(
allowed_values=('default', 'mic' ) allowed_values=('default', 'mic' )
), ),
BoolVariable( 'xmlRuntime', 'use a xml-file for runtime parameters', False ) BoolVariable( 'xmlRuntime', 'use a xml-file for runtime parameters', False ),
BoolVariable( 'copyenv', 'copy the whole environment', False )
) )
# external variables # external variables
...@@ -145,13 +148,20 @@ if env['parallelization'] != 'cuda' and env['openGL'] == True: ...@@ -145,13 +148,20 @@ if env['parallelization'] != 'cuda' and env['openGL'] == True:
print >> sys.stderr, '** The parallelization "'+env['parallelization']+'" does not support OpenGL visualization (CUDA only).' print >> sys.stderr, '** The parallelization "'+env['parallelization']+'" does not support OpenGL visualization (CUDA only).'
Exit(3) Exit(3)
# Copy whole environment?
if env['copyenv']:
env.AppendUnique(ENV=os.environ, delete_existing=1)
# #
# precompiler, compiler and linker flags # precompiler, compiler and linker flags
# #
# Select the compiler (MPI and/or Intel, GNU is default) # Select the compiler (MPI and/or Intel, GNU is default)
if env['parallelization'] in ['mpi', 'mpi_with_cuda']: if env['parallelization'] in ['mpi', 'mpi_with_cuda']:
env['CXX'] = env['LINKERFORPROGRAMS'] = env.Detect(['mpiCC', 'mpicxx']) if env['compiler'] == 'cray':
env['CXX'] = 'CC'
else:
env['CXX'] = env['LINKERFORPROGRAMS'] = env.Detect(['mpiCC', 'mpicxx'])
if not env['CXX']: if not env['CXX']:
print >> sys.stderr, '** MPI compiler not found, please update PATH environment variable' print >> sys.stderr, '** MPI compiler not found, please update PATH environment variable'
Exit(1) Exit(1)
...@@ -165,9 +175,12 @@ if env['parallelization'] in ['mpi', 'mpi_with_cuda']: ...@@ -165,9 +175,12 @@ if env['parallelization'] in ['mpi', 'mpi_with_cuda']:
else: else:
if env['compiler'] == 'intel': if env['compiler'] == 'intel':
env['CXX'] = 'icpc' env['CXX'] = 'icpc'
elif env['compiler'] == 'cray':
env['CXX'] = env['LINKERFORPROGRAMS'] = 'CC'
# eclipse specific flag # eclipse specific flag
env.Append(CCFLAGS=['-fmessage-length=0']) if env['compiler'] != 'cray':
env.Append(CCFLAGS=['-fmessage-length=0'])
# xml parameters for the compiler TODO # xml parameters for the compiler TODO
...@@ -181,6 +194,9 @@ if env['compileMode'] == 'debug': ...@@ -181,6 +194,9 @@ if env['compileMode'] == 'debug':
elif env['compiler'] == 'intel': elif env['compiler'] == 'intel':
env.Append(CCFLAGS=['-O0','-g']) env.Append(CCFLAGS=['-O0','-g'])
elif env['compiler'] == 'cray':
env.Append(CCFLAGS=['-O0'])
elif env['compileMode'] == 'release': elif env['compileMode'] == 'release':
env.Append(CPPDEFINES=['NDEBUG']) env.Append(CPPDEFINES=['NDEBUG'])
...@@ -189,9 +205,13 @@ elif env['compileMode'] == 'release': ...@@ -189,9 +205,13 @@ elif env['compileMode'] == 'release':
elif env['compiler'] == 'intel': elif env['compiler'] == 'intel':
env.Append(CCFLAGS=['-O2']) env.Append(CCFLAGS=['-O2'])
elif env['compiler'] == 'cray':
env.Append(CCFLAGS=['-O3'])
# Other compiler flags (for all compilers) # Other compiler flags (for all compilers)
env.Append(CCFLAGS=['-fstrict-aliasing', '-fargument-noalias']) if env['compiler'] != 'cray':
env.Append(CCFLAGS=['-fstrict-aliasing', '-fargument-noalias'])
# Vectorization? # Vectorization?
if env['compileMode'] == 'release' and env['vectorize']: if env['compileMode'] == 'release' and env['vectorize']:
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include "tools/CXMLConfig.hpp" #include "tools/CXMLConfig.hpp"
#endif #endif
#include "tools/args.hh"
#include "tools/help.hh" #include "tools/help.hh"
#include "tools/Logger.hh" #include "tools/Logger.hh"
#include "tools/ProgressBar.hh" #include "tools/ProgressBar.hh"
...@@ -88,25 +89,6 @@ void exchangeBottomTopGhostLayers( const int i_bottomNeighborRank, SWE_Block1D* ...@@ -88,25 +89,6 @@ void exchangeBottomTopGhostLayers( const int i_bottomNeighborRank, SWE_Block1D*
const int i_topNeighborRank, SWE_Block1D* o_topNeighborInflow, SWE_Block1D* i_topNeighborOutflow, const int i_topNeighborRank, SWE_Block1D* o_topNeighborInflow, SWE_Block1D* i_topNeighborOutflow,
const MPI_Datatype i_mpiRow); const MPI_Datatype i_mpiRow);
// Get command line argument by the specified name.
static char* getArgByName(std::vector<std::string> vargs, std::string arg_name, char** argv)
{
std::vector<std::string>::iterator it = std::find(vargs.begin(), vargs.end(), arg_name);
if (it == vargs.end()) {
std::cerr << "Cannot find the command line argument matching the name \"" <<
arg_name << "\"" << endl;
// abort MPI execution
MPI_Abort(MPI_COMM_WORLD, -1);
exit(1);
}
return argv[it - vargs.begin()];
}
#define ARG(arg_name) getArgByName(vargs, arg_name, argv)
/** /**
* Main program for the simulation on a single SWE_WavePropagationBlock. * Main program for the simulation on a single SWE_WavePropagationBlock.
*/ */
...@@ -141,32 +123,33 @@ int main( int argc, char** argv ) { ...@@ -141,32 +123,33 @@ int main( int argc, char** argv ) {
tools::Logger::logger.printNumberOfProcesses(l_numberOfProcesses); tools::Logger::logger.printNumberOfProcesses(l_numberOfProcesses);
// check if the necessary command line input parameters are given // check if the necessary command line input parameters are given
tools::Args args;
#ifndef READXML #ifndef READXML
std::vector<std::string> vargs; args.addOption("grid-size-x", 'x', "Number of cell in x direction");
vargs.push_back(argv[0]); args.addOption("grid-size-y", 'y', "Number of cell in y direction");
vargs.push_back("grid_size_x"); args.addOption("output-basepath", 'o', "Output base file name");
vargs.push_back("grid_size_y"); args.addOption("output-steps-count", 'c', "Number of output time steps");
vargs.push_back("output_basepath");
vargs.push_back("output_steps_count");
#ifdef ASAGI #ifdef ASAGI
vargs.push_back("bathymetry_file"); args.addOption("bathymetry-file", 'b', "File containing the bathymetry");
vargs.push_back("displacement_file"); args.addOption("displacement-file", 'd', "File containing the displacement");
vargs.push_back("simul_area_min_x"); args.addOption("simul-area-min-x", 0, "Simulation area");
vargs.push_back("simul_area_max_x"); args.addOption("simul-area-max-x", 0, "Simulation area");
vargs.push_back("simul_area_min_y"); args.addOption("simul-area-min-y", 0, "Simulation area");
vargs.push_back("simul_area_max_y"); args.addOption("simul-area-max-y", 0, "Simulation area");
vargs.push_back("simul_duration_secs"); args.addOption("simul-duration", 0, "Simulation time in seconds");
#endif #endif
if (argc != vargs.size()) {
std::cout << "Usage: " << vargs[0];
for (int i = 1, e = vargs.size(); i != e; i++)
std::cout << " <" << vargs[i] << ">";
std::cout << std::endl << std::flush;
MPI_Finalize();
return 1;
}
#endif #endif
tools::Args::Result ret = args.parse(argc, argv, l_mpiRank == 0);
switch (ret)
{
case tools::Args::Error:
MPI_Abort(MPI_COMM_WORLD, -1);
return 1;
case tools::Args::Help:
MPI_Finalize();
return 0;
}
//! total number of grid cell in x- and y-direction. //! total number of grid cell in x- and y-direction.
int l_nX, l_nY; int l_nX, l_nY;
...@@ -176,9 +159,9 @@ int main( int argc, char** argv ) { ...@@ -176,9 +159,9 @@ int main( int argc, char** argv ) {
// read command line parameters // read command line parameters
#ifndef READXML #ifndef READXML
l_nX = atoi(ARG("grid_size_x")); l_nX = args.getArgument<int>("grid-size-x");
l_nY = atoi(ARG("grid_size_y")); l_nY = args.getArgument<int>("grid-size-y");
l_baseName = std::string(ARG("output_basepath")); l_baseName = args.getArgument<std::string>("output-basepath");
#endif #endif
// read xml file // read xml file
...@@ -230,14 +213,14 @@ int main( int argc, char** argv ) { ...@@ -230,14 +213,14 @@ int main( int argc, char** argv ) {
//simulation area //simulation area
float simulationArea[4]; float simulationArea[4];
simulationArea[0] = atof(ARG("simul_area_min_x")); simulationArea[0] = args.getArgument<float>("simul-area-min-x");
simulationArea[1] = atof(ARG("simul_area_max_x")); simulationArea[1] = args.getArgument<float>("simul-area-max-x");
simulationArea[2] = atof(ARG("simul_area_min_y")); simulationArea[2] = args.getArgument<float>("simul-area-min-y");
simulationArea[3] = atof(ARG("simul_area_max_y")); simulationArea[3] = args.getArgument<float>("simul-area-max-y");
float simulationDuration = atof(ARG("simul_duration_secs")); float simulationDuration = args.getArgument<float>("simul-duration");
SWE_AsagiScenario l_scenario(ARG("bathymetry_file"), ARG("displacement_file"), SWE_AsagiScenario l_scenario(args.getArgument<std::string>("bathymetry-file"), args.getArgument<std::string>("displacement-file"),
simulationDuration, simulationArea); simulationDuration, simulationArea);
#else #else
// create a simple artificial scenario // create a simple artificial scenario
...@@ -245,7 +228,7 @@ int main( int argc, char** argv ) { ...@@ -245,7 +228,7 @@ int main( int argc, char** argv ) {
#endif #endif
//! number of checkpoints for visualization (at each checkpoint in time, an output file is written). //! number of checkpoints for visualization (at each checkpoint in time, an output file is written).
int l_numberOfCheckPoints = atoi(ARG("output_steps_count")); int l_numberOfCheckPoints = args.getArgument<int>("output-steps-count");
//! number of grid cells in x- and y-direction per process. //! number of grid cells in x- and y-direction per process.
int l_nXLocal, l_nYLocal; int l_nXLocal, l_nYLocal;
...@@ -450,7 +433,7 @@ int main( int argc, char** argv ) { ...@@ -450,7 +433,7 @@ int main( int argc, char** argv ) {
// do time steps until next checkpoint is reached // do time steps until next checkpoint is reached
while( l_t < l_checkPoints[c] ) { while( l_t < l_checkPoints[c] ) {
//reset CPU-Communication clock //reset CPU-Communication clock
tools::Logger::logger.resetCpuCommunicationClockToCurrentTime(); tools::Logger::logger.resetClockToCurrentTime("CpuCommunication");
// exchange ghost and copy layers // exchange ghost and copy layers
exchangeLeftRightGhostLayers( l_leftNeighborRank, l_leftInflow, l_leftOutflow, exchangeLeftRightGhostLayers( l_leftNeighborRank, l_leftInflow, l_leftOutflow,
...@@ -462,7 +445,7 @@ int main( int argc, char** argv ) { ...@@ -462,7 +445,7 @@ int main( int argc, char** argv ) {
l_mpiRow ); l_mpiRow );
// reset the cpu clock // reset the cpu clock
tools::Logger::logger.resetCpuClockToCurrentTime(); tools::Logger::logger.resetClockToCurrentTime("Cpu");
// set values in ghost cells // set values in ghost cells
l_wavePropgationBlock.setGhostLayer(); l_wavePropgationBlock.setGhostLayer();
...@@ -474,7 +457,7 @@ int main( int argc, char** argv ) { ...@@ -474,7 +457,7 @@ int main( int argc, char** argv ) {
float l_maxTimeStepWidth = l_wavePropgationBlock.getMaxTimestep(); float l_maxTimeStepWidth = l_wavePropgationBlock.getMaxTimestep();
// update the cpu time in the logger // update the cpu time in the logger
tools::Logger::logger.updateCpuTime(); tools::Logger::logger.updateTime("Cpu");
//! maximum allowed time steps of all blocks //! maximum allowed time steps of all blocks
float l_maxTimeStepWidthGlobal; float l_maxTimeStepWidthGlobal;
...@@ -483,14 +466,14 @@ int main( int argc, char** argv ) { ...@@ -483,14 +466,14 @@ int main( int argc, char** argv ) {
MPI_Allreduce(&l_maxTimeStepWidth, &l_maxTimeStepWidthGlobal, 1, MPI_FLOAT, MPI_MIN, MPI_COMM_WORLD); MPI_Allreduce(&l_maxTimeStepWidth, &l_maxTimeStepWidthGlobal, 1, MPI_FLOAT, MPI_MIN, MPI_COMM_WORLD);
// reset the cpu time // reset the cpu time
tools::Logger::logger.resetCpuClockToCurrentTime(); tools::Logger::logger.resetClockToCurrentTime("Cpu");
// update the cell values // update the cell values
l_wavePropgationBlock.updateUnknowns(l_maxTimeStepWidthGlobal); l_wavePropgationBlock.updateUnknowns(l_maxTimeStepWidthGlobal);
// update the cpu and CPU-communication time in the logger // update the cpu and CPU-communication time in the logger
tools::Logger::logger.updateCpuTime(); tools::Logger::logger.updateTime("Cpu");
tools::Logger::logger.updateCpuCommunicationTime(); tools::Logger::logger.updateTime("CpuCommunication");
// update simulation time with time step width. // update simulation time with time step width.
l_t += l_maxTimeStepWidthGlobal; l_t += l_maxTimeStepWidthGlobal;
...@@ -528,10 +511,10 @@ int main( int argc, char** argv ) { ...@@ -528,10 +511,10 @@ int main( int argc, char** argv ) {
tools::Logger::logger.printStatisticsMessage(); tools::Logger::logger.printStatisticsMessage();
// print the cpu time // print the cpu time
tools::Logger::logger.printCpuTime("CPU time"); tools::Logger::logger.printTime("Cpu", "CPU time");
// print CPU + Communication time // print CPU + Communication time
tools::Logger::logger.printCpuCommunicationTime(); tools::Logger::logger.printTime("CpuCommunication", "CPU + Communication time");
// print the wall clock time (includes plotting) // print the wall clock time (includes plotting)
tools::Logger::logger.printWallClockTime(time(NULL)); tools::Logger::logger.printWallClockTime(time(NULL));
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include "tools/CXMLConfig.hpp" #include "tools/CXMLConfig.hpp"
#endif #endif
#include "tools/args.hh"
#include "tools/help.hh" #include "tools/help.hh"
#include "tools/Logger.hh" #include "tools/Logger.hh"
#include "tools/ProgressBar.hh" #include "tools/ProgressBar.hh"
...@@ -64,16 +65,24 @@ int main( int argc, char** argv ) { ...@@ -64,16 +65,24 @@ int main( int argc, char** argv ) {
/** /**
* Initialization. * Initialization.
*/ */
// check if the necessary command line input parameters are given // Parse command line parameters
tools::Args args;
#ifndef READXML #ifndef READXML
if(argc != 4) { args.addOption("grid-size-x", 'x', "Number of cell in x direction");
std::cout << "Aborting ... please provide proper input parameters." << std::endl args.addOption("grid-size-y", 'y', "Number of cell in y direction");
<< "Example: ./SWE_parallel 200 300 /work/openmp_out" << std::endl args.addOption("output-basepath", 'o', "Output base file name");
<< "\tfor a single block of size 200 * 300" << std::endl;
return 1;
}
#endif #endif
tools::Args::Result ret = args.parse(argc, argv);
switch (ret)
{
case tools::Args::Error:
return 1;
case tools::Args::Help:
return 0;
}
//! number of grid cells in x- and y-direction. //! number of grid cells in x- and y-direction.
int l_nX, l_nY; int l_nX, l_nY;
...@@ -82,9 +91,9 @@ int main( int argc, char** argv ) { ...@@ -82,9 +91,9 @@ int main( int argc, char** argv ) {
// read command line parameters // read command line parameters
#ifndef READXML #ifndef READXML
l_nY = l_nX = atoi(argv[1]); l_nX = args.getArgument<int>("grid-size-x");
l_nY = atoi(argv[2]); l_nY = args.getArgument<int>("grid-size-y");
l_baseName = std::string(argv[3]); l_baseName = args.getArgument<std::string>("output-basepath");
#endif #endif
// read xml file // read xml file
...@@ -226,7 +235,7 @@ int main( int argc, char** argv ) { ...@@ -226,7 +235,7 @@ int main( int argc, char** argv ) {
l_wavePropgationBlock.setGhostLayer(); l_wavePropgationBlock.setGhostLayer();
// reset the cpu clock // reset the cpu clock
tools::Logger::logger.resetCpuClockToCurrentTime(); tools::Logger::logger.resetClockToCurrentTime("Cpu");
// approximate the maximum time step // approximate the maximum time step
// TODO: This calculation should be replaced by the usage of the wave speeds occuring during the flux computation // TODO: This calculation should be replaced by the usage of the wave speeds occuring during the flux computation
...@@ -243,7 +252,7 @@ int main( int argc, char** argv ) { ...@@ -243,7 +252,7 @@ int main( int argc, char** argv ) {
l_wavePropgationBlock.updateUnknowns(l_maxTimeStepWidth); l_wavePropgationBlock.updateUnknowns(l_maxTimeStepWidth);
// update the cpu time in the logger // update the cpu time in the logger
tools::Logger::logger.updateCpuTime(); tools::Logger::logger.updateTime("Cpu");
// update simulation time with time step width. // update simulation time with time step width.
l_t += l_maxTimeStepWidth; l_t += l_maxTimeStepWidth;
...@@ -275,7 +284,7 @@ int main( int argc, char** argv ) { ...@@ -275,7 +284,7 @@ int main( int argc, char** argv ) {
tools::Logger::logger.printStatisticsMessage(); tools::Logger::logger.printStatisticsMessage();
// print the cpu time // print the cpu time
tools::Logger::logger.printCpuTime(); tools::Logger::logger.printTime("Cpu", "CPU time");
// print the wall clock time (includes plotting) // print the wall clock time (includes plotting)
tools::Logger::logger.printWallClockTime(time(NULL)); tools::Logger::logger.printWallClockTime(time(NULL));
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <mpi.h> #include <mpi.h>
#endif #endif
#include <map>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <ctime> #include <ctime>
...@@ -88,25 +89,15 @@ class tools::Logger { ...@@ -88,25 +89,15 @@ class tools::Logger {
//! definition of indentation //! definition of indentation
const std::string indentation; const std::string indentation;
//! CPU clock //! Clocks
#if (defined USEMPI && !defined CUDA) #if (defined USEMPI && !defined CUDA)
double cpuClock; std::map<std::string, double> clocks;
#else #else
clock_t cpuClock; std::map<std::string, clock_t> clocks;
#endif #endif
//! CPU-Communication clock //! Timer
#if (defined USEMPI && !defined CUDA) std::map<std::string, double> timer;
double cpuCommClock;
#else
clock_t cpuCommClock;
#endif
//! CPU time
double cpuTime;
//! CPU and communication time
double cpuCommTime;
//! wall clock time: cpu, communication, IO //! wall clock time: cpu, communication, IO
double wallClockTime; double wallClockTime;
...@@ -178,8 +169,6 @@ class tools::Logger { ...@@ -178,8 +169,6 @@ class tools::Logger {
midDelimiter(i_midDelimiter), midDelimiter(i_midDelimiter),
largeDelimiter(i_largeDelimiter), largeDelimiter(i_largeDelimiter),
indentation(i_indentation) { indentation(i_indentation) {
//set time to zero
cpuTime = cpuCommTime = wallClockTime = 0.;
#ifndef USEMPI #ifndef USEMPI
// Since we have one static logger, we do not know the MPI rank in this // Since we have one static logger, we do not know the MPI rank in this
...@@ -427,40 +416,30 @@ class tools::Logger { ...@@ -427,40 +416,30 @@ class tools::Logger {
} }
/** /**
* Update the CPU time. * Update a timer
*
* @param i_name Name of timer
*/ */
void updateCpuTime() { void updateTime(const std::string &i_name) {
// If the timer does not yet exist it will be initialized with 0 by std::map
// Works only with [] no with .at()
#if (defined USEMPI && !defined CUDA) #if (defined USEMPI && !defined CUDA)
cpuTime += MPI_Wtime() - cpuClock; timer[i_name] += MPI_Wtime() - clocks.at(i_name);
#else #else
cpuTime += (clock() - cpuClock)/(double)CLOCKS_PER_SEC; timer[i_name] += (clock() - clocks.at(i_name))/(double)CLOCKS_PER_SEC;
#endif #endif
} }
/** /**
* Update the CPU-Communication time. * Reset a clock to the current time
*
* @param i_name Name of timer/clock
*/ */
void updateCpuCommunicationTime() { void resetClockToCurrentTime(const std::string &i_name) {
#if (defined USEMPI && !defined CUDA)
cpuCommTime += MPI_Wtime() - cpuCommClock;
#else
cpuCommTime += (clock() - cpuCommClock)/(double)CLOCKS_PER_SEC;
#endif
}
void resetCpuClockToCurrentTime() {
#if (defined USEMPI && !defined CUDA) #if (defined USEMPI && !defined CUDA)
cpuClock = MPI_Wtime(); clocks[i_name] = MPI_Wtime();
#else #else
cpuClock = clock(); clocks[i_name] = clock();
#endif
}
void resetCpuCommunicationClockToCurrentTime() {
#if (defined USEMPI && !defined CUDA)
cpuCommClock = MPI_Wtime();
#else
cpuCommClock = clock();
#endif #endif
} }
...@@ -487,25 +466,15 @@ class tools::Logger { ...@@ -487,25 +466,15 @@ class tools::Logger {
} }
/** /**
* Print elapsed CPU time. * Print elapsed time.
*
* @param i_cpuTimeMessage cpu time message.
*/
void printCpuTime(const std::string i_cpuTimeMessage = "CPU time" ) {
timeCout() << indentation << "process " << processRank << " - "
<< i_cpuTimeMessage << ": "
<< cpuTime << " seconds"<< std::endl;
}
/**
* Print elapsed CPU + communication time.
* *
* @param i_cpuCommunicationTimeMessage CPU + communication time message. * @param i_name Name of the timer
* @param i_message time message.
*/ */
void printCpuCommunicationTime( const std::string i_cpuCommunicationTimeMessage = "CPU + communication time" ) { void printTime(const std::string &i_name, const std::string &i_message ) {
timeCout() << indentation << "process " << processRank << " - " timeCout() << indentation << "process " << processRank << " - "
<< i_cpuCommunicationTimeMessage << ": " << i_message << ": "
<< cpuCommTime << " seconds"<< std::endl; << timer.at(i_name) << " seconds"<< std::endl;
} }
/** /**
...@@ -523,7 +492,7 @@ class tools::Logger { ...@@ -523,7 +492,7 @@ class tools::Logger {
} }
public: public:
/** The logger all classes shoud use */ /** The logger all classes should use */
static Logger logger; static Logger logger;
}; };
......
/**
* @file
* This file is part of SWE.
*
* @author Sebastian Rettenberger (rettenbs AT in.tum.de, http://www5.in.tum.de/wiki/index.php/Sebastian_Rettenberger,_M.Sc.)
*
* @section LICENSE
*
* SWE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SWE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SWE. If not, see <http://www.gnu.org/licenses/>.
*
*
* @section DESCRIPTION
*
* Command line argument parser
*/
#ifndef TOOLS_ARGS_H
#define TOOLS_ARGS_H
#include <getopt.h>
#include <algorithm>
#include <map>
#include <iomanip>
#include <string>
#include <sstream>
#include <vector>
namespace tools
{
/**
* Parses command line arguments
*/
class Args
{
private:
struct optionInfo {
std::string longOption; // We need a copy here to get the const char* correct
/** Name of the value in the help command */
std::string value;
std::string description;
bool required;
};
/**
* Convert a long option into an "argument" that is shown in the help message
*/
struct valueConvert {
void operator()(char& c)
{
c = toupper(static_cast<unsigned char>(c));
switch (c) {
case '-':
c = '_';
break;
}
}
};
/** Program description (can be empty) */
const std::string m_description;
/** Automatically add help option */
const bool m_addHelp;
/** The command line arguments */
std::vector<struct option> m_options;
/**
* Additional information for the command line arguments
* required to generate help information
*/
std::vector<optionInfo> m_optionInfo;
/** Maps from short option to index in m_options */
std::map<char, size_t> m_short2option;
/** Contains the arguments after parse was called */
std::map<std::string, std::string> m_arguments;
public:
enum Argument
{
Required = required_argument,
No = no_argument,
Optional = optional_argument
};
enum Result
{
Success = 0,
Error,
/** Help message printed */
Help
};
public:
Args(const std::string &description = "", bool addHelp = true)
: m_description(description),
m_addHelp(addHelp)
{
}
void addOption(const std::string &longOption,
char shortOption = 0,
const std::string& description = "",
Argument argument = Required,
bool required = true)
{
std::string value;
if (shortOption)
m_short2option[shortOption] = m_options.size();
if (argument != No) {
value = longOption;
for_each(value.begin(), value.end(), valueConvert());
}
struct optionInfo i = {longOption, value, description, required};
m_optionInfo.push_back(i);
struct option o = {m_optionInfo.back().longOption.c_str(), argument, 0, shortOption};
m_options.push_back(o);
}
/**
* @return True of options are successfully parsed, false otherwise
*/
Result parse(int argc, char* const* argv, bool printHelp = true)
{
if (m_addHelp)
addOption("help", 'h', "Show this help message", No, false);
std::ostringstream shortOptions;
for (std::vector<struct option>::const_iterator i = m_options.begin();
i != m_options.end(); i++) {
if (i->val != 0) {
shortOptions << static_cast<char>(i->val);
switch (i->has_arg)
{
case required_argument:
shortOptions << ':';
break;
case optional_argument:
shortOptions << "::";
break;
}
}
}
// Add null option
struct option o = {0, 0, 0, 0};
m_options.push_back(o);
while (true) {
int optionIndex = 0;
int c = getopt_long(argc, argv, shortOptions.str().c_str(),
&m_options[0], &optionIndex);
if (c < 0)
break;
switch (c) {
case '?':
if (printHelp)
helpMessage(argv[0], std::cerr);
return Error;
case 0:
// Nothing to do
break;
default:
optionIndex = m_short2option.at(c);
}
if (optarg == 0L)
m_arguments[m_options[optionIndex].name] = "";
else
m_arguments[m_options[optionIndex].name] = optarg;
}
if (m_addHelp && isSet("help")) {
if (printHelp)
helpMessage(argv[0]);
return Help;
}
for (std::vector<optionInfo>::const_iterator i = m_optionInfo.begin();
i != m_optionInfo.end(); i++) {
if (i->required && !isSet(i->longOption)) {
if (printHelp) {
std::cerr << argv[0] << ": option --" << i->longOption << " is required" << std::endl;
helpMessage(argv[0], std::cerr);
}
return Error;
}
}
return Success;
}
bool isSet(const std::string &option)
{
return m_arguments.find(option) != m_arguments.end();
}
template<typename T>
T getArgument(const std::string &option)
{
std::istringstream ss(m_arguments.at(option));
T result;
ss >> result;
return result;
}
template<typename T>
T getArgument(const std::string &option, T defaultArgument)
{
if (!isSet(option))
return defaultArgument;
return getArgument<T>(option);
}
void helpMessage(const char* prog, std::ostream &out = std::cout)
{
// First line with all short options
out << "Usage: " << prog;
for (size_t i = 0; i < m_options.size()-1; i++) {
out << ' ';
if (!m_optionInfo[i].required)
out << '[';
if (m_options[i].val != 0)
out << '-' << static_cast<char>(m_options[i].val);
else
out << "--" << m_options[i].name;
argumentInfo(i, out);
if (!m_optionInfo[i].required)
out << ']';
}
out << std::endl;
// General program description
if (!m_description.empty())
out << std::endl << m_description << std::endl;
// Optional arguments
out << std::endl << "optional arguments:" << std::endl;
for (size_t i = 0; i < m_options.size()-1; i++) {
out << " ";
// Number of characters used for the option
size_t length = 2;
if (m_options[i].val != 0) {
out << '-' << static_cast<char>(m_options[i].val);
out << ", ";
length += 4;
}
out << "--" << m_options[i].name;
length += m_optionInfo[i].longOption.size() + 2;
length += argumentInfo(i, out);
if (length >= 30) {
out << std::endl;
out << std::setw(30) << ' ';
} else
out << std::setw(30-length) << ' ';
out << m_optionInfo[i].description << std::endl;
}
}
private:
/**
* Writes the argument information to out
*
* @param i The index of the option for which the argument should be generated
* @return The number if characters written
*/
size_t argumentInfo(size_t i, std::ostream &out)
{
switch (m_options[i].has_arg) {
case required_argument:
out << ' ' << m_optionInfo[i].value;
return m_optionInfo[i].value.size() + 1;
case optional_argument:
out << " [" << m_optionInfo[i].value << ']';
return m_optionInfo[i].value.size() + 3;
}
return 0;
}
};
template<> inline
std::string tools::Args::getArgument(const std::string &option)
{
return m_arguments.at(option);
}
}
#endif // TOOLS_ARGS_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment