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:
parent
2ac67cff18
commit
d1e8a62396
@ -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 breakdown model for nOS-V.
|
||||
- New API to manage stream metadata `ovni_attr_*()`.
|
||||
|
||||
## [1.9.1] - 2024-05-10
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
|
||||
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
|
||||
* SPDX-License-Identifier: MIT */
|
||||
|
||||
#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);
|
||||
|
||||
/* 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
|
||||
}
|
||||
#endif
|
||||
|
215
src/rt/ovni.c
215
src/rt/ovni.c
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
|
||||
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
|
||||
* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include <dirent.h>
|
||||
@ -848,3 +848,216 @@ ovni_ev_emit(struct ovni_ev *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();
|
||||
}
|
||||
|
@ -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 "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)
|
||||
|
45
test/emu/ovni/libovni-attr.c
Normal file
45
test/emu/ovni/libovni-attr.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user