From 505245d54ccf442b64ac7fd22ed0902b4da075e3 Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Date: Fri, 14 Jun 2024 13:30:38 +0200 Subject: [PATCH] Implement emulator logic to parse mark metadata The marks are parsed from the metadata definition, then merged from all threads and a new channel for each mark type is created. The channel type is specified using a flag when calling ovni_mark_type(), so the channels is set to single or stack. For now, only ovni_mark_push() and ovni_mark_pop() are implemented. --- include/ovni.h.in | 5 +- src/emu/CMakeLists.txt | 1 + src/emu/ovni/event.c | 4 +- src/emu/ovni/mark.c | 259 +++++++++++++++++++++++++++++++++++ src/emu/ovni/mark.h | 19 +++ src/emu/ovni/ovni_priv.h | 7 +- src/emu/ovni/setup.c | 14 ++ src/rt/ovni.c | 11 +- test/emu/ovni/libovni-mark.c | 2 +- 9 files changed, 315 insertions(+), 7 deletions(-) create mode 100644 src/emu/ovni/mark.c create mode 100644 src/emu/ovni/mark.h diff --git a/include/ovni.h.in b/include/ovni.h.in index 237f63c..067e97f 100644 --- a/include/ovni.h.in +++ b/include/ovni.h.in @@ -143,7 +143,10 @@ char *ovni_attr_get_json(const char *key); void ovni_attr_flush(void); /* Mark */ -void ovni_mark_type(int32_t type, const char *title); +enum ovni_mark_flags { + OVNI_MARK_STACK = 1, /*< Use push/pop instead of set */ +}; +void ovni_mark_type(int32_t type, long flags, 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); diff --git a/src/emu/CMakeLists.txt b/src/emu/CMakeLists.txt index a655d84..97d696b 100644 --- a/src/emu/CMakeLists.txt +++ b/src/emu/CMakeLists.txt @@ -49,6 +49,7 @@ add_library(emu STATIC value.c ovni/event.c ovni/setup.c + ovni/mark.c nanos6/setup.c nanos6/event.c nanos6/breakdown.c diff --git a/src/emu/ovni/event.c b/src/emu/ovni/event.c index 338f48e..9f83844 100644 --- a/src/emu/ovni/event.c +++ b/src/emu/ovni/event.c @@ -16,6 +16,7 @@ #include "proc.h" #include "thread.h" #include "value.h" +#include "mark.h" static int pre_thread_execute(struct emu *emu, struct thread *th) @@ -478,8 +479,7 @@ model_ovni_event(struct emu *emu) /* Ignore sorting events */ return 0; case 'M': - /* TODO: Ignore mark events for now */ - return 0; + return mark_event(emu); default: err("unknown ovni event category %c", emu->ev->c); diff --git a/src/emu/ovni/mark.c b/src/emu/ovni/mark.c new file mode 100644 index 0000000..184a944 --- /dev/null +++ b/src/emu/ovni/mark.c @@ -0,0 +1,259 @@ +#include "mark.h" + +#include "chan.h" +#include "emu.h" +#include "emu_ev.h" +#include "emu_prv.h" +#include "ovni.h" +#include "ovni_priv.h" +#include "parson.h" +#include "pv/pcf.h" +#include "thread.h" +#include "uthash.h" +#include + +struct mark_value { + int32_t type; + char title[MAX_PCF_LABEL]; + struct chan ch; + struct pcf_type *pcftype; + UT_hash_handle hh; /* Indexed by type */ +}; + +struct mark_chan { + long type; + char title[MAX_PCF_LABEL]; + struct chan ch; + UT_hash_handle hh; /* Indexed by type */ +}; + +static int +parse_labels(struct mark_chan *c, JSON_Object *labels) +{ + UNUSED(c); + UNUSED(labels); + + /* TODO: Implement */ + + return 0; +} + +static struct mark_chan * +find_mark_chan(struct ovni_mark_emu *m, long type) +{ + struct mark_chan *c; + HASH_FIND_LONG(m->chan, &type, c); + return c; +} + +static struct mark_chan * +create_mark_chan(struct ovni_mark_emu *m, long type, const char *chan_type, const char *title) +{ + struct mark_chan *c = find_mark_chan(m, type); + + if (c != NULL) { + err("mark type %d already defined", type); + return NULL; + } + + c = calloc(1, sizeof(*c)); + if (c == NULL) { + err("calloc failed:"); + return NULL; + } + + c->type = type; + + int len = snprintf(c->title, MAX_PCF_LABEL, "%s", title); + if (len >= MAX_PCF_LABEL) { + err("mark title too long: %s", title); + return NULL; + } + + enum chan_type ctype; + if (strcmp(chan_type, "single") == 0) { + ctype = CHAN_SINGLE; + } else if (strcmp(chan_type, "stack") == 0) { + ctype = CHAN_STACK; + } else { + err("chan_type %s not understood", chan_type); + return NULL; + } + + chan_init(&c->ch, ctype, "mark%ld", type); + + HASH_ADD_LONG(m->chan, type, c); + + return c; +} + +static int +parse_mark(struct ovni_mark_emu *m, const char *typestr, JSON_Value *markval) +{ + errno = 0; + char *endptr = NULL; + long type = strtol(typestr, &endptr, 10); + + if (errno != 0 || endptr == typestr || endptr[0] != '\0') { + err("failed to parse type number: %s", typestr); + return -1; + } + + if (type < 0 || type >= 100) { + err("mark type should be in [0, 100) range: %ld", type); + return -1; + } + + JSON_Object *mark = json_value_get_object(markval); + if (mark == NULL) { + err("json_value_get_object() failed"); + return -1; + } + + const char *title = json_object_get_string(mark, "title"); + if (title == NULL) { + err("json_object_get_string() for title failed"); + return -1; + } + + const char *chan_type = json_object_get_string(mark, "chan_type"); + if (chan_type == NULL) { + err("json_object_get_string() for chan_type failed"); + return -1; + } + + JSON_Object *labels = json_object_get_object(mark, "labels"); + if (labels == NULL) { + err("json_object_get_object() for labels failed"); + return -1; + } + + struct mark_chan *c = find_mark_chan(m, type); + if (c == NULL) { + c = create_mark_chan(m, type, chan_type, title); + if (c == NULL) { + err("cannot create mark chan"); + return -1; + } + } else { + /* It may already exist as defined by other threads, so ensure + * they have the same title. */ + if (strcmp(c->title, title) != 0) { + err("mark with type %ld already registered with another title", type); + err(" old: %s", c->title); + err(" new: %s", title); + return -1; + } + } + + /* Now populate the mark channel with all value labels */ + + if (parse_labels(c, labels) != 0) { + err("cannot parse labels"); + return -1; + } + + return 0; +} + +static int +scan_thread(struct ovni_mark_emu *memu, struct thread *t) +{ + JSON_Object *obj = json_object_dotget_object(t->meta, "ovni.mark"); + + /* No marks in this thread */ + if (obj == NULL) + return 0; + + memu->has_marks = 1; + + size_t n = json_object_get_count(obj); + for (size_t i = 0; i < n; i++) { + const char *typestr = json_object_get_name(obj, i); + if (typestr == NULL) { + err("json_object_get_name failed"); + return -1; + } + JSON_Value *markval = json_object_get_value_at(obj, i); + if (markval == NULL) { + err("json_object_get_value_at failed"); + return -1; + } + + if (parse_mark(memu, typestr, markval) != 0) { + err("cannot parse mark"); + return -1; + } + } + + return 0; +} + +/* Scans streams for marks and creates the mark channels */ +int +mark_create(struct emu *emu) +{ + struct ovni_emu *oemu = EXT(emu, 'O'); + struct ovni_mark_emu *memu = &oemu->mark; + + memset(memu, 0, sizeof(*memu)); + + for (struct thread *th = emu->system.threads; th; th = th->gnext) { + if (scan_thread(memu, th) != 0) { + err("scan_thread failed"); + return -1; + } + } + + return 0; +} + +/* Connect the channels to the output PVTs */ +int +mark_connect(struct emu *emu) +{ + UNUSED(emu); + + /* TODO: Implement */ + + return 0; +} + +int +mark_event(struct emu *emu) +{ + if (emu->ev->payload_size != 8 + 4) { + err("unexpected payload size %d", emu->ev->payload_size); + return -1; + } + + struct ovni_emu *oemu = EXT(emu, 'O'); + struct ovni_mark_emu *memu = &oemu->mark; + + int64_t value = emu->ev->payload->i64[0]; + long type = (long) emu->ev->payload->i32[2]; /* always fits */ + + struct mark_chan *mc = find_mark_chan(memu, type); + + if (mc == NULL) { + err("cannot find mark with type %ld", type); + return -1; + } + + /* TODO: Remove stub */ + //struct chan *ch = &mc->ch; + + switch (emu->ev->v) { + case '[': + //return chan_push(ch, value_int64(value)); + info("chan_push(ch, value_int64(%ld))", value); + return 0; + case ']': + //return chan_pop(ch, value_int64(value)); + info("chan_pop(ch, value_int64(%ld))", value); + return 0; + default: + err("unknown mark event value %c", emu->ev->v); + return -1; + } +} diff --git a/src/emu/ovni/mark.h b/src/emu/ovni/mark.h new file mode 100644 index 0000000..7a4cb8d --- /dev/null +++ b/src/emu/ovni/mark.h @@ -0,0 +1,19 @@ +#ifndef MARK_H +#define MARK_H + +#include "common.h" + +struct emu; +struct mark_chan; + +struct ovni_mark_emu { + /* Hash table of channels */ + struct mark_chan *chan; + int has_marks; +}; + +USE_RET int mark_create(struct emu *emu); +USE_RET int mark_connect(struct emu *emu); +USE_RET int mark_event(struct emu *emu); + +#endif /* MARK_H */ diff --git a/src/emu/ovni/ovni_priv.h b/src/emu/ovni/ovni_priv.h index c5d2ccd..9e68d7c 100644 --- a/src/emu/ovni/ovni_priv.h +++ b/src/emu/ovni/ovni_priv.h @@ -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 OVNI_PRIV_H @@ -10,6 +10,7 @@ * execution by the kernel. */ #include "emu.h" +#include "mark.h" #include "model_cpu.h" #include "model_thread.h" #include @@ -39,6 +40,10 @@ struct ovni_cpu { struct model_cpu m; }; +struct ovni_emu { + struct ovni_mark_emu mark; +}; + int model_ovni_probe(struct emu *emu); int model_ovni_create(struct emu *emu); int model_ovni_connect(struct emu *emu); diff --git a/src/emu/ovni/setup.c b/src/emu/ovni/setup.c index 84be469..7d2f2f1 100644 --- a/src/emu/ovni/setup.c +++ b/src/emu/ovni/setup.c @@ -7,6 +7,7 @@ #include "emu.h" #include "emu_prv.h" #include "ev_spec.h" +#include "mark.h" #include "model.h" #include "model_chan.h" #include "model_cpu.h" @@ -178,6 +179,19 @@ model_ovni_create(struct emu *emu) return -1; } + struct ovni_emu *oemu = calloc(1, sizeof(*oemu)); + if (oemu == NULL) { + err("calloc failed:"); + return -1; + } + + extend_set(&emu->ext, 'O', oemu); + + if (mark_create(emu) != 0) { + err("mark_create failed"); + return -1; + } + return 0; } diff --git a/src/rt/ovni.c b/src/rt/ovni.c index 3c6d7ec..cab83eb 100644 --- a/src/rt/ovni.c +++ b/src/rt/ovni.c @@ -1067,7 +1067,7 @@ ovni_attr_flush(void) /** creates a new mark type. */ void -ovni_mark_type(int32_t type, const char *title) +ovni_mark_type(int32_t type, long flags, const char *title) { if (type < 0 || type >= 100) die("type must be in [0,100) range"); @@ -1089,7 +1089,14 @@ ovni_mark_type(int32_t type, const char *title) die("title key too long"); if (json_object_dotset_string(meta, key, title) != 0) - die("json_object_dotset_string() failed", type); + die("json_object_dotset_string() failed for title"); + + const char *chan_type = flags & OVNI_MARK_STACK ? "stack" : "single"; + if (snprintf(key, 128, "ovni.mark.%"PRId32".chan_type", type) >= 128) + die("chan_type key too long"); + + if (json_object_dotset_string(meta, key, chan_type) != 0) + die("json_object_dotset_string() failed for chan_type"); } /** creates a new mark type. */ diff --git a/test/emu/ovni/libovni-mark.c b/test/emu/ovni/libovni-mark.c index 25a167c..3dd5d55 100644 --- a/test/emu/ovni/libovni-mark.c +++ b/test/emu/ovni/libovni-mark.c @@ -18,7 +18,7 @@ main(void) { instr_start(0, 1); - ovni_mark_type(MARK_COLORS, "Colors"); + ovni_mark_type(MARK_COLORS, OVNI_MARK_STACK, "Colors"); if(!ovni_attr_has("ovni.mark.1.title")) die("missing mark title");