diff --git a/doc/user/runtime/tracing.md b/doc/user/runtime/tracing.md index bbd65c2..9a69e0b 100644 --- a/doc/user/runtime/tracing.md +++ b/doc/user/runtime/tracing.md @@ -11,11 +11,16 @@ trace is correct. - Call `ovni_proc_init()` when a new process begins the execution. - Call `ovni_thread_init()` when a new thread begins the execution -(including the main process thread). Call `ovni_flush()` and -`ovni_thread_free()` when it finishes (in that order). + (including the main process thread). + +- Call `ovni_thread_require()` with the required model version before + emitting events for that model. + +- Call `ovni_flush()` and `ovni_thread_free()` when it finishes (in that + order). - Call `ovni_proc_fini()` when a process ends, after all threads have -finished. + finished. You can use `ovni_ev_emit()` to record a new event. If you need more than 16 bytes of payload, use `ovni_ev_jumbo_emit()`. See the [trace diff --git a/include/ovni.h.in b/include/ovni.h.in index a30d730..19d0137 100644 --- a/include/ovni.h.in +++ b/include/ovni.h.in @@ -99,6 +99,8 @@ void ovni_proc_fini(void); void ovni_thread_init(pid_t tid); +void ovni_thread_require(const char *model, const char *version); + void ovni_thread_free(void); int ovni_thread_isready(void); diff --git a/src/rt/ovni.c b/src/rt/ovni.c index 221e36e..605e72b 100644 --- a/src/rt/ovni.c +++ b/src/rt/ovni.c @@ -32,6 +32,8 @@ struct ovni_rthread { /* Buffer to write events */ uint8_t *evbuf; + + JSON_Value *meta; }; /* State of each process on runtime */ @@ -232,7 +234,6 @@ proc_set_version(void) die("json_object_set_string for model_version failed"); } - void ovni_proc_set_rank(int rank, int nranks) { @@ -448,6 +449,53 @@ write_stream_header(void) flush_evbuf(); } +static void +thread_metadata_store(void) +{ + char path[PATH_MAX]; + int written = snprintf(path, PATH_MAX, "%s/thread.%d.json", + rproc.procdir, rthread.tid); + + if (written >= PATH_MAX) + die("thread trace path too long: %s/thread.%d.json", + rproc.procdir, rthread.tid); + + if (json_serialize_to_file_pretty(rthread.meta, path) != JSONSuccess) + die("failed to write thread metadata"); +} + +static void +thread_metadata_populate(void) +{ + JSON_Object *meta = json_value_get_object(rthread.meta); + + if (meta == NULL) + die("json_value_get_object failed"); + + if (json_object_dotset_number(meta, "version", OVNI_METADATA_VERSION) != 0) + die("json_object_dotset_string failed"); + + if (json_object_dotset_string(meta, "libovni.version", OVNI_LIB_VERSION) != 0) + die("json_object_dotset_string failed"); + + if (json_object_dotset_string(meta, "libovni.commit", OVNI_GIT_COMMIT) != 0) + die("json_object_dotset_string failed"); +} + +static void +thread_metadata_init(void) +{ + rthread.meta = json_value_init_object(); + + if (rthread.meta == NULL) + die("failed to create metadata JSON object"); + + thread_metadata_populate(); + + /* Store initial metadata on disk, to detect broken streams */ + thread_metadata_store(); +} + void ovni_thread_init(pid_t tid) { @@ -474,9 +522,51 @@ ovni_thread_init(pid_t tid) create_trace_stream(); write_stream_header(); + thread_metadata_init(); + rthread.ready = 1; } +void +ovni_thread_require(const char *model, const char *version) +{ + if (!rthread.ready) + die("thread not initialized"); + + /* Sanitize model */ + if (model == NULL) + die("model string is NULL"); + + if (strpbrk(model, " .") != NULL) + die("malformed model name"); + + if (strlen(model) <= 1) + die("model name must have more than 1 character"); + + /* Sanitize version */ + if (version == NULL) + die("version string is NULL"); + + int parsedver[3]; + if (version_parse(version, parsedver) != 0) + die("failed to parse provided version \"%s\"", version); + + /* Store into metadata */ + JSON_Object *meta = json_value_get_object(rthread.meta); + + if (meta == NULL) + die("json_value_get_object failed"); + + char dotpath[128]; + if (snprintf(dotpath, 128, "require.%s.version", model) >= 128) + die("model name too long"); + + /* TODO: What if is already set? */ + + if (json_object_dotset_string(meta, dotpath, version) != 0) + die("json_object_dotset_string failed"); +} + void ovni_thread_free(void) { @@ -616,6 +706,8 @@ ovni_flush(void) ovni_ev_set_mcv(&pre, "OF["); flush_evbuf(); + /* Also save metadata */ + thread_metadata_store(); ovni_ev_set_clock(&post, ovni_clock_now()); ovni_ev_set_mcv(&post, "OF]");