diff --git a/doc/USER_GUIDE b/doc/USER_GUIDE index bb265dd..1a211ef 100644 --- a/doc/USER_GUIDE +++ b/doc/USER_GUIDE @@ -142,6 +142,7 @@ These options are to be used on the command line. E.g., 'IOR -a POSIX -b 4K'. -k keepFile -- don't remove the test file(s) on program exit -K keepFileWithError -- keep error-filled file(s) after data-checking -l storeFileOffset -- use file offset as stored signature + -M S memoryPerNode -- hog memory on the node -m multiFile -- use number of reps (-i) for multiple file count -n noFill -- no fill in HDF5 file creation -N N numTasks -- number of tasks that should participate in the test @@ -304,6 +305,15 @@ GENERAL: file [0=FALSE] NOTE: this will affect performance measurements + * memoryPerNode - Allocate memory on each node to simulate real + application memory usage. Accepts a percentage of + node memory (e.g. "50%") on machines that support + sysconf(_SC_PHYS_PAGES) or a size. Allocation will + be split between tasks that share the node. + + * memoryPerTask - Allocate secified amount of memory per task to + simulate real application memory usage. + * maxTimeDuration - max time in minutes to run tests [0] NOTES: * setting this to zero (0) unsets this option * this option allows the current read/write diff --git a/src/ior.c b/src/ior.c index 9ed1389..f7added 100644 --- a/src/ior.c +++ b/src/ior.c @@ -68,7 +68,6 @@ static char *CheckTorF(char *); static size_t CompareBuffers(void *, void *, size_t, IOR_offset_t, IOR_param_t *, int); static int CountErrors(IOR_param_t *, int, int); -static int CountTasksPerNode(int, MPI_Comm); static void *CreateBuffer(size_t); static void DelaySecs(int); static void DestroyTests(IOR_test_t *tests_head); @@ -89,8 +88,6 @@ static void PrintHeader(int argc, char **argv); static void ReadCheck(void *, void *, void *, void *, IOR_param_t *, IOR_offset_t, IOR_offset_t, IOR_offset_t *, IOR_offset_t *, int, int *); -static void ReduceIterResults(IOR_test_t *test, double **timer, - int rep, int access); static void RemoveFile(char *, int, IOR_param_t *); static void SetupXferBuffers(void **, void **, void **, IOR_param_t *, int, int); @@ -1542,10 +1539,14 @@ static void ShowSetup(IOR_param_t *params) } fprintf(stdout, "\tclients = %d (%d per node)\n", params->numTasks, params->tasksPerNode); - fprintf(stdout, "\tmemoryPerTask = %s\n", - HumanReadable(params->memoryPerTask, BASE_TWO)); - fprintf(stdout, "\trepetitions = %d\n", params->repetitions); - fprintf(stdout, "\txfersize = %s\n", + if (params->memoryPerTask != 0) + printf("\tmemoryPerTask = %s\n", + HumanReadable(params->memoryPerTask, BASE_TWO)); + if (params->memoryPerNode != 0) + printf("\tmemoryPerNode = %s\n", + HumanReadable(params->memoryPerNode, BASE_TWO)); + printf("\trepetitions = %d\n", params->repetitions); + printf("\txfersize = %s\n", HumanReadable(params->transferSize, BASE_TWO)); fprintf(stdout, "\tblocksize = %s\n", HumanReadable(params->blockSize, BASE_TWO)); @@ -1588,6 +1589,7 @@ static void ShowTest(IOR_param_t * test) fprintf(stdout, "\t%s=%s\n", "options", test->options); fprintf(stdout, "\t%s=%d\n", "nodes", test->nodes); fprintf(stdout, "\t%s=%lu\n", "memoryPerTask", (unsigned long) test->memoryPerTask); + fprintf(stdout, "\t%s=%lu\n", "memoryPerNode", (unsigned long) test->memoryPerNode); fprintf(stdout, "\t%s=%d\n", "tasksPerNode", tasksPerNode); fprintf(stdout, "\t%s=%d\n", "repetitions", test->repetitions); fprintf(stdout, "\t%s=%d\n", "multiFile", test->multiFile); @@ -1865,7 +1867,7 @@ static void *malloc_and_touch(size_t size) buf = (char *)malloc(size); if (buf == NULL) - ERR("malloc failed"); + return NULL; for (ptr = buf; ptr < buf+size; ptr += page_size) { *ptr = (char)1; @@ -1874,6 +1876,35 @@ static void *malloc_and_touch(size_t size) return (void *)buf; } +/* + * hog some memory as a rough simulation of a real application's memory use + */ +static void *HogMemory(IOR_param_t *params) +{ + size_t size; + void *buf; + + if (params->memoryPerTask != 0) { + size = params->memoryPerTask; + } else if (params->memoryPerNode != 0) { + if (verbose >= VERBOSE_3) + fprintf(stderr, "This node hogging %ld bytes of memory\n", + params->memoryPerNode); + size = params->memoryPerNode / params->tasksPerNode; + } else { + return NULL; + } + + if (verbose >= VERBOSE_3) + fprintf(stderr, "This task hogging %ld bytes of memory\n", size); + + buf = malloc_and_touch(size); + if (buf == NULL) + ERR("malloc of simulated applciation buffer failed"); + + return buf; +} + /* * Using the test parameters, run iteration(s) of single test. */ @@ -1942,9 +1973,7 @@ static void TestIoSys(IOR_test_t *test) if (rank == 0 && verbose >= VERBOSE_0) ShowSetup(params); - /* hog some memory as a rough simulation of a real application's - memory use */ - hog_buf = malloc_and_touch(params->memoryPerTask); + hog_buf = HogMemory(params); startTime = GetTimeStamp(); maxTimeDuration = params->maxTimeDuration * 60; /* convert to seconds */ diff --git a/src/ior.h b/src/ior.h index 8d65652..be62897 100644 --- a/src/ior.h +++ b/src/ior.h @@ -95,7 +95,8 @@ typedef struct int randomSeed; /* random seed for write/read check */ int randomOffset; /* access is to random offsets */ MPI_Comm testComm; /* MPI communicator */ - size_t memoryPerTask; /* additional memory used per task */ + size_t memoryPerTask; /* additional memory used per task */ + size_t memoryPerNode; /* additional memory used per node */ /* POSIX variables */ int singleXferAttempt; /* do not retry transfer if incomplete */ diff --git a/src/parse_options.c b/src/parse_options.c index 520dcbb..2e001d2 100644 --- a/src/parse_options.c +++ b/src/parse_options.c @@ -21,10 +21,63 @@ #include "ior.h" #include "aiori.h" #include "parse_options.h" -#include "utilities.h" IOR_param_t initialTestParams; +/* + * Takes a string of the form 64, 8m, 128k, 4g, etc. and converts to bytes. + */ +static IOR_offset_t StringToBytes(char *size_str) +{ + IOR_offset_t size = 0; + char range; + int rc; + + rc = sscanf(size_str, " %lld %c ", &size, &range); + if (rc == 2) { + switch ((int)range) { + case 'k': + case 'K': + size <<= 10; + break; + case 'm': + case 'M': + size <<= 20; + break; + case 'g': + case 'G': + size <<= 30; + break; + } + } else if (rc == 0) { + size = -1; + } + return (size); +} + +static size_t NodeMemoryStringToBytes(char *size_str) +{ + int percent; + int rc; + long page_size; + long num_pages; + long long mem; + + rc = sscanf(size_str, " %d %% ", &percent); + if (rc == 0) + return (size_t)StringToBytes(size_str); + if (percent > 100 || percent < 0) + ERR("percentage must be between 0 and 100"); + + page_size = sysconf(_SC_PAGESIZE); + num_pages = sysconf(_SC_PHYS_PAGES); + if (num_pages == -1) + ERR("sysconf(_SC_PHYS_PAGES) is not supported"); + mem = page_size * num_pages; + + return mem / 100 * percent; +} + static void RecalculateExpectedFileSize(IOR_param_t *params) { params->expectedAggFileSize = @@ -176,6 +229,10 @@ void DecodeDirective(char *line, IOR_param_t *params) params->randomOffset = atoi(value); } else if (strcasecmp(option, "memoryPerTask") == 0) { params->memoryPerTask = StringToBytes(value); + params->memoryPerNode = 0; + } else if (strcasecmp(option, "memoryPerNode") == 0) { + params->memoryPerNode = NodeMemoryStringToBytes(value); + params->memoryPerTask = 0; } else if (strcasecmp(option, "lustrestripecount") == 0) { #ifndef HAVE_LUSTRE_LUSTRE_USER_H ERR("ior was not compiled with Lustre support"); @@ -340,7 +397,7 @@ IOR_test_t *ReadConfigScript(char *scriptName) IOR_test_t *ParseCommandLine(int argc, char **argv) { static const char *opts = - "A:a:b:BcCQ:ZX:d:D:YeEf:FgG:hHi:j:J:IkKlmnN:o:O:pPqrRs:St:T:uU:vVwWxz"; + "A:a:b:BcCQ:ZX:d:D:YeEf:FgG:hHi:j:J:IkKlmM:nN:o:O:pPqrRs:St:T:uU:vVwWxz"; int c, i; static IOR_test_t *tests = NULL; @@ -438,7 +495,8 @@ IOR_test_t *ParseCommandLine(int argc, char **argv) initialTestParams.storeFileOffset = TRUE; break; case 'M': - initialTestParams.memoryPerTask = StringToBytes(optarg); + initialTestParams.memoryPerNode = + NodeMemoryStringToBytes(optarg); break; case 'm': initialTestParams.multiFile = TRUE; diff --git a/src/utilities.h b/src/utilities.h index 41e4de7..1d9768c 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -21,7 +21,6 @@ void OutputToRoot(int, MPI_Comm, char *); int Regex(char *, char *); void ShowFileSystemSize(char *); void DumpBuffer(void *, size_t); -IOR_offset_t StringToBytes(char *); void SeedRandGen(MPI_Comm); #if USE_UNDOC_OPT void CorruptFile(char *, IOR_param_t *, int, int);