#include "../lib/helper.h" int stringToInt(char *string) { char *leftover = ""; errno = 0; int x = strtold(string, &leftover); if (*leftover != '\0' || leftover == string) { errno = EINVAL; return -1; } if (errno == ERANGE) { printf("Number is too large or too small!\n"); errno = EINVAL; return -1; } errno = 0; return x; } void help(char *progname) { fprintf(stdout, "Usage: %s [options...] \n\ -V, --version use a specific implementation\n\ -B, --benchmark [repetitons] benchmark the execution and optionally repeat it\n\ -T, --test run self-test. If set, no file is needed\n\ -h, --help print this help page\n\ \n\ is an integer between 0 and 4.\n\ 0: naive implementation\n\ 1: optimized implementation\n\ 2: memory efficient implementation\n\ 3: threaded implementation\n\ 4: reference implementation\n" #ifdef MD2_DETAILED_BENCHMARK "\n\ \n\033[1;33mWARNING: Detailed benchmarking is enabled. This will show detailed benchmaring results\n\ after each hash calculation but will decrease the overall performance.\033[0m" #endif // MD2_DETAILED_BENCHMARK "\n", progname); } enum argumentParseResult parseArguments(int argc, char **argv, struct configuration *c) { if (c == NULL) { return RESULT_EXIT_FAILURE; } c->implementationToUse = 0; c->doBenchmark = false; c->benchmarkingCycles = 1; c->runTests = false; int opt; while (1) { static struct option longOptions[] = { {"version", required_argument, NULL, 'V'}, {"benchmark", optional_argument, NULL, 'B'}, {"test", optional_argument, NULL, 'T'}, {"help", no_argument, NULL, 'h'}, {NULL}}; int longOptionIndex = 0; opt = getopt_long(argc, argv, "V:B::Th", longOptions, &longOptionIndex); if (-1 == opt) break; switch (opt) { case 'B': c->doBenchmark = true; if (optarg != NULL) { c->benchmarkingCycles = stringToInt(optarg); if (errno == 0) break; fprintf(stderr, "%s: invalid argument, has to be int -- 'B' got '%s'\n", argv[0], optarg); return RESULT_EXIT_FAILURE; } break; case 'V': c->implementationToUse = stringToInt(optarg); if (errno == 0) break; fprintf(stderr, "%s: invalid argument, has to be int -- 'V' got '%s'\n", argv[0], optarg); return RESULT_EXIT_FAILURE; case 'T': c->runTests = true; break; case 'h': help(argv[0]); return RESULT_EXIT_SUCCESS; default: return RESULT_EXIT_FAILURE; } } if (argc > optind) { c->filename = argv[optind]; } else if (!c->runTests) { fprintf(stderr, "%s: missing poisional argument -- 'file'\n", argv[0]); return RESULT_EXIT_FAILURE; } return RESULT_OK; } double current_time() { struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); return t.tv_sec + t.tv_nsec * 1e-9; } double run_benchmark(unsigned cycles, md2_hash_func func, size_t len, uint8_t *buf, uint8_t *out) { double start = current_time(); for (; cycles > 0; cycles--) { func(len, buf, out); } double end = current_time(); return end - start; }