Begin porting nanos6 model

This commit is contained in:
Rodrigo Arias 2023-01-30 22:43:57 +01:00 committed by Rodrigo Arias Mallo
parent 070c0f5e24
commit 524ccc4dd5
30 changed files with 1203 additions and 229 deletions

View File

@ -13,27 +13,31 @@ include_directories(
add_library(emu STATIC add_library(emu STATIC
../common.c ../common.c
bay.c
chan.c
clkoff.c
cpu.c cpu.c
loom.c
proc.c
thread.c
path.c
metadata.c
emu.c emu.c
system.c
#emu_system_thread.c
emu_args.c emu_args.c
emu_ev.c
emu_model.c
emu_player.c
emu_stream.c emu_stream.c
emu_trace.c emu_trace.c
emu_player.c loom.c
emu_model.c metadata.c
emu_ev.c model_nanos6.c
chan.c
bay.c
mux.c
prv.c
clkoff.c
model_ust.c model_ust.c
mux.c
path.c
proc.c
prv.c
pvt.c
recorder.c
system.c
task.c
thread.c
extend.c
) )
#add_library(emu STATIC #add_library(emu STATIC

View File

@ -1,4 +1,4 @@
//#define ENABLE_DEBUG #define ENABLE_DEBUG
#include "bay.h" #include "bay.h"
@ -6,11 +6,6 @@
#include "uthash.h" #include "uthash.h"
#include "utlist.h" #include "utlist.h"
//static char *propname[BAY_CB_MAX] = {
// [BAY_CB_DIRTY] = "dirty",
// [BAY_CB_EMIT] = "emit"
//};
/* Called from the channel when it becomes dirty */ /* Called from the channel when it becomes dirty */
static int static int
cb_chan_is_dirty(struct chan *chan, void *arg) cb_chan_is_dirty(struct chan *chan, void *arg)
@ -146,6 +141,13 @@ bay_init(struct bay *bay)
static int static int
propagate_chan(struct bay_chan *bchan, enum bay_cb_type type) propagate_chan(struct bay_chan *bchan, enum bay_cb_type type)
{ {
char *propname[BAY_CB_MAX] = {
[BAY_CB_DIRTY] = "dirty",
[BAY_CB_EMIT] = "emit"
};
UNUSED(propname);
dbg("- propagating channel '%s' phase %s\n", dbg("- propagating channel '%s' phase %s\n",
bchan->chan->name, propname[type]); bchan->chan->name, propname[type]);

View File

@ -6,6 +6,8 @@
#include "chan.h" #include "chan.h"
#include "value.h" #include "value.h"
#include "utlist.h" #include "utlist.h"
#include "pvt.h"
#include "prv.h"
static const char chan_fmt[] = "cpu%ld.%s"; static const char chan_fmt[] = "cpu%ld.%s";
static const char *chan_name[] = { static const char *chan_name[] = {
@ -16,6 +18,14 @@ static const char *chan_name[] = {
[CPU_CHAN_FLUSH] = "flush_running", [CPU_CHAN_FLUSH] = "flush_running",
}; };
static int chan_type[] = {
[CPU_CHAN_PID] = 1,
[CPU_CHAN_TID] = 2,
[CPU_CHAN_NRUN] = 3,
[CPU_CHAN_APPID] = 5,
[CPU_CHAN_FLUSH] = 7,
};
void void
cpu_init_begin(struct cpu *cpu, int phyid) cpu_init_begin(struct cpu *cpu, int phyid)
{ {
@ -71,18 +81,34 @@ cpu_init_end(struct cpu *cpu)
} }
int int
cpu_connect(struct cpu *cpu, struct bay *bay) cpu_connect(struct cpu *cpu, struct bay *bay, struct recorder *rec)
{ {
if (!cpu->is_init) { if (!cpu->is_init) {
err("cpu not initialized"); err("cpu not initialized");
return -1; return -1;
} }
/* Get cpu prv */
struct pvt *pvt = recorder_find_pvt(rec, "cpu");
if (pvt == NULL) {
err("cannot find cpu pvt");
return -1;
}
struct prv *prv = pvt_get_prv(pvt);
for (int i = 0; i < CPU_CHAN_MAX; i++) { for (int i = 0; i < CPU_CHAN_MAX; i++) {
if (bay_register(bay, &cpu->chan[i]) != 0) { struct chan *c = &cpu->chan[i];
if (bay_register(bay, c) != 0) {
err("bay_register failed"); err("bay_register failed");
return -1; return -1;
} }
long type = chan_type[i];
long row = cpu->gindex;
if (prv_register(prv, row, type, bay, c)) {
err("prv_register failed");
return -1;
}
} }
return 0; return 0;
@ -127,10 +153,26 @@ cpu_update(struct cpu *cpu)
cpu->nth_running = running; cpu->nth_running = running;
cpu->nth_active = active; cpu->nth_active = active;
if (running == 1) struct value tid_running;
struct value pid_running;
if (running == 1) {
cpu->th_running = th_running; cpu->th_running = th_running;
else tid_running = value_int64(th_running->tid);
pid_running = value_int64(th_running->proc->pid);
} else {
cpu->th_running = NULL; cpu->th_running = NULL;
tid_running = value_null();
pid_running = value_null();
}
if (chan_set(&cpu->chan[CPU_CHAN_TID], tid_running) != 0) {
err("chan_set tid failed");
return -1;
}
if (chan_set(&cpu->chan[CPU_CHAN_PID], pid_running) != 0) {
err("chan_set pid failed");
return -1;
}
if (active == 1) if (active == 1)
cpu->th_active = th_active; cpu->th_active = th_active;
@ -138,8 +180,7 @@ cpu_update(struct cpu *cpu)
cpu->th_active = NULL; cpu->th_active = NULL;
/* Update nth_running number in the channel */ /* Update nth_running number in the channel */
struct chan *nrun = &cpu->chan[CPU_CHAN_NRUN]; if (chan_set(&cpu->chan[CPU_CHAN_NRUN], value_int64(running)) != 0) {
if (chan_set(nrun, value_int64(cpu->nth_running)) != 0) {
err("chan_set nth_running failed"); err("chan_set nth_running failed");
return -1; return -1;
} }

View File

@ -10,6 +10,8 @@ struct cpu; /* Needed for thread */
#include "chan.h" #include "chan.h"
#include "bay.h" #include "bay.h"
#include "uthash.h" #include "uthash.h"
#include "recorder.h"
#include "extend.h"
#include <linux/limits.h> #include <linux/limits.h>
enum cpu_chan { enum cpu_chan {
@ -52,7 +54,7 @@ struct cpu {
/* Channels */ /* Channels */
struct chan chan[CPU_CHAN_MAX]; struct chan chan[CPU_CHAN_MAX];
//struct model_ctx ctx; struct extend ext;
UT_hash_handle hh; /* CPUs in the loom */ UT_hash_handle hh; /* CPUs in the loom */
}; };
@ -63,7 +65,7 @@ int cpu_get_phyid(struct cpu *cpu);
void cpu_set_gindex(struct cpu *cpu, int64_t gindex); void cpu_set_gindex(struct cpu *cpu, int64_t gindex);
void cpu_set_name(struct cpu *cpu, const char *name); void cpu_set_name(struct cpu *cpu, const char *name);
int cpu_init_end(struct cpu *cpu); int cpu_init_end(struct cpu *cpu);
int cpu_connect(struct cpu *cpu, struct bay *bay); int cpu_connect(struct cpu *cpu, struct bay *bay, struct recorder *rec);
int cpu_update(struct cpu *cpu); int cpu_update(struct cpu *cpu);
int cpu_add_thread(struct cpu *cpu, struct thread *thread); int cpu_add_thread(struct cpu *cpu, struct thread *thread);

View File

@ -3,10 +3,13 @@
#define _POSIX_C_SOURCE 2 #define _POSIX_C_SOURCE 2
#define ENABLE_DEBUG
#include "emu.h" #include "emu.h"
#include <unistd.h> #include <unistd.h>
#include "model_ust.h" #include "model_ust.h"
#include "model_nanos6.h"
int int
emu_init(struct emu *emu, int argc, char *argv[]) emu_init(struct emu *emu, int argc, char *argv[])
@ -17,8 +20,7 @@ emu_init(struct emu *emu, int argc, char *argv[])
/* Load the streams into the trace */ /* Load the streams into the trace */
if (emu_trace_load(&emu->trace, emu->args.tracedir) != 0) { if (emu_trace_load(&emu->trace, emu->args.tracedir) != 0) {
err("emu_init: cannot load trace '%s'\n", err("cannot load trace '%s'\n", emu->args.tracedir);
emu->args.tracedir);
return -1; return -1;
} }
@ -29,11 +31,17 @@ emu_init(struct emu *emu, int argc, char *argv[])
return -1; return -1;
} }
/* Place output inside the same tracedir directory */
if (recorder_init(&emu->recorder, emu->args.tracedir) != 0) {
err("recorder_init failed");
return -1;
}
/* Initialize the bay */ /* Initialize the bay */
bay_init(&emu->bay); bay_init(&emu->bay);
/* Connect system channels to bay */ /* Connect system channels to bay */
if (system_connect(&emu->system, &emu->bay) != 0) { if (system_connect(&emu->system, &emu->bay, &emu->recorder) != 0) {
err("system_connect failed"); err("system_connect failed");
return -1; return -1;
} }
@ -48,6 +56,31 @@ emu_init(struct emu *emu, int argc, char *argv[])
// emu_model_register(&emu->model, &ovni_model_spec, emu); // emu_model_register(&emu->model, &ovni_model_spec, emu);
// //
if (model_ust.create && model_ust.create(emu) != 0) {
err("model ust create failed");
return -1;
}
if (model_nanos6.create && model_nanos6.create(emu) != 0) {
err("model nanos6 create failed");
return -1;
}
return 0;
}
int
emu_connect(struct emu *emu)
{
if (model_ust.connect && model_ust.connect(emu) != 0) {
err("model ust connect failed");
return -1;
}
if (model_nanos6.connect && model_nanos6.connect(emu) != 0) {
err("model nanos6 connect failed");
return -1;
}
return 0; return 0;
} }
@ -98,12 +131,20 @@ emu_step(struct emu *emu)
/* Error happened */ /* Error happened */
if (ret < 0) { if (ret < 0) {
err("emu_step: emu_player_step failed\n"); err("emu_player_step failed");
return -1; return -1;
} }
set_current(emu); set_current(emu);
dbg("----- mvc=%s dclock=%ld -----", emu->ev->mcv, emu->ev->dclock);
/* Advance recorder clock */
if (recorder_advance(&emu->recorder, emu->ev->dclock) != 0) {
err("recorder_advance failed");
return -1;
}
/* Otherwise progress */ /* Otherwise progress */
if (emu->ev->m == 'O' && model_ust.event(emu) != 0) { if (emu->ev->m == 'O' && model_ust.event(emu) != 0) {
err("ovni event failed"); err("ovni event failed");
@ -111,6 +152,12 @@ emu_step(struct emu *emu)
return -1; return -1;
} }
if (emu->ev->m == '6' && model_nanos6.event(emu) != 0) {
err("nanos6 event failed");
panic(emu);
return -1;
}
if (bay_propagate(&emu->bay) != 0) { if (bay_propagate(&emu->bay) != 0) {
err("bay_propagate failed"); err("bay_propagate failed");
return -1; return -1;

View File

@ -4,16 +4,14 @@
#ifndef EMU_H #ifndef EMU_H
#define EMU_H #define EMU_H
struct emu;
#include "bay.h" #include "bay.h"
#include "pvtrace.h"
#include "emu_trace.h" #include "emu_trace.h"
#include "emu_args.h" #include "emu_args.h"
#include "system.h" #include "system.h"
#include "emu_player.h" #include "emu_player.h"
#include "emu_model.h" #include "emu_model.h"
#include "emu_ev.h" #include "emu_ev.h"
#include "recorder.h"
enum error_values { enum error_values {
ST_BAD = 666, ST_BAD = 666,
@ -22,13 +20,13 @@ enum error_values {
struct emu { struct emu {
struct bay bay; struct bay bay;
struct pvman *pvman;
struct emu_args args; struct emu_args args;
struct emu_trace trace; struct emu_trace trace;
struct system system; struct system system;
struct emu_player player; struct emu_player player;
struct emu_model model; struct emu_model model;
struct recorder recorder;
/* Quick access */ /* Quick access */
struct emu_stream *stream; struct emu_stream *stream;
@ -39,6 +37,7 @@ struct emu {
}; };
int emu_init(struct emu *emu, int argc, char *argv[]); int emu_init(struct emu *emu, int argc, char *argv[]);
int emu_connect(struct emu *emu);
int emu_step(struct emu *emu); int emu_step(struct emu *emu);
static inline struct emu * static inline struct emu *

View File

@ -9,9 +9,9 @@
/* Easier to parse emulation event */ /* Easier to parse emulation event */
struct emu_ev { struct emu_ev {
char m; uint8_t m;
char c; uint8_t c;
char v; uint8_t v;
char mcv[4]; char mcv[4];
int64_t rclock; /* As-is clock in the binary stream */ int64_t rclock; /* As-is clock in the binary stream */

10
src/emu/emu_hook.h Normal file
View File

@ -0,0 +1,10 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef EMU_HOOK_H
#define EMU_HOOK_H
struct emu;
typedef int (emu_hook_t)(struct emu *emu);
#endif /* EMU_HOOK_H */

View File

@ -4,7 +4,7 @@
#ifndef EMU_MODEL_H #ifndef EMU_MODEL_H
#define EMU_MODEL_H #define EMU_MODEL_H
typedef int (emu_hook_t)(void *ptr); #include "emu_hook.h"
struct model_spec { struct model_spec {
char *name; char *name;

16
src/emu/extend.c Normal file
View File

@ -0,0 +1,16 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "extend.h"
void
extend_set(struct extend *ext, int id, void *ctx)
{
ext->ctx[id] = ctx;
}
void *
extend_get(struct extend *ext, int id)
{
return ext->ctx[id];
}

16
src/emu/extend.h Normal file
View File

@ -0,0 +1,16 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef EXTEND_H
#define EXTEND_H
#define MAX_EXTEND 256
struct extend {
void *ctx[MAX_EXTEND];
};
void extend_set(struct extend *ext, int id, void *ctx);
void *extend_get(struct extend *ext, int id);
#endif /* EXTEND_H */

386
src/emu/model_nanos6.c Normal file
View File

@ -0,0 +1,386 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#define ENABLE_DEBUG
#include "model_nanos6.h"
#include "emu.h"
#include "loom.h"
#include "common.h"
#include "chan.h"
/* Raw channels */
static const char chan_cpu_fmt[] = "nanos6.cpu%ld.%s.raw";
static const char chan_th_fmt[] = "nanos6.thread%ld.%s.raw";
/* Channels filtered by tracking */
//static const char chan_fcpu_fmt[] = "nanos6.cpu%ld.%s.filtered";
static const char chan_fth_fmt[] = "nanos6.thread%ld.%s.filtered";
static const char *chan_name[] = {
[NANOS6_CHAN_TASKID] = "taskid",
[NANOS6_CHAN_TYPE] = "task_type",
[NANOS6_CHAN_SUBSYSTEM] = "subsystem",
[NANOS6_CHAN_RANK] = "rank",
[NANOS6_CHAN_THREAD] = "thread_type",
};
static const char *th_track[] = {
[NANOS6_CHAN_TASKID] = "running",
[NANOS6_CHAN_TYPE] = "running",
[NANOS6_CHAN_SUBSYSTEM] = "active",
[NANOS6_CHAN_RANK] = "running",
[NANOS6_CHAN_THREAD] = "none",
};
static const int chan_stack[] = {
[NANOS6_CHAN_SUBSYSTEM] = 1,
[NANOS6_CHAN_THREAD] = 1,
};
static const int th_type[] = {
[NANOS6_CHAN_TASKID] = 35,
[NANOS6_CHAN_TYPE] = 36,
[NANOS6_CHAN_SUBSYSTEM] = 37,
[NANOS6_CHAN_RANK] = 38,
[NANOS6_CHAN_THREAD] = 39,
};
enum { PUSH = 1, POP = 2, IGN = 3 };
#define CHSS NANOS6_CHAN_SUBSYSTEM
#define CHTT NANOS6_CHAN_THREAD
static const int ss_table[256][256][3] = {
['W'] = {
['['] = { CHSS, PUSH, ST_NANOS6_WORKER_LOOP },
[']'] = { CHSS, POP, ST_NANOS6_WORKER_LOOP },
['t'] = { CHSS, PUSH, ST_NANOS6_HANDLING_TASK },
['T'] = { CHSS, POP, ST_NANOS6_HANDLING_TASK },
['w'] = { CHSS, PUSH, ST_NANOS6_SWITCH_TO },
['W'] = { CHSS, POP, ST_NANOS6_SWITCH_TO },
['m'] = { CHSS, PUSH, ST_NANOS6_MIGRATE },
['M'] = { CHSS, POP, ST_NANOS6_MIGRATE },
['s'] = { CHSS, PUSH, ST_NANOS6_SUSPEND },
['S'] = { CHSS, POP, ST_NANOS6_SUSPEND },
['r'] = { CHSS, PUSH, ST_NANOS6_RESUME },
['R'] = { CHSS, POP, ST_NANOS6_RESUME },
['*'] = { CHSS, IGN, -1 },
},
['C'] = {
['['] = { CHSS, PUSH, ST_NANOS6_TASK_CREATING },
[']'] = { CHSS, POP, ST_NANOS6_TASK_CREATING },
},
['U'] = {
['['] = { CHSS, PUSH, ST_NANOS6_TASK_SUBMIT },
[']'] = { CHSS, POP, ST_NANOS6_TASK_SUBMIT },
},
['F'] = {
['['] = { CHSS, PUSH, ST_NANOS6_TASK_SPAWNING },
[']'] = { CHSS, POP, ST_NANOS6_TASK_SPAWNING },
},
['O'] = {
['['] = { CHSS, PUSH, ST_NANOS6_TASK_FOR },
[']'] = { CHSS, POP, ST_NANOS6_TASK_FOR },
},
['t'] = {
['['] = { CHSS, PUSH, ST_NANOS6_TASK_BODY },
[']'] = { CHSS, POP, ST_NANOS6_TASK_BODY },
},
['M'] = {
['a'] = { CHSS, PUSH, ST_NANOS6_ALLOCATING },
['A'] = { CHSS, POP, ST_NANOS6_ALLOCATING },
['f'] = { CHSS, PUSH, ST_NANOS6_FREEING },
['F'] = { CHSS, POP, ST_NANOS6_FREEING },
},
['D'] = {
['r'] = { CHSS, PUSH, ST_NANOS6_DEP_REG },
['R'] = { CHSS, POP, ST_NANOS6_DEP_REG },
['u'] = { CHSS, PUSH, ST_NANOS6_DEP_UNREG },
['U'] = { CHSS, POP, ST_NANOS6_DEP_UNREG },
},
['S'] = {
['['] = { CHSS, PUSH, ST_NANOS6_SCHED_SERVING },
[']'] = { CHSS, POP, ST_NANOS6_SCHED_SERVING },
['a'] = { CHSS, PUSH, ST_NANOS6_SCHED_ADDING },
['A'] = { CHSS, POP, ST_NANOS6_SCHED_ADDING },
['p'] = { CHSS, PUSH, ST_NANOS6_SCHED_PROCESSING },
['P'] = { CHSS, POP, ST_NANOS6_SCHED_PROCESSING },
['@'] = { CHSS, IGN, -1 },
['r'] = { CHSS, IGN, -1 },
['s'] = { CHSS, IGN, -1 },
},
['B'] = {
['b'] = { CHSS, PUSH, ST_NANOS6_BLK_BLOCKING },
['B'] = { CHSS, POP, ST_NANOS6_BLK_BLOCKING },
['u'] = { CHSS, PUSH, ST_NANOS6_BLK_UNBLOCKING },
['U'] = { CHSS, POP, ST_NANOS6_BLK_UNBLOCKING },
['w'] = { CHSS, PUSH, ST_NANOS6_BLK_TASKWAIT },
['W'] = { CHSS, POP, ST_NANOS6_BLK_TASKWAIT },
['f'] = { CHSS, PUSH, ST_NANOS6_BLK_WAITFOR },
['F'] = { CHSS, POP, ST_NANOS6_BLK_WAITFOR },
},
['H'] = {
['e'] = { CHTT, PUSH, ST_NANOS6_TH_EXTERNAL },
['E'] = { CHTT, POP, ST_NANOS6_TH_EXTERNAL },
['w'] = { CHTT, PUSH, ST_NANOS6_TH_WORKER },
['W'] = { CHTT, POP, ST_NANOS6_TH_WORKER },
['l'] = { CHTT, PUSH, ST_NANOS6_TH_LEADER },
['L'] = { CHTT, POP, ST_NANOS6_TH_LEADER },
['m'] = { CHTT, PUSH, ST_NANOS6_TH_MAIN },
['M'] = { CHTT, POP, ST_NANOS6_TH_MAIN },
},
};
static int
nanos6_probe(struct emu *emu)
{
if (emu->system.nthreads == 0)
return -1;
return 0;
}
static int
init_chans(struct bay *bay, struct chan chans[], const char *fmt, int64_t gindex, int filtered)
{
for (int i = 0; i < NANOS6_CHAN_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
nanos6_create(struct emu *emu)
{
struct system *sys = &emu->system;
struct bay *bay = &emu->bay;
/* Create nanos6 cpu data */
struct nanos6_cpu *cpus = calloc(sys->ncpus, sizeof(*cpus));
if (cpus == NULL) {
err("calloc failed:");
return -1;
}
for (struct cpu *c = sys->cpus; c; c = c->next) {
struct nanos6_cpu *cpu = &cpus[c->gindex];
if (init_chans(bay, cpu->chans, chan_cpu_fmt, c->gindex, 0) != 0) {
err("init_chans failed");
return -1;
}
extend_set(&c->ext, model_nanos6.model, cpu);
}
/* Create nanos6 thread data */
struct nanos6_thread *threads = calloc(sys->nthreads, sizeof(*threads));
if (threads == NULL) {
err("calloc failed:");
return -1;
}
for (struct thread *t = sys->threads; t; t = t->gnext) {
struct nanos6_thread *th = &threads[t->gindex];
if (init_chans(bay, th->chans, chan_th_fmt, t->gindex, 0) != 0) {
err("init_chans failed");
return -1;
}
if (init_chans(bay, th->fchans, chan_fth_fmt, t->gindex, 1) != 0) {
err("init_chans failed");
return -1;
}
extend_set(&t->ext, model_nanos6.model, th);
}
return 0;
}
static int
connect_thread_mux(struct emu *emu, struct thread *thread)
{
struct nanos6_thread *th = extend_get(&thread->ext, '6');
for (int i = 0; i < NANOS6_CHAN_MAX; i++) {
struct mux *mux = &th->muxers[i];
const char *tracking = th_track[i];
mux_select_func_t selfun;
struct chan *inp = &th->chans[i];
/* TODO: Let the thread take the select channel
* and build the mux as a tracking mode */
struct chan *sel = &thread->chan[TH_CHAN_STATE];
if (strcmp(tracking, "running") == 0) {
selfun = thread_select_running;
} else if (strcmp(tracking, "active") == 0) {
selfun = thread_select_active;
} else {
th->ochans[i] = inp;
/* No tracking */
continue;
}
struct chan *out = &th->fchans[i];
th->ochans[i] = out;
if (mux_init(mux, &emu->bay, sel, out, selfun) != 0) {
err("mux_init failed");
return -1;
}
if (mux_add_input(mux, value_int64(0), inp) != 0) {
err("mux_add_input failed");
return -1;
}
/* Connect to prv output */
}
return 0;
}
static int
connect_thread_prv(struct emu *emu, struct thread *thread, struct prv *prv)
{
struct nanos6_thread *th = extend_get(&thread->ext, '6');
for (int i = 0; i < NANOS6_CHAN_MAX; i++) {
struct chan *out = &th->fchans[i];
long type = th_type[i];
long row = thread->gindex;
if (prv_register(prv, row, type, &emu->bay, out)) {
err("prv_register failed");
return -1;
}
}
return 0;
}
static int
nanos6_connect(struct emu *emu)
{
struct system *sys = &emu->system;
for (struct thread *t = sys->threads; t; t = t->gnext) {
if (connect_thread_mux(emu, t) != 0) {
err("connect_thread_mux failed");
return -1;
}
}
/* Get thread PRV */
struct pvt *pvt = recorder_find_pvt(&emu->recorder, "thread");
if (pvt == NULL) {
err("cannot find thread pvt");
return -1;
}
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;
}
}
return 0;
}
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 nanos6_thread *th = extend_get(&emu->thread->ext, '6');
struct chan *ch = &th->chans[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 Nanos6 subsystem event");
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 'C':
case 'S':
case 'U':
case 'F':
case 'O':
case 't':
case 'H':
case 'D':
case 'B':
case 'W':
return simple(emu);
// case 'T':
// pre_task(emu);
// break;
// case 'Y':
// pre_type(emu);
// break;
default:
err("unknown Nanos6 event category");
// return -1;
}
/* Not reached */
return 0;
}
static int
nanos6_event(struct emu *emu)
{
if (emu->ev->m != model_nanos6.model) {
err("unexpected event model %c\n", emu->ev->m);
return -1;
}
dbg("got nanos6 event %s", emu->ev->mcv);
if (process_ev(emu) != 0) {
err("error processing Nanos6 event");
return -1;
}
//check_affinity(emu);
return 0;
}
struct model_spec model_nanos6 = {
.name = "nanos6",
.model = '6',
.create = nanos6_create,
.connect = nanos6_connect,
.event = nanos6_event,
.probe = nanos6_probe,
};

80
src/emu/model_nanos6.h Normal file
View File

@ -0,0 +1,80 @@
/* Copyright (c) 2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef MODEL_NANOS6_H
#define MODEL_NANOS6_H
#include "emu_model.h"
extern struct model_spec model_nanos6;
#include "chan.h"
#include "mux.h"
#include "task.h"
enum nanos6_chan_type {
NANOS6_CHAN_TASKID = 0,
NANOS6_CHAN_TYPE,
NANOS6_CHAN_SUBSYSTEM,
NANOS6_CHAN_RANK,
NANOS6_CHAN_THREAD,
NANOS6_CHAN_MAX,
};
enum nanos6_ss_state {
ST_NANOS6_TASK_BODY = 1,
ST_NANOS6_TASK_CREATING,
ST_NANOS6_TASK_SUBMIT,
ST_NANOS6_TASK_SPAWNING,
ST_NANOS6_TASK_FOR,
ST_NANOS6_SCHED_ADDING,
ST_NANOS6_SCHED_PROCESSING,
ST_NANOS6_SCHED_SERVING,
ST_NANOS6_DEP_REG,
ST_NANOS6_DEP_UNREG,
ST_NANOS6_BLK_TASKWAIT,
ST_NANOS6_BLK_WAITFOR,
ST_NANOS6_BLK_BLOCKING,
ST_NANOS6_BLK_UNBLOCKING,
ST_NANOS6_ALLOCATING,
ST_NANOS6_FREEING,
ST_NANOS6_HANDLING_TASK,
ST_NANOS6_WORKER_LOOP,
ST_NANOS6_SWITCH_TO,
ST_NANOS6_MIGRATE,
ST_NANOS6_SUSPEND,
ST_NANOS6_RESUME,
/* Value 51 is broken in old Paraver */
EV_NANOS6_SCHED_RECV = 60,
EV_NANOS6_SCHED_SEND,
EV_NANOS6_SCHED_SELF,
EV_NANOS6_CPU_IDLE,
EV_NANOS6_CPU_ACTIVE,
EV_NANOS6_SIGNAL,
};
enum nanos6_thread_type {
ST_NANOS6_TH_LEADER = 1,
ST_NANOS6_TH_MAIN = 2,
ST_NANOS6_TH_WORKER = 3,
ST_NANOS6_TH_EXTERNAL = 4,
};
struct nanos6_thread {
struct chan chans[NANOS6_CHAN_MAX];
struct chan fchans[NANOS6_CHAN_MAX];
struct chan *ochans[NANOS6_CHAN_MAX];
struct mux muxers[NANOS6_CHAN_MAX];
struct task_stack task_stack;
};
struct nanos6_cpu {
struct chan chans[NANOS6_CHAN_MAX];
};
struct nanos6_proc {
struct task_info task_info;
};
#endif /* MODEL_NANOS6_H */

View File

@ -413,10 +413,8 @@ process_ev(struct emu *emu)
} }
static int static int
ust_probe(void *p) ust_probe(struct emu *emu)
{ {
struct emu *emu = emu_get(p);
if (emu->system.nthreads == 0) if (emu->system.nthreads == 0)
return -1; return -1;
@ -424,9 +422,8 @@ ust_probe(void *p)
} }
static int static int
ust_event(void *ptr) ust_event(struct emu *emu)
{ {
struct emu *emu = emu_get(ptr);
if (emu->ev->m != model_ust.model) { if (emu->ev->m != model_ust.model) {
err("unexpected event model %c\n", emu->ev->m); err("unexpected event model %c\n", emu->ev->m);
return -1; return -1;

View File

@ -64,8 +64,10 @@ cb_select(struct chan *sel_chan, void *ptr)
return -1; return -1;
} }
dbg("mux selects input key=%s chan=%s\n", if (input) {
value_str(sel_value, buf), input->chan->name); dbg("mux selects input key=%s chan=%s\n",
value_str(sel_value, buf), input->chan->name);
}
/* Set to null by default */ /* Set to null by default */
struct value out_value = value_null(); struct value out_value = value_null();
@ -227,5 +229,7 @@ mux_add_input(struct mux *mux, struct value key, struct chan *chan)
return -1; return -1;
} }
mux->ninputs++;
return 0; return 0;
} }

View File

@ -7,7 +7,10 @@
/* No loom dependency here */ /* No loom dependency here */
#include "thread.h" #include "thread.h"
#include "parson.h" #include "parson.h"
#include "uthash.h"
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
#include <linux/limits.h>
struct proc { struct proc {
int64_t gindex; int64_t gindex;

View File

@ -1,6 +1,8 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) /* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */ * SPDX-License-Identifier: GPL-3.0-or-later */
#define ENABLE_DEBUG
#include "prv.h" #include "prv.h"
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
@ -32,7 +34,7 @@ prv_open(struct prv *prv, long nrows, const char *path)
FILE *f = fopen(path, "w"); FILE *f = fopen(path, "w");
if (f == NULL) { if (f == NULL) {
die("prv_open: cannot open file '%s' for writting: %s\n", die("cannot open file '%s' for writting: %s\n",
path, strerror(errno)); path, strerror(errno));
return -1; return -1;
} }
@ -75,34 +77,51 @@ emit(struct prv *prv, struct prv_chan *rchan)
{ {
struct value value; struct value value;
struct chan *chan = rchan->chan; struct chan *chan = rchan->chan;
char buf[128];
if (chan_read(chan, &value) != 0) { if (chan_read(chan, &value) != 0) {
err("prv_emit: chan_read %s failed\n", chan->name); err("chan_read %s failed\n", chan->name);
return -1; return -1;
} }
/* Ensure we don't emit the same value twice */ /* Ensure we don't emit the same value twice */
if (rchan->last_value_set) { if (rchan->last_value_set) {
/* TODO: skip optionally */
if (value_is_equal(&value, &rchan->last_value)) { if (value_is_equal(&value, &rchan->last_value)) {
char buf[128]; char buf[128];
err("prv_emit: cannot emit value %s twice for channel %s\n", err("skipping duplicated value %s for channel %s\n",
value_str(value, buf), chan->name); value_str(value, buf), chan->name);
return -1; return 0;
} }
} }
if (value.type != VALUE_INT64) { long val = 0;
char buf[128]; switch (value.type) {
err("prv_emit: chan_read %s only int64 supported: %s\n", case VALUE_INT64:
chan->name, value_str(value, buf)); val = value.i;
return -1; //if (val == 0) {
// err("forbidden value 0 in %s: %s\n",
// chan->name,
// value_str(value, buf));
// return -1;
//}
break;
case VALUE_NULL:
val = 0;
break;
default:
err("chan_read %s only int64 and null supported: %s\n",
chan->name, value_str(value, buf));
return -1;
} }
if (write_line(prv, rchan->row_base1, rchan->type, value.i) != 0) { if (write_line(prv, rchan->row_base1, rchan->type, val) != 0) {
err("prv_emit: write_line failed for channel %s\n", err("write_line failed for channel %s\n",
chan->name); chan->name);
return -1; return -1;
} }
dbg("written %s for chan %s", value_str(value, buf), chan->name);
rchan->last_value = value; rchan->last_value = value;
rchan->last_value_set = 1; rchan->last_value_set = 1;
@ -122,16 +141,16 @@ cb_prv(struct chan *chan, void *ptr)
int int
prv_register(struct prv *prv, long row, long type, struct bay *bay, struct chan *chan) prv_register(struct prv *prv, long row, long type, struct bay *bay, struct chan *chan)
{ {
/* FIXME: use the type instead of channel name as key */
struct prv_chan *rchan = find_prv_chan(prv, chan->name); struct prv_chan *rchan = find_prv_chan(prv, chan->name);
if (rchan != NULL) { if (rchan != NULL) {
err("prv_register: channel %s already registered\n", err("channel %s already registered", chan->name);
chan->name);
return -1; return -1;
} }
rchan = calloc(1, sizeof(struct prv_chan)); rchan = calloc(1, sizeof(struct prv_chan));
if (rchan == NULL) { if (rchan == NULL) {
err("prv_register: calloc failed\n"); err("calloc failed:");
return -1; return -1;
} }
@ -144,7 +163,7 @@ prv_register(struct prv *prv, long row, long type, struct bay *bay, struct chan
/* Add emit callback */ /* Add emit callback */
if (bay_add_cb(bay, BAY_CB_EMIT, chan, cb_prv, rchan) != 0) { if (bay_add_cb(bay, BAY_CB_EMIT, chan, cb_prv, rchan) != 0) {
err("prv_register: bay_add_cb failed\n"); err("bay_add_cb failed");
return -1; return -1;
} }
@ -158,7 +177,7 @@ int
prv_advance(struct prv *prv, int64_t time) prv_advance(struct prv *prv, int64_t time)
{ {
if (time < prv->time) { if (time < prv->time) {
err("prv_advance: cannot move to previous time\n"); err("cannot move to previous time");
return -1; return -1;
} }

42
src/emu/pvt.c Normal file
View File

@ -0,0 +1,42 @@
#include "pvt.h"
int
pvt_open(struct pvt *pvt, long nrows, const char *dir, const char *name)
{
memset(pvt, 0, sizeof(struct pvt));
if (snprintf(pvt->dir, PATH_MAX, "%s", dir) >= PATH_MAX) {
err("snprintf failed: name too long");
return -1;
}
if (snprintf(pvt->name, PATH_MAX, "%s", name) >= PATH_MAX) {
err("snprintf failed: name too long");
return -1;
}
char prvpath[PATH_MAX];
if (snprintf(prvpath, PATH_MAX, "%s/%s.prv", dir, name) >= PATH_MAX) {
err("snprintf failed: path too long");
return -1;
}
if (prv_open(&pvt->prv, nrows, prvpath) != 0) {
err("prv_open failed");
return -1;
}
return 0;
}
struct prv *
pvt_get_prv(struct pvt *pvt)
{
return &pvt->prv;
}
int
pvt_advance(struct pvt *pvt, int64_t time)
{
return prv_advance(&pvt->prv, time);
}

26
src/emu/pvt.h Normal file
View File

@ -0,0 +1,26 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef PVT_H
#define PVT_H
#include "prv.h"
#include "pcf.h"
#include "uthash.h"
#include <linux/limits.h>
struct pvt {
char dir[PATH_MAX];
char name[PATH_MAX]; /* Without .prv extension */
struct prv prv;
struct pcf_file pcf;
struct UT_hash_handle hh; /* For recorder */
};
int pvt_open(struct pvt *pvt, long nrows, const char *dir, const char *name);
struct prv *pvt_get_prv(struct pvt *pvt);
struct pcf *pvt_get_pcf(struct pvt *pvt);
int pvt_advance(struct pvt *pvt, int64_t time);
#endif /* PVT_H */

View File

View File

@ -1,30 +0,0 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef PVTRACE_H
#define PVTRACE_H
#include "prv.h"
#include "pcf.h"
#include "uthash.h"
#include <stdio.h>
#include <linux/limits.h>
struct pvtrace {
char name[PATH_MAX];
struct prv prv;
struct pcf_file pcf;
};
struct pvmanager {
struct pvtrace *traces;
};
int pvmanager_init(struct pvmanager *man);
struct pvt *pvman_new(struct pvmanager *man,
const char *path, long nrows);
struct prv *pvt_get_prv(struct pvtrace *trace);
struct pcf *pvt_get_pcf(struct pvtrace *trace);
#endif /* PRV_H */

66
src/emu/recorder.c Normal file
View File

@ -0,0 +1,66 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#define ENABLE_DEBUG
#include "recorder.h"
int
recorder_init(struct recorder *rec, const char *dir)
{
memset(rec, 0, sizeof(struct recorder));
if (snprintf(rec->dir, PATH_MAX, "%s", dir) >= PATH_MAX) {
err("snprintf failed: path too long");
return -1;
}
return 0;
}
struct pvt *
recorder_find_pvt(struct recorder *rec, const char *name)
{
struct pvt *pvt = NULL;
HASH_FIND_STR(rec->pvt, name, pvt);
return pvt;
}
struct pvt *
recorder_add_pvt(struct recorder *rec, const char *name, long nrows)
{
struct pvt *pvt = recorder_find_pvt(rec, name);
if (pvt != NULL) {
err("pvt %s already registered", name);
return NULL;
}
pvt = calloc(1, sizeof(struct pvt));
if (pvt == NULL) {
err("calloc failed:");
return NULL;
}
if (pvt_open(pvt, nrows, rec->dir, name) != 0) {
err("pvt_open failed");
return NULL;
}
HASH_ADD_STR(rec->pvt, name, pvt);
return pvt;
}
int
recorder_advance(struct recorder *rec, int64_t time)
{
for (struct pvt *pvt = rec->pvt; pvt; pvt = pvt->hh.next) {
if (pvt_advance(pvt, time) != 0) {
err("pvt_advance failed");
return -1;
}
}
return 0;
}

23
src/emu/recorder.h Normal file
View File

@ -0,0 +1,23 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef RECORDER_H
#define RECORDER_H
/* Records data into files (Paraver traces only for now) */
#include "pvt.h"
#include <linux/limits.h>
struct recorder {
char dir[PATH_MAX]; /* To place the traces */
struct pvt *pvt; /* Hash table by name */
};
int recorder_init(struct recorder *rec, const char *dir);
struct pvt *recorder_find_pvt(struct recorder *rec, const char *name);
struct pvt *recorder_add_pvt(struct recorder *rec, const char *name, long nrows);
int recorder_advance(struct recorder *rec, int64_t time);
#endif /* RECORDER_H */

View File

@ -28,7 +28,7 @@ create_thread(struct proc *proc, const char *relpath)
return NULL; return NULL;
} }
if (thread_init_begin(thread, relpath) != 0) { if (thread_init_begin(thread, proc, relpath) != 0) {
err("cannot init thread"); err("cannot init thread");
return NULL; return NULL;
} }
@ -532,17 +532,27 @@ system_get_lpt(struct emu_stream *stream)
} }
int int
system_connect(struct system *sys, struct bay *bay) system_connect(struct system *sys, struct bay *bay, struct recorder *rec)
{ {
/* Create Paraver traces */
if (recorder_add_pvt(rec, "cpu", sys->ncpus) == NULL) {
err("recorder_add_pvt failed");
return -1;
}
if (recorder_add_pvt(rec, "thread", sys->nthreads) == NULL) {
err("recorder_add_pvt failed");
return -1;
}
for (struct thread *th = sys->threads; th; th = th->gnext) { for (struct thread *th = sys->threads; th; th = th->gnext) {
if (thread_connect(th, bay) != 0) { if (thread_connect(th, bay, rec) != 0) {
err("thread_connect failed\n"); err("thread_connect failed\n");
return -1; return -1;
} }
} }
for (struct cpu *cpu = sys->cpus; cpu; cpu = cpu->next) { for (struct cpu *cpu = sys->cpus; cpu; cpu = cpu->next) {
if (cpu_connect(cpu, bay) != 0) { if (cpu_connect(cpu, bay, rec) != 0) {
err("cpu_connect failed\n"); err("cpu_connect failed\n");
return -1; return -1;
} }

View File

@ -12,6 +12,7 @@
#include "thread.h" #include "thread.h"
#include "cpu.h" #include "cpu.h"
#include "clkoff.h" #include "clkoff.h"
#include "recorder.h"
#include <stddef.h> #include <stddef.h>
/* Map from stream to lpt */ /* Map from stream to lpt */
@ -27,7 +28,7 @@ struct system {
size_t nlooms; size_t nlooms;
size_t nthreads; size_t nthreads;
size_t nprocs; size_t nprocs;
size_t ncpus; /* Physical */ size_t ncpus; /* Including virtual cpus */
struct loom *looms; struct loom *looms;
struct proc *procs; struct proc *procs;
@ -43,7 +44,7 @@ struct system {
}; };
int system_init(struct system *sys, struct emu_args *args, struct emu_trace *trace); int system_init(struct system *sys, struct emu_args *args, struct emu_trace *trace);
int system_connect(struct system *sys, struct bay *bay); int system_connect(struct system *sys, struct bay *bay, struct recorder *rec);
struct lpt *system_get_lpt(struct emu_stream *stream); struct lpt *system_get_lpt(struct emu_stream *stream);
//struct emu_cpu *system_find_cpu(struct emu_loom *loom, int cpuid); //struct emu_cpu *system_find_cpu(struct emu_loom *loom, int cpuid);
//int model_ctx_set(struct model_ctx *ctx, int model, void *data); //int model_ctx_set(struct model_ctx *ctx, int model, void *data);

View File

@ -1,15 +1,11 @@
/* Copyright (c) 2022 Barcelona Supercomputing Center (BSC) /* Copyright (c) 2022 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */ * SPDX-License-Identifier: GPL-3.0-or-later */
#include "task.h"
#include "uthash.h" #include "uthash.h"
#include "utlist.h" #include "utlist.h"
#include "chan.h"
#include "emu.h"
#include "task.h"
#include "ovni.h"
#include "prv.h"
struct task * struct task *
task_find(struct task *tasks, uint32_t task_id) task_find(struct task *tasks, uint32_t task_id)
{ {
@ -28,24 +24,28 @@ task_type_find(struct task_type *types, uint32_t type_id)
return type; return type;
} }
void int
task_create(struct ovni_emu *emu, struct task_info *info, task_create(struct task_info *info, uint32_t type_id, uint32_t task_id)
uint32_t type_id, uint32_t task_id)
{ {
/* Ensure the task id is new */ /* Ensure the task id is new */
if (task_find(info->tasks, task_id) != NULL) if (task_find(info->tasks, task_id) != NULL) {
edie(emu, "cannot create task: task_id %u already exists\n", err("task_id %u already exists", task_id);
task_id); return -1;
}
/* Ensure the type exists */ /* Ensure the type exists */
struct task_type *type = task_type_find(info->types, type_id); struct task_type *type = task_type_find(info->types, type_id);
if (type == NULL) if (type == NULL) {
edie(emu, "cannot create task: unknown type id %u\n", type_id); err("unknown type id %u", type_id);
return -1;
}
struct task *task = calloc(1, sizeof(struct task)); struct task *task = calloc(1, sizeof(struct task));
if (task == NULL) if (task == NULL) {
die("calloc failed\n"); err("calloc failed:");
return -1;
}
task->id = task_id; task->id = task_id;
task->type = type; task->type = type;
@ -55,114 +55,162 @@ task_create(struct ovni_emu *emu, struct task_info *info,
/* Add the new task to the hash table */ /* Add the new task to the hash table */
HASH_ADD_INT(info->tasks, id, task); HASH_ADD_INT(info->tasks, id, task);
dbg("new task created id=%d\n", task->id); dbg("new task created id=%d", task->id);
return 0;
} }
void int
task_execute(struct ovni_emu *emu, task_execute(struct task_stack *stack, struct task *task)
struct task_stack *stack, struct task *task)
{ {
if (task == NULL) if (task == NULL) {
edie(emu, "cannot execute: task is NULL\n"); err("task is NULL");
return -1;
}
if (task->state != TASK_ST_CREATED) if (task->state != TASK_ST_CREATED) {
edie(emu, "cannot execute task %u: state is not created\n", task->id); err("cannot execute task %u: state is not created", task->id);
return -1;
}
if (task->thread != NULL) if (task->thread != NULL) {
edie(emu, "task already has a thread assigned\n"); err("task already has a thread assigned");
return -1;
}
if (stack->thread->state != TH_ST_RUNNING) if (stack->thread->state != TH_ST_RUNNING) {
edie(emu, "thread state is not running\n"); err("thread state is not running");
return -1;
}
if (stack->top == task) if (stack->top == task) {
edie(emu, "thread already has assigned task %u\n", task->id); err("thread already has assigned task %u", task->id);
return -1;
}
if (stack->top && stack->top->state != TASK_ST_RUNNING) if (stack->top && stack->top->state != TASK_ST_RUNNING) {
edie(emu, "cannot execute a nested task from a non-running task\n"); err("cannot execute a nested task from a non-running task");
return -1;
}
task->state = TASK_ST_RUNNING; task->state = TASK_ST_RUNNING;
task->thread = stack->thread; task->thread = stack->thread;
DL_PREPEND(stack->tasks, task); DL_PREPEND(stack->tasks, task);
dbg("task id=%u runs now\n", task->id); dbg("task id=%u runs now", task->id);
return 0;
} }
void int
task_pause(struct ovni_emu *emu, task_pause(struct task_stack *stack, struct task *task)
struct task_stack *stack, struct task *task)
{ {
if (task == NULL) if (task == NULL) {
edie(emu, "cannot pause: task is NULL\n"); err("cannot pause: task is NULL");
return -1;
}
if (task->state != TASK_ST_RUNNING) if (task->state != TASK_ST_RUNNING) {
edie(emu, "cannot pause: task state is not running\n"); err("cannot pause: task state is not running");
return -1;
}
if (task->thread == NULL) if (task->thread == NULL) {
edie(emu, "cannot pause: task has no thread assigned\n"); err("cannot pause: task has no thread assigned");
return -1;
}
if (stack->thread->state != TH_ST_RUNNING) if (stack->thread->state != TH_ST_RUNNING) {
edie(emu, "cannot pause: thread state is not running\n"); err("cannot pause: thread state is not running");
return -1;
}
if (stack->top != task) if (stack->top != task) {
edie(emu, "thread has assigned a different task\n"); err("thread has assigned a different task");
return -1;
}
if (stack->thread != task->thread) if (stack->thread != task->thread) {
edie(emu, "task is assigned to a different thread\n"); err("task is assigned to a different thread");
return -1;
}
task->state = TASK_ST_PAUSED; task->state = TASK_ST_PAUSED;
dbg("task id=%d pauses\n", task->id); dbg("task id=%d pauses", task->id);
return 0;
} }
void int
task_resume(struct ovni_emu *emu, task_resume(struct task_stack *stack, struct task *task)
struct task_stack *stack, struct task *task)
{ {
if (task == NULL) if (task == NULL) {
edie(emu, "cannot resume: task is NULL\n"); err("cannot resume: task is NULL");
return -1;
}
if (task->state != TASK_ST_PAUSED) if (task->state != TASK_ST_PAUSED) {
edie(emu, "task state is not paused\n"); err("task state is not paused");
return -1;
}
if (task->thread == NULL) if (task->thread == NULL) {
edie(emu, "cannot resume: task has no thread assigned\n"); err("cannot resume: task has no thread assigned");
return -1;
}
if (stack->thread->state != TH_ST_RUNNING) if (stack->thread->state != TH_ST_RUNNING) {
edie(emu, "thread is not running\n"); err("thread is not running");
return -1;
}
if (stack->top != task) if (stack->top != task) {
edie(emu, "thread has assigned a different task\n"); err("thread has assigned a different task");
return -1;
}
if (stack->thread != task->thread) if (stack->thread != task->thread) {
edie(emu, "task is assigned to a different thread\n"); err("task is assigned to a different thread");
return -1;
}
task->state = TASK_ST_RUNNING; task->state = TASK_ST_RUNNING;
dbg("task id=%d resumes\n", task->id); dbg("task id=%d resumes", task->id);
return 0;
} }
void int
task_end(struct ovni_emu *emu, task_end(struct task_stack *stack, struct task *task)
struct task_stack *stack, struct task *task)
{ {
if (task == NULL) if (task == NULL) {
edie(emu, "cannot end: task is NULL\n"); err("cannot end: task is NULL");
return -1;
}
if (task->state != TASK_ST_RUNNING) if (task->state != TASK_ST_RUNNING) {
edie(emu, "task state is not running\n"); err("task state is not running");
return -1;
}
if (task->thread == NULL) if (task->thread == NULL) {
edie(emu, "cannot end: task has no thread assigned\n"); err("cannot end: task has no thread assigned");
return -1;
}
if (stack->thread->state != TH_ST_RUNNING) if (stack->thread->state != TH_ST_RUNNING) {
edie(emu, "cannot end task: thread is not running\n"); err("cannot end task: thread is not running");
return -1;
}
if (stack->top != task) if (stack->top != task) {
edie(emu, "thread has assigned a different task\n"); err("thread has assigned a different task");
return -1;
}
if (stack->thread != task->thread) if (stack->thread != task->thread) {
edie(emu, "task is assigned to a different thread\n"); err("task is assigned to a different thread");
return -1;
}
task->state = TASK_ST_DEAD; task->state = TASK_ST_DEAD;
@ -171,7 +219,8 @@ task_end(struct ovni_emu *emu,
DL_DELETE(stack->tasks, task); DL_DELETE(stack->tasks, task);
dbg("task id=%d ends\n", task->id); dbg("task id=%d ends", task->id);
return 0;
} }
static uint32_t static uint32_t
@ -193,56 +242,63 @@ get_task_type_gid(const char *label)
return gid; return gid;
} }
void int
task_type_create(struct task_info *info, uint32_t type_id, const char *label) task_type_create(struct task_info *info, uint32_t type_id, const char *label)
{ {
struct task_type *type; struct task_type *type;
/* Ensure the type id is new */ /* Ensure the type id is new */
HASH_FIND_INT(info->types, &type_id, type); HASH_FIND_INT(info->types, &type_id, type);
if (type != NULL) if (type != NULL) {
die("a task type with id %u already exists\n", type_id); err("a task type with id %u already exists", type_id);
return -1;
}
type = calloc(1, sizeof(*type)); type = calloc(1, sizeof(*type));
if (type == NULL) {
if (type == NULL) err("calloc failed:");
die("calloc failed"); return -1;
}
type->id = type_id; type->id = type_id;
if (type->id == 0) if (type->id == 0) {
die("invalid task type id %d\n", type->id); err("invalid task type id %d", type->id);
return -1;
}
type->gid = get_task_type_gid(label); type->gid = get_task_type_gid(label);
int n = snprintf(type->label, MAX_PCF_LABEL, "%s", label); int n = snprintf(type->label, MAX_PCF_LABEL, "%s", label);
if (n >= MAX_PCF_LABEL) if (n >= MAX_PCF_LABEL) {
die("task type label too long: %s\n", label); err("task type label too long: %s", label);
return -1;
}
/* Add the new task type to the hash table */ /* Add the new task type to the hash table */
HASH_ADD_INT(info->types, id, type); HASH_ADD_INT(info->types, id, type);
dbg("new task type created id=%d label=%s\n", type->id, dbg("new task type created id=%d label=%s", type->id, type->label);
type->label); return 0;
} }
void //void
task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types) //task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types)
{ //{
/* Emit types for all task types */ // /* Emit types for all task types */
for (struct task_type *tt = types; tt != NULL; tt = tt->hh.next) { // for (struct task_type *tt = types; tt != NULL; tt = tt->hh.next) {
struct pcf_value *pcfvalue = pcf_find_value(pcftype, tt->gid); // struct pcf_value *pcfvalue = pcf_find_value(pcftype, tt->gid);
if (pcfvalue != NULL) { // if (pcfvalue != NULL) {
/* Ensure the label is the same, so we know that // /* Ensure the label is the same, so we know that
* no collision occurred */ // * no collision occurred */
if (strcmp(pcfvalue->label, tt->label) != 0) // if (strcmp(pcfvalue->label, tt->label) != 0)
die("collision occurred in task type labels\n"); // die("collision occurred in task type labels");
else // else
continue; // continue;
} // }
//
pcf_add_value(pcftype, tt->gid, tt->label); // pcf_add_value(pcftype, tt->gid, tt->label);
} // }
} //}
struct task * struct task *
task_get_running(struct task_stack *stack) task_get_running(struct task_stack *stack)

View File

@ -1,23 +1,70 @@
/* Copyright (c) 2022 Barcelona Supercomputing Center (BSC) /* Copyright (c) 2022-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */ * SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef OVNI_EMU_TASK_H #ifndef TASK_H
#define OVNI_EMU_TASK_H #define TASK_H
#include "emu.h" #include <stdint.h>
#include "uthash.h"
#include "pcf.h"
#include "thread.h"
enum task_state {
TASK_ST_CREATED,
TASK_ST_RUNNING,
TASK_ST_PAUSED,
TASK_ST_DEAD,
};
struct task_type {
uint32_t id; /* Per-process task identifier */
uint32_t gid; /* Global identifier computed from the label */
char label[MAX_PCF_LABEL];
UT_hash_handle hh;
};
struct task {
uint32_t id;
struct task_type *type;
/* TODO: Use a pointer to task_stack instead of thread */
/* The thread that has began to execute the task. It cannot
* changed after being set, even if the task ends. */
struct thread *thread;
enum task_state state;
UT_hash_handle hh;
/* List handle for nested task support */
struct task *next;
struct task *prev;
};
struct task_info {
/* Both hash maps of all known tasks and types */
struct task_type *types;
struct task *tasks;
};
struct task_stack {
union {
struct task *top; /* Synctactic sugar */
struct task *tasks;
};
struct thread *thread;
};
struct task *task_find(struct task *tasks, uint32_t task_id); struct task *task_find(struct task *tasks, uint32_t task_id);
void task_create(struct ovni_emu *emu, struct task_info *info, uint32_t type_id, uint32_t task_id); int task_create(struct task_info *info, uint32_t type_id, uint32_t task_id);
void task_execute(struct ovni_emu *emu, struct task_stack *stack, struct task *task); int task_execute(struct task_stack *stack, struct task *task);
void task_pause(struct ovni_emu *emu, struct task_stack *stack, struct task *task); int task_pause(struct task_stack *stack, struct task *task);
void task_resume(struct ovni_emu *emu, struct task_stack *stack, struct task *task); int task_resume(struct task_stack *stack, struct task *task);
void task_end(struct ovni_emu *emu, struct task_stack *stack, struct task *task); int task_end(struct task_stack *stack, struct task *task);
struct task_type *task_type_find(struct task_type *types, uint32_t type_id); struct task_type *task_type_find(struct task_type *types, uint32_t type_id);
void task_type_create(struct task_info *info, uint32_t type_id, const char *label); int task_type_create(struct task_info *info, uint32_t type_id, const char *label);
void task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types); //void task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types);
struct task *task_get_running(struct task_stack *stack); struct task *task_get_running(struct task_stack *stack);
#endif /* OVNI_EMU_TASK_H */ #endif /* TASK_H */

View File

@ -18,6 +18,13 @@ static const int chan_stack[] = {
[TH_CHAN_FLUSH] = 1, [TH_CHAN_FLUSH] = 1,
}; };
static const int chan_type[] = {
[TH_CHAN_TID] = 2,
[TH_CHAN_STATE] = 4,
[TH_CHAN_CPU] = 6,
[TH_CHAN_FLUSH] = 7,
};
static int static int
get_tid(const char *id, int *tid) get_tid(const char *id, int *tid)
{ {
@ -60,12 +67,13 @@ thread_relpath_get_tid(const char *relpath, int *tid)
} }
int int
thread_init_begin(struct thread *thread, const char *relpath) thread_init_begin(struct thread *thread, struct proc *proc, const char *relpath)
{ {
memset(thread, 0, sizeof(struct thread)); memset(thread, 0, sizeof(struct thread));
thread->state = TH_ST_UNKNOWN; thread->state = TH_ST_UNKNOWN;
thread->gindex = -1; thread->gindex = -1;
thread->proc = proc;
if (snprintf(thread->id, PATH_MAX, "%s", relpath) >= PATH_MAX) { if (snprintf(thread->id, PATH_MAX, "%s", relpath) >= PATH_MAX) {
err("relpath too long"); err("relpath too long");
@ -111,18 +119,34 @@ thread_init_end(struct thread *th)
} }
int int
thread_connect(struct thread *th, struct bay *bay) thread_connect(struct thread *th, struct bay *bay, struct recorder *rec)
{ {
if (!th->is_init) { if (!th->is_init) {
err("thread is not initialized"); err("thread is not initialized");
return -1; return -1;
} }
/* Get thread prv */
struct pvt *pvt = recorder_find_pvt(rec, "thread");
if (pvt == NULL) {
err("cannot find thread pvt");
return -1;
}
struct prv *prv = pvt_get_prv(pvt);
for (int i = 0; i < TH_CHAN_MAX; i++) { for (int i = 0; i < TH_CHAN_MAX; i++) {
if (bay_register(bay, &th->chan[i]) != 0) { struct chan *c = &th->chan[i];
if (bay_register(bay, c) != 0) {
err("bay_register failed"); err("bay_register failed");
return -1; return -1;
} }
long type = chan_type[i];
long row = th->gindex;
if (prv_register(prv, row, type, bay, c)) {
err("prv_register failed");
return -1;
}
} }
return 0; return 0;
@ -171,6 +195,78 @@ thread_set_state(struct thread *th, enum thread_state state)
return 0; return 0;
} }
int
thread_select_active(struct mux *mux,
struct value value,
struct mux_input **input)
{
if (value.type == VALUE_NULL) {
*input = NULL;
return 0;
}
if (value.type != VALUE_INT64) {
err("expecting NULL or INT64 channel value");
return -1;
}
enum thread_state state = (enum thread_state) value.i;
if (mux->ninputs != 1) {
err("expecting NULL or INT64 channel value");
return -1;
}
switch (state) {
case TH_ST_RUNNING:
case TH_ST_COOLING:
case TH_ST_WARMING:
*input = mux->input;
break;
default:
*input = NULL;
break;
}
return 0;
}
int
thread_select_running(struct mux *mux,
struct value value,
struct mux_input **input)
{
if (value.type == VALUE_NULL) {
*input = NULL;
return 0;
}
if (value.type != VALUE_INT64) {
err("expecting NULL or INT64 channel value");
return -1;
}
enum thread_state state = (enum thread_state) value.i;
if (mux->ninputs != 1) {
err("mux doesn't have one input but %d", mux->ninputs);
return -1;
}
switch (state) {
case TH_ST_RUNNING:
*input = mux->input;
break;
default:
*input = NULL;
break;
}
return 0;
}
int int
thread_set_cpu(struct thread *th, struct cpu *cpu) thread_set_cpu(struct thread *th, struct cpu *cpu)
{ {

View File

@ -7,9 +7,13 @@
struct thread; /* Needed for cpu */ struct thread; /* Needed for cpu */
#include "cpu.h" #include "cpu.h"
#include "proc.h"
#include "chan.h" #include "chan.h"
#include "bay.h" #include "bay.h"
#include "uthash.h" #include "uthash.h"
#include "recorder.h"
#include "extend.h"
#include "mux.h"
#include <stddef.h> #include <stddef.h>
#include <linux/limits.h> #include <linux/limits.h>
@ -64,12 +68,13 @@ struct thread {
struct chan chan[TH_CHAN_MAX]; struct chan chan[TH_CHAN_MAX];
//struct model_ctx ctx; struct extend ext;
UT_hash_handle hh; /* threads in the process */ UT_hash_handle hh; /* threads in the process */
}; };
int thread_relpath_get_tid(const char *relpath, int *tid); int thread_relpath_get_tid(const char *relpath, int *tid);
int thread_init_begin(struct thread *thread, const char *relpath); int thread_init_begin(struct thread *thread, struct proc *proc, const char *relpath);
int thread_init_end(struct thread *thread); int thread_init_end(struct thread *thread);
int thread_set_state(struct thread *th, enum thread_state state); int thread_set_state(struct thread *th, enum thread_state state);
int thread_set_cpu(struct thread *th, struct cpu *cpu); int thread_set_cpu(struct thread *th, struct cpu *cpu);
@ -77,6 +82,9 @@ int thread_unset_cpu(struct thread *th);
int thread_migrate_cpu(struct thread *th, struct cpu *cpu); int thread_migrate_cpu(struct thread *th, struct cpu *cpu);
int thread_get_tid(struct thread *thread); int thread_get_tid(struct thread *thread);
void thread_set_gindex(struct thread *th, int64_t gindex); void thread_set_gindex(struct thread *th, int64_t gindex);
int thread_connect(struct thread *th, struct bay *bay); int thread_connect(struct thread *th, struct bay *bay, struct recorder *rec);
int thread_select_active(struct mux *mux, struct value value, struct mux_input **input);
int thread_select_running(struct mux *mux, struct value value, struct mux_input **input);
#endif /* THREAD_H */ #endif /* THREAD_H */

View File

@ -16,6 +16,9 @@ int main(void)
if (emu_init(&emu, argc, argv) != 0) if (emu_init(&emu, argc, argv) != 0)
die("emu_init failed\n"); die("emu_init failed\n");
if (emu_connect(&emu) != 0)
die("emu_connect failed\n");
int ret = 0; int ret = 0;
while ((ret = emu_step(&emu)) == 0) { while ((ret = emu_step(&emu)) == 0) {