From 5afb6c6f0d395142fcc0356e717f050df2618571 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 20 May 2024 16:31:26 -0400 Subject: [PATCH] WIP --- tests/soak.c | 190 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 159 insertions(+), 31 deletions(-) diff --git a/tests/soak.c b/tests/soak.c index 53b4cd1..3edb522 100644 --- a/tests/soak.c +++ b/tests/soak.c @@ -17,8 +17,6 @@ #define INITIAL_AMOUNT 1024 * 2 -bool recording = true; - typedef size_t pgno_t; typedef enum { SM, ML, RB } container_impl_t; @@ -133,6 +131,8 @@ typedef struct container { } container_t; +#define digest(name) containers[type].name##_stats.td + char * bytes_as(double bytes, char *s, size_t size) { @@ -316,6 +316,8 @@ b64_decode(const char *in, unsigned char *out, size_t outlen) /* recording ------------------------------------------------------------- */ +bool recording = false; + static void record_set_mutation(FILE *out, pgno_t pg) { @@ -871,7 +873,9 @@ __roar_validate(void *handle) return true; } -/* histogram ------------------------------------------------------------- */ +/* statistics ------------------------------------------------------------ */ + +bool statistics = false; typedef struct sw { struct timespec t1; /* start time */ @@ -892,7 +896,7 @@ elapsed(struct timespec *s, struct timespec *e) long sec, nanos; sec = e->tv_sec - s->tv_sec; - nanos = e->tv_nsec - e->tv_nsec; + nanos = e->tv_nsec - s->tv_nsec; if (nanos < 0) { nanos += 1e9; sec--; @@ -1102,7 +1106,8 @@ container_t containers[] = { void *handles[(sizeof((containers)) / sizeof((containers)[0]))]; void *new_handles[(sizeof((containers)) / sizeof((containers)[0]))]; -FILE *fp; +FILE *record_fp; +FILE *stats_fp; #define alloc(type, size) containers[type].alloc(size); #define cast(type, fn, ...) \ @@ -1110,15 +1115,15 @@ FILE *fp; containers[type].fn(handles[type], ##__VA_ARGS__) #define invoke(type, fn, ...) __stats_##fn(containers[type].fn##_stats.td, containers[type].fn##_stats.fn, handles[type], __VA_ARGS__) -#define mutate(type, fn, ...) \ - (type == 0) ? record_##fn##_mutation(fp, __VA_ARGS__) : (void)0, \ +#define mutate(type, fn, ...) \ + (type == 0) ? record_##fn##_mutation(record_fp, __VA_ARGS__) : (void)0, \ __stats_##fn(containers[type].fn##_stats.td, containers[type].fn##_stats.fn, &handles[type], __VA_ARGS__) #define foreach(set) for (unsigned type = 0; type < (sizeof((set)) / sizeof((set)[0])); type++) #define checkpoint(set) \ for (unsigned type = 1; type < (sizeof((set)) / sizeof((set)[0])); type++) { \ verify_eq(0, handles[0], type, handles[type]); \ } \ - record_checkpoint(fp, handles[0]) + record_checkpoint(record_fp, handles[0]) bool verify_sm_eq_rb(sparsemap_t *map, roaring_bitmap_t *rbm) @@ -1186,36 +1191,39 @@ verify_eq(unsigned a, void *ad, unsigned b, void *bd) return ret; } -#define SHORT_OPT "r:fa:bh" -#define LONG_OPT "record:,force,amount:,buffer,help" - void print_usage(const char *program_name) { printf("Usage: %s [OPTIONS]\n", program_name); - printf(" -r, --record Path to the file for recording (optional)\n"); - printf(" -f, --force Force overwrite of existing file (optional)\n"); - printf(" -b, --buffer Disable buffering writes to stdout/err (optional)\n"); - printf(" -a, --amount Specify the number of entries to record (must be positive, optional)\n"); - printf(" -h, --help Print this help message\n"); + printf(" -r Path to the file for recording (optional)\n"); + printf(" -s Path to the file for statistics (optional)\n"); + printf(" -f Force overwrite of existing file (optional)\n"); + printf(" -b Disable buffering writes to stdout/err (optional)\n"); + printf(" -a Specify the number of entries to record (must be positive, optional)\n"); + printf(" -h Print this help message\n"); } +#define SHORT_OPT "r:s:fa:bh" int main(int argc, char *argv[]) { int opt; const char *record_file = NULL; + const char *stats_file = NULL; int force_flag = 0; size_t left, iteration = 0, amt = INITIAL_AMOUNT; bool buffer = true; - fp = stdout; - - while ((opt = getopt(argc, argv, SHORT_OPT LONG_OPT)) != -1) { + while ((opt = getopt(argc, argv, SHORT_OPT)) != -1) { switch (opt) { case 'r': + recording = true; record_file = optarg; break; + case 's': + statistics = true; + stats_file = optarg; + break; case 'f': force_flag = 1; break; @@ -1240,10 +1248,9 @@ main(int argc, char *argv[]) } } - // Check if record file is specified - if (record_file == NULL) { - recording = false; - } else { + if (recording) { + record_fp = stdout; + // Check for existing file without force flag if (access(record_file, F_OK) == 0 && !force_flag) { fprintf(stderr, "Warning: File '%s' already exists. Use -f or --force to overwrite.\n", record_file); @@ -1251,17 +1258,38 @@ main(int argc, char *argv[]) } // Open the file for writing (truncate if force flag is set) - fp = fopen(record_file, force_flag ? "w" : "a"); - if (fp == NULL) { + record_fp = fopen(record_file, force_flag ? "w" : "a"); + if (record_fp == NULL) { perror("Error opening file"); return 1; } } + // Check if statistics file is specified + if (statistics) { + if (stats_file[0] == '-') { + stats_fp = stdout; + setvbuf(stdout, NULL, _IONBF, 0); + } else { + // Check for existing file without force flag + if (access(stats_file, F_OK) == 0 && !force_flag) { + fprintf(stderr, "Warning: File '%s' already exists. Use -f or --force to overwrite.\n", stats_file); + return 1; + } + + // Open the file for writing (truncate if force flag is set) + stats_fp = fopen(stats_file, force_flag ? "w" : "a"); + if (stats_fp == NULL) { + perror("Error opening file"); + return 1; + } + } + } + // disable buffering if (!buffer) { - setvbuf(stdout, NULL, _IONBF, 0); - setvbuf(fp, NULL, _IONBF, 0); + setvbuf(record_fp, NULL, _IONBF, 0); + setvbuf(stats_fp, NULL, _IONBF, 0); } unsigned types[] = { SM, ML, RB }; unsigned num_types = (sizeof((types)) / sizeof((types)[0])); @@ -1280,9 +1308,6 @@ main(int argc, char *argv[]) containers[type].is_empty_stats.td = NULL; containers[type].is_first_stats.td = NULL; containers[type].merge_stats.td = td_new(100); - containers[type].size = NULL; - containers[type].count = NULL; - containers[type].validate = NULL; } /* Setup: add an amt of bits to each container. */ @@ -1299,6 +1324,77 @@ main(int argc, char *argv[]) checkpoint(types); left = amt; + if (statistics) { + const char *names[] = { "sm", "ml", "rb" }; + const char *dists[] = { "p50", "p75", "p90", "p99", "p999" }; + fprintf(stats_fp, "timestamp,iterations,"); + foreach(types) + { + fprintf(stats_fp, "%s_size,%s_bytes,", names[type], names[type]); + if (digest(alloc) != NULL) { + for (int i = 0; i < 5; i++) { + fprintf(stats_fp, "%s_alloc_%s,", names[type], dists[i]); + } + } + if (digest(free) != NULL) { + for (int i = 0; i < 5; i++) { + fprintf(stats_fp, "%s_free_%s,", names[type], dists[i]); + } + } + if (digest(set) != NULL) { + for (int i = 0; i < 5; i++) { + fprintf(stats_fp, "%s_set_%s,", names[type], dists[i]); + } + } + if (digest(is_set) != NULL) { + for (int i = 0; i < 5; i++) { + fprintf(stats_fp, "%s_is_set_%s,", names[type], dists[i]); + } + } + if (digest(clear) != NULL) { + for (int i = 0; i < 5; i++) { + fprintf(stats_fp, "%s_clear_%s,", names[type], dists[i]); + } + } + if (digest(find_span) != NULL) { + for (int i = 0; i < 5; i++) { + fprintf(stats_fp, "%s_find_span_%s,", names[type], dists[i]); + } + } + if (digest(take_span) != NULL) { + for (int i = 0; i < 5; i++) { + fprintf(stats_fp, "%s_take_span_%s,", names[type], dists[i]); + } + } + if (digest(release_span) != NULL) { + for (int i = 0; i < 5; i++) { + fprintf(stats_fp, "%s_release_span_%s,", names[type], dists[i]); + } + } + if (digest(is_span) != NULL) { + for (int i = 0; i < 5; i++) { + fprintf(stats_fp, "%s_is_span_%s,", names[type], dists[i]); + } + } + if (digest(is_empty) != NULL) { + for (int i = 0; i < 5; i++) { + fprintf(stats_fp, "%s_is_empty_%s,", names[type], dists[i]); + } + } + if (digest(is_first) != NULL) { + for (int i = 0; i < 5; i++) { + fprintf(stats_fp, "%s_is_first_%s,", names[type], dists[i]); + } + } + if (digest(merge) != NULL) { + for (int i = 0; i < 5; i++) { + fprintf(stats_fp, "%s_merge_%s,", names[type], dists[i]); + } + } + } + fprintf(stats_fp, "\n"); + } + while (true) { iteration++; // the an amount [1, 16] of pages to find preferring smaller sizes @@ -1395,7 +1491,39 @@ main(int argc, char *argv[]) containers[type].free(new_handles[type]); } } + if (statistics) { + const float dists[] = { 0.5, 0.75, 0.90, 0.99, 0.999 }; + fprintf(stats_fp, "%f,%zu,", nsts(), iteration); + foreach(types) + { + fprintf(stats_fp, "%zu,%zu,", containers[type].count(handles[type]), containers[type].size(handles[type])); + // clang-format off + td_histogram_t *td[] = { + digest(alloc), + digest(free), + digest(set), + digest(is_set), + digest(clear), + digest(find_span), + digest(take_span), + digest(release_span), + digest(is_span), + digest(is_empty), + digest(is_first), + digest(merge) + }; + // clang-format on + for (int i = 0; i < 12; i++) { + if (td[i] != NULL) { + td_compress(td[i]); + for (int j = 0; j < 5; j++) { + fprintf(stats_fp, "%.10f,", td_quantile(td[i], dists[j])); + } + } + } + } + fprintf(stats_fp, "\n"); + } } - return 0; }