From 3c0521f9365f7240bc6aa7e6e3f78f068bde8623 Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Date: Wed, 15 Feb 2023 17:45:23 +0100 Subject: [PATCH] Remove boilerplate from nosv model --- src/emu/CMakeLists.txt | 6 +- src/emu/nanos6/setup.c | 7 - src/emu/nosv/connect.c | 95 ------------- src/emu/nosv/create.c | 153 --------------------- src/emu/nosv/event.c | 20 +-- src/emu/nosv/finish.c | 44 ------- src/emu/nosv/nosv_priv.h | 13 +- src/emu/nosv/probe.c | 20 --- src/emu/nosv/pvt.c | 273 -------------------------------------- src/emu/nosv/setup.c | 278 +++++++++++++++++++++++++++++++++++++++ 10 files changed, 293 insertions(+), 616 deletions(-) delete mode 100644 src/emu/nosv/connect.c delete mode 100644 src/emu/nosv/create.c delete mode 100644 src/emu/nosv/finish.c delete mode 100644 src/emu/nosv/probe.c delete mode 100644 src/emu/nosv/pvt.c create mode 100644 src/emu/nosv/setup.c diff --git a/src/emu/CMakeLists.txt b/src/emu/CMakeLists.txt index be2d169..b3f2344 100644 --- a/src/emu/CMakeLists.txt +++ b/src/emu/CMakeLists.txt @@ -45,12 +45,8 @@ add_library(emu STATIC ovni/event.c nanos6/setup.c nanos6/event.c - nosv/probe.c - nosv/connect.c - nosv/create.c + nosv/setup.c nosv/event.c - nosv/pvt.c - nosv/finish.c nodes/probe.c nodes/connect.c nodes/create.c diff --git a/src/emu/nanos6/setup.c b/src/emu/nanos6/setup.c index 08e2b51..69ec790 100644 --- a/src/emu/nanos6/setup.c +++ b/src/emu/nanos6/setup.c @@ -46,12 +46,6 @@ static const char *pcf_prefix[CH_MAX] = { [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" }, @@ -101,7 +95,6 @@ static const struct pcf_value_label (*pcf_labels[CH_MAX])[] = { static const struct model_pvt_spec pvt_spec = { .type = pvt_type, .prefix = pcf_prefix, - .suffix = pcf_suffix, .label = pcf_labels, }; diff --git a/src/emu/nosv/connect.c b/src/emu/nosv/connect.c deleted file mode 100644 index 6b6c7e9..0000000 --- a/src/emu/nosv/connect.c +++ /dev/null @@ -1,95 +0,0 @@ -#include "nosv_priv.h" - -static const int th_track[CH_MAX] = { - [CH_TASKID] = TRACK_TH_RUN, - [CH_TYPE] = TRACK_TH_RUN, - [CH_APPID] = TRACK_TH_RUN, - [CH_SUBSYSTEM] = TRACK_TH_ACT, - [CH_RANK] = TRACK_TH_RUN, -}; - -static const int cpu_track[CH_MAX] = { - [CH_TASKID] = TRACK_TH_RUN, - [CH_TYPE] = TRACK_TH_RUN, - [CH_APPID] = TRACK_TH_RUN, - [CH_SUBSYSTEM] = TRACK_TH_RUN, - [CH_RANK] = TRACK_TH_RUN, -}; - -int -nosv_get_track(int c, int 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 nosv_cpu *cpu = EXT(scpu, 'V'); - 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 = nosv_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 nosv_thread *th = EXT(t, 'V'); - - /* 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, nosv_get_track(i, CT_CPU)); - } - - return 0; -} - -int -nosv_connect(struct emu *emu) -{ - struct system *sys = &emu->system; - - /* threads */ - for (struct thread *t = sys->threads; t; t = t->gnext) { - struct nosv_thread *th = EXT(t, 'V'); - 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 (nosv_init_pvt(emu) != 0) { - err("init_pvt failed"); - return -1; - } - - return 0; -} diff --git a/src/emu/nosv/create.c b/src/emu/nosv/create.c deleted file mode 100644 index 77303f3..0000000 --- a/src/emu/nosv/create.c +++ /dev/null @@ -1,153 +0,0 @@ -#include "nosv_priv.h" - -static const char *chan_name[CH_MAX] = { - [CH_TASKID] = "taskid", - [CH_TYPE] = "task_type", - [CH_APPID] = "appid", - [CH_SUBSYSTEM] = "subsystem", - [CH_RANK] = "rank", -}; - -static const int chan_stack[CH_MAX] = { - [CH_SUBSYSTEM] = 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_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 nosv_cpu *cpu = calloc(1, sizeof(struct nosv_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 = "nosv.cpu%ld.%s"; - if (init_tracks(bay, cpu->track, fmt, syscpu->gindex) != 0) { - err("init_chans failed"); - return -1; - } - - extend_set(&syscpu->ext, 'V', cpu); - return 0; -} - -static int -init_thread(struct bay *bay, struct thread *systh) -{ - struct nosv_thread *th = calloc(1, sizeof(struct nosv_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 = "nosv.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, 'V', th); - - return 0; -} - -static int -init_proc(struct proc *sysproc) -{ - struct nosv_proc *proc = calloc(1, sizeof(struct nosv_proc)); - if (proc == NULL) { - err("calloc failed:"); - return -1; - } - - extend_set(&sysproc->ext, 'V', proc); - - return 0; -} - -int -nosv_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/nosv/event.c b/src/emu/nosv/event.c index 4b24e84..6f4ace7 100644 --- a/src/emu/nosv/event.c +++ b/src/emu/nosv/event.c @@ -56,7 +56,7 @@ simple(struct emu *emu) int st = entry[2]; struct nosv_thread *th = EXT(emu->thread, 'V'); - struct chan *ch = &th->ch[chind]; + struct chan *ch = &th->m.ch[chind]; if (action == PUSH) { return chan_push(ch, value_int64(st)); @@ -78,29 +78,29 @@ chan_task_stopped(struct emu *emu) struct nosv_thread *th = EXT(emu->thread, 'V'); 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; } - if (chan_set(&th->ch[CH_APPID], null) != 0) { + if (chan_set(&th->m.ch[CH_APPID], null) != 0) { err("chan_set appid 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; } } /* FIXME: Do we need this transition? */ - if (chan_pop(&th->ch[CH_SUBSYSTEM], value_int64(ST_TASK_RUNNING)) != 0) { + if (chan_pop(&th->m.ch[CH_SUBSYSTEM], value_int64(ST_TASK_RUNNING)) != 0) { err("chan_pop subsystem failed"); return -1; } @@ -113,7 +113,7 @@ chan_task_running(struct emu *emu, struct task *task) { struct nosv_thread *th = EXT(emu->thread, 'V'); struct proc *proc = emu->proc; - struct chan *ch = th->ch; + struct chan *ch = th->m.ch; if (task->id == 0) { err("task id cannot be 0"); @@ -188,14 +188,14 @@ chan_task_switch(struct emu *emu, /* No need to change the rank or app ID 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; } @@ -322,7 +322,7 @@ enforce_task_rules(struct emu *emu, char tr, struct task *next) struct nosv_thread *th = EXT(emu->thread, 'V'); 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/nosv/finish.c b/src/emu/nosv/finish.c deleted file mode 100644 index b60ac9b..0000000 --- a/src/emu/nosv/finish.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "nosv_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 nosv_thread *th = EXT(t, 'V'); - 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 nosv subsystems, top=\"%s\"\n", - t->tid, stacked, nosv_ss_name(top.i)); - return -1; - } - } - - return 0; -} - -int -nosv_finish(struct emu *emu) -{ - if (nosv_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/nosv/nosv_priv.h b/src/emu/nosv/nosv_priv.h index 4fd19b3..afd5ef8 100644 --- a/src/emu/nosv/nosv_priv.h +++ b/src/emu/nosv/nosv_priv.h @@ -8,15 +8,11 @@ #include "chan.h" #include "mux.h" #include "task.h" +#include "model_cpu.h" +#include "model_thread.h" /* Private enums */ -enum nosv_chan_type { - CT_TH = 0, - CT_CPU, - CT_MAX -}; - enum nosv_chan { CH_TASKID = 0, CH_TYPE, @@ -55,13 +51,12 @@ enum nosv_ss_values { }; struct nosv_thread { - struct chan *ch; - struct track *track; + struct model_thread m; struct task_stack task_stack; }; struct nosv_cpu { - struct track *track; + struct model_cpu m; }; struct nosv_proc { diff --git a/src/emu/nosv/probe.c b/src/emu/nosv/probe.c deleted file mode 100644 index 93fc071..0000000 --- a/src/emu/nosv/probe.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "nosv_priv.h" - -struct model_spec model_nosv = { - .name = "nosv", - .model = 'V', - .create = nosv_create, - .connect = nosv_connect, - .event = nosv_event, - .probe = nosv_probe, - .finish = nosv_finish, -}; - -int -nosv_probe(struct emu *emu) -{ - if (emu->system.nthreads == 0) - return 1; - - return 0; -} diff --git a/src/emu/nosv/pvt.c b/src/emu/nosv/pvt.c deleted file mode 100644 index 7513855..0000000 --- a/src/emu/nosv/pvt.c +++ /dev/null @@ -1,273 +0,0 @@ -#include "nosv_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] = 10, - [CH_TYPE] = 11, - [CH_APPID] = 12, - [CH_SUBSYSTEM] = 13, - [CH_RANK] = 14, -}; - -static const char *pcf_prefix[CH_MAX] = { - [CH_TASKID] = "nOS-V task ID", - [CH_TYPE] = "nOS-V task type", - [CH_APPID] = "nOS-V task AppID", - [CH_SUBSYSTEM] = "nOS-V subsystem", - [CH_RANK] = "nOS-V task MPI rank", -}; - - -static const char *pcf_suffix[TRACK_MAX] = { - [NONE] = "", - [RUN_TH] = "of the RUNNING thread", - [ACT_TH] = "of the ACTIVE thread", -}; - -static const struct pcf_value_label nosv_ss_values[] = { - { ST_SCHED_HUNGRY, "Scheduler: Hungry" }, - { ST_SCHED_SERVING, "Scheduler: Serving" }, - { ST_SCHED_SUBMITTING, "Scheduler: Submitting" }, - { ST_MEM_ALLOCATING, "Memory: Allocating" }, - { ST_MEM_FREEING, "Memory: Freeing" }, - { ST_TASK_RUNNING, "Task: Running" }, - { ST_API_SUBMIT, "API: Submit" }, - { ST_API_PAUSE, "API: Pause" }, - { ST_API_YIELD, "API: Yield" }, - { ST_API_WAITFOR, "API: Waitfor" }, - { ST_API_SCHEDPOINT, "API: Scheduling point" }, - { ST_ATTACH, "Thread: Attached" }, - { ST_WORKER, "Thread: Worker" }, - { ST_DELEGATE, "Thread: Delegate" }, - { EV_SCHED_SEND, "EV Scheduler: Send task" }, - { EV_SCHED_RECV, "EV Scheduler: Recv task" }, - { EV_SCHED_SELF, "EV Scheduler: Self-assign task" }, - { -1, NULL }, -}; - -static const struct pcf_value_label (*pcf_chan_value_labels[CH_MAX])[] = { - [CH_SUBSYSTEM] = &nosv_ss_values, -}; - -/* ------------------------------ 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 nosv_chan c, enum nosv_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 = nosv_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 nosv_chan_type ct) -{ - /* Create default types and values */ - for (enum nosv_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 nosv_thread *th = EXT(thread, 'V'); - 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 nosv_cpu *cpu = EXT(scpu, 'V'); - 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 -nosv_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 -nosv_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 nosv_proc *nosvproc = EXT(p, 'V'); - struct task_info *info = &nosvproc->task_info; - if (task_create_pcf_types(pcftype, info->types) != 0) { - err("task_create_pcf_types failed"); - return -1; - } - } - } - - return 0; -} - -const char * -nosv_ss_name(int ss) -{ - static const char *unknown = "(unknown)"; - const char *name = unknown; - const struct pcf_value_label *pv; - for (pv = &nosv_ss_values[0]; pv->label; pv++) { - if (pv->value == ss) { - name = pv->label; - break; - } - } - - return name; -} diff --git a/src/emu/nosv/setup.c b/src/emu/nosv/setup.c new file mode 100644 index 0000000..555eb39 --- /dev/null +++ b/src/emu/nosv/setup.c @@ -0,0 +1,278 @@ +#include "nosv_priv.h" + +static const char model_name[] = "nosv"; +static const int model_id = 'V'; + +struct model_spec model_nosv = { + .name = model_name, + .model = model_id, + .create = nosv_create, + .connect = nosv_connect, + .event = nosv_event, + .probe = nosv_probe, + .finish = nosv_finish, +}; + +/* ----------------- channels ------------------ */ + +static const char *chan_name[CH_MAX] = { + [CH_TASKID] = "taskid", + [CH_TYPE] = "task_type", + [CH_APPID] = "appid", + [CH_SUBSYSTEM] = "subsystem", + [CH_RANK] = "rank", +}; + +static const int chan_stack[CH_MAX] = { + [CH_SUBSYSTEM] = 1, +}; + +/* ----------------- pvt ------------------ */ + +static const int pvt_type[] = { + [CH_TASKID] = 10, + [CH_TYPE] = 11, + [CH_APPID] = 12, + [CH_SUBSYSTEM] = 13, + [CH_RANK] = 14, +}; + +static const char *pcf_prefix[CH_MAX] = { + [CH_TASKID] = "nOS-V task ID", + [CH_TYPE] = "nOS-V task type", + [CH_APPID] = "nOS-V task AppID", + [CH_SUBSYSTEM] = "nOS-V subsystem", + [CH_RANK] = "nOS-V task MPI rank", +}; + +static const struct pcf_value_label nosv_ss_values[] = { + { ST_SCHED_HUNGRY, "Scheduler: Hungry" }, + { ST_SCHED_SERVING, "Scheduler: Serving" }, + { ST_SCHED_SUBMITTING, "Scheduler: Submitting" }, + { ST_MEM_ALLOCATING, "Memory: Allocating" }, + { ST_MEM_FREEING, "Memory: Freeing" }, + { ST_TASK_RUNNING, "Task: Running" }, + { ST_API_SUBMIT, "API: Submit" }, + { ST_API_PAUSE, "API: Pause" }, + { ST_API_YIELD, "API: Yield" }, + { ST_API_WAITFOR, "API: Waitfor" }, + { ST_API_SCHEDPOINT, "API: Scheduling point" }, + { ST_ATTACH, "Thread: Attached" }, + { ST_WORKER, "Thread: Worker" }, + { ST_DELEGATE, "Thread: Delegate" }, + { EV_SCHED_SEND, "EV Scheduler: Send task" }, + { EV_SCHED_RECV, "EV Scheduler: Recv task" }, + { EV_SCHED_SELF, "EV Scheduler: Self-assign task" }, + { -1, NULL }, +}; + +static const struct pcf_value_label (*pcf_labels[CH_MAX])[] = { + [CH_SUBSYSTEM] = &nosv_ss_values, +}; + +static const struct model_pvt_spec pvt_spec = { + .type = pvt_type, + .prefix = pcf_prefix, + .label = pcf_labels, +}; + +/* ----------------- tracking ------------------ */ + +static const int th_track[CH_MAX] = { + [CH_TASKID] = TRACK_TH_RUN, + [CH_TYPE] = TRACK_TH_RUN, + [CH_APPID] = TRACK_TH_RUN, + [CH_SUBSYSTEM] = TRACK_TH_ACT, + [CH_RANK] = TRACK_TH_RUN, +}; + +static const int cpu_track[CH_MAX] = { + [CH_TASKID] = TRACK_TH_RUN, + [CH_TYPE] = TRACK_TH_RUN, + [CH_APPID] = TRACK_TH_RUN, + [CH_SUBSYSTEM] = TRACK_TH_RUN, + [CH_RANK] = 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 nosv_cpu), + .chan = &cpu_chan, + .model = &model_nosv, +}; + +static const struct model_thread_spec th_spec = { + .size = sizeof(struct nosv_thread), + .chan = &th_chan, + .model = &model_nosv, +}; + +/* ----------------------------------------------------- */ + +int +nosv_probe(struct emu *emu) +{ + if (emu->system.nthreads == 0) + return 1; + + return 0; +} + +static int +init_proc(struct proc *sysproc) +{ + struct nosv_proc *proc = calloc(1, sizeof(struct nosv_proc)); + if (proc == NULL) { + err("calloc failed:"); + return -1; + } + + extend_set(&sysproc->ext, model_id, proc); + + return 0; +} + +int +nosv_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 nosv_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 +nosv_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 nosv_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 nosv 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 nosv_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 +nosv_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; +}