diff --git a/src/emu/CMakeLists.txt b/src/emu/CMakeLists.txt index 0efd337..be2d169 100644 --- a/src/emu/CMakeLists.txt +++ b/src/emu/CMakeLists.txt @@ -18,6 +18,9 @@ add_library(emu STATIC emu_args.c emu_ev.c model.c + model_cpu.c + model_thread.c + model_pvt.c models.c player.c stream.c @@ -40,12 +43,8 @@ add_library(emu STATIC ovni/probe.c ovni/create.c ovni/event.c - nanos6/probe.c - nanos6/connect.c - nanos6/create.c + nanos6/setup.c nanos6/event.c - nanos6/pvt.c - nanos6/finish.c nosv/probe.c nosv/connect.c nosv/create.c diff --git a/src/emu/model.h b/src/emu/model.h index f2d821d..8fa6f79 100644 --- a/src/emu/model.h +++ b/src/emu/model.h @@ -7,7 +7,7 @@ #include "emu_hook.h" struct model_spec { - char *name; + const char *name; int model; char *depends; emu_hook_t *probe; diff --git a/src/emu/model_chan.h b/src/emu/model_chan.h new file mode 100644 index 0000000..ab955ac --- /dev/null +++ b/src/emu/model_chan.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef MODEL_CHAN_H +#define MODEL_CHAN_H + +#include "model_pvt.h" + +struct model_chan_spec { + int nch; + const char *prefix; + const char **ch_names; + const int *ch_stack; + const struct model_pvt_spec *pvt; + const int *track; +}; + +#endif /* MODEL_CHAN_H */ diff --git a/src/emu/model_cpu.c b/src/emu/model_cpu.c new file mode 100644 index 0000000..4176790 --- /dev/null +++ b/src/emu/model_cpu.c @@ -0,0 +1,135 @@ +#include "model_cpu.h" + +#include "model_thread.h" + +static struct model_cpu * +get_model_cpu(struct cpu *cpu, int id) +{ + return EXT(cpu, id); +} + +static int +init_chan(struct model_cpu *cpu, const struct model_chan_spec *spec, int64_t gindex) +{ + cpu->track = calloc(spec->nch, sizeof(struct track)); + if (cpu->track == NULL) { + err("calloc failed:"); + return -1; + } + + for (int i = 0; i < spec->nch; i++) { + struct track *track = &cpu->track[i]; + + const char *name = cpu->spec->model->name; + const char *ch_name = spec->ch_names[i]; + + if (track_init(track, cpu->bay, TRACK_TYPE_TH, "%s.cpu%ld.%s", + name, gindex, ch_name) != 0) { + err("track_init failed"); + return -1; + } + } + + return 0; +} + +static int +init_cpu(struct cpu *syscpu, struct bay *bay, const struct model_cpu_spec *spec) +{ + /* The first member must be a struct model_cpu */ + struct model_cpu *cpu = calloc(1, spec->size); + if (cpu == NULL) { + err("calloc failed:"); + return -1; + } + + cpu->spec = spec; + cpu->bay = bay; + + if (init_chan(cpu, spec->chan, syscpu->gindex) != 0) { + err("init_chan failed"); + return -1; + } + + extend_set(&syscpu->ext, spec->model->model, cpu); + return 0; +} + +int +model_cpu_create(struct emu *emu, const struct model_cpu_spec *spec) +{ + struct system *sys = &emu->system; + struct bay *bay = &emu->bay; + + for (struct cpu *c = sys->cpus; c; c = c->next) { + if (init_cpu(c, bay, spec) != 0) { + err("init_cpu failed"); + return -1; + } + } + + return 0; +} + +static int +connect_cpu(struct emu *emu, struct cpu *scpu, int id) +{ + struct model_cpu *cpu = get_model_cpu(scpu, id); + const struct model_chan_spec *chan_spec = cpu->spec->chan; + + for (int i = 0; i < chan_spec->nch; i++) { + struct track *track = &cpu->track[i]; + + /* Choose select CPU channel based on tracking mode (only + * TRACK_TH_RUN allowed, as active may cause collisions) */ + int mode = chan_spec->track[i]; + struct chan *sel = cpu_get_th_chan(scpu, mode); + if (track_set_select(track, mode, sel, NULL) != 0) { + err("track_select failed"); + return -1; + } + + /* Add each thread as input */ + for (struct thread *t = emu->system.threads; t; t = t->gnext) { + struct model_thread *th = EXT(t, id); + + /* Choose input channel from the thread output channels + * based on CPU tracking mode */ + struct value key = value_int64(t->gindex); + struct chan *inp = track_get_output(&th->track[i], mode); + + if (track_add_input(track, mode, key, inp) != 0) { + err("track_add_input failed"); + return -1; + } + } + + /* Set the PRV output */ + track_set_default(track, mode); + } + + return 0; +} + +int +model_cpu_connect(struct emu *emu, const struct model_cpu_spec *spec) +{ + struct system *sys = &emu->system; + int id = spec->model->model; + + /* Connect track channels */ + for (struct cpu *c = sys->cpus; c; c = c->next) { + if (connect_cpu(emu, c, id) != 0) { + err("connect_cpu failed"); + return -1; + } + } + + /* Connect channels to Paraver trace */ + if (model_pvt_connect_cpu(emu, spec) != 0) { + err("model_pvt_connect_cpu failed"); + return -1; + } + + return 0; +} diff --git a/src/emu/model_cpu.h b/src/emu/model_cpu.h new file mode 100644 index 0000000..8b2ce51 --- /dev/null +++ b/src/emu/model_cpu.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef MODEL_CPU_H +#define MODEL_CPU_H + +struct model_cpu_spec; + +#include "emu.h" +#include "bay.h" +#include "track.h" +#include "model.h" +#include "model_chan.h" + +struct model_cpu_spec { + size_t size; + const struct model_chan_spec *chan; + const struct model_spec *model; +}; + +struct model_cpu { + const struct model_cpu_spec *spec; + struct bay *bay; + struct track *track; +}; + +int model_cpu_create(struct emu *emu, const struct model_cpu_spec *spec); +int model_cpu_connect(struct emu *emu, const struct model_cpu_spec *spec); + +#endif /* MODEL_CPU_H */ diff --git a/src/emu/model_pvt.c b/src/emu/model_pvt.c new file mode 100644 index 0000000..de257b2 --- /dev/null +++ b/src/emu/model_pvt.c @@ -0,0 +1,171 @@ +#include "model_pvt.h" + +static const char *pcf_suffix[TRACK_TH_MAX] = { + [TRACK_TH_ANY] = "", + [TRACK_TH_RUN] = "of the RUNNING thread", + [TRACK_TH_ACT] = "of the ACTIVE thread", +}; + +static int +create_values(const struct model_pvt_spec *pvt, + struct pcf_type *t, int i) +{ + const struct pcf_value_label(*q)[] = pvt->label[i]; + + if (q == NULL) + return 0; + + for (const struct pcf_value_label *p = *q; p->label != NULL; p++) + pcf_add_value(t, p->value, p->label); + + return 0; +} + +static int +create_type(const struct model_pvt_spec *pvt, + struct pcf *pcf, int i, int track_mode) +{ + long type = pvt->type[i]; + + if (type == -1) + return 0; + + /* Compute the label by joining the two parts */ + const char *prefix = pvt->prefix[i]; + const char *suffix = pcf_suffix[track_mode]; + + char label[MAX_PCF_LABEL]; + int ret = snprintf(label, MAX_PCF_LABEL, "%s %s", + prefix, suffix); + + if (ret >= MAX_PCF_LABEL) { + err("computed type label too long"); + return -1; + } + + struct pcf_type *pcftype = pcf_add_type(pcf, type, label); + + if (create_values(pvt, pcftype, i) != 0) { + err("create_values failed"); + return -1; + } + + return 0; +} + +static int +init_pcf(const struct model_chan_spec *chan, struct pcf *pcf) +{ + const struct model_pvt_spec *pvt = chan->pvt; + + /* Create default types and values */ + for (int i = 0; i < chan->nch; i++) { + int track_mode = chan->track[i]; + if (create_type(pvt, pcf, i, track_mode) != 0) { + err("create_type failed"); + return -1; + } + } + + return 0; +} + +static int +connect_cpu_prv(struct emu *emu, struct cpu *scpu, struct prv *prv, int id) +{ + struct model_cpu *cpu = EXT(scpu, id); + const struct model_chan_spec *spec = cpu->spec->chan; + for (int i = 0; i < spec->nch; i++) { + struct chan *out = track_get_default(&cpu->track[i]); + long type = spec->pvt->type[i]; + long row = scpu->gindex; + if (prv_register(prv, row, type, &emu->bay, out, PRV_DUP)) { + err("prv_register failed"); + return -1; + } + } + + return 0; +} + +int +model_pvt_connect_cpu(struct emu *emu, const struct model_cpu_spec *spec) +{ + struct system *sys = &emu->system; + int id = spec->model->model; + + /* Get cpu PRV */ + struct pvt *pvt = recorder_find_pvt(&emu->recorder, "cpu"); + if (pvt == NULL) { + err("cannot find cpu pvt"); + return -1; + } + + /* Connect CPU channels to PRV */ + struct prv *prv = pvt_get_prv(pvt); + for (struct cpu *c = sys->cpus; c; c = c->next) { + if (connect_cpu_prv(emu, c, prv, id) != 0) { + err("connect_cpu_prv failed"); + return -1; + } + } + + /* Init CPU PCF */ + struct pcf *pcf = pvt_get_pcf(pvt); + if (init_pcf(spec->chan, pcf) != 0) { + err("init_pcf failed"); + return -1; + } + + return 0; +} + +static int +connect_thread_prv(struct emu *emu, struct thread *sth, struct prv *prv, int id) +{ + struct model_thread *th = EXT(sth, id); + const struct model_chan_spec *spec = th->spec->chan; + for (int i = 0; i < spec->nch; i++) { + struct chan *out = track_get_default(&th->track[i]); + long type = spec->pvt->type[i]; + long row = sth->gindex; + if (prv_register(prv, row, type, &emu->bay, out, PRV_DUP)) { + err("prv_register failed"); + return -1; + } + } + + return 0; +} + +int +model_pvt_connect_thread(struct emu *emu, const struct model_thread_spec *spec) +{ + struct system *sys = &emu->system; + int id = spec->model->model; + + /* Get cpu PRV */ + struct pvt *pvt = recorder_find_pvt(&emu->recorder, "thread"); + if (pvt == NULL) { + err("cannot find cpu pvt"); + return -1; + } + + /* Connect thread channels to PRV */ + struct prv *prv = pvt_get_prv(pvt); + for (struct thread *t = sys->threads; t; t = t->gnext) { + if (connect_thread_prv(emu, t, prv, id) != 0) { + err("connect_thread_prv failed"); + return -1; + } + } + + /* Init thread PCF */ + struct pcf *pcf = pvt_get_pcf(pvt); + if (init_pcf(spec->chan, pcf) != 0) { + err("init_pcf failed"); + return -1; + } + + return 0; +} diff --git a/src/emu/model_pvt.h b/src/emu/model_pvt.h new file mode 100644 index 0000000..f9cfb85 --- /dev/null +++ b/src/emu/model_pvt.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef MODEL_PRV_H +#define MODEL_PRV_H + +#include "emu.h" +#include "pv/pcf.h" + +struct model_pvt_spec { + const int *type; + const char **prefix; + const char **suffix; + const struct pcf_value_label (**label)[]; +}; + +#include "model_cpu.h" +#include "model_thread.h" + +int model_pvt_connect_cpu(struct emu *emu, const struct model_cpu_spec *spec); +int model_pvt_connect_thread(struct emu *emu, const struct model_thread_spec *spec); + +#endif /* MODEL_PRV_H */ diff --git a/src/emu/model_thread.c b/src/emu/model_thread.c new file mode 100644 index 0000000..14c1f20 --- /dev/null +++ b/src/emu/model_thread.c @@ -0,0 +1,112 @@ +#include "model_thread.h" + +#include "model_pvt.h" + +static int +init_chan(struct model_thread *th, const struct model_chan_spec *spec, int64_t gindex) +{ + const char *fmt = "%s.thread%ld.%s"; + const char *prefix = spec->prefix; + + th->ch = calloc(spec->nch, sizeof(struct chan)); + if (th->ch == NULL) { + err("calloc failed:"); + return -1; + } + + for (int i = 0; i < spec->nch; i++) { + struct chan *c = &th->ch[i]; + int type = spec->ch_stack[i]; + const char *ch_name = spec->ch_names[i]; + chan_init(c, type, fmt, prefix, gindex, ch_name); + + if (bay_register(th->bay, c) != 0) { + err("bay_register failed"); + return -1; + } + } + + th->track = calloc(spec->nch, sizeof(struct track)); + if (th->track == NULL) { + err("calloc failed:"); + return -1; + } + + for (int i = 0; i < spec->nch; i++) { + struct track *track = &th->track[i]; + + const char *ch_name = spec->ch_names[i]; + + if (track_init(track, th->bay, TRACK_TYPE_TH, fmt, + prefix, gindex, ch_name) != 0) { + err("track_init failed"); + return -1; + } + } + + return 0; +} + +static int +init_thread(struct thread *systh, struct bay *bay, const struct model_thread_spec *spec) +{ + struct model_thread *th = calloc(1, spec->size); + if (th == NULL) { + err("calloc failed:"); + return -1; + } + + th->spec = spec; + th->bay = bay; + + if (init_chan(th, spec->chan, systh->gindex) != 0) { + err("init_chan failed"); + return -1; + } + + extend_set(&systh->ext, spec->model->model, th); + + return 0; +} + +int +model_thread_create(struct emu *emu, const struct model_thread_spec *spec) +{ + struct system *sys = &emu->system; + struct bay *bay = &emu->bay; + + for (struct thread *t = sys->threads; t; t = t->gnext) { + if (init_thread(t, bay, spec) != 0) { + err("init_thread failed"); + return -1; + } + } + + return 0; +} + +int +model_thread_connect(struct emu *emu, const struct model_thread_spec *spec) +{ + int id = spec->model->model; + struct system *sys = &emu->system; + + for (struct thread *t = sys->threads; t; t = t->gnext) { + struct model_thread *th = EXT(t, id); + struct chan *sel = &t->chan[TH_CHAN_STATE]; + const int *modes = th->spec->chan->track; + int nch = th->spec->chan->nch; + if (track_connect_thread(th->track, th->ch, modes, sel, nch) != 0) { + err("track_thread failed"); + return -1; + } + } + + /* Connect channels to Paraver trace */ + if (model_pvt_connect_thread(emu, spec) != 0) { + err("model_pvt_connect_thread failed"); + return -1; + } + + return 0; +} diff --git a/src/emu/model_thread.h b/src/emu/model_thread.h new file mode 100644 index 0000000..cc7614d --- /dev/null +++ b/src/emu/model_thread.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef MODEL_THREAD_H +#define MODEL_THREAD_H + +struct model_thread_spec; + +#include "emu.h" +#include "bay.h" +#include "track.h" +#include "model.h" +#include "model_chan.h" + +struct model_thread_spec { + size_t size; + const struct model_chan_spec *chan; + const struct model_spec *model; +}; + +struct model_thread { + const struct model_thread_spec *spec; + struct bay *bay; + struct chan *ch; + struct track *track; +}; + +int model_thread_create(struct emu *emu, const struct model_thread_spec *spec); +int model_thread_connect(struct emu *emu, const struct model_thread_spec *spec); + +#endif /* MODEL_THREAD_H */ diff --git a/src/emu/nanos6/connect.c b/src/emu/nanos6/connect.c deleted file mode 100644 index 06dc4b0..0000000 --- a/src/emu/nanos6/connect.c +++ /dev/null @@ -1,95 +0,0 @@ -#include "nanos6_priv.h" - -static const int th_track[CH_MAX] = { - [CH_TASKID] = TRACK_TH_RUN, - [CH_TYPE] = TRACK_TH_RUN, - [CH_SUBSYSTEM] = TRACK_TH_ACT, - [CH_RANK] = TRACK_TH_RUN, - [CH_THREAD] = TRACK_TH_ANY, -}; - -static const int cpu_track[CH_MAX] = { - [CH_TASKID] = TRACK_TH_RUN, - [CH_TYPE] = TRACK_TH_RUN, - [CH_SUBSYSTEM] = TRACK_TH_RUN, - [CH_RANK] = TRACK_TH_RUN, - [CH_THREAD] = TRACK_TH_RUN, -}; - -int -nanos6_get_track(enum nanos6_chan c, enum nanos6_chan_type type) -{ - if (type == CT_TH) - return th_track[c]; - else - return cpu_track[c]; -} - -static int -connect_cpu(struct emu *emu, struct cpu *scpu) -{ - struct nanos6_cpu *cpu = EXT(scpu, '6'); - for (int i = 0; i < CH_MAX; i++) { - struct track *track = &cpu->track[i]; - - /* Choose select CPU channel based on tracking mode (only - * TRACK_TH_RUN allowed, as active may cause collisions) */ - int mode = nanos6_get_track(i, CT_CPU); - struct chan *sel = cpu_get_th_chan(scpu, mode); - if (track_set_select(track, mode, sel, NULL) != 0) { - err("track_select failed"); - return -1; - } - - /* Add each thread as input */ - for (struct thread *t = emu->system.threads; t; t = t->gnext) { - struct nanos6_thread *th = EXT(t, '6'); - - /* Choose input channel from the thread output channels - * based on CPU tracking mode */ - struct value key = value_int64(t->gindex); - struct chan *inp = track_get_output(&th->track[i], mode); - - if (track_add_input(track, mode, key, inp) != 0) { - err("track_add_input failed"); - return -1; - } - } - - /* Set the PRV output */ - track_set_default(track, nanos6_get_track(i, CT_CPU)); - } - - return 0; -} - -int -nanos6_connect(struct emu *emu) -{ - struct system *sys = &emu->system; - - /* threads */ - for (struct thread *t = sys->threads; t; t = t->gnext) { - struct nanos6_thread *th = EXT(t, '6'); - struct chan *sel = &t->chan[TH_CHAN_STATE]; - if (track_connect_thread(th->track, th->ch, th_track, sel, CH_MAX) != 0) { - err("track_thread failed"); - return -1; - } - } - - /* cpus */ - for (struct cpu *c = sys->cpus; c; c = c->next) { - if (connect_cpu(emu, c) != 0) { - err("connect_cpu failed"); - return -1; - } - } - - if (nanos6_init_pvt(emu) != 0) { - err("init_pvt failed"); - return -1; - } - - return 0; -} diff --git a/src/emu/nanos6/create.c b/src/emu/nanos6/create.c deleted file mode 100644 index 3e54b10..0000000 --- a/src/emu/nanos6/create.c +++ /dev/null @@ -1,154 +0,0 @@ -#include "nanos6_priv.h" - -static const char *chan_name[CH_MAX] = { - [CH_TASKID] = "taskid", - [CH_TYPE] = "task_type", - [CH_SUBSYSTEM] = "subsystem", - [CH_RANK] = "rank", - [CH_THREAD] = "thread_type", -}; - -static const int chan_stack[CH_MAX] = { - [CH_SUBSYSTEM] = 1, - [CH_THREAD] = 1, -}; - -static int -init_chans(struct bay *bay, struct chan *chans, const char *fmt, int64_t gindex) -{ - for (int i = 0; i < CH_MAX; i++) { - struct chan *c = &chans[i]; - int type = chan_stack[i] ? CHAN_STACK : CHAN_SINGLE; - chan_init(c, type, fmt, gindex, chan_name[i]); - - if (bay_register(bay, c) != 0) { - err("bay_register failed"); - return -1; - } - } - - return 0; -} - -static int -init_tracks(struct bay *bay, struct track *tracks, const char *fmt, int64_t gindex) -{ - for (int i = 0; i < CH_MAX; i++) { - struct track *track = &tracks[i]; - - if (track_init(track, bay, TRACK_TYPE_TH, fmt, gindex, chan_name[i]) != 0) { - err("track_init failed"); - return -1; - } - } - - return 0; -} - -static int -init_cpu(struct bay *bay, struct cpu *syscpu) -{ - struct nanos6_cpu *cpu = calloc(1, sizeof(struct nanos6_cpu)); - if (cpu == NULL) { - err("calloc failed:"); - return -1; - } - - cpu->track = calloc(CH_MAX, sizeof(struct track)); - if (cpu->track == NULL) { - err("calloc failed:"); - return -1; - } - - char *fmt = "nanos6.cpu%ld.%s"; - if (init_tracks(bay, cpu->track, fmt, syscpu->gindex) != 0) { - err("init_tracks failed"); - return -1; - } - - extend_set(&syscpu->ext, '6', cpu); - return 0; -} - -static int -init_thread(struct bay *bay, struct thread *systh) -{ - struct nanos6_thread *th = calloc(1, sizeof(struct nanos6_thread)); - if (th == NULL) { - err("calloc failed:"); - return -1; - } - - th->ch = calloc(CH_MAX, sizeof(struct chan)); - if (th->ch == NULL) { - err("calloc failed:"); - return -1; - } - - th->track = calloc(CH_MAX, sizeof(struct track)); - if (th->track == NULL) { - err("calloc failed:"); - return -1; - } - - char *fmt = "nanos6.thread%ld.%s"; - if (init_chans(bay, th->ch, fmt, systh->gindex) != 0) { - err("init_chans failed"); - return -1; - } - - if (init_tracks(bay, th->track, fmt, systh->gindex) != 0) { - err("init_tracks failed"); - return -1; - } - - th->task_stack.thread = systh; - - extend_set(&systh->ext, '6', th); - - return 0; -} - -static int -init_proc(struct proc *sysproc) -{ - struct nanos6_proc *proc = calloc(1, sizeof(struct nanos6_proc)); - if (proc == NULL) { - err("calloc failed:"); - return -1; - } - - extend_set(&sysproc->ext, '6', proc); - - return 0; -} - -int -nanos6_create(struct emu *emu) -{ - struct system *sys = &emu->system; - struct bay *bay = &emu->bay; - - for (struct cpu *c = sys->cpus; c; c = c->next) { - if (init_cpu(bay, c) != 0) { - err("init_cpu failed"); - return -1; - } - } - - for (struct thread *t = sys->threads; t; t = t->gnext) { - if (init_thread(bay, t) != 0) { - err("init_thread failed"); - return -1; - } - } - - for (struct proc *p = sys->procs; p; p = p->gnext) { - if (init_proc(p) != 0) { - err("init_proc failed"); - return -1; - } - } - - return 0; -} diff --git a/src/emu/nanos6/event.c b/src/emu/nanos6/event.c index 0cc9e20..660c1f8 100644 --- a/src/emu/nanos6/event.c +++ b/src/emu/nanos6/event.c @@ -95,7 +95,7 @@ simple(struct emu *emu) int st = entry[2]; struct nanos6_thread *th = EXT(emu->thread, '6'); - struct chan *ch = &th->ch[chind]; + struct chan *ch = &th->m.ch[chind]; if (action == PUSH) { return chan_push(ch, value_int64(st)); @@ -117,19 +117,19 @@ chan_task_stopped(struct emu *emu) struct nanos6_thread *th = EXT(emu->thread, '6'); struct value null = value_null(); - if (chan_set(&th->ch[CH_TASKID], null) != 0) { + if (chan_set(&th->m.ch[CH_TASKID], null) != 0) { err("chan_set taskid failed"); return -1; } - if (chan_set(&th->ch[CH_TYPE], null) != 0) { + if (chan_set(&th->m.ch[CH_TYPE], null) != 0) { err("chan_set type failed"); return -1; } struct proc *proc = emu->proc; if (proc->rank >= 0) { - if (chan_set(&th->ch[CH_RANK], null) != 0) { + if (chan_set(&th->m.ch[CH_RANK], null) != 0) { err("chan_set rank failed"); return -1; } @@ -153,17 +153,17 @@ chan_task_running(struct emu *emu, struct task *task) return -1; } - if (chan_set(&th->ch[CH_TASKID], value_int64(task->id)) != 0) { + if (chan_set(&th->m.ch[CH_TASKID], value_int64(task->id)) != 0) { err("chan_set taskid failed"); return -1; } - if (chan_set(&th->ch[CH_TYPE], value_int64(task->type->gid)) != 0) { + if (chan_set(&th->m.ch[CH_TYPE], value_int64(task->type->gid)) != 0) { err("chan_set type failed"); return -1; } if (proc->rank >= 0) { struct value vrank = value_int64(proc->rank + 1); - if (chan_set(&th->ch[CH_RANK], vrank) != 0) { + if (chan_set(&th->m.ch[CH_RANK], vrank) != 0) { err("chan_set rank failed"); return -1; } @@ -205,14 +205,14 @@ chan_task_switch(struct emu *emu, /* No need to change the rank as we will switch to tasks from * same thread */ - if (chan_set(&th->ch[CH_TASKID], value_int64(next->id)) != 0) { + if (chan_set(&th->m.ch[CH_TASKID], value_int64(next->id)) != 0) { err("chan_set taskid failed"); return -1; } /* TODO: test when switching to another task with the same type. We * should emit the same type state value as previous task. */ - if (chan_set(&th->ch[CH_TYPE], value_int64(next->type->gid)) != 0) { + if (chan_set(&th->m.ch[CH_TYPE], value_int64(next->type->gid)) != 0) { err("chan_set type failed"); return -1; } @@ -339,7 +339,7 @@ enforce_task_rules(struct emu *emu, char tr, struct task *next) struct nanos6_thread *th = EXT(emu->thread, '6'); struct value ss; - if (chan_read(&th->ch[CH_SUBSYSTEM], &ss) != 0) { + if (chan_read(&th->m.ch[CH_SUBSYSTEM], &ss) != 0) { err("chan_read failed"); return -1; } diff --git a/src/emu/nanos6/finish.c b/src/emu/nanos6/finish.c deleted file mode 100644 index e860414..0000000 --- a/src/emu/nanos6/finish.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "nanos6_priv.h" - -static int -end_lint(struct emu *emu) -{ - struct system *sys = &emu->system; - - /* Ensure we run out of subsystem states */ - for (struct thread *t = sys->threads; t; t = t->gnext) { - struct nanos6_thread *th = EXT(t, '6'); - struct chan *ch = &th->ch[CH_SUBSYSTEM]; - int stacked = ch->data.stack.n; - if (stacked > 0) { - struct value top; - if (chan_read(ch, &top) != 0) { - err("chan_read failed for subsystem"); - return -1; - } - - err("thread %d ended with %d stacked nanos6 subsystems, top=\"%s\"\n", - t->tid, stacked, nanos6_ss_name(top.i)); - return -1; - } - } - - return 0; -} - -int -nanos6_finish(struct emu *emu) -{ - if (nanos6_finish_pvt(emu) != 0) { - err("finish_pvt failed"); - return -1; - } - - /* When running in linter mode perform additional checks */ - if (emu->args.linter_mode && end_lint(emu) != 0) { - err("end_lint failed"); - return -1; - } - - return 0; -} diff --git a/src/emu/nanos6/nanos6_priv.h b/src/emu/nanos6/nanos6_priv.h index fdd6210..d250423 100644 --- a/src/emu/nanos6/nanos6_priv.h +++ b/src/emu/nanos6/nanos6_priv.h @@ -9,15 +9,12 @@ #include "mux.h" #include "task.h" #include "track.h" +#include "model_cpu.h" +#include "model_thread.h" +#include "model_pvt.h" /* Private enums */ -enum nanos6_chan_type { - CT_TH = 0, - CT_CPU, - CT_MAX -}; - enum nanos6_chan { CH_TASKID = 0, CH_TYPE, @@ -68,13 +65,12 @@ enum nanos6_thread_type { }; struct nanos6_thread { - struct chan *ch; - struct track *track; + struct model_thread m; struct task_stack task_stack; }; struct nanos6_cpu { - struct track *track; + struct model_cpu m; }; struct nanos6_proc { @@ -87,9 +83,4 @@ int nanos6_connect(struct emu *emu); int nanos6_event(struct emu *emu); int nanos6_finish(struct emu *emu); -int nanos6_init_pvt(struct emu *emu); -int nanos6_finish_pvt(struct emu *emu); -const char *nanos6_ss_name(int ss); -int nanos6_get_track(enum nanos6_chan c, enum nanos6_chan_type type); - #endif /* NANOS6_PRIV_H */ diff --git a/src/emu/nanos6/probe.c b/src/emu/nanos6/probe.c deleted file mode 100644 index 0deb9a6..0000000 --- a/src/emu/nanos6/probe.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "nanos6_priv.h" - -struct model_spec model_nanos6 = { - .name = "nanos6", - .model = '6', - .create = nanos6_create, - .connect = nanos6_connect, - .event = nanos6_event, - .probe = nanos6_probe, - .finish = nanos6_finish, -}; - -int -nanos6_probe(struct emu *emu) -{ - if (emu->system.nthreads == 0) - return 1; - - return 0; -} diff --git a/src/emu/nanos6/pvt.c b/src/emu/nanos6/pvt.c deleted file mode 100644 index 3c321cc..0000000 --- a/src/emu/nanos6/pvt.c +++ /dev/null @@ -1,293 +0,0 @@ -#include "nanos6_priv.h" - -/* TODO: Assign types on runtime and generate configs */ - -static const char *pvt_name[CT_MAX] = { - [CT_TH] = "thread", - [CT_CPU] = "cpu", -}; - -static const int pvt_type[] = { - [CH_TASKID] = 35, - [CH_TYPE] = 36, - [CH_SUBSYSTEM] = 37, - [CH_RANK] = 38, - [CH_THREAD] = 39, -}; - -static const char *pcf_prefix[CH_MAX] = { - [CH_TASKID] = "Nanos6 task ID", - [CH_TYPE] = "Nanos6 task type", - [CH_SUBSYSTEM] = "Nanos6 subsystem", - [CH_RANK] = "Nanos6 task MPI rank", - [CH_THREAD] = "Nanos6 thread type", -}; - -static const char *pcf_suffix[TRACK_TH_MAX] = { - [TRACK_TH_ANY] = "", - [TRACK_TH_RUN] = "of the RUNNING thread", - [TRACK_TH_ACT] = "of the ACTIVE thread", -}; - -static const struct pcf_value_label nanos6_ss_values[] = { - { ST_TASK_BODY, "Task: Running body" }, - { ST_TASK_CREATING, "Task: Creating" }, - { ST_TASK_SUBMIT, "Task: Submitting" }, - { ST_TASK_SPAWNING, "Task: Spawning function" }, - { ST_TASK_FOR, "Task: Running task for" }, - { ST_SCHED_SERVING, "Scheduler: Serving tasks" }, - { ST_SCHED_ADDING, "Scheduler: Adding ready tasks" }, - { ST_SCHED_PROCESSING, "Scheduler: Processing ready tasks" }, - { ST_DEP_REG, "Dependency: Registering" }, - { ST_DEP_UNREG, "Dependency: Unregistering" }, - { ST_BLK_TASKWAIT, "Blocking: Taskwait" }, - { ST_BLK_BLOCKING, "Blocking: Blocking current task" }, - { ST_BLK_UNBLOCKING, "Blocking: Unblocking remote task" }, - { ST_BLK_WAITFOR, "Blocking: Wait for deadline" }, - { ST_HANDLING_TASK, "Worker: Handling task" }, - { ST_WORKER_LOOP, "Worker: Looking for work" }, - { ST_SWITCH_TO, "Worker: Switching to another thread" }, - { ST_MIGRATE, "Worker: Migrating CPU" }, - { ST_SUSPEND, "Worker: Suspending thread" }, - { ST_RESUME, "Worker: Resuming another thread" }, - { ST_ALLOCATING, "Memory: Allocating" }, - { ST_FREEING, "Memory: Freeing" }, - - { EV_SCHED_SEND, "EV Scheduler: Send task" }, - { EV_SCHED_RECV, "EV Scheduler: Recv task" }, - { EV_SCHED_SELF, "EV Scheduler: Self-assign task" }, - { EV_CPU_IDLE, "EV CPU: Becomes idle" }, - { EV_CPU_ACTIVE, "EV CPU: Becomes active" }, - { EV_SIGNAL, "EV Worker: Wakening another thread" }, - { -1, NULL }, -}; - -static const struct pcf_value_label nanos6_thread_type[] = { - { ST_TH_EXTERNAL, "External" }, - { ST_TH_WORKER, "Worker" }, - { ST_TH_LEADER, "Leader" }, - { ST_TH_MAIN, "Main" }, - { -1, NULL }, -}; - -static const struct pcf_value_label (*pcf_chan_value_labels[CH_MAX])[] = { - [CH_SUBSYSTEM] = &nanos6_ss_values, - [CH_THREAD] = &nanos6_thread_type, -}; - -/* ------------------------------ pcf ------------------------------ */ - -static int -create_values(struct pcf_type *t, int c) -{ - const struct pcf_value_label(*q)[] = pcf_chan_value_labels[c]; - - if (q == NULL) - return 0; - - for (const struct pcf_value_label *p = *q; p->label != NULL; p++) - pcf_add_value(t, p->value, p->label); - - return 0; -} - -static int -create_type(struct pcf *pcf, enum nanos6_chan c, enum nanos6_chan_type ct) -{ - long type = pvt_type[c]; - - if (type == -1) - return 0; - - /* Compute the label by joining the two parts */ - const char *prefix = pcf_prefix[c]; - int track_mode = nanos6_get_track(c, ct); - const char *suffix = pcf_suffix[track_mode]; - - char label[MAX_PCF_LABEL]; - int ret = snprintf(label, MAX_PCF_LABEL, "%s %s", - prefix, suffix); - - if (ret >= MAX_PCF_LABEL) { - err("computed type label too long"); - return -1; - } - - struct pcf_type *pcftype = pcf_add_type(pcf, type, label); - - return create_values(pcftype, c); -} - -static int -init_pcf(struct pcf *pcf, enum nanos6_chan_type ct) -{ - /* Create default types and values */ - for (enum nanos6_chan c = 0; c < CH_MAX; c++) { - if (create_type(pcf, c, ct) != 0) { - err("create_type failed"); - return -1; - } - } - - return 0; -} - -/* ------------------------------ prv ------------------------------ */ - -static int -connect_thread_prv(struct emu *emu, struct thread *thread, struct prv *prv) -{ - struct nanos6_thread *th = EXT(thread, '6'); - for (int i = 0; i < CH_MAX; i++) { - struct chan *out = track_get_default(&th->track[i]); - long type = pvt_type[i]; - long row = thread->gindex; - if (prv_register(prv, row, type, &emu->bay, out, PRV_DUP)) { - err("prv_register failed"); - return -1; - } - } - - return 0; -} - -static int -connect_cpu_prv(struct emu *emu, struct cpu *scpu, struct prv *prv) -{ - struct nanos6_cpu *cpu = EXT(scpu, '6'); - for (int i = 0; i < CH_MAX; i++) { - struct chan *out = track_get_default(&cpu->track[i]); - long type = pvt_type[i]; - long row = scpu->gindex; - if (prv_register(prv, row, type, &emu->bay, out, PRV_DUP)) { - err("prv_register failed"); - return -1; - } - } - - return 0; -} - -static int -connect_threads(struct emu *emu) -{ - struct system *sys = &emu->system; - - /* Get thread 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 = sys->threads; t; t = t->gnext) { - if (connect_thread_prv(emu, t, prv) != 0) { - err("connect_thread_prv failed"); - return -1; - } - } - - /* Init thread PCF */ - struct pcf *pcf = pvt_get_pcf(pvt); - if (init_pcf(pcf, CT_TH) != 0) { - err("init_pcf failed"); - return -1; - } - - return 0; -} - -static int -connect_cpus(struct emu *emu) -{ - struct system *sys = &emu->system; - - /* Get cpu PRV */ - struct pvt *pvt = recorder_find_pvt(&emu->recorder, "cpu"); - if (pvt == NULL) { - err("cannot find cpu pvt"); - return -1; - } - - /* Connect CPU channels to PRV */ - struct prv *prv = pvt_get_prv(pvt); - for (struct cpu *c = sys->cpus; c; c = c->next) { - if (connect_cpu_prv(emu, c, prv) != 0) { - err("connect_cpu_prv failed"); - return -1; - } - } - - /* Init CPU PCF */ - struct pcf *pcf = pvt_get_pcf(pvt); - if (init_pcf(pcf, CT_CPU) != 0) { - err("init_pcf failed"); - return -1; - } - - return 0; -} - -/* Connect all outputs to the paraver trace and setup PCF types */ -int -nanos6_init_pvt(struct emu *emu) -{ - if (connect_threads(emu) != 0) { - err("connect_threads failed"); - return -1; - } - - if (connect_cpus(emu) != 0) { - err("connect_cpus failed"); - return -1; - } - - return 0; -} - -int -nanos6_finish_pvt(struct emu *emu) -{ - struct system *sys = &emu->system; - - /* Emit task types for all channel types and processes */ - for (enum chan_type ct = 0; ct < CHAN_MAXTYPE; ct++) { - struct pvt *pvt = recorder_find_pvt(&emu->recorder, pvt_name[ct]); - if (pvt == NULL) { - err("cannot find pvt with name '%s'", pvt_name[ct]); - return -1; - } - struct pcf *pcf = pvt_get_pcf(pvt); - long typeid = pvt_type[CH_TYPE]; - struct pcf_type *pcftype = pcf_find_type(pcf, typeid); - - for (struct proc *p = sys->procs; p; p = p->gnext) { - struct nanos6_proc *nanos6proc = EXT(p, '6'); - struct task_info *info = &nanos6proc->task_info; - if (task_create_pcf_types(pcftype, info->types) != 0) { - err("task_create_pcf_types failed"); - return -1; - } - } - } - - return 0; -} - -const char * -nanos6_ss_name(int ss) -{ - static const char *unknown = "(unknown)"; - const char *name = unknown; - const struct pcf_value_label *pv; - for (pv = &nanos6_ss_values[0]; pv->label; pv++) { - if (pv->value == ss) { - name = pv->label; - break; - } - } - - return name; -} diff --git a/src/emu/nanos6/setup.c b/src/emu/nanos6/setup.c new file mode 100644 index 0000000..08e2b51 --- /dev/null +++ b/src/emu/nanos6/setup.c @@ -0,0 +1,307 @@ +#include "nanos6_priv.h" + +static const char model_name[] = "nanos6"; +static const int model_id = '6'; + +struct model_spec model_nanos6 = { + .name = model_name, + .model = model_id, + .create = nanos6_create, + .connect = nanos6_connect, + .event = nanos6_event, + .probe = nanos6_probe, + .finish = nanos6_finish, +}; + +/* ----------------- channels ------------------ */ + +static const char *chan_name[CH_MAX] = { + [CH_TASKID] = "taskid", + [CH_TYPE] = "task_type", + [CH_SUBSYSTEM] = "subsystem", + [CH_RANK] = "rank", + [CH_THREAD] = "thread_type", +}; + +static const int chan_stack[CH_MAX] = { + [CH_SUBSYSTEM] = 1, + [CH_THREAD] = 1, +}; + +/* ----------------- pvt ------------------ */ + +static const int pvt_type[] = { + [CH_TASKID] = 35, + [CH_TYPE] = 36, + [CH_SUBSYSTEM] = 37, + [CH_RANK] = 38, + [CH_THREAD] = 39, +}; + +static const char *pcf_prefix[CH_MAX] = { + [CH_TASKID] = "Nanos6 task ID", + [CH_TYPE] = "Nanos6 task type", + [CH_SUBSYSTEM] = "Nanos6 subsystem", + [CH_RANK] = "Nanos6 task MPI rank", + [CH_THREAD] = "Nanos6 thread type", +}; + +static const char *pcf_suffix[TRACK_TH_MAX] = { + [TRACK_TH_ANY] = "", + [TRACK_TH_RUN] = "of the RUNNING thread", + [TRACK_TH_ACT] = "of the ACTIVE thread", +}; + +static const struct pcf_value_label nanos6_ss_values[] = { + { ST_TASK_BODY, "Task: Running body" }, + { ST_TASK_CREATING, "Task: Creating" }, + { ST_TASK_SUBMIT, "Task: Submitting" }, + { ST_TASK_SPAWNING, "Task: Spawning function" }, + { ST_TASK_FOR, "Task: Running task for" }, + { ST_SCHED_SERVING, "Scheduler: Serving tasks" }, + { ST_SCHED_ADDING, "Scheduler: Adding ready tasks" }, + { ST_SCHED_PROCESSING, "Scheduler: Processing ready tasks" }, + { ST_DEP_REG, "Dependency: Registering" }, + { ST_DEP_UNREG, "Dependency: Unregistering" }, + { ST_BLK_TASKWAIT, "Blocking: Taskwait" }, + { ST_BLK_BLOCKING, "Blocking: Blocking current task" }, + { ST_BLK_UNBLOCKING, "Blocking: Unblocking remote task" }, + { ST_BLK_WAITFOR, "Blocking: Wait for deadline" }, + { ST_HANDLING_TASK, "Worker: Handling task" }, + { ST_WORKER_LOOP, "Worker: Looking for work" }, + { ST_SWITCH_TO, "Worker: Switching to another thread" }, + { ST_MIGRATE, "Worker: Migrating CPU" }, + { ST_SUSPEND, "Worker: Suspending thread" }, + { ST_RESUME, "Worker: Resuming another thread" }, + { ST_ALLOCATING, "Memory: Allocating" }, + { ST_FREEING, "Memory: Freeing" }, + + { EV_SCHED_SEND, "EV Scheduler: Send task" }, + { EV_SCHED_RECV, "EV Scheduler: Recv task" }, + { EV_SCHED_SELF, "EV Scheduler: Self-assign task" }, + { EV_CPU_IDLE, "EV CPU: Becomes idle" }, + { EV_CPU_ACTIVE, "EV CPU: Becomes active" }, + { EV_SIGNAL, "EV Worker: Waking another thread" }, + { -1, NULL }, +}; + +static const struct pcf_value_label nanos6_thread_type[] = { + { ST_TH_EXTERNAL, "External" }, + { ST_TH_WORKER, "Worker" }, + { ST_TH_LEADER, "Leader" }, + { ST_TH_MAIN, "Main" }, + { -1, NULL }, +}; + +static const struct pcf_value_label (*pcf_labels[CH_MAX])[] = { + [CH_SUBSYSTEM] = &nanos6_ss_values, + [CH_THREAD] = &nanos6_thread_type, +}; + +static const struct model_pvt_spec pvt_spec = { + .type = pvt_type, + .prefix = pcf_prefix, + .suffix = pcf_suffix, + .label = pcf_labels, +}; + +/* ----------------- tracking ------------------ */ + +static const int th_track[CH_MAX] = { + [CH_TASKID] = TRACK_TH_RUN, + [CH_TYPE] = TRACK_TH_RUN, + [CH_SUBSYSTEM] = TRACK_TH_ACT, + [CH_RANK] = TRACK_TH_RUN, + [CH_THREAD] = TRACK_TH_ANY, +}; + +static const int cpu_track[CH_MAX] = { + [CH_TASKID] = TRACK_TH_RUN, + [CH_TYPE] = TRACK_TH_RUN, + [CH_SUBSYSTEM] = TRACK_TH_RUN, + [CH_RANK] = TRACK_TH_RUN, + [CH_THREAD] = TRACK_TH_RUN, +}; + +/* ----------------- chan_spec ------------------ */ + +static const struct model_chan_spec th_chan = { + .nch = CH_MAX, + .prefix = model_name, + .ch_names = chan_name, + .ch_stack = chan_stack, + .pvt = &pvt_spec, + .track = th_track, +}; + +static const struct model_chan_spec cpu_chan = { + .nch = CH_MAX, + .prefix = model_name, + .ch_names = chan_name, + .ch_stack = chan_stack, + .pvt = &pvt_spec, + .track = cpu_track, +}; + +/* ----------------- models ------------------ */ + +static const struct model_cpu_spec cpu_spec = { + .size = sizeof(struct nanos6_cpu), + .chan = &cpu_chan, + .model = &model_nanos6, +}; + +static const struct model_thread_spec th_spec = { + .size = sizeof(struct nanos6_thread), + .chan = &th_chan, + .model = &model_nanos6, +}; + +/* ----------------------------------------------------- */ + +int +nanos6_probe(struct emu *emu) +{ + if (emu->system.nthreads == 0) + return 1; + + return 0; +} + +static int +init_proc(struct proc *sysproc) +{ + struct nanos6_proc *proc = calloc(1, sizeof(struct nanos6_proc)); + if (proc == NULL) { + err("calloc failed:"); + return -1; + } + + extend_set(&sysproc->ext, model_id, proc); + + return 0; +} + +int +nanos6_create(struct emu *emu) +{ + struct system *sys = &emu->system; + + if (model_thread_create(emu, &th_spec) != 0) { + err("model_thread_init failed"); + return -1; + } + + if (model_cpu_create(emu, &cpu_spec) != 0) { + err("model_cpu_init failed"); + return -1; + } + + /* Init task stack thread pointer */ + for (struct thread *t = sys->threads; t; t = t->gnext) { + struct nanos6_thread *th = EXT(t, model_id); + th->task_stack.thread = t; + } + + for (struct proc *p = sys->procs; p; p = p->gnext) { + if (init_proc(p) != 0) { + err("init_proc failed"); + return -1; + } + } + + return 0; +} + +int +nanos6_connect(struct emu *emu) +{ + if (model_thread_connect(emu, &th_spec) != 0) { + err("model_thread_connect failed"); + return -1; + } + + if (model_cpu_connect(emu, &cpu_spec) != 0) { + err("model_cpu_connect failed"); + return -1; + } + + return 0; +} + +/* TODO: Automatically check all stack channels at the end */ +static int +end_lint(struct emu *emu) +{ + struct system *sys = &emu->system; + + /* Ensure we run out of subsystem states */ + for (struct thread *t = sys->threads; t; t = t->gnext) { + struct nanos6_thread *th = EXT(t, model_id); + struct chan *ch = &th->m.ch[CH_SUBSYSTEM]; + int stacked = ch->data.stack.n; + if (stacked > 0) { + struct value top; + if (chan_read(ch, &top) != 0) { + err("chan_read failed for subsystem"); + return -1; + } + + err("thread %d ended with %d stacked nanos6 subsystems\n", + t->tid, stacked); + return -1; + } + } + + return 0; +} + +static int +finish_pvt(struct emu *emu, const char *name) +{ + struct system *sys = &emu->system; + + /* Emit task types for all channel types and processes */ + struct pvt *pvt = recorder_find_pvt(&emu->recorder, name); + if (pvt == NULL) { + err("cannot find pvt with name '%s'", name); + return -1; + } + struct pcf *pcf = pvt_get_pcf(pvt); + long typeid = pvt_type[CH_TYPE]; + struct pcf_type *pcftype = pcf_find_type(pcf, typeid); + + for (struct proc *p = sys->procs; p; p = p->gnext) { + struct nanos6_proc *proc = EXT(p, model_id); + struct task_info *info = &proc->task_info; + if (task_create_pcf_types(pcftype, info->types) != 0) { + err("task_create_pcf_types failed"); + return -1; + } + } + + return 0; +} + +int +nanos6_finish(struct emu *emu) +{ + /* Fill task types */ + if (finish_pvt(emu, "thread") != 0) { + err("finish_pvt thread failed"); + return -1; + } + + if (finish_pvt(emu, "cpu") != 0) { + err("finish_pvt cpu failed"); + return -1; + } + + /* When running in linter mode perform additional checks */ + if (emu->args.linter_mode && end_lint(emu) != 0) { + err("end_lint failed"); + return -1; + } + + return 0; +} diff --git a/test/emu/nanos6/CMakeLists.txt b/test/emu/nanos6/CMakeLists.txt index 5a6f819..76d9851 100644 --- a/test/emu/nanos6/CMakeLists.txt +++ b/test/emu/nanos6/CMakeLists.txt @@ -7,4 +7,4 @@ ovni_test(nested-tasks-bad.c SHOULD_FAIL ovni_test(task-types.c MP) ovni_test(blocking.c MP) ovni_test(ss-mismatch.c SHOULD_FAIL - REGEX "thread [0-9]\\+ ended with 1 stacked nanos6 subsystems, top=\"Worker: Looking for work\"") + REGEX "thread [0-9]\\+ ended with 1 stacked nanos6 subsystems")