gra-projekt/Implementierung/src/helper.c

126 lines
3.3 KiB
C

#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...] <file>\n\
-V, --version <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\
<version> 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;
}