Remove boilerplate from nosv model

This commit is contained in:
Rodrigo Arias 2023-02-15 17:45:23 +01:00 committed by Rodrigo Arias Mallo
parent cd39230089
commit 3c0521f936
10 changed files with 293 additions and 616 deletions

View File

@ -45,12 +45,8 @@ add_library(emu STATIC
ovni/event.c ovni/event.c
nanos6/setup.c nanos6/setup.c
nanos6/event.c nanos6/event.c
nosv/probe.c nosv/setup.c
nosv/connect.c
nosv/create.c
nosv/event.c nosv/event.c
nosv/pvt.c
nosv/finish.c
nodes/probe.c nodes/probe.c
nodes/connect.c nodes/connect.c
nodes/create.c nodes/create.c

View File

@ -46,12 +46,6 @@ static const char *pcf_prefix[CH_MAX] = {
[CH_THREAD] = "Nanos6 thread type", [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[] = { static const struct pcf_value_label nanos6_ss_values[] = {
{ ST_TASK_BODY, "Task: Running body" }, { ST_TASK_BODY, "Task: Running body" },
{ ST_TASK_CREATING, "Task: Creating" }, { 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 = { static const struct model_pvt_spec pvt_spec = {
.type = pvt_type, .type = pvt_type,
.prefix = pcf_prefix, .prefix = pcf_prefix,
.suffix = pcf_suffix,
.label = pcf_labels, .label = pcf_labels,
}; };

View File

@ -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;
}

View File

@ -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;
}

View File

@ -56,7 +56,7 @@ simple(struct emu *emu)
int st = entry[2]; int st = entry[2];
struct nosv_thread *th = EXT(emu->thread, 'V'); struct nosv_thread *th = EXT(emu->thread, 'V');
struct chan *ch = &th->ch[chind]; struct chan *ch = &th->m.ch[chind];
if (action == PUSH) { if (action == PUSH) {
return chan_push(ch, value_int64(st)); 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 nosv_thread *th = EXT(emu->thread, 'V');
struct value null = value_null(); 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"); err("chan_set taskid failed");
return -1; 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"); err("chan_set type failed");
return -1; 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"); err("chan_set appid failed");
return -1; return -1;
} }
struct proc *proc = emu->proc; struct proc *proc = emu->proc;
if (proc->rank >= 0) { 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"); err("chan_set rank failed");
return -1; return -1;
} }
} }
/* FIXME: Do we need this transition? */ /* 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"); err("chan_pop subsystem failed");
return -1; return -1;
} }
@ -113,7 +113,7 @@ chan_task_running(struct emu *emu, struct task *task)
{ {
struct nosv_thread *th = EXT(emu->thread, 'V'); struct nosv_thread *th = EXT(emu->thread, 'V');
struct proc *proc = emu->proc; struct proc *proc = emu->proc;
struct chan *ch = th->ch; struct chan *ch = th->m.ch;
if (task->id == 0) { if (task->id == 0) {
err("task id cannot be 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 /* No need to change the rank or app ID as we will switch
* to tasks from same thread */ * 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"); err("chan_set taskid failed");
return -1; return -1;
} }
/* TODO: test when switching to another task with the same type. We /* TODO: test when switching to another task with the same type. We
* should emit the same type state value as previous task. */ * 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"); err("chan_set type failed");
return -1; 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 nosv_thread *th = EXT(emu->thread, 'V');
struct value ss; 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"); err("chan_read failed");
return -1; return -1;
} }

View File

@ -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;
}

View File

@ -8,15 +8,11 @@
#include "chan.h" #include "chan.h"
#include "mux.h" #include "mux.h"
#include "task.h" #include "task.h"
#include "model_cpu.h"
#include "model_thread.h"
/* Private enums */ /* Private enums */
enum nosv_chan_type {
CT_TH = 0,
CT_CPU,
CT_MAX
};
enum nosv_chan { enum nosv_chan {
CH_TASKID = 0, CH_TASKID = 0,
CH_TYPE, CH_TYPE,
@ -55,13 +51,12 @@ enum nosv_ss_values {
}; };
struct nosv_thread { struct nosv_thread {
struct chan *ch; struct model_thread m;
struct track *track;
struct task_stack task_stack; struct task_stack task_stack;
}; };
struct nosv_cpu { struct nosv_cpu {
struct track *track; struct model_cpu m;
}; };
struct nosv_proc { struct nosv_proc {

View File

@ -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;
}

View File

@ -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;
}

278
src/emu/nosv/setup.c Normal file
View File

@ -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;
}