135
139
TimeHack gTotalWriteTransferTime;
136
140
capacity_t gTotalBytesRead = 0;
137
141
capacity_t gTotalBytesWritten = 0;
142
capacity_t gTotalWriteOps = 0;
143
capacity_t gTotalReadOps = 0;
138
144
TimeHack gProgramStartTime;
139
145
unsigned int gFoundTransferErrors = 0;
142
147
//////////////////////////////////////////////////////////////////////////////
143
148
//////////////////// Function Prototypes ///////////////////////////////////
144
149
//////////////////////////////////////////////////////////////////////////////
145
150
void error_msg(char *fmt, ...);
146
151
void note(char *fmt, ...);
148
bool parse_options(int argc, const char **argv);
153
bool parse_options(int argc, const char **argv, string& cmdArgs);
149
154
bool validate_options();
152
155
void end_program(int exitCode);
153
156
void end_program(int exitCode, char *fmt, ...);
154
157
void update_transfer_totals(const Job *job,
358
365
units = TERABYTES;
361
error_msg("Invalid units - use kKmMgG.\n");
368
error_msg("Invalid unit in argument \"%s\" - use kKmMgG.\n", arg);
362
369
exit(EXIT_ERROR_USAGE);
368
error_msg("Could not parse units.\n");
375
error_msg("Could not parse units in argument \"%s\"\n", arg);
369
376
exit(EXIT_ERROR_USAGE);
382
////////////////////////// parse_rcfile() ///////////////////////////////////
383
bool parse_rcfile(FILE *rcfile,
386
char rcArgs[MAX_TMP_STR_LEN];
388
while (fgets(rcArgs, MAX_TMP_STR_LEN, rcfile) != (char *)NULL)
390
// Chop off string after comment character.
391
char *commentStart = strchr(rcArgs, '#');
393
*commentStart = '\0';
394
len = strlen(rcArgs);
395
if (rcArgs[len - 1] == '\n')
396
rcArgs[len - 1] = '\0';
397
if (rcArgs[0] != '\0')
407
////////////////////////// read_rcfiles() ///////////////////////////////////
408
bool read_rcfiles(int argc, const char **argv, string& cmdArgs)
412
vector<string> rcFilePaths;
415
// Check command-line for --no-rcfiles option.
416
for (int i = 0; i < argc; i++)
418
if (strncmp(argv[i], "--no-rcfiles", strlen("--no-rcfiles")) == 0)
420
gUseStdRcFiles = false;
425
// Read standard config locations.
428
// Read system-wide rcfile if it exists.
429
rcFilePath = QUOTE(SYSCONFDIR);
431
rcFilePath += SYSTEM_SPEWRC_FILENAME;
432
if (stat(rcFilePath.c_str(), &statbuf) >= 0)
434
rcFilePaths.push_back(rcFilePath);
440
error_msg("Cannot access rc file \"%s\" -- %s.\n",
441
rcFilePath.c_str(), strError(errno).c_str());
446
if (getenv(SPEWRC_ENV))
448
rcFilePath = getenv(SPEWRC_ENV);
452
char *home = getenv("HOME");
457
rcFilePath += DEFAULT_SPEWRC_FILENAME;
460
if (stat(rcFilePath.c_str(), &statbuf) >= 0)
462
rcFilePaths.push_back(rcFilePath);
468
error_msg("Cannot access rc file \"%s\" -- %s.\n",
469
rcFilePath.c_str(), strError(errno).c_str());
474
// Check the command-line for --rcfile.
475
for (int i = 1; i < argc; i++)
478
if (strncmp(argv[i], "--rcfile", 8) == 0)
480
char *eqPos = strrchr(argv[i], '=');
481
if (eqPos == (char *)NULL)
485
rcFilePath = argv[i+1];
489
error_msg("Missing RCFILE argument.\n");
495
rcFilePath = eqPos + 1;
497
if (stat(rcFilePath.c_str(), &statbuf) < 0)
499
error_msg("Cannot access RCFILE \"%s\" -- %s.\n",
500
rcFilePath.c_str(), strError(errno).c_str());
504
rcFilePaths.push_back(rcFilePath);
509
vector<string>::iterator pathIter;
510
for (pathIter = rcFilePaths.begin();
511
pathIter != rcFilePaths.end();
514
FILE *rcfile = fopen(pathIter->c_str(), "r");
515
if (rcfile == (FILE *)NULL)
517
error_msg("Cannot open rc file \"%s\" -- %s.\n",
518
pathIter->c_str(), strError(errno).c_str());
522
parse_rcfile(rcfile, cmdArgs);
376
531
////////////////////////// parse_options() /////////////////////////////////
377
bool parse_options(int argc, const char **argv)
532
bool parse_options(int argc, const char **argv, string& cmdArgs)
379
534
char *minBufferSizeArgStr = (char *)NULL;
380
535
char *maxBufferSizeArgStr = (char *)NULL;
412
568
{"iterations", 'i', POPT_ARG_INT, &iterationsArg, 0, "Write/read data COUNT times. If count is 0, repeats forever.", "COUNT"},
413
569
{"logfile", 'l', POPT_ARG_STRING, &logfilePathArgStr, 0, "Send log messages to LOGFILE.", "LOGFILE"},
414
570
{"no-progress", 0, POPT_ARG_NONE, &noProgressArg, 0, "Don't show progess (default).", NULL},
571
{"no-rcfiles", 0, POPT_ARG_NONE, NULL, 0, "Don't use standard rcfiles.", NULL},
572
{"no-statistics", 'q', POPT_ARG_NONE, &noStatisticsArg, 0, "Don't output statistics.", NULL},
415
573
{"no-tui", 0, POPT_ARG_NONE, &noTuiArg, 0, "Don't use TUI interface.", NULL},
416
574
{"offset", 'o', POPT_ARG_STRING, &offsetArgStr, 0, "Seek to OFFSET before starting I/O.", "OFFSET"},
417
575
{"progress", 'P', POPT_ARG_NONE, &progressArg, 0, "Show progess.", NULL},
418
576
{"pattern", 'p', POPT_ARG_STRING, &patternArgStr, 0, "Use data pattern PATTERN when reading or writing data.", "PATTERN"},
419
{"no-statistics", 'q', POPT_ARG_NONE, &noStatisticsArg, 0, "Don't output statistics.", NULL},
420
577
{"random", 'r', POPT_ARG_NONE, &randomArg, 0, "Read/Write buffers to random offsets.", NULL},
421
578
{"raw", 0, POPT_ARG_NONE, &readAfterWriteArg, 0, "An alias for --read-after-write.", NULL},
579
{"rcfile", 0, POPT_ARG_STRING, &dummyArgStr, 0, "Read command-line options from RCFILE.", "RCFILE"},
422
580
{"read", 0, POPT_ARG_NONE, &readArg, 0, "Read date from FILE.", NULL},
423
581
{"read-after-write", 0, POPT_ARG_NONE, &readAfterWriteArg, 0, "Read back data after writing to FILE.", NULL},
424
582
{"seed", 'S', POPT_ARG_LONG, &gSeed, 0, "Use SEED for random number seed.","SEED"},
431
589
{"detailed-statistics", 'v', POPT_ARG_NONE, &detailedStatisticsArg, 0, "Output detailed statistics.", NULL},
432
590
{"write", 0, POPT_ARG_NONE, &writeArg, 0, "Write data to FILE.", NULL},
433
591
{"help", '?', POPT_ARG_NONE, &helpArg, 0, "Show this help and exit.", NULL},
434
{ NULL, 0, 0, NULL, 0 }
437
poptContext context = poptGetContext(gPrgName, argc, argv, optionsTable, 0);
596
if (!read_rcfiles(argc, argv, cmdArgs))
598
for (int i = 1; i < argc; i++)
603
cmdArgs = " " + cmdArgs;
604
cmdArgs = argv[0] + cmdArgs;
606
const char **newArgv;
607
poptParseArgvString((char *)cmdArgs.c_str(), &newArgc, &newArgv);
608
poptContext context = poptGetContext(gPrgName,
612
POPT_CONTEXT_POSIXMEHARDER);
438
614
int rc = poptGetNextOpt(context);
441
error_msg("%s\n", poptStrerror(rc));
619
case POPT_ERROR_BADOPT:
620
error_msg("bad or unknown option \"%s\"\n.",
621
poptBadOption(context, 0));
624
error_msg("%s.\n", poptStrerror(rc));
443
628
poptFreeContext(context);
843
1027
jobTransferTime.getTime(),
844
1028
gTotalBytesRead,
845
1029
gTotalReadTransferTime.getTime(),
846
1031
gTotalBytesWritten,
847
1032
gTotalWriteTransferTime.getTime(),
848
1034
now - gProgramStartTime);
850
1036
long double transferRate = convertCapacity((long double)job->getJobBytesTransferred(), gUnits)/jobTransferTime.getTime();
1037
long double iops = (long double)job->getTotalNumberOfTransfers()/(long double)jobTransferTime.getTime();
852
1039
switch (ioDirection)
855
gLogger->logNote("Iter: %5d Read Transfer rate: %11.2Lf %-5s Transfer time: %s\n",
1042
gLogger->logNote("Iter: %5d RTR: %11.2Lf %-5s TT: %s IOPS: %11.2Lf\n",
858
1045
getTransferRateUnitsStr(gUnits),
859
jobTransferTime.getElapsedTimeStr().c_str());
1046
jobTransferTime.getElapsedTimeStr().c_str(),
862
gLogger->logNote("Iter: %5d Write Transfer rate: %11.2Lf %-5s Transfer time: %s\n",
1050
gLogger->logNote("Iter: %5d WTR: %11.2Lf %-5s TT: %s IOPS: %11.2Lf\n",
865
1053
getTransferRateUnitsStr(gUnits),
866
jobTransferTime.getElapsedTimeStr().c_str());
1054
jobTransferTime.getElapsedTimeStr().c_str(),
876
1065
device = Log::OUTPUT_LOG_STDOUT;
877
1066
if (gVerbosity == VERBOSITY_LONG)
878
1067
device |= Log::OUTPUT_DISPLAY_STDOUT;
1069
TimeHack now(TimeHack::getCurrentTime());
1072
gLogger->note(device, "\n");
1073
gLogger->note(device, "Total iterations: %17u\n",
1075
gLogger->note(device, "Total runtime: %17s\n",
1076
gProgramStartTime.getTimeDiffStr(now).c_str());
1078
if (gTotalBytesWritten > 0)
880
TimeHack now(TimeHack::getCurrentTime());
883
gLogger->note(device, "\n");
884
gLogger->note(device, "Total iterations: %17u\n", iterations);
885
gLogger->note(device, "Total runtime: %17s\n",
886
gProgramStartTime.getTimeDiffStr(now).c_str());
888
if (gTotalBytesWritten > 0)
890
long double writeTransferRate = convertCapacity((long double)gTotalBytesWritten, gUnits)/(long double)gTotalWriteTransferTime.getTime();
891
gLogger->note(device, "Total write transfer time: %17s\n",
892
gTotalWriteTransferTime.getElapsedTimeStr().c_str());
893
gLogger->note(device, "Total write transfer rate: %11.2Lf %-5s\n",
894
writeTransferRate, getTransferRateUnitsStr(gUnits));
896
if (gTotalBytesRead > 0)
1080
long double writeTransferRate = convertCapacity((long double)gTotalBytesWritten, gUnits)/(long double)gTotalWriteTransferTime.getTime();
1081
long double writeIops = (long double)gTotalWriteOps/(long double)gTotalWriteTransferTime.getTime();
1082
gLogger->note(device, "Total write transfer time (WTT): %17s\n",
1083
gTotalWriteTransferTime.getElapsedTimeStr().c_str());
1084
gLogger->note(device, "Total write transfer rate (WTR): %11.2Lf %-5s\n",
1085
writeTransferRate, getTransferRateUnitsStr(gUnits));
1086
gLogger->note(device, "Total write IOPS: %11.2Lf IOPS\n", writeIops);
1089
if (gTotalBytesRead > 0)
899
long double readTransferRate = convertCapacity((long double)gTotalBytesRead, gUnits)/(long double)gTotalReadTransferTime.getTime();
900
gLogger->note(device, "Total read transfer time: %17s\n",
901
gTotalReadTransferTime.getElapsedTimeStr().c_str());
902
gLogger->note(device, "Total read transfer rate: %11.2Lf %-5s\n",
903
readTransferRate, getTransferRateUnitsStr(gUnits));
1092
long double readTransferRate = convertCapacity((long double)gTotalBytesRead, gUnits)/(long double)gTotalReadTransferTime.getTime();
1093
long double readIops = (long double)gTotalReadOps/(long double)gTotalWriteTransferTime.getTime();
1094
gLogger->note(device, "Total read transfer time (RTT): %17s\n",
1095
gTotalReadTransferTime.getElapsedTimeStr().c_str());
1096
gLogger->note(device, "Total read transfer rate (RTR): %11.2Lf %-5s\n",
1097
readTransferRate, getTransferRateUnitsStr(gUnits));
1098
gLogger->note(device, "Total read IOPS: %11.2Lf IOPS\n", readIops);