Add API to manage metadata in streams

The ovni_attr_* set of functions allows users to write and read metadata
stores in the thread stream. The metadata information is available to
the emulator at the beginning of the emulation.
This commit is contained in:
Rodrigo Arias 2024-06-12 16:43:52 +02:00
parent 2ac67cff18
commit d1e8a62396
5 changed files with 274 additions and 2 deletions

View File

@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add support for nOS-V progressing events VP{pra}. - Add support for nOS-V progressing events VP{pra}.
- Add breakdown model for nOS-V. - Add breakdown model for nOS-V.
- New API to manage stream metadata `ovni_attr_*()`.
## [1.9.1] - 2024-05-10 ## [1.9.1] - 2024-05-10

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: MIT */ * SPDX-License-Identifier: MIT */
#ifndef OVNI_H #ifndef OVNI_H
@ -130,6 +130,18 @@ void ovni_ev_jumbo_emit(struct ovni_ev *ev, const uint8_t *buf, uint32_t bufsize
void ovni_flush(void); void ovni_flush(void);
/* Attributes */
int ovni_attr_has(const char *key);
void ovni_attr_set_double(const char *key, double num);
void ovni_attr_set_boolean(const char *key, int value);
void ovni_attr_set_str(const char *key, const char *value);
void ovni_attr_set_json(const char *key, const char *json);
double ovni_attr_get_double(const char *key);
int ovni_attr_get_boolean(const char *key);
const char *ovni_attr_get_str(const char *key);
char *ovni_attr_get_json(const char *key);
void ovni_attr_flush(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #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: MIT */ * SPDX-License-Identifier: MIT */
#include <dirent.h> #include <dirent.h>
@ -848,3 +848,216 @@ ovni_ev_emit(struct ovni_ev *ev)
{ {
ovni_ev_add(ev); ovni_ev_add(ev);
} }
/* Attributes */
static JSON_Object *
get_thread_metadata(void)
{
if (rthread.finished)
die("thread already finished");
if (!rthread.ready)
die("thread not initialized");
JSON_Object *meta = json_value_get_object(rthread.meta);
if (meta == NULL)
die("json_value_get_object failed");
return meta;
}
/**
* Determines if the key exists in the metadata.
*
* @returns 1 if the key exists, 0 otherwise.
*/
int
ovni_attr_has(const char *key)
{
JSON_Object *obj = get_thread_metadata();
JSON_Value *val = json_object_dotget_value(obj, key);
if (val == NULL)
return 0;
return 1;
}
/**
* Stores a double attribute.
*
* @param key The key of the attribute as a dot path.
* @param num The double value to be stored.
*/
void
ovni_attr_set_double(const char *key, double num)
{
JSON_Object *obj = get_thread_metadata();
if (json_object_dotset_number(obj, key, num) != 0)
die("json_object_dotset_number() failed");
}
/**
* Retrieves a double attribute.
*
* @param key The key of the attribute as a dot path.
*
* @return The double on the key. If there is any problem it aborts.
*/
double
ovni_attr_get_double(const char *key)
{
JSON_Object *obj = get_thread_metadata();
JSON_Value *val = json_object_dotget_value(obj, key);
if (val == NULL)
die("key not found: %s", key);
if (json_value_get_type(val) != JSONNumber)
die("value with key '%s' is not a number", key);
return json_value_get_number(val);
}
/**
* Retrieves a boolean attribute.
*
* @param key The key of the attribute as a dot path.
*
* @return The boolean on the key. If there is any problem it aborts.
*/
int
ovni_attr_get_boolean(const char *key)
{
JSON_Object *obj = get_thread_metadata();
JSON_Value *val = json_object_dotget_value(obj, key);
if (val == NULL)
die("key not found: %s", key);
if (json_value_get_type(val) != JSONBoolean)
die("value with key '%s' is not a boolean", key);
return json_value_get_boolean(val);
}
/**
* Stores a boolean attribute.
*
* @param key The key of the attribute as a dot path.
* @param num The boolean value to be stored.
*/
void
ovni_attr_set_boolean(const char *key, int value)
{
JSON_Object *obj = get_thread_metadata();
if (json_object_dotset_boolean(obj, key, value) != 0)
die("json_object_dotset_boolean() failed");
}
/**
* Stores a string attribute.
*
* @param key The key of the attribute as a dot path.
* @param str The string value to be stored. It will be internally duplicated,
* so it can be free on return.
*/
void
ovni_attr_set_str(const char *key, const char *value)
{
JSON_Object *obj = get_thread_metadata();
if (json_object_dotset_string(obj, key, value) != 0)
die("json_object_dotset_string() failed");
}
/**
* Retrieves a string attribute from a key.
* If not found or if there is any problem it aborts before returning.
*
* @param key The key of the attribute as a dot path.
*
* @return A pointer to a not-NULL read-only string value for the given key.
*/
const char *
ovni_attr_get_str(const char *key)
{
JSON_Object *obj = get_thread_metadata();
JSON_Value *val = json_object_dotget_value(obj, key);
if (val == NULL)
die("key not found: %s", key);
if (json_value_get_type(val) != JSONString)
die("value with key '%s' is not a string", key);
return json_value_get_string(val);
}
/**
* Stores a JSON value into an attribute.
*
* @param key The key of the attribute as a dot path.
* @param json The JSON value to be stored.
*
* The value specified as a JSON string can be of any type (dictionary, array,
* string, double...) as long as it is valid JSON. Any errors in parsing the
* JSON string or in storing the resulting value will abort the program.
*/
void
ovni_attr_set_json(const char *key, const char *json)
{
JSON_Object *obj = get_thread_metadata();
JSON_Value *val = json_parse_string(json);
if (val == NULL)
die("cannot parse json: %s", json);
if (json_object_dotset_value(obj, key, val) != 0)
die("json_object_dotset_value() failed");
}
/**
* Serializes a JSON value into a string.
*
* @param key The key of the attribute as a dot path.
*
* @resurn A zero-terminated string containing the serialized JSON
* representation of the provided key. This string is allocated with malloc()
* and it is reponsability of the user to liberate the memory with free().
*
* Any errors will abort the program.
*/
char *
ovni_attr_get_json(const char *key)
{
JSON_Object *obj = get_thread_metadata();
JSON_Value *val = json_object_dotget_value(obj, key);
if (val == NULL)
die("key not found: %s", key);
char *str = json_serialize_to_string(val);
if (str == NULL)
die("json_serialize_to_string() failed");
return str;
}
/**
* Writes the metadata attributes to disk.
* Only used to ensure they are not lost in a crash. They are already written in
* ovni_thread_free().
*/
void
ovni_attr_flush(void)
{
if (rthread.finished)
die("thread already finished");
if (!rthread.ready)
die("thread not initialized");
thread_metadata_store();
}

View File

@ -28,3 +28,4 @@ test_emu(tmpdir-metadata.c MP DRIVER "tmpdir-metadata.driver.sh")
test_emu(dummy.c NAME "ovniver" DRIVER "ovniver.driver.sh") 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-events" DRIVER "match-doc-events.sh")
test_emu(dummy.c NAME "match-doc-version" DRIVER "match-doc-version.sh") test_emu(dummy.c NAME "match-doc-version" DRIVER "match-doc-version.sh")
test_emu(libovni-attr.c)

View File

@ -0,0 +1,45 @@
/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include <string.h>
#include "instr.h"
#include "ovni.h"
/* Check stream attribute setting and getting. */
int
main(void)
{
instr_start(0, 1);
ovni_attr_set_double("ovni.test.double", 123.5);
if (ovni_attr_get_double("ovni.test.double") != 123.5)
die("mismatch double");
ovni_attr_set_boolean("ovni.test.boolean", 1);
if (!ovni_attr_get_boolean("ovni.test.boolean"))
die("mismatch boolean");
ovni_attr_set_str("ovni.test.str", "foo");
const char *str = ovni_attr_get_str("ovni.test.str");
if (str == NULL || strcmp(str, "foo") != 0)
die("mismatch string");
const char *json = "{\"foo\":42}";
ovni_attr_set_json("nosv.test.json", json);
char *json2 = ovni_attr_get_json("nosv.test.json");
if (strcmp(json, json2) != 0)
die("mismatch json: in '%s' out '%s'", json, json2);
if (!ovni_attr_has("nosv.test.json.foo"))
die("missing attribute");
if (ovni_attr_get_double("nosv.test.json.foo") != 42.0)
die("mismatch double");
free(json2);
instr_end();
return 0;
}