Connect mark channels to PRV

There must be one channel per thread and type.
This commit is contained in:
Rodrigo Arias 2024-06-14 15:39:17 +02:00
parent 1b2f72cc3a
commit ea79c90c89
6 changed files with 162 additions and 62 deletions

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 */ * SPDX-License-Identifier: GPL-3.0-or-later */
#include "model_pvt.h" #include "model_pvt.h"
@ -178,7 +178,7 @@ model_pvt_connect_thread(struct emu *emu, const struct model_thread_spec *spec)
/* Get cpu PRV */ /* Get cpu PRV */
struct pvt *pvt = recorder_find_pvt(&emu->recorder, "thread"); struct pvt *pvt = recorder_find_pvt(&emu->recorder, "thread");
if (pvt == NULL) { if (pvt == NULL) {
err("cannot find cpu pvt"); err("cannot find thread pvt");
return -1; return -1;
} }

View File

@ -9,6 +9,8 @@
#include "ovni_priv.h" #include "ovni_priv.h"
#include "parson.h" #include "parson.h"
#include "pv/pcf.h" #include "pv/pcf.h"
#include "pv/prv.h"
#include "pv/pvt.h"
#include "thread.h" #include "thread.h"
#include "uthash.h" #include "uthash.h"
#include <errno.h> #include <errno.h>
@ -19,10 +21,11 @@ struct mark_label {
UT_hash_handle hh; /* Indexed by value */ UT_hash_handle hh; /* Indexed by value */
}; };
struct mark_chan { struct mark_type {
long type; long type;
long index; /* From 0 to ntypes - 1 */
enum chan_type ctype;
struct mark_label *labels; /* Hash table of labels */ struct mark_label *labels; /* Hash table of labels */
struct chan ch;
char title[MAX_PCF_LABEL]; char title[MAX_PCF_LABEL];
UT_hash_handle hh; /* Indexed by type */ UT_hash_handle hh; /* Indexed by type */
}; };
@ -44,17 +47,17 @@ parse_number(const char *str, int64_t *result)
} }
static struct mark_label * 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; struct mark_label *l;
HASH_FIND(hh, c->labels, &value, sizeof(value), l); HASH_FIND(hh, t->labels, &value, sizeof(value), l);
return l; return l;
} }
static int 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 (l != NULL) {
if (strcmp(l->label, label) == 0) { if (strcmp(l->label, label) == 0) {
@ -80,17 +83,14 @@ add_label(struct mark_chan *c, int64_t value, const char *label)
return -1; return -1;
} }
HASH_ADD(hh, c->labels, value, sizeof(value), l); HASH_ADD(hh, t->labels, value, sizeof(value), l);
return 0; return 0;
} }
static int 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 /* It may happen that we call this function several times with
* overlapping subsets of values. The only restriction is that we don't * overlapping subsets of values. The only restriction is that we don't
* define two values with different label. */ * define two values with different label. */
@ -121,7 +121,7 @@ parse_labels(struct mark_chan *c, JSON_Object *labels)
return -1; return -1;
} }
if (add_label(c, value, label) != 0) { if (add_label(t, value, label) != 0) {
err("add_label() failed"); err("add_label() failed");
return -1; return -1;
} }
@ -130,53 +130,52 @@ parse_labels(struct mark_chan *c, JSON_Object *labels)
return 0; return 0;
} }
static struct mark_chan * static struct mark_type *
find_mark_chan(struct ovni_mark_emu *m, long type) find_mark_type(struct ovni_mark_emu *m, long type)
{ {
struct mark_chan *c; struct mark_type *t;
HASH_FIND_LONG(m->chan, &type, c); HASH_FIND_LONG(m->types, &type, t);
return c; return t;
} }
static struct mark_chan * static struct mark_type *
create_mark_chan(struct ovni_mark_emu *m, long type, const char *chan_type, const char *title) 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); err("mark type %d already defined", type);
return NULL; return NULL;
} }
c = calloc(1, sizeof(*c)); t = calloc(1, sizeof(*t));
if (c == NULL) { if (t == NULL) {
err("calloc failed:"); err("calloc failed:");
return NULL; 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) { if (len >= MAX_PCF_LABEL) {
err("mark title too long: %s", title); err("mark title too long: %s", title);
return NULL; return NULL;
} }
enum chan_type ctype;
if (strcmp(chan_type, "single") == 0) { if (strcmp(chan_type, "single") == 0) {
ctype = CHAN_SINGLE; t->ctype = CHAN_SINGLE;
} else if (strcmp(chan_type, "stack") == 0) { } else if (strcmp(chan_type, "stack") == 0) {
ctype = CHAN_STACK; t->ctype = CHAN_STACK;
} else { } else {
err("chan_type %s not understood", chan_type); err("chan_type %s not understood", chan_type);
return NULL; 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 t;
return c;
} }
static int static int
@ -220,27 +219,27 @@ parse_mark(struct ovni_mark_emu *m, const char *typestr, JSON_Value *markval)
return -1; return -1;
} }
struct mark_chan *c = find_mark_chan(m, type); struct mark_type *t = find_mark_type(m, type);
if (c == NULL) { if (t == NULL) {
c = create_mark_chan(m, type, chan_type, title); t = create_mark_type(m, type, chan_type, title);
if (c == NULL) { if (t == NULL) {
err("cannot create mark chan"); err("cannot create mark type");
return -1; return -1;
} }
} else { } else {
/* It may already exist as defined by other threads, so ensure /* It may already exist as defined by other threads, so ensure
* they have the same title. */ * 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("mark with type %ld already registered with another title", type);
err(" old: %s", c->title); err(" old: %s", t->title);
err(" new: %s", title); err(" new: %s", title);
return -1; 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"); err("cannot parse labels");
return -1; return -1;
} }
@ -257,8 +256,6 @@ scan_thread(struct ovni_mark_emu *memu, struct thread *t)
if (obj == NULL) if (obj == NULL)
return 0; return 0;
memu->has_marks = 1;
size_t n = json_object_get_count(obj); size_t n = json_object_get_count(obj);
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
const char *typestr = json_object_get_name(obj, 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; 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 */ /* Scans streams for marks and creates the mark channels */
int int
mark_create(struct emu *emu) 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; return 0;
} }
@ -304,9 +389,12 @@ mark_create(struct emu *emu)
int int
mark_connect(struct emu *emu) 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; return 0;
} }
@ -325,25 +413,24 @@ mark_event(struct emu *emu)
int64_t value = emu->ev->payload->i64[0]; int64_t value = emu->ev->payload->i64[0];
long type = (long) emu->ev->payload->i32[2]; /* always fits */ 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) { if (mc == NULL) {
err("cannot find mark with type %ld", type); err("cannot find mark with type %ld", type);
return -1; return -1;
} }
/* TODO: Remove stub */ long index = mc->index;
//struct chan *ch = &mc->ch; 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) { switch (emu->ev->v) {
case '[': case '[':
//return chan_push(ch, value_int64(value)); return chan_push(ch, value_int64(value));
info("chan_push(ch, value_int64(%ld))", value);
return 0;
case ']': case ']':
//return chan_pop(ch, value_int64(value)); return chan_pop(ch, value_int64(value));
info("chan_pop(ch, value_int64(%ld))", value);
return 0;
default: default:
err("unknown mark event value %c", emu->ev->v); err("unknown mark event value %c", emu->ev->v);
return -1; return -1;

View File

@ -2,14 +2,20 @@
#define MARK_H #define MARK_H
#include "common.h" #include "common.h"
#include "chan.h"
struct emu; struct emu;
struct mark_chan; struct mark_chan;
struct ovni_mark_emu { struct ovni_mark_emu {
/* Hash table of channels */ /* Hash table of types of marks */
struct mark_chan *chan; struct mark_type *types;
int has_marks; long ntypes;
};
struct ovni_mark_thread {
struct chan *channels;
long nchannels;
}; };
USE_RET int mark_create(struct emu *emu); USE_RET int mark_create(struct emu *emu);

View File

@ -34,6 +34,8 @@ struct ovni_thread {
int64_t burst_time[MAX_BURSTS]; int64_t burst_time[MAX_BURSTS];
int64_t flush_start; int64_t flush_start;
struct ovni_mark_thread mark;
}; };
struct ovni_cpu { struct ovni_cpu {

View File

@ -208,6 +208,11 @@ model_ovni_connect(struct emu *emu)
return -1; return -1;
} }
if (mark_connect(emu) != 0) {
err("mark_connect failed");
return -1;
}
return 0; return 0;
} }

View File

@ -23,9 +23,9 @@ main(void)
if(!ovni_attr_has("ovni.mark.1.title")) if(!ovni_attr_has("ovni.mark.1.title"))
die("missing mark title"); die("missing mark title");
ovni_mark_label(MARK_COLORS, 1, "Red"); ovni_mark_label(MARK_COLORS, 1, "Blue");
ovni_mark_label(MARK_COLORS, 2, "Blue"); ovni_mark_label(MARK_COLORS, 2, "Gray");
ovni_mark_label(MARK_COLORS, 3, "Green"); 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_RED);
sleep_us(10); ovni_mark_push(MARK_COLORS, COL_BLUE); sleep_us(10); ovni_mark_push(MARK_COLORS, COL_BLUE);