Add support for nOS-V

Most of the model is taken from nanos6, we should refactor them.
This commit is contained in:
Rodrigo Arias 2023-02-07 13:34:18 +01:00 committed by Rodrigo Arias Mallo
parent 55a5be7d13
commit a818795d88
28 changed files with 1331 additions and 61 deletions

View File

@ -45,6 +45,12 @@ add_library(emu STATIC
nanos6/event.c
nanos6/pvt.c
nanos6/finish.c
nosv/probe.c
nosv/connect.c
nosv/create.c
nosv/event.c
nosv/pvt.c
nosv/finish.c
)
add_executable(ovniemu ovniemu.c)

View File

@ -30,11 +30,12 @@ static int chan_type[] = {
};
void
cpu_init_begin(struct cpu *cpu, int phyid)
cpu_init_begin(struct cpu *cpu, int phyid, int is_virtual)
{
memset(cpu, 0, sizeof(struct cpu));
cpu->phyid = phyid;
cpu->is_virtual = is_virtual;
dbg("cpu init %d", phyid);
}
@ -166,6 +167,13 @@ cpu_update(struct cpu *cpu)
cpu->nth_running = running;
cpu->nth_active = active;
/* Only virtual cpus can be oversubscribed */
if (cpu->nth_running > 1 && !cpu->is_virtual) {
err("physical cpu %s has %d thread running at the same time",
cpu->name, cpu->nth_running);
return -1;
}
struct value tid_running;
struct value pid_running;
struct value gid_running;

View File

@ -61,7 +61,7 @@ struct cpu {
UT_hash_handle hh; /* CPUs in the loom */
};
void cpu_init_begin(struct cpu *cpu, int phyid);
void cpu_init_begin(struct cpu *cpu, int phyid, int is_virtual);
int cpu_get_phyid(struct cpu *cpu);
//int cpu_get_index(struct cpu *cpu);
void cpu_set_gindex(struct cpu *cpu, int64_t gindex);

View File

@ -3,7 +3,7 @@
#define _POSIX_C_SOURCE 2
//#define ENABLE_DEBUG
#define ENABLE_DEBUG
#include "emu.h"

View File

@ -64,7 +64,7 @@ loom_init_begin(struct loom *loom, const char *name)
set_hostname(loom->hostname, loom->name);
loom->id = loom->name;
cpu_init_begin(&loom->vcpu, -1);
cpu_init_begin(&loom->vcpu, -1, 1);
dbg("creating new loom %s", loom->id);

View File

@ -105,7 +105,7 @@ load_cpus(struct loom *loom, JSON_Object *meta)
return -1;
}
cpu_init_begin(cpu, phyid);
cpu_init_begin(cpu, phyid, 0);
if (loom_add_cpu(loom, cpu) != 0) {
err("loom_add_cpu() failed");

View File

@ -1,6 +1,8 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#define ENABLE_DEBUG
#include "model.h"
#include "common.h"
@ -18,6 +20,8 @@ model_register(struct model *model, struct model_spec *spec)
int i = spec->model;
model->spec[i] = spec;
model->registered[i] = 1;
dbg("registered model %c", (char) i);
}
int
@ -37,8 +41,12 @@ model_probe(struct model *model, struct emu *emu)
return -1;
}
if (ret == 0)
if (ret == 0) {
model->enabled[i] = 1;
dbg("model %c enabled", (char) i);
} else {
dbg("model %c disabled", (char) i);
}
}
return 0;
}
@ -77,6 +85,8 @@ model_connect(struct model *model, struct emu *emu)
err("connect failed for model '%c'", (char) i);
return -1;
}
dbg("connect for model %c ok", (char) i);
}
return 0;
}

View File

@ -7,10 +7,12 @@
extern struct model_spec model_ovni;
extern struct model_spec model_nanos6;
extern struct model_spec model_nosv;
static struct model_spec *models[] = {
&model_ovni,
&model_nanos6,
&model_nosv,
NULL
};

View File

@ -1,6 +1,6 @@
#include "nanos6_priv.h"
const enum nanos6_track chan_track[CH_MAX][CT_MAX] = {
const enum nanos6_track nanos6_chan_track[CH_MAX][CT_MAX] = {
/* Thread CPU */
[CH_TASKID] = { RUN_TH, RUN_TH },
[CH_TYPE] = { RUN_TH, RUN_TH },
@ -49,7 +49,7 @@ connect_thread_mux(struct emu *emu, struct thread *thread)
/* The tracking only sets the ch_out, but we keep both tracking
* updated as the CPU tracking channels may use them. */
enum nanos6_track track = chan_track[i][CT_TH];
enum nanos6_track track = nanos6_chan_track[i][CT_TH];
if (track == RUN_TH)
th->ch_out[i] = &th->ch_run[i];
else if (track == ACT_TH)
@ -70,7 +70,7 @@ add_inputs_cpu_mux(struct emu *emu, struct mux *mux, int i)
/* Choose input thread channel based on tracking mode */
struct chan *inp = NULL;
enum nanos6_track track = chan_track[i][CT_CPU];
enum nanos6_track track = nanos6_chan_track[i][CT_CPU];
if (track == RUN_TH)
inp = &th->ch_run[i];
else if (track == ACT_TH)
@ -97,7 +97,7 @@ connect_cpu_mux(struct emu *emu, struct cpu *scpu)
/* Choose select CPU channel based on tracking mode */
struct chan *sel = NULL;
enum nanos6_track track = chan_track[i][CT_CPU];
enum nanos6_track track = nanos6_chan_track[i][CT_CPU];
if (track == RUN_TH)
sel = &scpu->chan[CPU_CHAN_THRUN];
else if (track == ACT_TH)
@ -140,7 +140,7 @@ nanos6_connect(struct emu *emu)
}
}
if (init_pvt(emu) != 0) {
if (nanos6_init_pvt(emu) != 0) {
err("init_pvt failed");
return -1;
}

View File

@ -7,7 +7,7 @@ static const char chan_fmt_th_raw[] = "nanos6.thread%ld.%s.raw";
static const char chan_fmt_th_run[] = "nanos6.thread%ld.%s.run";
static const char chan_fmt_th_act[] = "nanos6.thread%ld.%s.act";
static const char *chan_name[] = {
static const char *chan_name[CH_MAX] = {
[CH_TASKID] = "taskid",
[CH_TYPE] = "task_type",
[CH_SUBSYSTEM] = "subsystem",
@ -15,7 +15,7 @@ static const char *chan_name[] = {
[CH_THREAD] = "thread_type",
};
static const int chan_stack[] = {
static const int chan_stack[CH_MAX] = {
[CH_SUBSYSTEM] = 1,
[CH_THREAD] = 1,
};

View File

@ -520,7 +520,5 @@ nanos6_event(struct emu *emu)
return -1;
}
//check_affinity(emu);
return 0;
}

View File

@ -18,7 +18,7 @@ end_lint(struct emu *emu)
}
err("thread %d ended with %d stacked nanos6 subsystems, top=\"%s\"\n",
t->tid, stacked, ss_name(top.i));
t->tid, stacked, nanos6_ss_name(top.i));
return -1;
}
}
@ -29,7 +29,7 @@ end_lint(struct emu *emu)
int
nanos6_finish(struct emu *emu)
{
if (finish_pvt(emu) != 0) {
if (nanos6_finish_pvt(emu) != 0) {
err("finish_pvt failed");
return -1;
}

View File

@ -33,7 +33,7 @@ enum nanos6_track {
TRACK_MAX,
};
extern const enum nanos6_track chan_track[CH_MAX][CT_MAX];
extern const enum nanos6_track nanos6_chan_track[CH_MAX][CT_MAX];
enum nanos6_ss_state {
ST_TASK_BODY = 1,
@ -100,8 +100,8 @@ int nanos6_connect(struct emu *emu);
int nanos6_event(struct emu *emu);
int nanos6_finish(struct emu *emu);
int init_pvt(struct emu *emu);
int finish_pvt(struct emu *emu);
const char *ss_name(int ss);
int nanos6_init_pvt(struct emu *emu);
int nanos6_finish_pvt(struct emu *emu);
const char *nanos6_ss_name(int ss);
#endif /* NANOS6_PRIV_H */

View File

@ -101,7 +101,7 @@ create_type(struct pcf *pcf, enum nanos6_chan c, enum nanos6_chan_type ct)
/* Compute the label by joining the two parts */
const char *prefix = pcf_prefix[c];
int track_mode = chan_track[c][ct];
int track_mode = nanos6_chan_track[c][ct];
const char *suffix = pcf_suffix[track_mode];
char label[MAX_PCF_LABEL];
@ -232,7 +232,7 @@ connect_cpus(struct emu *emu)
/* Connect all outputs to the paraver trace and setup PCF types */
int
init_pvt(struct emu *emu)
nanos6_init_pvt(struct emu *emu)
{
if (connect_threads(emu) != 0) {
err("connect_threads failed");
@ -248,7 +248,7 @@ init_pvt(struct emu *emu)
}
int
finish_pvt(struct emu *emu)
nanos6_finish_pvt(struct emu *emu)
{
struct system *sys = &emu->system;
@ -277,7 +277,7 @@ finish_pvt(struct emu *emu)
}
const char *
ss_name(int ss)
nanos6_ss_name(int ss)
{
static const char *unknown = "(unknown)";
const char *name = unknown;

150
src/emu/nosv/connect.c Normal file
View File

@ -0,0 +1,150 @@
#include "nosv_priv.h"
const enum nosv_track nosv_chan_track[CH_MAX][CT_MAX] = {
/* Thread CPU */
[CH_TASKID] = { RUN_TH, RUN_TH },
[CH_TYPE] = { RUN_TH, RUN_TH },
[CH_APPID] = { RUN_TH, RUN_TH },
[CH_SUBSYSTEM] = { ACT_TH, RUN_TH },
[CH_RANK] = { RUN_TH, RUN_TH },
};
static int
connect_thread_mux(struct emu *emu, struct thread *thread)
{
struct nosv_thread *th = EXT(thread, 'V');
for (int i = 0; i < CH_MAX; i++) {
/* TODO: Let the thread take the select channel
* and build the mux as a tracking mode */
struct chan *inp = &th->ch[i];
struct chan *sel = &thread->chan[TH_CHAN_STATE];
struct mux *mux_run = &th->mux_run[i];
mux_select_func_t selrun = thread_select_running;
if (mux_init(mux_run, &emu->bay, sel, &th->ch_run[i], selrun) != 0) {
err("mux_init failed");
return -1;
}
if (mux_add_input(mux_run, value_int64(0), inp) != 0) {
err("mux_add_input failed");
return -1;
}
struct mux *mux_act = &th->mux_act[i];
mux_select_func_t selact = thread_select_active;
if (mux_init(mux_act, &emu->bay, sel, &th->ch_act[i], selact) != 0) {
err("mux_init failed");
return -1;
}
if (mux_add_input(mux_act, value_int64(0), inp) != 0) {
err("mux_add_input failed");
return -1;
}
if (mux_act->ninputs != 1)
die("expecting one input only");
/* The tracking only sets the ch_out, but we keep both tracking
* updated as the CPU tracking channels may use them. */
enum nosv_track track = nosv_chan_track[i][CT_TH];
if (track == RUN_TH)
th->ch_out[i] = &th->ch_run[i];
else if (track == ACT_TH)
th->ch_out[i] = &th->ch_act[i];
else
th->ch_out[i] = &th->ch[i];
}
return 0;
}
static int
add_inputs_cpu_mux(struct emu *emu, struct mux *mux, int i)
{
for (struct thread *t = emu->system.threads; t; t = t->gnext) {
struct nosv_thread *th = EXT(t, 'V');
/* Choose input thread channel based on tracking mode */
struct chan *inp = NULL;
enum nosv_track track = nosv_chan_track[i][CT_CPU];
if (track == RUN_TH)
inp = &th->ch_run[i];
else if (track == ACT_TH)
inp = &th->ch_act[i];
else
die("cpu tracking must be running or active");
if (mux_add_input(mux, value_int64(t->gindex), inp) != 0) {
err("mux_add_input failed");
return -1;
}
}
return 0;
}
static int
connect_cpu_mux(struct emu *emu, struct cpu *scpu)
{
struct nosv_cpu *cpu = EXT(scpu, 'V');
for (int i = 0; i < CH_MAX; i++) {
struct mux *mux = &cpu->mux[i];
struct chan *out = &cpu->ch[i];
/* Choose select CPU channel based on tracking mode */
struct chan *sel = NULL;
enum nosv_track track = nosv_chan_track[i][CT_CPU];
if (track == RUN_TH)
sel = &scpu->chan[CPU_CHAN_THRUN];
else if (track == ACT_TH)
sel = &scpu->chan[CPU_CHAN_THACT];
else
die("cpu tracking must be running or active");
if (mux_init(mux, &emu->bay, sel, out, NULL) != 0) {
err("mux_init failed");
return -1;
}
if (add_inputs_cpu_mux(emu, mux, i) != 0) {
err("add_inputs_cpu_mux failed");
return -1;
}
}
return 0;
}
int
nosv_connect(struct emu *emu)
{
struct system *sys = &emu->system;
/* threads */
for (struct thread *t = sys->threads; t; t = t->gnext) {
if (connect_thread_mux(emu, t) != 0) {
err("connect_thread_mux failed");
return -1;
}
}
/* cpus */
for (struct cpu *c = sys->cpus; c; c = c->next) {
if (connect_cpu_mux(emu, c) != 0) {
err("connect_cpu_mux failed");
return -1;
}
}
if (nosv_init_pvt(emu) != 0) {
err("init_pvt failed");
return -1;
}
return 0;
}

179
src/emu/nosv/create.c Normal file
View File

@ -0,0 +1,179 @@
#include "nosv_priv.h"
static const char chan_fmt_cpu_raw[] = "nosv.cpu%ld.%s";
//static const char chan_fmt_cpu_run[] = "nosv.cpu%ld.%s.run";
//static const char chan_fmt_cpu_act[] = "nosv.cpu%ld.%s.act";
static const char chan_fmt_th_raw[] = "nosv.thread%ld.%s.raw";
static const char chan_fmt_th_run[] = "nosv.thread%ld.%s.run";
static const char chan_fmt_th_act[] = "nosv.thread%ld.%s.act";
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, int filtered)
{
for (int i = 0; i < CH_MAX; i++) {
struct chan *c = &chans[i];
int type = (chan_stack[i] && !filtered) ? 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_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->ch = calloc(CH_MAX, sizeof(struct chan));
if (cpu->ch == NULL) {
err("calloc failed:");
return -1;
}
cpu->mux = calloc(CH_MAX, sizeof(struct mux));
if (cpu->mux == NULL) {
err("calloc failed:");
return -1;
}
if (init_chans(bay, cpu->ch, chan_fmt_cpu_raw, syscpu->gindex, 1) != 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->ch_run = calloc(CH_MAX, sizeof(struct chan));
if (th->ch_run == NULL) {
err("calloc failed:");
return -1;
}
th->ch_act = calloc(CH_MAX, sizeof(struct chan));
if (th->ch_act == NULL) {
err("calloc failed:");
return -1;
}
th->ch_out = calloc(CH_MAX, sizeof(struct chan *));
if (th->ch_out == NULL) {
err("calloc failed:");
return -1;
}
th->mux_run = calloc(CH_MAX, sizeof(struct mux));
if (th->mux_run == NULL) {
err("calloc failed:");
return -1;
}
th->mux_act = calloc(CH_MAX, sizeof(struct mux));
if (th->mux_act == NULL) {
err("calloc failed:");
return -1;
}
if (init_chans(bay, th->ch, chan_fmt_th_raw, systh->gindex, 0) != 0) {
err("init_chans failed");
return -1;
}
if (init_chans(bay, th->ch_run, chan_fmt_th_run, systh->gindex, 1) != 0) {
err("init_chans failed");
return -1;
}
if (init_chans(bay, th->ch_act, chan_fmt_th_act, systh->gindex, 1) != 0) {
err("init_chans 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;
}

501
src/emu/nosv/event.c Normal file
View File

@ -0,0 +1,501 @@
#include "nosv_priv.h"
enum { PUSH = 1, POP = 2, IGN = 3 };
#define CHSS CH_SUBSYSTEM
static const int ss_table[256][256][3] = {
['S'] = {
['h'] = { CHSS, PUSH, ST_SCHED_HUNGRY },
['f'] = { CHSS, POP, ST_SCHED_HUNGRY },
['['] = { CHSS, PUSH, ST_SCHED_SERVING },
[']'] = { CHSS, POP, ST_SCHED_SERVING },
['@'] = { CHSS, IGN, -1 },
['r'] = { CHSS, IGN, -1 },
['s'] = { CHSS, IGN, -1 },
},
['U'] = {
['['] = { CHSS, PUSH, ST_SCHED_SUBMITTING },
[']'] = { CHSS, POP, ST_SCHED_SUBMITTING },
},
['M'] = {
['a'] = { CHSS, PUSH, ST_MEM_ALLOCATING },
['A'] = { CHSS, POP, ST_MEM_ALLOCATING },
['f'] = { CHSS, PUSH, ST_MEM_FREEING },
['F'] = { CHSS, POP, ST_MEM_FREEING },
},
['A'] = {
['s'] = { CHSS, PUSH, ST_API_SUBMIT },
['S'] = { CHSS, POP, ST_API_SUBMIT },
['p'] = { CHSS, PUSH, ST_API_PAUSE },
['P'] = { CHSS, POP, ST_API_PAUSE },
['y'] = { CHSS, PUSH, ST_API_YIELD },
['Y'] = { CHSS, POP, ST_API_YIELD },
['w'] = { CHSS, PUSH, ST_API_WAITFOR },
['W'] = { CHSS, POP, ST_API_WAITFOR },
['c'] = { CHSS, PUSH, ST_API_SCHEDPOINT },
['C'] = { CHSS, POP, ST_API_SCHEDPOINT },
},
/* FIXME: Move thread type to another channel, like nanos6 */
['H'] = {
['a'] = { CHSS, PUSH, ST_ATTACH },
['A'] = { CHSS, POP, ST_ATTACH },
['w'] = { CHSS, PUSH, ST_WORKER },
['W'] = { CHSS, POP, ST_WORKER },
['d'] = { CHSS, PUSH, ST_DELEGATE },
['D'] = { CHSS, POP, ST_DELEGATE },
},
};
static int
simple(struct emu *emu)
{
const int *entry = ss_table[emu->ev->c][emu->ev->v];
int chind = entry[0];
int action = entry[1];
int st = entry[2];
struct nosv_thread *th = EXT(emu->thread, 'V');
struct chan *ch = &th->ch[chind];
if (action == PUSH) {
return chan_push(ch, value_int64(st));
} else if (action == POP) {
return chan_pop(ch, value_int64(st));
} else if (action == IGN) {
return 0; /* do nothing */
} else {
err("unknown nOS-V subsystem event");
return -1;
}
return 0;
}
static int
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) {
err("chan_set taskid failed");
return -1;
}
if (chan_set(&th->ch[CH_TYPE], null) != 0) {
err("chan_set type failed");
return -1;
}
if (chan_set(&th->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) {
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) {
err("chan_pop subsystem failed");
return -1;
}
return 0;
}
static int
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;
if (task->id == 0) {
err("task id cannot be 0");
return -1;
}
if (task->type->gid == 0) {
err("task type gid cannot be 0");
return -1;
}
if (proc->appid <= 0) {
err("app id must be positive");
return -1;
}
if (chan_set(&ch[CH_TASKID], value_int64(task->id)) != 0) {
err("chan_set taskid failed");
return -1;
}
if (chan_set(&ch[CH_TYPE], value_int64(task->type->gid)) != 0) {
err("chan_set type failed");
return -1;
}
if (chan_set(&ch[CH_APPID], value_int64(proc->appid)) != 0) {
err("chan_set appid failed");
return -1;
}
if (proc->rank >= 0) {
struct value vrank = value_int64(proc->rank + 1);
if (chan_set(&ch[CH_RANK], vrank) != 0) {
err("chan_set rank failed");
return -1;
}
}
if (chan_push(&ch[CH_SUBSYSTEM], value_int64(ST_TASK_RUNNING)) != 0) {
err("chan_push subsystem failed");
return -1;
}
return 0;
}
static int
chan_task_switch(struct emu *emu,
struct task *prev, struct task *next)
{
struct nosv_thread *th = EXT(emu->thread, 'V');
if (!prev || !next) {
err("cannot switch to or from a NULL task");
return -1;
}
if (prev == next) {
err("cannot switch to the same task");
return -1;
}
if (next->id == 0) {
err("next task id cannot be 0");
return -1;
}
if (next->type->gid == 0) {
err("next task type id cannot be 0");
return -1;
}
if (prev->thread != next->thread) {
err("cannot switch to a task of another thread");
return -1;
}
/* 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) {
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) {
err("chan_set type failed");
return -1;
}
return 0;
}
static int
update_task_state(struct emu *emu)
{
if (emu->ev->payload_size < 4) {
err("missing task id in payload");
return -1;
}
uint32_t task_id = emu->ev->payload->u32[0];
struct nosv_thread *th = EXT(emu->thread, 'V');
struct nosv_proc *proc = EXT(emu->proc, 'V');
struct task_info *info = &proc->task_info;
struct task_stack *stack = &th->task_stack;
struct task *task = task_find(info->tasks, task_id);
if (task == NULL) {
err("cannot find task with id %u", task_id);
return -1;
}
int ret = 0;
switch (emu->ev->v) {
case 'x':
ret = task_execute(stack, task);
break;
case 'e':
ret = task_end(stack, task);
break;
case 'p':
ret = task_pause(stack, task);
break;
case 'r':
ret = task_resume(stack, task);
break;
default:
err("unexpected nOS-V task event");
return -1;
}
if (ret != 0) {
err("cannot change task state");
return -1;
}
return 0;
}
static int
expand_transition_value(struct emu *emu, int was_running, int runs_now, char *tr_p)
{
char tr = emu->ev->v;
/* Ensure we don't clobber the value */
if (tr == 'X' || tr == 'E') {
err("unexpected event value %c", tr);
return -1;
}
/* Modify the event value to detect nested transitions */
if (tr == 'x' && was_running)
tr = 'X'; /* Execute a new nested task */
else if (tr == 'e' && runs_now)
tr = 'E'; /* End a nested task */
*tr_p = tr;
return 0;
}
static int
update_task_channels(struct emu *emu,
char tr, struct task *prev, struct task *next)
{
int ret = 0;
switch (tr) {
case 'x':
case 'r':
ret = chan_task_running(emu, next);
break;
case 'e':
case 'p':
ret = chan_task_stopped(emu);
break;
/* Additional nested transitions */
case 'X':
case 'E':
ret = chan_task_switch(emu, prev, next);
break;
default:
err("unexpected transition value %c", tr);
return -1;
}
if (ret != 0) {
err("cannot update task channels");
return -1;
}
return 0;
}
static int
enforce_task_rules(struct emu *emu, char tr, struct task *next)
{
if (tr != 'x' && tr != 'X')
return 0;
/* If a task has just entered the running state, it must show
* the running task body subsystem */
if (next->state != TASK_ST_RUNNING) {
err("task not in running state on begin");
return -1;
}
struct nosv_thread *th = EXT(emu->thread, 'V');
struct value ss;
if (chan_read(&th->ch[CH_SUBSYSTEM], &ss) != 0) {
err("chan_read failed");
return -1;
}
if (ss.type == VALUE_INT64 && ss.i != ST_TASK_RUNNING) {
err("wrong subsystem state on task begin");
//return -1;
return 0; // FIXME
}
return 0;
}
static int
update_task(struct emu *emu)
{
struct nosv_thread *th = EXT(emu->thread, 'V');
struct task_stack *stack = &th->task_stack;
struct task *prev = task_get_running(stack);
/* Update the emulator state, but don't modify the channels */
if (update_task_state(emu) != 0) {
err("update_task_state failed");
return -1;
}
struct task *next = task_get_running(stack);
int was_running = (prev != NULL);
int runs_now = (next != NULL);
char tr;
if (expand_transition_value(emu, was_running, runs_now, &tr) != 0) {
err("expand_transition_value failed");
return -1;
}
/* Update the task related channels now */
update_task_channels(emu, tr, prev, next);
if (enforce_task_rules(emu, tr, next) != 0) {
err("enforce_task_rules failed");
return -1;
}
return 0;
}
static int
create_task(struct emu *emu)
{
if (emu->ev->payload_size != 8) {
err("unexpected payload size");
return -1;
}
uint32_t task_id = emu->ev->payload->u32[0];
uint32_t type_id = emu->ev->payload->u32[1];
struct nosv_proc *proc = EXT(emu->proc, 'V');
struct task_info *info = &proc->task_info;
if (task_create(info, type_id, task_id) != 0) {
err("task_create failed");
return -1;
}
dbg("task created with taskid %u", task_id);
return 0;
}
static int
pre_task(struct emu *emu)
{
int ret = 0;
switch (emu->ev->v) {
case 'c':
ret = create_task(emu);
break;
case 'x':
case 'e':
case 'r':
case 'p':
ret = update_task(emu);
break;
default:
err("unexpected nOS-V task event value");
return -1;
}
if (ret != 0) {
err("cannot update task state");
return -1;
}
return 0;
}
static int
pre_type(struct emu *emu)
{
uint8_t value = emu->ev->v;
if (value != 'c') {
err("unexpected event value %c", value);
return -1;
}
if (!emu->ev->is_jumbo) {
err("expecting a jumbo event");
return -1;
}
const uint8_t *data = &emu->ev->payload->jumbo.data[0];
uint32_t typeid = *(uint32_t *) data;
data += 4;
const char *label = (const char *) data;
struct nosv_proc *proc = EXT(emu->proc, 'V');
struct task_info *info = &proc->task_info;
if (task_type_create(info, typeid, label) != 0) {
err("task_type_create failed");
return -1;
}
return 0;
}
static int
process_ev(struct emu *emu)
{
if (!emu->thread->is_active) {
err("current thread %d not active", emu->thread->tid);
return -1;
}
switch (emu->ev->c) {
case 'S':
case 'U':
case 'M':
case 'H':
case 'A':
return simple(emu);
case 'T':
return pre_task(emu);
case 'Y':
return pre_type(emu);
default:
err("unknown nOS-V event category");
return -1;
}
/* Not reached */
return 0;
}
int
nosv_event(struct emu *emu)
{
dbg("in nosv_event");
if (emu->ev->m != 'V') {
err("unexpected event model %c\n", emu->ev->m);
return -1;
}
dbg("got nosv event %s", emu->ev->mcv);
if (process_ev(emu) != 0) {
err("error processing nOS-V event");
return -1;
}
return 0;
}

44
src/emu/nosv/finish.c Normal file
View File

@ -0,0 +1,44 @@
#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;
}

88
src/emu/nosv/nosv_priv.h Normal file
View File

@ -0,0 +1,88 @@
/* Copyright (c) 2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef NOSV_PRIV_H
#define NOSV_PRIV_H
#include "emu.h"
#include "chan.h"
#include "mux.h"
#include "task.h"
/* Private enums */
enum nosv_chan_type {
CT_TH = 0,
CT_CPU,
CT_MAX
};
enum nosv_chan {
CH_TASKID = 0,
CH_TYPE,
CH_APPID,
CH_SUBSYSTEM,
CH_RANK,
CH_MAX,
};
enum nosv_track {
NONE = 0,
RUN_TH,
ACT_TH,
TRACK_MAX,
};
extern const enum nosv_track nosv_chan_track[CH_MAX][CT_MAX];
enum nosv_ss_values {
ST_SCHED_HUNGRY = 6,
ST_SCHED_SERVING,
ST_SCHED_SUBMITTING,
ST_MEM_ALLOCATING,
ST_MEM_FREEING,
ST_TASK_RUNNING,
ST_API_SUBMIT,
ST_API_PAUSE,
ST_API_YIELD,
ST_API_WAITFOR,
ST_API_SCHEDPOINT,
ST_ATTACH,
ST_WORKER,
ST_DELEGATE,
EV_SCHED_RECV,
EV_SCHED_SEND,
EV_SCHED_SELF,
};
struct nosv_thread {
struct chan *ch; /* Raw, modified by nosv */
struct chan *ch_run; /* Tracking running thread */
struct chan *ch_act; /* Tracking active thread */
struct chan **ch_out; /* Output to PRV */
struct mux *mux_run;
struct mux *mux_act;
struct task_stack task_stack;
};
struct nosv_cpu {
struct chan *ch;
struct mux *mux;
};
struct nosv_proc {
struct task_info task_info;
};
int nosv_probe(struct emu *emu);
int nosv_create(struct emu *emu);
int nosv_connect(struct emu *emu);
int nosv_event(struct emu *emu);
int nosv_finish(struct emu *emu);
int nosv_init_pvt(struct emu *emu);
int nosv_finish_pvt(struct emu *emu);
const char *nosv_ss_name(int ss);
#endif /* NOSV_PRIV_H */

20
src/emu/nosv/probe.c Normal file
View File

@ -0,0 +1,20 @@
#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;
}

273
src/emu/nosv/pvt.c Normal file
View File

@ -0,0 +1,273 @@
#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_chan_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 = th->ch_out[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 = &cpu->ch[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;
}

View File

@ -307,6 +307,22 @@ pre_affinity(struct emu *emu)
return 0;
}
static int
pre_cpu(struct emu *emu)
{
switch (emu->ev->v) {
case 'n':
err("ignoring old event OCn");
return 0;
default:
err("unknown cpu event value %c\n",
emu->ev->v);
return -1;
}
return 0;
}
static int
compare_int64(const void *a, const void *b)
{
@ -402,8 +418,9 @@ process_ev(struct emu *emu)
case 'A':
return pre_affinity(emu);
case 'B':
pre_burst(emu);
break;
return pre_burst(emu);
case 'C':
return pre_cpu(emu);
case 'F':
return pre_flush(emu);
default:

View File

@ -92,32 +92,6 @@ const int pcf_palette_len = ARRAY_LEN(pcf_def_palette);
// { -1, NULL },
//};
//
//struct pcf_value_label nosv_ss_values[] = {
// /* Errors */
// { ST_BAD, "Unknown: bad happened (report bug)" },
// { ST_TOO_MANY_TH, "Unknown: multiple threads running" },
// /* Good values */
// { ST_NULL, "No subsystem" },
// { ST_NOSV_SCHED_HUNGRY, "Scheduler: Hungry" },
// { ST_NOSV_SCHED_SERVING, "Scheduler: Serving" },
// { ST_NOSV_SCHED_SUBMITTING, "Scheduler: Submitting" },
// { ST_NOSV_MEM_ALLOCATING, "Memory: Allocating" },
// { ST_NOSV_MEM_FREEING, "Memory: Freeing" },
// { ST_NOSV_TASK_RUNNING, "Task: Running" },
// { ST_NOSV_API_SUBMIT, "API: Submit" },
// { ST_NOSV_API_PAUSE, "API: Pause" },
// { ST_NOSV_API_YIELD, "API: Yield" },
// { ST_NOSV_API_WAITFOR, "API: Waitfor" },
// { ST_NOSV_API_SCHEDPOINT, "API: Scheduling point" },
// { ST_NOSV_ATTACH, "Thread: Attached" },
// { ST_NOSV_WORKER, "Thread: Worker" },
// { ST_NOSV_DELEGATE, "Thread: Delegate" },
// { EV_NOSV_SCHED_SEND, "EV Scheduler: Send task" },
// { EV_NOSV_SCHED_RECV, "EV Scheduler: Recv task" },
// { EV_NOSV_SCHED_SELF, "EV Scheduler: Self-assign task" },
// { -1, NULL },
//};
//
//struct pcf_value_label nodes_mode_values[] = {
// { ST_NULL, "NULL" },
// { ST_TOO_MANY_TH, "NODES: Multiple threads running" },

View File

@ -2,5 +2,5 @@
# SPDX-License-Identifier: GPL-3.0-or-later
add_subdirectory(ovni)
#add_subdirectory(nosv)
add_subdirectory(nosv)
add_subdirectory(nanos6)

View File

@ -3,7 +3,7 @@
ovni_test(nested-tasks.c)
ovni_test(nested-tasks-bad.c SHOULD_FAIL
REGEX "fatal: cannot execute task 1: state is not created")
REGEX "cannot execute task 1: state is not created")
ovni_test(task-types.c MP)
ovni_test(pause.c MP)
ovni_test(mp-rank.c MP)

View File

@ -3,4 +3,4 @@
add_subdirectory(nanos6)
#add_subdirectory(nodes)
#add_subdirectory(nosv)
add_subdirectory(nosv)

View File

@ -23,6 +23,6 @@ function(nosv_test)
ENVIRONMENT "NOSV_CONFIG=${OVNI_TEST_SOURCE_DIR}/rt/nosv/nosv.toml")
endfunction()
nosv_test(attach.c SORT)
nosv_test(waitfor.c SORT)
nosv_test(several-tasks.c SORT)
nosv_test(attach.c)
nosv_test(waitfor.c)
nosv_test(several-tasks.c)

View File

@ -41,7 +41,7 @@ test_negative_cpu(struct loom *loom)
die("loom_init_begin failed");
struct cpu cpu;
cpu_init_begin(&cpu, -1);
cpu_init_begin(&cpu, -1, 0);
if (loom_add_cpu(loom, &cpu) == 0)
die("loom_add_cpu didn't fail");
@ -56,7 +56,7 @@ test_duplicate_cpus(struct loom *loom)
die("loom_init_begin failed");
struct cpu cpu;
cpu_init_begin(&cpu, 123);
cpu_init_begin(&cpu, 123, 0);
if (loom_add_cpu(loom, &cpu) != 0)
die("loom_add_cpu failed");