diff --git a/src/emu/clkoff.c b/src/emu/clkoff.c new file mode 100644 index 0000000..f5fd041 --- /dev/null +++ b/src/emu/clkoff.c @@ -0,0 +1,138 @@ +#include "clkoff.h" + +#include "common.h" +#include + +static struct clkoff_entry * +cfind(struct clkoff *off, const char *name) +{ + struct clkoff_entry *entry = NULL; + + HASH_FIND_STR(off->entries, name, entry); + return entry; +} + +static int +cadd(struct clkoff *table, struct clkoff_entry e) +{ + if (cfind(table, e.name) != NULL) { + err("entry with name '%s' already exists\n", e.name); + return -1; + } + + struct clkoff_entry *entry = calloc(1, sizeof(struct clkoff_entry)); + if (entry == NULL) { + err("calloc failed\n"); + return -1; + } + + memcpy(entry, &e, sizeof(*entry)); + + HASH_ADD_STR(table->entries, name, entry); + table->nentries++; + + return 0; +} + +static int +cparse(struct clkoff *table, FILE *file) +{ + /* Ignore header line */ + char buf[1024]; + if (fgets(buf, 1024, file) == NULL) { + err("missing header line in clock offset\n"); + return -1; + } + + for (int line = 1; ; line++) { + errno = 0; + struct clkoff_entry e = { 0 }; + + if (fgets(buf, 1024, file) == NULL) + break; + + /* Empty line */ + if (buf[0] == '\n') + continue; + + int ret = sscanf(buf, "%ld %s %lf %lf %lf", + &e.index, e.name, + &e.median, &e.mean, &e.stdev); + + if (ret == EOF && errno == 0) + break; + + if (ret == EOF && errno != 0) { + err("fscanf() failed in line %d\n", line); + return -1; + } + + if (ret != 5) { + err("fscanf() read %d instead of 5 fields in line %d\n", + ret, line); + return -1; + } + + if (cadd(table, e) != 0) { + err("cannot add entry of line %d\n", + line); + return -1; + } + } + + return 0; +} + +static int +cindex(struct clkoff *table) +{ + if (table->nentries < 1) { + err("no entries\n"); + return -1; + } + + table->index = calloc(table->nentries, sizeof(struct clkoff_entry *)); + + if (table->index == NULL) { + err("calloc failed\n"); + return -1; + } + + struct clkoff_entry *e; + int i = 0; + for (e = table->entries; e; e = e->hh.next) + table->index[i++] = e; + + return 0; +} + +int +clkoff_init(struct clkoff *table, FILE *file) +{ + memset(table, 0, sizeof(struct clkoff)); + + if (cparse(table, file) != 0) { + err("clkoff_init: failed parsing clock table\n"); + return -1; + } + + /* Create index array */ + if (cindex(table) != 0) { + err("clkoff_init: failed indexing table\n"); + return -1; + } + + return 0; +} + +int +clkoff_count(struct clkoff *table) +{ + return table->nentries; +} + +struct clkoff_entry * +clkoff_get(struct clkoff *table, int i) +{ + return table->index[i]; +} diff --git a/src/emu/clkoff.h b/src/emu/clkoff.h new file mode 100644 index 0000000..aecd9cc --- /dev/null +++ b/src/emu/clkoff.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef CLKOFF_H +#define CLKOFF_H + +#include "uthash.h" + +#include +#include + +struct clkoff_entry { + int64_t index; + char name[PATH_MAX]; + double median; + double mean; + double stdev; + UT_hash_handle hh; +}; + +struct clkoff { + int nentries; + struct clkoff_entry *entries; + struct clkoff_entry **index; +}; + +int clkoff_init(struct clkoff *table, FILE *file); +int clkoff_count(struct clkoff *table); +struct clkoff_entry *clkoff_get(struct clkoff *table, int i); + +#endif /* CLKOFF_H */ diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index b41c2dc..101d2f1 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -17,3 +17,4 @@ unit_test(prv.c) #unit_test(ovni_model.c) unit_test(emu_trace.c) unit_test(emu.c) +unit_test(clkoff.c) diff --git a/test/unit/clkoff.c b/test/unit/clkoff.c new file mode 100644 index 0000000..3536822 --- /dev/null +++ b/test/unit/clkoff.c @@ -0,0 +1,73 @@ +#define _POSIX_C_SOURCE 200809L + +#include "emu/clkoff.h" +#include "common.h" +#include + +static int +test_ok(void) +{ + char table_str[] = + "rank hostname offset_median offset_mean offset_std\n" + "0 s09r2b21 0 0.000000 0.000000\n" + "1 s09r2b22 -451607967 -451608083.500000 316.087397\n" + "2 s09r2b23 4526 4542.200000 124.33432\n" + "3 s09r2b24 342455 342462.300000 342.39755\n"; + + FILE *f = fmemopen(table_str, ARRAYLEN(table_str), "r"); + + if (f == NULL) + die("fmemopen failed\n"); + + struct clkoff table; + clkoff_init(&table); + if (clkoff_load(&table, f) != 0) + die("clkoff_load failed\n"); + + if (clkoff_count(&table) != 4) + die("clkoff_count failed\n"); + + struct clkoff_entry *entry = clkoff_get(&table, 3); + if (entry == NULL) + die("clkoff_get returned NULL\n"); + + if (entry->index != 3) + die("clkoff_get returned wrong index\n"); + + fclose(f); + + return 0; +} + +static int +test_dup(void) +{ + static char table_str[] = + "rank hostname offset_median offset_mean offset_std\n" + "0 s09r2b21 0 0.000000 0.000000\n" + "1 s09r2b22 -451607967 -451608083.500000 316.087397\n" + "2 s09r2b23 4526 4542.200000 124.33432\n" + "3 s09r2b23 342455 342462.300000 342.39755\n"; + + FILE *f = fmemopen(table_str, ARRAYLEN(table_str), "r"); + + if (f == NULL) + die("fmemopen failed\n"); + + struct clkoff table; + + clkoff_init(&table); + if (clkoff_load(&table, f) == 0) + die("clkoff_load didn't fail\n"); + + fclose(f); + + return 0; +} + +int main(void) +{ + test_ok(); + test_dup(); + return 0; +}