diff --git a/src/emu/model_pvt.c b/src/emu/model_pvt.c index e87f49b..860f2d5 100644 --- a/src/emu/model_pvt.c +++ b/src/emu/model_pvt.c @@ -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 */ #include "model_pvt.h" @@ -178,7 +178,7 @@ model_pvt_connect_thread(struct emu *emu, const struct model_thread_spec *spec) /* Get cpu PRV */ struct pvt *pvt = recorder_find_pvt(&emu->recorder, "thread"); if (pvt == NULL) { - err("cannot find cpu pvt"); + err("cannot find thread pvt"); return -1; } diff --git a/src/emu/ovni/mark.c b/src/emu/ovni/mark.c index eceebd6..0c765b6 100644 --- a/src/emu/ovni/mark.c +++ b/src/emu/ovni/mark.c @@ -9,6 +9,8 @@ #include "ovni_priv.h" #include "parson.h" #include "pv/pcf.h" +#include "pv/prv.h" +#include "pv/pvt.h" #include "thread.h" #include "uthash.h" #include @@ -19,10 +21,11 @@ struct mark_label { UT_hash_handle hh; /* Indexed by value */ }; -struct mark_chan { +struct mark_type { long type; + long index; /* From 0 to ntypes - 1 */ + enum chan_type ctype; struct mark_label *labels; /* Hash table of labels */ - struct chan ch; char title[MAX_PCF_LABEL]; UT_hash_handle hh; /* Indexed by type */ }; @@ -44,17 +47,17 @@ parse_number(const char *str, int64_t *result) } static struct mark_label * -find_label(struct mark_chan *c, int64_t value) +find_label(struct mark_type *t, int64_t value) { struct mark_label *l; - HASH_FIND(hh, c->labels, &value, sizeof(value), l); + HASH_FIND(hh, t->labels, &value, sizeof(value), l); return l; } static int -add_label(struct mark_chan *c, int64_t value, const char *label) +add_label(struct mark_type *t, int64_t value, const char *label) { - struct mark_label *l = find_label(c, value); + struct mark_label *l = find_label(t, value); if (l != NULL) { if (strcmp(l->label, label) == 0) { @@ -80,17 +83,14 @@ add_label(struct mark_chan *c, int64_t value, const char *label) return -1; } - HASH_ADD(hh, c->labels, value, sizeof(value), l); + HASH_ADD(hh, t->labels, value, sizeof(value), l); return 0; } static int -parse_labels(struct mark_chan *c, JSON_Object *labels) +parse_labels(struct mark_type *t, JSON_Object *labels) { - UNUSED(c); - UNUSED(labels); - /* It may happen that we call this function several times with * overlapping subsets of values. The only restriction is that we don't * define two values with different label. */ @@ -121,7 +121,7 @@ parse_labels(struct mark_chan *c, JSON_Object *labels) return -1; } - if (add_label(c, value, label) != 0) { + if (add_label(t, value, label) != 0) { err("add_label() failed"); return -1; } @@ -130,53 +130,52 @@ parse_labels(struct mark_chan *c, JSON_Object *labels) return 0; } -static struct mark_chan * -find_mark_chan(struct ovni_mark_emu *m, long type) +static struct mark_type * +find_mark_type(struct ovni_mark_emu *m, long type) { - struct mark_chan *c; - HASH_FIND_LONG(m->chan, &type, c); - return c; + struct mark_type *t; + HASH_FIND_LONG(m->types, &type, t); + return t; } -static struct mark_chan * -create_mark_chan(struct ovni_mark_emu *m, long type, const char *chan_type, const char *title) +static struct mark_type * +create_mark_type(struct ovni_mark_emu *m, long type, const char *chan_type, const char *title) { - struct mark_chan *c = find_mark_chan(m, type); + struct mark_type *t = find_mark_type(m, type); - if (c != NULL) { + if (t != NULL) { err("mark type %d already defined", type); return NULL; } - c = calloc(1, sizeof(*c)); - if (c == NULL) { + t = calloc(1, sizeof(*t)); + if (t == NULL) { err("calloc failed:"); return NULL; } - c->type = type; + t->type = type; + t->index = m->ntypes; - int len = snprintf(c->title, MAX_PCF_LABEL, "%s", title); + int len = snprintf(t->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; + t->ctype = CHAN_SINGLE; } else if (strcmp(chan_type, "stack") == 0) { - ctype = CHAN_STACK; + t->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->types, type, t); + m->ntypes++; - HASH_ADD_LONG(m->chan, type, c); - - return c; + return t; } static int @@ -220,27 +219,27 @@ parse_mark(struct ovni_mark_emu *m, const char *typestr, JSON_Value *markval) 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"); + struct mark_type *t = find_mark_type(m, type); + if (t == NULL) { + t = create_mark_type(m, type, chan_type, title); + if (t == NULL) { + err("cannot create mark type"); 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) { + if (strcmp(t->title, title) != 0) { err("mark with type %ld already registered with another title", type); - err(" old: %s", c->title); + err(" old: %s", t->title); err(" new: %s", title); return -1; } } - /* Now populate the mark channel with all value labels */ + /* Now populate the mark type with all value labels */ - if (parse_labels(c, labels) != 0) { + if (parse_labels(t, labels) != 0) { err("cannot parse labels"); return -1; } @@ -257,8 +256,6 @@ scan_thread(struct ovni_mark_emu *memu, struct thread *t) 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); @@ -281,6 +278,39 @@ scan_thread(struct ovni_mark_emu *memu, struct thread *t) return 0; } +static int +create_thread_chan(struct ovni_mark_emu *m, struct bay *bay, struct thread *th) +{ + struct ovni_thread *oth = EXT(th, 'O'); + struct ovni_mark_thread *t = &oth->mark; + + /* Create as many channels as required */ + t->channels = calloc(m->ntypes, sizeof(struct chan)); + if (t->channels == NULL) { + err("calloc failed:"); + return -1; + } + + t->nchannels = m->ntypes; + + struct mark_type *type; + for (type = m->types; type; type = type->hh.next) { + /* TODO: We may use a vector of thread channels in every type to + * avoid the double hash access in events */ + long i = type->index; + struct chan *ch = &t->channels[i]; + chan_init(ch, type->ctype, "thread%ld.mark%ld", + th->gindex, type->type); + + if (bay_register(bay, ch) != 0) { + err("bay_register failed"); + return -1; + } + } + + return 0; +} + /* Scans streams for marks and creates the mark channels */ int mark_create(struct emu *emu) @@ -297,6 +327,61 @@ mark_create(struct emu *emu) } } + for (struct thread *th = emu->system.threads; th; th = th->gnext) { + if (create_thread_chan(memu, &emu->bay, th) != 0) { + err("create_thread_chan failed"); + return -1; + } + } + + return 0; +} + +static int +connect_thread_prv(struct emu *emu, struct thread *sth, struct prv *prv) +{ + struct ovni_emu *oemu = EXT(emu, 'O'); + struct ovni_mark_emu *memu = &oemu->mark; + struct ovni_thread *oth = EXT(sth, 'O'); + struct ovni_mark_thread *mth = &oth->mark; + + for (struct mark_type *type = memu->types; type; type = type->hh.next) { + /* TODO: We may use a vector of thread channels in every type to + * avoid the double hash access in events */ + long i = type->index; + struct chan *ch = &mth->channels[i]; + long row = sth->gindex; + long flags = 0; + long prvtype = type->type + PRV_OVNI_MARK; + if (prv_register(prv, row, prvtype, &emu->bay, ch, flags)) { + err("prv_register failed"); + return -1; + } + } + + return 0; +} + +static int +connect_thread(struct emu *emu) +{ + /* Get cpu PRV */ + struct pvt *pvt = recorder_find_pvt(&emu->recorder, "thread"); + if (pvt == NULL) { + err("cannot find thread pvt"); + return -1; + } + + /* Connect thread channels to PRV */ + struct prv *prv = pvt_get_prv(pvt); + for (struct thread *t = emu->system.threads; t; t = t->gnext) { + if (connect_thread_prv(emu, t, prv) != 0) { + err("connect_thread_prv failed"); + return -1; + } + } + + /* TODO: Init thread PCF */ return 0; } @@ -304,9 +389,12 @@ mark_create(struct emu *emu) int mark_connect(struct emu *emu) { - UNUSED(emu); + if (connect_thread(emu) != 0) { + err("connect_thread() failed"); + return -1; + } - /* TODO: Implement */ + /* TODO: Connect CPU */ return 0; } @@ -325,25 +413,24 @@ mark_event(struct emu *emu) 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); + struct mark_type *mc = find_mark_type(memu, type); if (mc == NULL) { err("cannot find mark with type %ld", type); return -1; } - /* TODO: Remove stub */ - //struct chan *ch = &mc->ch; + long index = mc->index; + struct ovni_thread *oth = EXT(emu->thread, 'O'); + struct ovni_mark_thread *mth = &oth->mark; + + struct chan *ch = &mth->channels[index]; switch (emu->ev->v) { case '[': - //return chan_push(ch, value_int64(value)); - info("chan_push(ch, value_int64(%ld))", value); - return 0; + return chan_push(ch, value_int64(value)); case ']': - //return chan_pop(ch, value_int64(value)); - info("chan_pop(ch, value_int64(%ld))", value); - return 0; + return chan_pop(ch, value_int64(value)); 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 index 7a4cb8d..d5585ed 100644 --- a/src/emu/ovni/mark.h +++ b/src/emu/ovni/mark.h @@ -2,14 +2,20 @@ #define MARK_H #include "common.h" +#include "chan.h" struct emu; struct mark_chan; struct ovni_mark_emu { - /* Hash table of channels */ - struct mark_chan *chan; - int has_marks; + /* Hash table of types of marks */ + struct mark_type *types; + long ntypes; +}; + +struct ovni_mark_thread { + struct chan *channels; + long nchannels; }; USE_RET int mark_create(struct emu *emu); diff --git a/src/emu/ovni/ovni_priv.h b/src/emu/ovni/ovni_priv.h index 9e68d7c..294b9cc 100644 --- a/src/emu/ovni/ovni_priv.h +++ b/src/emu/ovni/ovni_priv.h @@ -34,6 +34,8 @@ struct ovni_thread { int64_t burst_time[MAX_BURSTS]; int64_t flush_start; + + struct ovni_mark_thread mark; }; struct ovni_cpu { diff --git a/src/emu/ovni/setup.c b/src/emu/ovni/setup.c index 7d2f2f1..7e56f26 100644 --- a/src/emu/ovni/setup.c +++ b/src/emu/ovni/setup.c @@ -208,6 +208,11 @@ model_ovni_connect(struct emu *emu) return -1; } + if (mark_connect(emu) != 0) { + err("mark_connect failed"); + return -1; + } + return 0; } diff --git a/test/emu/ovni/libovni-mark.c b/test/emu/ovni/libovni-mark.c index 3dd5d55..730d239 100644 --- a/test/emu/ovni/libovni-mark.c +++ b/test/emu/ovni/libovni-mark.c @@ -23,9 +23,9 @@ main(void) 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"); + ovni_mark_label(MARK_COLORS, 1, "Blue"); + ovni_mark_label(MARK_COLORS, 2, "Gray"); + ovni_mark_label(MARK_COLORS, 3, "Red"); sleep_us(10); ovni_mark_push(MARK_COLORS, COL_RED); sleep_us(10); ovni_mark_push(MARK_COLORS, COL_BLUE);