diff --git a/doc/runtime/tracing.md b/doc/runtime/tracing.md index 72f07c4..4f233cd 100644 --- a/doc/runtime/tracing.md +++ b/doc/runtime/tracing.md @@ -6,6 +6,8 @@ trace is correct. ## Trace processes and threads +- Call `ovni_version_check()` once before calling any ovni function. + - Call `ovni_proc_init()` when a new process begins the execution. - Call `ovni_thread_init()` when a new thread begins the execution diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2875534..4b4544b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,6 +6,10 @@ add_library(ovni SHARED parson.c ) +set_target_properties(ovni PROPERTIES + VERSION 1.0.0 + SOVERSION 1) + target_include_directories(ovni PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) configure_file("config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h" ) diff --git a/src/ovni.c b/src/ovni.c index 82a00af..4de2a2c 100644 --- a/src/ovni.c +++ b/src/ovni.c @@ -24,6 +24,88 @@ struct ovni_rproc rproc = {0}; /* Data per thread */ _Thread_local struct ovni_rthread rthread = {0}; +static int +parse_version(const char *version, int tuple[3]) +{ + char buf[64]; + + if (strlen(version) >= 64) { + err("parse_version: version too long: %s\n", version); + return -1; + } + + strcpy(buf, version); + + char *str = buf; + char *which[] = { "major", "minor", "patch" }; + char *delim[] = { ".", ".", ".-" }; + char *save = NULL; + + for (int i = 0; i < 3; i++) { + char *num = strtok_r(str, delim[i], &save); + + /* Subsequent calls need NULL as string */ + str = NULL; + + if (num == NULL) { + err("parse_version: missing %s number: %s\n", + which[i], version); + return -1; + } + + errno = 0; + char *endptr = NULL; + int v = (int) strtol(num, &endptr, 10); + + if (errno != 0 || endptr == num || endptr[0] != '\0') { + err("parse_version: failed to parse %s number: %s\n", + which[i], version); + return -1; + } + + if (v < 0) { + err("parse_version: invalid negative %s number: %s\n", + which[i], version); + return -1; + } + + tuple[i] = v; + } + + return 0; +} + +void ovni_version_check_str(const char *version) +{ + if (version == NULL) + die("ovni version string is NULL\n"); + + int provided[3]; + int expected[3]; + + if (parse_version(version, provided) != 0) + die("failed to parse provided version \"%s\"\n", version); + + if (parse_version(OVNI_LIB_VERSION, expected) != 0) + die("failed to parse expected version \"%s\"\n", OVNI_LIB_VERSION); + + /* Match the major */ + if (provided[0] != expected[0]) { + die("ovni major version mismatch: found %d (%s), expected %d (%s)\n", + provided[0], version, + expected[0], OVNI_LIB_VERSION); + } + + /* Only fail if the minor is older */ + if (provided[1] < expected[1]) { + die("ovni minor version too old: found %d (%s), expected %d (%s)\n", + provided[1], version, + expected[1], OVNI_LIB_VERSION); + } + + /* Ignore the patch number */ +} + static void create_trace_stream(void) { diff --git a/src/ovni.h b/src/ovni.h index 739ce96..3034ab5 100644 --- a/src/ovni.h +++ b/src/ovni.h @@ -31,6 +31,9 @@ typedef struct json_value_t JSON_Value; #define OVNI_STREAM_VERSION 1 #define OVNI_MODEL_VERSION "O1 V1 T1 M1 D1 K1 61" +/* Follow https://semver.org rules for versioning */ +#define OVNI_LIB_VERSION "1.0.0" + /* ----------------------- common ------------------------ */ enum ovni_ev_flags { @@ -120,6 +123,9 @@ struct ovni_rproc { JSON_Value *meta; }; +#define ovni_version_check() ovni_version_check_str(OVNI_LIB_VERSION) +void ovni_version_check_str(const char *version); + void ovni_proc_init(int app, const char *loom, int pid); /* Sets the MPI rank of the current process and the number of total nranks */ diff --git a/test/emu/instr.h b/test/emu/instr.h index 24678bc..3241df0 100644 --- a/test/emu/instr.h +++ b/test/emu/instr.h @@ -86,6 +86,7 @@ instr_start(int rank, int nranks) sprintf(rankname, "%s.%d", hostname, rank); + ovni_version_check(); ovni_proc_init(1, rankname, getpid()); ovni_proc_set_rank(rank, nranks); ovni_thread_init(gettid()); diff --git a/test/emu/ovni/CMakeLists.txt b/test/emu/ovni/CMakeLists.txt index e0327d7..b6f281a 100644 --- a/test/emu/ovni/CMakeLists.txt +++ b/test/emu/ovni/CMakeLists.txt @@ -14,3 +14,5 @@ ovni_test(sort-first-and-full-ring.c SORT ovni_test(burst-stats.c REGEX "burst stats: median 33 ns, avg 33\.0 ns, max 33 ns") ovni_test(mp-simple.c MP) ovni_test(mp-rank.c MP) +ovni_test(version-good.c) +ovni_test(version-bad.c SHOULD_FAIL REGEX "version mismatch") diff --git a/test/emu/ovni/version-bad.c b/test/emu/ovni/version-bad.c new file mode 100644 index 0000000..f49399c --- /dev/null +++ b/test/emu/ovni/version-bad.c @@ -0,0 +1,15 @@ +/* Copyright (c) 2021-2022 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "ovni.h" + +#undef OVNI_LIB_VERSION +#define OVNI_LIB_VERSION "0.0.0" /* Cause the major to fail */ + +int +main(void) +{ + /* Should fail */ + ovni_version_check(); + return 0; +} diff --git a/test/emu/ovni/version-good.c b/test/emu/ovni/version-good.c new file mode 100644 index 0000000..bf076a0 --- /dev/null +++ b/test/emu/ovni/version-good.c @@ -0,0 +1,16 @@ +/* Copyright (c) 2021-2022 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "instr_ovni.h" + +int +main(void) +{ + ovni_version_check(); + + /* Create a dummy trace */ + instr_start(0, 1); + instr_end(); + + return 0; +}