diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cache.c | 15 | ||||
-rw-r--r-- | src/cache.h | 1 | ||||
-rw-r--r-- | src/defs.h | 10 | ||||
-rw-r--r-- | src/main.c | 74 | ||||
-rw-r--r-- | src/mergesort.c | 32 | ||||
-rw-r--r-- | src/mergesort.h | 1 | ||||
-rw-r--r-- | src/meson.build | 4 | ||||
-rw-r--r-- | src/stream.c (renamed from src/io.c) | 80 | ||||
-rw-r--r-- | src/stream.h (renamed from src/io.h) | 2 |
9 files changed, 148 insertions, 71 deletions
diff --git a/src/cache.c b/src/cache.c index f8a2026..19c5a92 100644 --- a/src/cache.c +++ b/src/cache.c @@ -8,8 +8,8 @@ #include <rin/definitions.h> #include <rin/diagnostic.h> #include "defs.h" - -static int cache_rewind(struct stream * const in); +#include "stream.h" +#include "cache.h" int cache_create(struct stream * const in) { @@ -34,6 +34,7 @@ int cache_populate(struct stream * const in) struct entry_l *tmp; try(in->settings->access != cached, err, EINVAL, "cannot populate cache: stream is uncached"); + try(!in->cache, err, EINVAL, "stream has no cache allocated"); /* if reading a a randstream, fall back to the one-element-at-a-time mode */ if (in->type == stream_randread) { @@ -48,7 +49,7 @@ int cache_populate(struct stream * const in) } } } else if (in->type == stream_in) { - try(1, err, ENOSYS, "populating cache from file is a TODO"); + try_s((ret == stream_readfile(in)), err); } else { try(1, err, EINVAL, "cannot populate a non-reading stream cache"); } @@ -94,7 +95,7 @@ int cache_block_copy(struct stream const * const src, struct stream * const dest try(src->settings->access != cached || dest->settings->access != cached, err, EINVAL, "cannot cache-copy between uncached streams"); try(!src->cache, err, EINVAL, "no cache to transfer"); - try(src->n > dest->settings->to, err, EINVAL, "invalid copy size"); + try(src->n < dest->settings->to, err, EINVAL, "invalid copy size"); try(!dest->cache, err, EINVAL, "no cache to transfer to"); memcpy(dest->cache, src->cache_a + dest->settings->ss, (dest->settings->to - dest->settings->ss) * dest->settings->stride); @@ -135,13 +136,13 @@ int cache_block_split(struct stream * const src, struct stream * const A, struct A->n = src->n / 2; B->n = src->n / 2 + (src->n & 1ul); A->index = B->index = 0; - A->parentid = B->parentid = random(); /* generate random parent ID that needs to match between children */ - A->type = B->type = stream_invalid; /* disallow any stream operations other than split/merge on children */ + A->type = B->type = stream_cache; /* disallow any stream operations other than split/merge on children */ A->fd = B->fd = -1; /* if we're splitting, these are for holding cache only */ /* we only care about these three functions for these temporary streams */ A->get_next_element_cache = B->get_next_element_cache = src->get_next_element_cache; A->place_next_element_cache = B->place_next_element_cache = src->place_next_element_cache; A->split = B->split = src->split; + A->rewind = B->rewind = src->rewind; tmp_settings = *src->settings; A->settings = B->settings = &tmp_settings; @@ -158,7 +159,7 @@ int cache_block_split(struct stream * const src, struct stream * const A, struct try_s((ret = cache_create(B)), err); try_s((ret = cache_block_copy(src, B)), err); - A->settings = B->settings = &tmp_settings; + A->settings = B->settings = src->settings; err: return ret; diff --git a/src/cache.h b/src/cache.h index 63f5560..dc22836 100644 --- a/src/cache.h +++ b/src/cache.h @@ -19,6 +19,7 @@ int cache_block_copy(struct stream const * const src, struct stream * const dest int cache_list_copy(struct stream * const src, struct stream * const dest); int cache_block_split(struct stream * const src, struct stream * const A, struct stream * const B); int cache_list_split(struct stream * const src, struct stream * const A, struct stream * const B); +int cache_rewind(struct stream * const in); /* GET */ struct entry_l *cached_get_array(struct stream * const in); @@ -45,10 +45,6 @@ #define get(in) (in->settings->access == cached ? in->get_next_element_cache(in) : in->get_next_element_direct(in)) #define put(in, data) (in->settings->access == cached ? in->place_next_element_cache(in, data) : in->place_next_element_direct(in, data)) -#define stream_blank .fd = -1, .settings = &settings, .get_next_element_direct = stub_getnext, \ - .get_next_element_cache = stub_getnext, .place_next_element_direct = stub_put, \ - .place_next_element_cache = stub_put, .split = stub_split, .flush = stub_flush - union nextoff { struct entry_l *next; ptrdiff_t offset; @@ -89,15 +85,15 @@ enum dataformat { }; enum streamtype { - stream_invalid = -1, + stream_invalid, stream_in, stream_out, stream_outlite, + stream_cache, stream_randread }; struct stream { - long int parentid; size_t n; int fd; enum streamtype type; @@ -112,7 +108,7 @@ struct stream { int (*place_next_element_direct)(struct stream * const, struct entry_l const * const); int (*place_next_element_cache)(struct stream * const, struct entry_l const * const); int (*split)(struct stream * const, struct stream * const, struct stream * const); - int (*flush)(struct stream * const); + int (*rewind)(struct stream * const); }; struct settings { @@ -8,32 +8,48 @@ #include <stdio.h> #include <string.h> #include <rin/diagnostic.h> -#include "io.h" +#include <rin/time.h> +#include "stream.h" #include "defs.h" #include "cache.h" #include "datagen.h" #include "mergesort.h" -static struct settings settings = {0}; +static struct settings settings = {0, 0, 0, NULL, NULL, mode_normal, array, cached}; static int parseargs(int argc, char **argv, struct settings * settings); -int load_io_functions(struct settings const * const s, struct stream * const in); -void printhelp(const char * const name); -struct entry_l *stub_getnext(struct stream * const restrict in); +static int load_io_functions(struct settings const * const s, struct stream * const in); +static void printhelp(const char * const name); +static struct entry_l *stub_getnext(struct stream * const restrict in); static int stub_put(struct stream * const restrict in, struct entry_l const * const data); static int stub_split(struct stream * const in, struct stream * const a, struct stream * const b); -static int stub_flush(struct stream * const in); -/* these need to go AFTER the stub declarations */ -static struct stream file_in = {stream_blank, .type = stream_in}; -static struct stream file_out = {stream_blank, .type = stream_out}; -static struct stream file_tmp = {stream_blank, .type = stream_outlite}; +static const struct stream stream_blank = { + .n = 0, .type = stream_invalid, .fd = -1, .settings = &settings, + .name = NULL, .index = 0, .pnode = NULL, .cnode = NULL, .cache = NULL, + .get_next_element_direct = stub_getnext, + .get_next_element_cache = stub_getnext, + .place_next_element_direct = stub_put, + .place_next_element_cache = stub_put, .split = stub_split }; + +static struct stream file_in = stream_blank; +static struct stream file_out = stream_blank; +static struct stream file_tmp; + +static struct rin_bench_result bongholio; int main(int argc, char **argv) { int ret = 0; rin_diag_init(); + rin_diag_format(rin_diag_info, "C:mn"); + rin_diag_channel_set_enabled_state(rin_diag_err, 0); + + file_in.type = stream_in; + file_out.type = stream_out; + file_tmp.type = stream_outlite; + try_s((ret = parseargs(argc, argv, &settings)), early_out); if (settings.opmode == mode_generate) { @@ -47,7 +63,7 @@ int main(int argc, char **argv) file_out.name = settings.fileout ? settings.fileout : settings.filein; try_s((ret = stream_open(&file_in)), out); - file_out.n = file_in.n - settings.ss; + 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); @@ -68,8 +84,18 @@ int main(int argc, char **argv) try_s((ret = cache_transfer(&file_in, &file_out)), out); break; case mode_normal: - try_s((ret = cache_create(&file_out)), out); - try_s((ret = merge_sort(&file_in, &file_out)), out); + + /* BENCHMARK STARTS HERE */ + rin_bench_start(); + try_s((ret = merge_sort(&file_in, &file_tmp)), out); + rin_bench_stop(&bongholio); + /* BENCHMARK ENDS HERE */ + rin_info("wall: %lus%6luµs", bongholio.wall.tv_sec, bongholio.wall.tv_nsec / 1000); + rin_info("system: %lus%6luµs", bongholio.system.tv_sec, bongholio.system.tv_usec); + rin_info("user: %lus%6luµs", bongholio.user.tv_sec, bongholio.user.tv_usec); + rin_info("total: %lus%6luµs", bongholio.total.tv_sec, bongholio.total.tv_usec); + + try_s((ret = cache_transfer(&file_tmp, &file_out)), out); } } else { /* uncached */ @@ -78,6 +104,7 @@ int main(int argc, char **argv) stream_close(&file_in); stream_close(&file_out); + stream_close(&file_tmp); while (0) { out: @@ -170,7 +197,7 @@ err: return ret; } -int load_io_functions(struct settings const * const s, struct stream * const in) +static int load_io_functions(struct settings const * const s, struct stream * const in) { int ret = 0; @@ -178,6 +205,8 @@ int load_io_functions(struct settings const * const s, struct stream * const in) if (s->format == array) { in->get_next_element_cache = cached_get_array; in->place_next_element_cache = cached_put_array; + in->split = cache_block_split; + in->rewind = cache_rewind; } else { /* if (s->format == list */ /* TODO */ } @@ -185,6 +214,8 @@ int load_io_functions(struct settings const * const s, struct stream * const in) if (s->format == array) { in->get_next_element_cache = cached_get_array; in->place_next_element_cache = cached_put_array; + in->split = cache_block_split; + in->rewind = cache_rewind; } else { /* if (s->format == list */ /* TODO */ } @@ -203,7 +234,7 @@ int load_io_functions(struct settings const * const s, struct stream * const in) return ret; } -void printhelp(const char * const name) +static void printhelp(const char * const name) { printf( "This is a mergesort program and such\n" "\n" @@ -226,7 +257,7 @@ void printhelp(const char * const name) return; } -struct entry_l *stub_getnext(struct stream * const restrict in) +static struct entry_l *stub_getnext(struct stream * const restrict in) { struct entry_l *ret = NULL; @@ -261,14 +292,3 @@ static int stub_split(struct stream * const in, struct stream * const a, struct return ret; } - -static int stub_flush(struct stream * const in) -{ - int ret = ENOSYS; - - (void) in; - - rin_warn("stub!"); - - return ret; -} diff --git a/src/mergesort.c b/src/mergesort.c index c431b31..7391544 100644 --- a/src/mergesort.c +++ b/src/mergesort.c @@ -5,42 +5,49 @@ #include <errno.h> #include <stdlib.h> #include "defs.h" -#include "io.h" +#include "stream.h" #include "mergesort.h" +static int merge(struct stream * const dest, struct stream * const A, struct stream * const B); + /* bottom-up variantas */ int merge_sort(struct stream * const src, struct stream * const dest) { int ret = 0; - struct stream tmp[4]; /* I can't into stream reuse, hence four. A yeet, followed by a dab. */ + struct stream tmp[4] = {0}; /* I can't into stream reuse, hence four. A yeet, followed by a dab. */ size_t i; try(!src || !dest, err, EINVAL, "cannot sort what's not there"); - if (src->n > 1) { /* stream of size one is inherently sorted */ + try_s((ret = stream_shallow_copy(src, dest)), err); + + if (src->n > 1) { src->split(src, tmp, tmp + 2); /* split stream in half */ - merge_sort(tmp + 1, tmp); /* recurse-sort first half */ - merge_sort(tmp + 3, tmp + 2); /* recurse-sort second half */ - merge(dest, tmp, tmp + 2); /* merge the two halves back */ - } + merge_sort(tmp, tmp + 1); /* recurse-sort first half */ + merge_sort(tmp + 2, tmp + 3); /* recurse-sort second half */ + merge(dest, tmp + 1, tmp + 3); /* merge the two halves back */ + dest->rewind(dest); - for (i = 0; i < (sizeof(tmp) / sizeof(*tmp)); ++i) { - stream_close(tmp + i); + for (i = 0; i < (sizeof(tmp) / sizeof(*tmp)); ++i) { + stream_close(tmp + i); + } + } else { /* stream of size one is inherently sorted, simply src with dest */ + *tmp = *dest; + *dest = *src; + *src = *tmp; } err: return ret; } -int merge(struct stream * const dest, struct stream * const A, struct stream * const B) +static int merge(struct stream * const dest, struct stream * const A, struct stream * const B) { int ret = 0; struct entry_l *a; struct entry_l *b; - try(A->parentid != B->parentid, err, EINVAL, "cannot merge blocks: uncommon parent!"); - a = get(A); b = get(B); @@ -54,7 +61,6 @@ int merge(struct stream * const dest, struct stream * const A, struct stream * c } } -err: return ret; } diff --git a/src/mergesort.h b/src/mergesort.h index ea66a8b..8842906 100644 --- a/src/mergesort.h +++ b/src/mergesort.h @@ -8,6 +8,5 @@ #include "defs.h" int merge_sort(struct stream * const src, struct stream * const dest); -int merge(struct stream * const dest, struct stream * const A, struct stream * const B); #endif /* ALGOS_MERGESORT_H_INCLUDED */ diff --git a/src/meson.build b/src/meson.build index b714823..aed222e 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,7 +1,7 @@ source_files = [ 'cache.c', 'datagen.c', - 'io.c', + 'stream.c', 'main.c', 'mergesort.c', ] @@ -10,7 +10,7 @@ header_files = [ 'cache.h', 'defs.h', 'datagen.h', - 'io.h', + 'stream.h', 'mergesort.h', ] @@ -12,7 +12,7 @@ #include <stdlib.h> #include <string.h> #include <libgen.h> -#include "io.h" +#include "stream.h" #include "defs.h" #include "datagen.h" #include "cache.h" @@ -57,8 +57,6 @@ int stream_close(struct stream * const in) { int ret = 0; - try(!in || (in->fd < 0 && in->type != stream_randread), early_err, EINVAL, "invalid argunent"); - if (in->type != stream_out) { goto out; } @@ -89,13 +87,68 @@ int stream_close(struct stream * const in) } out: - if (in->settings->access == cached) { + if (in->settings && in->settings->access == cached) { cache_destroy(in); } err: - close(in->fd); + in->fd > 2 ? close(in->fd) : 0; in->fd = -1; -early_err: + return ret; +} + +int stream_readfile(struct stream * const in) +{ + ssize_t ret = 0; + size_t remaining = in->n * in->settings->stride; + ssize_t bytesread = 0; + size_t i; + + try(in->fd < 3, err, EINVAL, "no file open for reading"); + + do { + ret = read(in->fd, in->cache + bytesread, remaining); + if (ret < 0) { + try(errno != EAGAIN, err, errno, "Writing to stream failed with %zi", ret); + } else { + bytesread += ret; + remaining -= ret; + } + } while (ret); + + /* if this is a list, we need to adjust the link pointers from file offsets + * to buffer addresses. 'Cept for the last one, which needs to be NULL. + */ + if (in->settings->format == list) { + for (i = 0; i < (in->n - 1); ++i) { + in->cache_l[i].offset = (char *) in->cache_l[i].next - in->cache; + } + } + +err: + return ret; +} + +int stream_shallow_copy(struct stream const * const restrict src, struct stream * const dest) +{ + int ret = 0; + + dest->n = src->n; + dest->settings = src->settings; + dest->index = 0; + + if (src->settings->access == cached) { + dest->type = stream_cache; + dest->get_next_element_cache = src->get_next_element_cache; + dest->place_next_element_cache = src->place_next_element_cache; + dest->split = src->split; + dest->rewind = src->rewind; + try_s((ret = cache_create(dest)), err); + } else { + rin_warn("stub!"); + ret = ENOSYS; + } + +err: return ret; } @@ -168,7 +221,7 @@ err: return ret; } -int stream_flush(struct stream * const in) +static int stream_flush(struct stream * const in) { int ret = 0; @@ -184,12 +237,14 @@ err: return ret; } -int stream_flush_array(struct stream * const in) +static int stream_flush_array(struct stream * const in) { ssize_t ret = 0; size_t remaining = in->n * in->settings->stride; ssize_t written = 0; + try(in->fd < 3, err, EINVAL, "can't dump without an open file"); + do { ret = write(in->fd, in->cache + written, remaining); if (ret < 0) { @@ -205,11 +260,11 @@ err: return ret; } -int stream_flush_list(struct stream * const in) +static int stream_flush_list(struct stream * const in) { ssize_t ret = 0; - size_t remaining; - ssize_t written; + size_t remaining = in->n * in->settings->stride; + ssize_t written = 0; size_t i; /* adjust pointers to have a base starting at 0, to cater to disk storage format. @@ -222,9 +277,6 @@ int stream_flush_list(struct stream * const in) } /* dump the bloody list */ - written = 0; - remaining = in->n * in->settings->stride; - do { ret = write(in->fd, in->cache + written, remaining); if (ret < 0) { @@ -9,6 +9,7 @@ int stream_open(struct stream * const in); int stream_close(struct stream * const in); +int stream_readfile(struct stream * const in); int direct_get_array(struct stream * const restrict in, ssize_t idx, struct entry_l * const data); int direct_get_list(struct stream * const restrict in, ssize_t idx, struct entry_l * const data); @@ -16,4 +17,5 @@ int direct_get_list(struct stream * const restrict in, ssize_t idx, struct entry int direct_put_array(struct stream * const restrict in, ssize_t idx, const struct entry_l * const data); int direct_put_list(struct stream * const restrict in, ssize_t idx, const struct entry_l * const data); +int stream_shallow_copy(struct stream const * const restrict src, struct stream * const dest); #endif /* ALGOS_IO_H_INCLUDED */ |