Add support for nOS-V
Most of the model is taken from nanos6, we should refactor them.
This commit is contained in:
parent
55a5be7d13
commit
a818795d88
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#define _POSIX_C_SOURCE 2
|
||||
|
||||
//#define ENABLE_DEBUG
|
||||
#define ENABLE_DEBUG
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -520,7 +520,5 @@ nanos6_event(struct emu *emu)
|
||||
return -1;
|
||||
}
|
||||
|
||||
//check_affinity(emu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
150
src/emu/nosv/connect.c
Normal 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
179
src/emu/nosv/create.c
Normal 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
501
src/emu/nosv/event.c
Normal 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
44
src/emu/nosv/finish.c
Normal 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
88
src/emu/nosv/nosv_priv.h
Normal 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
20
src/emu/nosv/probe.c
Normal 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
273
src/emu/nosv/pvt.c
Normal 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;
|
||||
}
|
@ -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:
|
||||
|
@ -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" },
|
||||
|
@ -2,5 +2,5 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
add_subdirectory(ovni)
|
||||
#add_subdirectory(nosv)
|
||||
add_subdirectory(nosv)
|
||||
add_subdirectory(nanos6)
|
||||
|
@ -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)
|
||||
|
@ -3,4 +3,4 @@
|
||||
|
||||
add_subdirectory(nanos6)
|
||||
#add_subdirectory(nodes)
|
||||
#add_subdirectory(nosv)
|
||||
add_subdirectory(nosv)
|
||||
|
@ -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)
|
||||
|
@ -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");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user