Connect mark channels to PRV
There must be one channel per thread and type.
This commit is contained in:
parent
1b2f72cc3a
commit
ea79c90c89
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 <errno.h>
|
||||
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user