diff --git a/source/utils/adios_iotest/settings.cpp b/source/utils/adios_iotest/settings.cpp index bab37393a8..77dccb606d 100644 --- a/source/utils/adios_iotest/settings.cpp +++ b/source/utils/adios_iotest/settings.cpp @@ -10,6 +10,8 @@ #include "settings.h" +#include +#include #include #include #include @@ -20,6 +22,7 @@ struct option options[] = {{"help", no_argument, NULL, 'h'}, {"appid", required_argument, NULL, 'a'}, {"config", required_argument, NULL, 'c'}, {"decomp", required_argument, NULL, 'd'}, + {"decomp-ratio", required_argument, NULL, 'D'}, {"xml", required_argument, NULL, 'x'}, {"strong-scaling", no_argument, NULL, 's'}, {"weak-scaling", no_argument, NULL, 'w'}, @@ -30,7 +33,7 @@ struct option options[] = {{"help", no_argument, NULL, 'h'}, #endif {NULL, 0, NULL, 0}}; -static const char *optstring = "-hvswtFHa:c:d:x:"; +static const char *optstring = "-hvswtFHa:c:d:D:x:"; size_t Settings::ndigits(size_t n) const { @@ -42,7 +45,8 @@ size_t Settings::ndigits(size_t n) const void Settings::displayHelp() { std::cout - << "Usage: adios_iotest -a appid -c config {-s | -w} -d d1 [d2 .. dN] " + << "Usage: adios_iotest -a appid -c config {-s | -w} {-d d1[,d2,..,dN] " + "| -D r1[,r2,..,rN]}" "[-x " "file]\n" << " -a appID: unique number for each application in the workflow\n" @@ -51,6 +55,13 @@ void Settings::displayHelp() << " d1: number of processes in 1st (slowest) dimension\n" << " dN: number of processes in Nth dimension\n" << " d1*d2*..*dN must equal the number of processes\n" + << " -D ... define process decomposition ratio:\n" + << " r1: ratio of process decomposition in the 1st " + "(slowest) dimension\n" + << " rN: ratio of process decomposition in the Nth " + "dimension\n" + << " r1xr2x..xrN must scale up to process count" + "count without remainder\n" << " -s OR -w: strong or weak scaling. \n" << " Dimensions in config are treated accordingly\n" << " -x file ADIOS configuration XML file\n" @@ -77,10 +88,56 @@ size_t Settings::stringToNumber(const std::string &varName, return retval; } +int Settings::parseCSDecomp(const char *arg) +{ + char *argCopy = (char *)malloc(strlen(arg) * sizeof(*argCopy)); + char *ratio; + + strcpy(argCopy, arg); + ratio = strtok(argCopy, ","); + while (ratio) + { + processDecomp[nDecomp++] = stringToNumber("decomposition ratio", ratio); + ratio = strtok(NULL, ","); + } + + free(argCopy); + + return (0); +} + +int Settings::rescaleDecomp() +{ + size_t ratioProd = 1; + size_t scaleFactor; + + for (size_t i = 0; i < nDecomp; i++) + { + ratioProd *= processDecomp[i]; + } + + for (scaleFactor = 1; ratioProd * pow(scaleFactor, nDecomp) <= nProc; + scaleFactor++) + { + if (ratioProd * pow(scaleFactor, nDecomp) == nProc) + { + for (size_t i = 0; i < nDecomp; i++) + { + processDecomp[i] *= scaleFactor; + } + return (0); + } + } + + throw std::invalid_argument( + "decomposition ratios must scale up to process count"); +} + int Settings::processArgs(int argc, char *argv[]) { bool appIdDefined = false; bool scalingDefined = false; + bool decompDefined = false; int c; int last_c = '_'; @@ -97,9 +154,41 @@ int Settings::processArgs(int argc, char *argv[]) configFileName = optarg; break; case 'd': - processDecomp[nDecomp] = - stringToNumber("decomposition in dimension 1", optarg); - ++nDecomp; + if (decompDefined && isRatioDecomp) + { + throw std::invalid_argument( + "Cannot have -D and -d used at the same time "); + } + if (strchr(optarg, ',')) + { + parseCSDecomp(optarg); + } + else + { + processDecomp[nDecomp] = + stringToNumber("decomposition in dimension 1", optarg); + ++nDecomp; + } + decompDefined = true; + break; + case 'D': + if (decompDefined && !isRatioDecomp) + { + throw std::invalid_argument( + "Cannot have -D and -d used at the same time "); + } + if (strchr(optarg, ',')) + { + parseCSDecomp(optarg); + } + else + { + processDecomp[nDecomp] = + stringToNumber("decomposition in dimension 1", optarg); + ++nDecomp; + } + decompDefined = true; + isRatioDecomp = true; break; case 'F': fixedPattern = true; @@ -146,7 +235,7 @@ int Settings::processArgs(int argc, char *argv[]) /* This means a field is unknown, or could be multiple arg or bad * arg*/ - if (last_c == 'd') + if (last_c == 'd' || last_c == 'D') { // --decomp extra arg (or not if not a number) processDecomp[nDecomp] = stringToNumber( "decomposition in dimension " + std::to_string(nDecomp + 1), @@ -220,6 +309,11 @@ int Settings::processArguments(int argc, char *argv[], MPI_Comm worldComm) MPI_Comm_size(appComm, &nproc); myRank = static_cast(rank); nProc = static_cast(nproc); + + if (isRatioDecomp) + { + rescaleDecomp(); + } } catch (std::exception &e) // command-line argument errors { diff --git a/source/utils/adios_iotest/settings.h b/source/utils/adios_iotest/settings.h index 647dd7aa11..c3b2a4775c 100644 --- a/source/utils/adios_iotest/settings.h +++ b/source/utils/adios_iotest/settings.h @@ -40,6 +40,7 @@ class Settings bool isStrongScaling = true; // strong or weak scaling bool ioTimer = false; // used to measure io time bool fixedPattern = false; // should Lock definitions? + bool isRatioDecomp = false; IOLib iolib = IOLib::ADIOS; // process decomposition std::vector processDecomp = {1, 1, 1, 1, 1, 1, 1, 1, @@ -57,6 +58,8 @@ class Settings int processArguments(int argc, char *argv[], MPI_Comm worldComm); int extraArgumentChecks(); size_t stringToNumber(const std::string &varName, const char *arg) const; + int parseCSDecomp(const char *arg); + int rescaleDecomp(); size_t ndigits(size_t n) const; private: