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.
This commit is contained in:
parent
93ab5a5833
commit
505245d54c
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
259
src/emu/ovni/mark.c
Normal file
259
src/emu/ovni/mark.c
Normal file
@ -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 <errno.h>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
19
src/emu/ovni/mark.h
Normal file
19
src/emu/ovni/mark.h
Normal file
@ -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 */
|
@ -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 <stdint.h>
|
||||
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user