Add ovni_mark_* API to store custom states

In order to allow easy debugging of some programs and runtimes, it is
often neccessary to add extra information in the timeline views. The
modification of the emulator to accomodate those temporal events is time
consuming and requires knowlegde of the emulator internals.

To improve the situation, a new set of functions are added to libovni
which allow users to define their own views. Up to 100 types of events
can be declared, where each type can have an unlimited number ov values
with an optional label attached.
This commit is contained in:
Rodrigo Arias 2024-06-13 15:46:55 +02:00
parent 247ea7e7c3
commit 93ab5a5833
7 changed files with 144 additions and 3 deletions

View File

@ -142,6 +142,12 @@ const char *ovni_attr_get_str(const char *key);
char *ovni_attr_get_json(const char *key);
void ovni_attr_flush(void);
/* Mark */
void ovni_mark_type(int32_t type, const char *title);
void ovni_mark_label(int32_t type, int64_t value, const char *label);
void ovni_mark_push(int32_t type, int64_t value);
void ovni_mark_pop(int32_t type, int64_t value);
#ifdef __cplusplus
}
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef EMU_PRV_H
@ -33,7 +33,9 @@ enum emu_prv_types {
PRV_NANOS6_BREAKDOWN = 41,
PRV_KERNEL_CS = 45,
PRV_OPENMP_SUBSYSTEM = 50,
PRV_RESERVED = 100,
PRV_OVNI_MARK = 100,
/* User marks [100, 200) */
PRV_RESERVED = 200,
};
#endif /* EMU_PRV_H */

View File

@ -477,6 +477,9 @@ model_ovni_event(struct emu *emu)
case 'U':
/* Ignore sorting events */
return 0;
case 'M':
/* TODO: Ignore mark events for now */
return 0;
default:
err("unknown ovni event category %c",
emu->ev->c);

View File

@ -37,12 +37,15 @@ static struct ev_decl model_evlist[] = {
PAIR_B("OF[", "OF]", "flushing events to disk")
PAIR_E("OU[", "OU]", "unordered event region")
{ "OM[(i64 value, i32 type)", "push mark with value %{value} from type %{type}" },
{ "OM](i64 value, i32 type)", "pop mark with value %{value} from type %{type}" },
{ NULL, NULL },
};
struct model_spec model_ovni = {
.name = model_name,
.version = "1.0.0",
.version = "1.1.0",
.evlist = model_evlist,
.model = model_id,
.create = model_ovni_create,

View File

@ -3,6 +3,7 @@
#include <dirent.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
@ -1061,3 +1062,88 @@ ovni_attr_flush(void)
thread_metadata_store();
}
/* Mark */
/** creates a new mark type. */
void
ovni_mark_type(int32_t type, const char *title)
{
if (type < 0 || type >= 100)
die("type must be in [0,100) range");
if (!title || title[0] == '\0')
die("bad title");
JSON_Object *meta = get_thread_metadata();
char key[128];
if (snprintf(key, 128, "ovni.mark.%"PRId32, type) >= 128)
die("type key too long");
JSON_Value *val = json_object_dotget_value(meta, key);
if (val != NULL)
die("type %"PRId32" already defined", type);
if (snprintf(key, 128, "ovni.mark.%"PRId32".title", type) >= 128)
die("title key too long");
if (json_object_dotset_string(meta, key, title) != 0)
die("json_object_dotset_string() failed", type);
}
/** creates a new mark type. */
void
ovni_mark_label(int32_t type, int64_t value, const char *label)
{
if (type < 0 || type >= 100)
die("type must be in [0,100) range");
if (value <= 0)
die("value must be >0");
if (!label || label[0] == '\0')
die("bad label");
JSON_Object *meta = get_thread_metadata();
char key[128];
if (snprintf(key, 128, "ovni.mark.%"PRId32, type) >= 128)
die("type key too long");
JSON_Value *valtype = json_object_dotget_value(meta, key);
if (valtype == NULL)
die("type %"PRId32" not defined", type);
if (snprintf(key, 128, "ovni.mark.%"PRId32".labels.%"PRId64, type, value) >= 128)
die("value key too long");
JSON_Value *val = json_object_dotget_value(meta, key);
if (val != NULL)
die("label '%s' already defined", label);
if (json_object_dotset_string(meta, key, label) != 0)
die("json_object_dotset_string() failed", type);
}
void
ovni_mark_push(int32_t type, int64_t value)
{
struct ovni_ev ev = {0};
ovni_ev_set_clock(&ev, ovni_clock_now());
ovni_ev_set_mcv(&ev, "OM[");
ovni_payload_add(&ev, (uint8_t *) &value, sizeof(value));
ovni_payload_add(&ev, (uint8_t *) &type, sizeof(type));
ovni_ev_add(&ev);
}
void
ovni_mark_pop(int32_t type, int64_t value)
{
struct ovni_ev ev = {0};
ovni_ev_set_clock(&ev, ovni_clock_now());
ovni_ev_set_mcv(&ev, "OM]");
ovni_payload_add(&ev, (uint8_t *) &value, sizeof(value));
ovni_payload_add(&ev, (uint8_t *) &type, sizeof(type));
ovni_ev_add(&ev);
}

View File

@ -29,3 +29,4 @@ test_emu(dummy.c NAME "ovniver" DRIVER "ovniver.driver.sh")
test_emu(dummy.c NAME "match-doc-events" DRIVER "match-doc-events.sh")
test_emu(dummy.c NAME "match-doc-version" DRIVER "match-doc-version.sh")
test_emu(libovni-attr.c)
test_emu(libovni-mark.c)

View File

@ -0,0 +1,40 @@
/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include <string.h>
#include "instr.h"
#include "ovni.h"
enum {
MARK_COLORS = 1,
COL_RED = 1,
COL_BLUE = 2,
COL_GREEN = 3,
};
/* Check ovni_mark_* API. */
int
main(void)
{
instr_start(0, 1);
ovni_mark_type(MARK_COLORS, "Colors");
if(!ovni_attr_has("ovni.mark.1.title"))
die("missing mark title");
ovni_mark_label(MARK_COLORS, 1, "Red");
ovni_mark_label(MARK_COLORS, 2, "Blue");
ovni_mark_label(MARK_COLORS, 3, "Green");
sleep_us(10); ovni_mark_push(MARK_COLORS, COL_RED);
sleep_us(10); ovni_mark_push(MARK_COLORS, COL_BLUE);
sleep_us(10); ovni_mark_push(MARK_COLORS, COL_GREEN);
sleep_us(10); ovni_mark_pop(MARK_COLORS, COL_GREEN);
sleep_us(10); ovni_mark_pop(MARK_COLORS, COL_BLUE);
sleep_us(10); ovni_mark_pop(MARK_COLORS, COL_RED);
instr_end();
return 0;
}