bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch) { /* Process any command-line options */ int nParamCnt = argc - 1; const char** args = argv + 1; // create targets vector<Target> vTargets; int iFirstFile = -1; for (int i = 1; i < argc; i++) { if (argv[i][0] != '-' && argv[i][0] != '/') { iFirstFile = i; Target target; target.SetPath(argv[i]); vTargets.push_back(target); } } // find block size (other parameters may be stated in terms of blocks) for (int x = 1; x < argc; ++x) { if ((nullptr != argv[x]) && (('-' == argv[x][0]) || ('/' == argv[x][0])) && ('b' == argv[x][1]) && ('\0' != argv[x][2])) { _dwBlockSize = 0; UINT64 ullBlockSize; if (_GetSizeInBytes(&argv[x][2], ullBlockSize)) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { // TODO: UINT64->DWORD i->SetBlockSizeInBytes((DWORD)ullBlockSize); } } else { fprintf(stderr, "Invalid block size passed to -b\n"); exit(1); } _dwBlockSize = (DWORD)ullBlockSize; break; } } TimeSpan timeSpan; bool bExit = false; while (nParamCnt) { const char* arg = *args; bool fError = false; // check if it is a parameter or already path if ('-' != *arg && '/' != *arg) { break; } // skip '-' or '/' ++arg; if ('\0' == *arg) { fprintf(stderr, "Invalid option\n"); exit(1); } switch (*arg) { case '?': _DisplayUsageInfo(argv[0]); exit(0); case 'a': //affinity //-a1,2,3,4 (assign threads to cpus 1,2,3,4 (round robin)) if (!_ParseAffinity(arg, &timeSpan)) { fError = true; } break; case 'b': //block size // nop - block size has been taken care of before the loop break; case 'B': //base file offset (offset from the beggining of the file), cannot be used with 'random' if (*(arg + 1) != '\0') { UINT64 cb; if (_GetSizeInBytes(arg + 1, cb)) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetBaseFileOffsetInBytes(cb); } } else { fprintf(stderr, "Invalid base file offset passed to -B\n"); fError = true; } } else { fError = true; } break; case 'c': //create file of the given size if (*(arg + 1) != '\0') { UINT64 cb; if (_GetSizeInBytes(arg + 1, cb)) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetFileSize(cb); i->SetCreateFile(true); } } else { fprintf(stderr, "Invalid file size passed to -c\n"); fError = true; } } else { fError = true; } break; case 'C': //cool down time { int c = atoi(arg + 1); if (c >= 0) { timeSpan.SetCooldown(c); } else { fError = true; } } break; case 'd': //duration { int x = atoi(arg + 1); if (x > 0) { timeSpan.SetDuration(x); } else { fError = true; } } break; case 'D': //standard deviation { timeSpan.SetCalculateIopsStdDev(true); int x = atoi(arg + 1); if (x > 0) { timeSpan.SetIoBucketDurationInMilliseconds(x); } } break; case 'e': //etw if (!_ParseETWParameter(arg, pProfile)) { fError = true; } break; case 'f': if ('r' == *(arg + 1)) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetRandomAccessHint(true); } } else if ('s' == *(arg + 1)) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetSequentialScanHint(true); } } else { if (*(arg + 1) != '\0') { UINT64 cb; if (_GetSizeInBytes(arg + 1, cb)) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetMaxFileSize(cb); } } else { fprintf(stderr, "Invalid max file size passed to -f\n"); fError = true; } } else { fError = true; } } break; case 'F': //total number of threads { int c = atoi(arg + 1); if (c > 0) { timeSpan.SetThreadCount(c); } else { fError = true; } } break; case 'g': //throughput in bytes per millisecond { int c = atoi(arg + 1); if (c > 0) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetThroughput(c); } } else { fError = true; } } break; case 'h': //disable both software and hardware caching for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetDisableAllCache(true); } break; case 'i': //number of IOs to issue before think time { int c = atoi(arg + 1); if (c > 0) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetBurstSize(c); i->SetUseBurstSize(true); } } else { fError = true; } } break; case 'j': //time to wait between bursts of IOs { int c = atoi(arg + 1); if (c > 0) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetThinkTime(c); i->SetEnableThinkTime(true); } } else { fError = true; } } break; case 'I': //io priority { int x = atoi(arg + 1); if (x > 0 && x < 4) { PRIORITY_HINT hint[] = { IoPriorityHintVeryLow, IoPriorityHintLow, IoPriorityHintNormal }; for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetIOPriorityHint(hint[x - 1]); } } else { fError = true; } } break; case 'l': //large pages for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetUseLargePages(true); } break; case 'L': //measure latency timeSpan.SetMeasureLatency(true); break; case 'n': //disable affinity (by default simple affinity is turned on) timeSpan.SetDisableAffinity(true); break; case 'o': //request count (1==synchronous) { int c = atoi(arg + 1); if (c > 0) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetRequestCount(c); } } else { fError = true; } } break; case 'p': //start async IO operations with the same offset //makes sense only for -o2 and greater for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetUseParallelAsyncIO(true); } break; case 'P': //show progress every x IO operations { int c = atoi(arg + 1); if (c < 1) { c = 65536; } pProfile->SetProgress(c); } break; case 'r': //random access { UINT64 cb = _dwBlockSize; if (*(arg + 1) != '\0') { if (!_GetSizeInBytes(arg + 1, cb) || (cb == 0)) { fprintf(stderr, "Invalid alignment passed to -r\n"); fError = true; } } if (!fError) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetUseRandomAccessPattern(true); i->SetBlockAlignmentInBytes(cb); } } } break; case 'R': //custom result parser if (0 != *(arg + 1)) { const char* pszArg = arg + 1; if (strcmp(pszArg, "xml") == 0) { pProfile->SetResultsFormat(ResultsFormat::Xml); } else if (strcmp(pszArg, "text") != 0) { fError = true; fprintf(stderr, "Invalid results format: '%s'.\n", pszArg); } } else { fError = true; } break; case 's': //stride size { int idx = 1; if ('i' == *(arg + idx)) { // do interlocked sequential mode // ISSUE-REVIEW: this does nothing if -r is specified // ISSUE-REVIEW: this does nothing if -p is specified // ISSUE-REVIEW: this does nothing if we are single-threaded for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetUseInterlockedSequential(true); } idx++; } if (*(arg + idx) != '\0') { UINT64 cb; if (_GetSizeInBytes(arg + idx, cb)) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetBlockAlignmentInBytes(cb); } } else { fprintf(stderr, "Invalid stride size passed to -s\n"); fError = true; } } } break; case 'S': //disable OS caching (software buffering) //IMPORTANT: File access must begin at byte offsets within the file that are integer multiples of the volume's sector size. // File access must be for numbers of bytes that are integer multiples of the volume's sector size. For example, if the sector // size is 512 bytes, an application can request reads and writes of 512, 1024, or 2048 bytes, but not of 335, 981, or 7171 bytes. // Buffer addresses for read and write operations should be sector aligned (aligned on addresses in memory that are integer // multiples of the volume's sector size). Depending on the disk, this requirement may not be enforced. for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetDisableOSCache(true); } break; case 't': //number of threads per file { int c = atoi(arg + 1); if (c > 0) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetThreadsPerFile(c); } } else { fError = true; } } break; case 'T': //offsets between threads reading the same file { UINT64 cb; if (_GetSizeInBytes(arg + 1, cb) && (cb > 0)) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetThreadStrideInBytes(cb); } } else { fprintf(stderr, "Invalid offset passed to -T\n"); fError = true; } } break; case 'v': //verbose mode pProfile->SetVerbose(true); break; case 'w': //write test [default=read] { int c = -1; if (*(arg + 1) == '\0') { c = _ulWriteRatio; } else { c = atoi(arg + 1); if (c < 0 || c > 100) { c = -1; fError = true; } } if (c != -1) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetWriteRatio(c); } } } break; case 'W': //warm up time { int c = atoi(arg + 1); if (c >= 0) { timeSpan.SetWarmup(c); } else { fError = true; } } break; case 'x': //completion routines timeSpan.SetCompletionRoutines(true); break; case 'y': //external synchronization switch (*(arg + 1)) { case 's': _hEventStarted = CreateEvent(NULL, TRUE, FALSE, arg + 2); if (NULL == _hEventStarted) { fprintf(stderr, "Error creating/opening start notification event: '%s'\n", arg + 2); exit(1); // TODO: this class shouldn't terminate the process } break; case 'f': _hEventFinished = CreateEvent(NULL, TRUE, FALSE, arg + 2); if (NULL == _hEventFinished) { fprintf(stderr, "Error creating/opening finish notification event: '%s'\n", arg + 2); exit(1); // TODO: this class shouldn't terminate the process } break; case 'r': synch->hStartEvent = CreateEvent(NULL, TRUE, FALSE, arg + 2); if (NULL == synch->hStartEvent) { fprintf(stderr, "Error creating/opening wait-for-start event: '%s'\n", arg + 2); exit(1); // TODO: this class shouldn't terminate the process } break; case 'p': synch->hStopEvent = CreateEvent(NULL, TRUE, FALSE, arg + 2); if (NULL == synch->hStopEvent) { fprintf(stderr, "Error creating/opening force-stop event: '%s'\n", arg + 2); exit(1); // TODO: this class shouldn't terminate the process } break; case 'e': { HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, arg + 2); if (NULL == hEvent) { fprintf(stderr, "Error opening event '%s'\n", arg + 2); exit(1); // TODO: this class shouldn't terminate the process } if (!SetEvent(hEvent)) { fprintf(stderr, "Error setting event '%s'\n", arg + 2); exit(1); // TODO: this class shouldn't terminate the process } CloseHandle(hEvent); printf("Succesfully set event: '%s'\n", arg + 2); bExit = true; break; } default: fError = true; } case 'z': //random seed if (*(arg + 1) == '\0') { timeSpan.SetRandSeed((ULONG)GetTickCount64()); } else { int c = atoi(arg + 1); if (c >= 0) { timeSpan.SetRandSeed(c); } else { fError = true; } } break; case 'Z': //zero write buffers if (*(arg + 1) == '\0') { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetZeroWriteBuffers(true); } } else { UINT64 cb = 0; string sPath; if (_GetRandomDataWriteBufferData(string(arg + 1), cb, sPath) && (cb > 0)) { for (auto i = vTargets.begin(); i != vTargets.end(); i++) { i->SetRandomDataWriteBufferSize(cb); i->SetRandomDataWriteBufferSourcePath(sPath); } } else { fprintf(stderr, "Invalid size passed to -Z\n"); fError = true; } } break; default: fprintf(stderr, "Invalid option: '%s'\n", arg); exit(1); // TODO: this class shouldn't terminate the process } if (fError) { fprintf(stderr, "Incorrectly provided option: '%s'\n", arg); exit(1); // TODO: this class shouldn't terminate the process } --nParamCnt; ++args; } // // exit if a user specified an action which was already satisfied and doesn't require running test // if (bExit) { printf("Now exiting...\n"); exit(1); // TODO: this class shouldn't terminate the process } if (vTargets.size() < 1) { fprintf(stderr, "You need to provide at least one filename\n"); return false; } for (auto i = vTargets.begin(); i != vTargets.end(); i++) { timeSpan.AddTarget(*i); } pProfile->AddTimeSpan(timeSpan); return true; }
int main (void) { PtSet set1 = NULL, set2 = NULL, set3 = NULL; char filename[21], car; int st; system ("clear"); printf ("\nLer conjunto do ficheiro - Read set from a text file\n"); do { printf ("Nome do ficheiro (Filename) -> "); st = scanf ("%20[^\n]", filename); scanf ("%*[^\n]"); scanf ("%*c"); } while (st == 0); set1 = SetCreateFile (filename); printf ("\nConjunto lido do ficheiro - Set acquired from text file %s\n", filename); WriteSet (set1); printf ("\nLer conjunto do teclado [# para terminar] - Read set from keyboard [# to stop]\n"); set2 = SetCreate (); do { do { printf ("Elemento do conjunto (Set's element) ? "); st = scanf ("%c", &car); scanf ("%*[^\n]"); scanf ("%*c"); } while (st == 0); car = toupper (car); if (isupper(car)) SetInsertElement (set2, car); } while (car != '#'); printf ("\nConjunto lido do teclado - Set acquired from keyboard\n"); WriteSet (set2); printf ("\nEscrever conjunto no ficheiro - Storing the set in a text file\n"); do { printf ("Nome do ficheiro (Filename) -> "); st = scanf ("%20[^\n]", filename); scanf ("%*[^\n]"); scanf ("%*c"); } while (st == 0); SetStoreFile (set2, filename); set3 = SetReunion (set1, set2); printf ("\nConjunto Reuniao - Union set\n"); WriteSet (set3); SetDestroy (&set3); set3 = SetIntersection (set1, set2); printf ("\nConjunto Interseccao - Intersection set\n"); WriteSet (set3); SetDestroy (&set3); set3 = SetSymmetricDifference (set1, set2); printf ("\nConjunto Diferença - Symmetric Difference set\n"); WriteSet (set3); printf ("\nDestruir os conjuntos - Releasing the sets\n"); SetDestroy (&set1); SetDestroy (&set2); SetDestroy (&set3); WriteSet (set3); return 0; }