/* SPDX-License-Identifier: LGPL-2.1-only */ /* Copyright (C) 2020-2021 Gediminas Jakutis */ #include #include #include #include #include #include #include #include "stream.h" #include "defs.h" #include "cache.h" #include "datagen.h" #include "mergesort.h" static struct settings settings = {0, 0, 0, NULL, NULL, mode_normal, array, cached}; static int bench (struct stream * const in, struct stream * const out); static int parseargs(int argc, char **argv, struct settings * settings); static int load_io_functions(struct settings const * const s, struct stream * const in); static void printhelp(const char * const name); static const struct stream stream_blank = { .n = 0, .type = stream_invalid, .fd = -1, .settings = &settings, .name = NULL, .index = 0, .cnode = NULL, .cache = NULL }; static struct stream file_in = stream_blank; static struct stream file_out = stream_blank; static struct stream file_tmp = stream_blank; int main(int argc, char **argv) { int ret = 0; rin_diag_init(); rin_diag_format(rin_diag_info, "C:mn"); file_in.type = stream_in; file_out.type = stream_out; try_s((ret = parseargs(argc, argv, &settings)), early_out); if (settings.opmode == mode_generate) { file_in.type = stream_randread; file_in.n = settings.to; } else { file_in.name = settings.filein; } load_io_functions(&settings, &file_in); file_out.name = settings.fileout ? settings.fileout : settings.filein; try_s((ret = stream_open(&file_in)), out); file_out.n = settings.opmode == mode_normal ? file_in.n : file_in.n - settings.ss; try_s((ret = stream_open(&file_out)), out); load_io_functions(&settings, &file_out); if (settings.access == cached) { try_s((ret = cache_create(&file_in)), out); try_s((ret = cache_populate(&file_in)), out); switch (settings.opmode) { case mode_fetch: if (settings.format == array) { try_s((ret = cache_block_copy(&file_in, &file_out)), out); } else { /* settings.format == list */ try_s((ret = stream_copy_range(&file_in, &file_out)), out); } break; case mode_generate: try_s((ret = cache_transfer(&file_in, &file_out)), out); break; case mode_normal: bench(&file_in, &file_tmp); try_s((ret = cache_transfer(&file_tmp, &file_out)), out); } } else { /* uncached */ /* TODO */ } stream_close(&file_in); stream_close(&file_out); stream_close(&file_tmp); while (0) { out: stream_close(&file_in); file_out.type = stream_invalid; /* in case of error-exit, just close, don't link */ stream_close(&file_out); stream_close(&file_tmp); } early_out: return ret; } static int bench(struct stream * const in, struct stream * const out) { int ret; struct rin_bench_result bongholio; /* BENCHMARK STARTS HERE */ rin_bench_start(); try_s((ret = merge_sort(in, out)), err); /* BENCHMARK ENDS HERE */ rin_bench_stop(&bongholio); rin_info("wall: %lus %3lums %3luµs", bongholio.wall.tv_sec, bongholio.wall.tv_nsec / (1000 * 1000), (bongholio.wall.tv_nsec / 1000) % 1000); rin_info("system: %lus %3lums %3luµs", bongholio.system.tv_sec, bongholio.system.tv_usec / 1000, bongholio.system.tv_usec % 1000); rin_info("user: %lus %3lums %3luµs", bongholio.user.tv_sec, bongholio.user.tv_usec / 1000, bongholio.user.tv_usec % 1000); rin_info("total: %lus %3lums %3luµs", bongholio.total.tv_sec, bongholio.total.tv_usec / 1000, bongholio.total.tv_usec % 1000); err: return ret; } static int parseargs(int argc, char **argv, struct settings * settings) { struct settings s = {0}; ssize_t i; int ret = 0; if (argc < 2) { goto err; } for (i = 1; i < argc - 1; ++i) { if (!(strcmp(argv[i], "--sort"))) { s.opmode = mode_normal; } else if (!(strcmp(argv[i], "--fetch"))) { s.opmode = mode_fetch; } else if (!(strcmp(argv[i], "--generate"))) { s.opmode = mode_generate; } else if (!(strcmp(argv[i], "--array"))) { s.format = array; } else if (!(strcmp(argv[i], "--list"))) { s.format = list; } else if (!(strcmp(argv[i], "--cache"))) { s.access = cached; } else if (!(strcmp(argv[i], "--no-cache"))) { s.access = direct; } else if (!(strncmp(argv[i], "--position=", 11))) { if (strlen(argv[i]) > 11) { s.ss = strtoul(argv[i] + 11, NULL, 10); } else { goto err; } } else if (!(strncmp(argv[i], "--num=", 6))) { if (strlen(argv[i]) > 6) { s.to = strtoul(argv[i] + 6, NULL, 10); } else { goto err; } } else if (!(strncmp(argv[i], "--out=", 6))) { if (strlen(argv[i]) > 6) { s.fileout = argv[i] + 6; } else { goto err; } } else { goto err; } } if (!strncmp(argv[i], "--", 2)) { goto err; } else { s.filein = argv[i]; } if (!s.fileout) { s.fileout = s.filein; } if (s.opmode == mode_generate) { /* we always generate in-memory for PERFORMANCE */ s.access = cached; } else if (s.opmode == mode_fetch) { s.to = s.ss + s.to; } s.stride = s.format == list ? sizeof(struct entry_l) : sizeof(struct entry); *settings = s; while (0) { err: ret = EINVAL; printhelp(*argv); } return ret; } static int load_io_functions(struct settings const * const s, struct stream * const in) { int ret = 0; if (in->settings->access == cached) { if (in->type == stream_randread) { /* data generation streams only support data generation and not much else */ if (s->format == array) { in->get = gen_get_array; in->put = cached_put_array; } else { /* if (s->format == list */ in->get = gen_get_list; in->put = cached_put_list; } } else { if (s->format == array) { in->get = cached_get_array; in->put = cached_put_array; in->copy = cache_block_copy; } else { /* if (s->format == list */ in->get = cached_get_list; in->put = cached_put_list; in->copy = stream_copy_range; } } } else { ret = ENOSYS; } return ret; } static void printhelp(const char * const name) { printf( "This is a mergesort program and such\n" "\n" "usage:\t%s [OPTION]... FILE" "\n" "Options:\n" " --sort sort mode (default)\n" " --fetch do not sort, fetch element(s) instead\n" " --generate generate an input dataset\n" " --array use an array data format (default)\n" " --list use a linked list data format\n" " --[no]-cache cache data in memory (default) or process data in-place\n" " --position= fetch element from position \n" " --num= of elements to fetch/generate\n" " --out= write output to instead of FILE\n" "\n" "In case more than one same option is provided, the last one take precedence\n" "\n", name); return; }