Remove boilerplate from the models
This commit is contained in:
parent
819b9aefa7
commit
cd39230089
@ -18,6 +18,9 @@ add_library(emu STATIC
|
||||
emu_args.c
|
||||
emu_ev.c
|
||||
model.c
|
||||
model_cpu.c
|
||||
model_thread.c
|
||||
model_pvt.c
|
||||
models.c
|
||||
player.c
|
||||
stream.c
|
||||
@ -40,12 +43,8 @@ add_library(emu STATIC
|
||||
ovni/probe.c
|
||||
ovni/create.c
|
||||
ovni/event.c
|
||||
nanos6/probe.c
|
||||
nanos6/connect.c
|
||||
nanos6/create.c
|
||||
nanos6/setup.c
|
||||
nanos6/event.c
|
||||
nanos6/pvt.c
|
||||
nanos6/finish.c
|
||||
nosv/probe.c
|
||||
nosv/connect.c
|
||||
nosv/create.c
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "emu_hook.h"
|
||||
|
||||
struct model_spec {
|
||||
char *name;
|
||||
const char *name;
|
||||
int model;
|
||||
char *depends;
|
||||
emu_hook_t *probe;
|
||||
|
18
src/emu/model_chan.h
Normal file
18
src/emu/model_chan.h
Normal file
@ -0,0 +1,18 @@
|
||||
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
|
||||
#ifndef MODEL_CHAN_H
|
||||
#define MODEL_CHAN_H
|
||||
|
||||
#include "model_pvt.h"
|
||||
|
||||
struct model_chan_spec {
|
||||
int nch;
|
||||
const char *prefix;
|
||||
const char **ch_names;
|
||||
const int *ch_stack;
|
||||
const struct model_pvt_spec *pvt;
|
||||
const int *track;
|
||||
};
|
||||
|
||||
#endif /* MODEL_CHAN_H */
|
135
src/emu/model_cpu.c
Normal file
135
src/emu/model_cpu.c
Normal file
@ -0,0 +1,135 @@
|
||||
#include "model_cpu.h"
|
||||
|
||||
#include "model_thread.h"
|
||||
|
||||
static struct model_cpu *
|
||||
get_model_cpu(struct cpu *cpu, int id)
|
||||
{
|
||||
return EXT(cpu, id);
|
||||
}
|
||||
|
||||
static int
|
||||
init_chan(struct model_cpu *cpu, const struct model_chan_spec *spec, int64_t gindex)
|
||||
{
|
||||
cpu->track = calloc(spec->nch, sizeof(struct track));
|
||||
if (cpu->track == NULL) {
|
||||
err("calloc failed:");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < spec->nch; i++) {
|
||||
struct track *track = &cpu->track[i];
|
||||
|
||||
const char *name = cpu->spec->model->name;
|
||||
const char *ch_name = spec->ch_names[i];
|
||||
|
||||
if (track_init(track, cpu->bay, TRACK_TYPE_TH, "%s.cpu%ld.%s",
|
||||
name, gindex, ch_name) != 0) {
|
||||
err("track_init failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
init_cpu(struct cpu *syscpu, struct bay *bay, const struct model_cpu_spec *spec)
|
||||
{
|
||||
/* The first member must be a struct model_cpu */
|
||||
struct model_cpu *cpu = calloc(1, spec->size);
|
||||
if (cpu == NULL) {
|
||||
err("calloc failed:");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cpu->spec = spec;
|
||||
cpu->bay = bay;
|
||||
|
||||
if (init_chan(cpu, spec->chan, syscpu->gindex) != 0) {
|
||||
err("init_chan failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
extend_set(&syscpu->ext, spec->model->model, cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
model_cpu_create(struct emu *emu, const struct model_cpu_spec *spec)
|
||||
{
|
||||
struct system *sys = &emu->system;
|
||||
struct bay *bay = &emu->bay;
|
||||
|
||||
for (struct cpu *c = sys->cpus; c; c = c->next) {
|
||||
if (init_cpu(c, bay, spec) != 0) {
|
||||
err("init_cpu failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
connect_cpu(struct emu *emu, struct cpu *scpu, int id)
|
||||
{
|
||||
struct model_cpu *cpu = get_model_cpu(scpu, id);
|
||||
const struct model_chan_spec *chan_spec = cpu->spec->chan;
|
||||
|
||||
for (int i = 0; i < chan_spec->nch; i++) {
|
||||
struct track *track = &cpu->track[i];
|
||||
|
||||
/* Choose select CPU channel based on tracking mode (only
|
||||
* TRACK_TH_RUN allowed, as active may cause collisions) */
|
||||
int mode = chan_spec->track[i];
|
||||
struct chan *sel = cpu_get_th_chan(scpu, mode);
|
||||
if (track_set_select(track, mode, sel, NULL) != 0) {
|
||||
err("track_select failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add each thread as input */
|
||||
for (struct thread *t = emu->system.threads; t; t = t->gnext) {
|
||||
struct model_thread *th = EXT(t, id);
|
||||
|
||||
/* Choose input channel from the thread output channels
|
||||
* based on CPU tracking mode */
|
||||
struct value key = value_int64(t->gindex);
|
||||
struct chan *inp = track_get_output(&th->track[i], mode);
|
||||
|
||||
if (track_add_input(track, mode, key, inp) != 0) {
|
||||
err("track_add_input failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the PRV output */
|
||||
track_set_default(track, mode);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
model_cpu_connect(struct emu *emu, const struct model_cpu_spec *spec)
|
||||
{
|
||||
struct system *sys = &emu->system;
|
||||
int id = spec->model->model;
|
||||
|
||||
/* Connect track channels */
|
||||
for (struct cpu *c = sys->cpus; c; c = c->next) {
|
||||
if (connect_cpu(emu, c, id) != 0) {
|
||||
err("connect_cpu failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Connect channels to Paraver trace */
|
||||
if (model_pvt_connect_cpu(emu, spec) != 0) {
|
||||
err("model_pvt_connect_cpu failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
30
src/emu/model_cpu.h
Normal file
30
src/emu/model_cpu.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
|
||||
#ifndef MODEL_CPU_H
|
||||
#define MODEL_CPU_H
|
||||
|
||||
struct model_cpu_spec;
|
||||
|
||||
#include "emu.h"
|
||||
#include "bay.h"
|
||||
#include "track.h"
|
||||
#include "model.h"
|
||||
#include "model_chan.h"
|
||||
|
||||
struct model_cpu_spec {
|
||||
size_t size;
|
||||
const struct model_chan_spec *chan;
|
||||
const struct model_spec *model;
|
||||
};
|
||||
|
||||
struct model_cpu {
|
||||
const struct model_cpu_spec *spec;
|
||||
struct bay *bay;
|
||||
struct track *track;
|
||||
};
|
||||
|
||||
int model_cpu_create(struct emu *emu, const struct model_cpu_spec *spec);
|
||||
int model_cpu_connect(struct emu *emu, const struct model_cpu_spec *spec);
|
||||
|
||||
#endif /* MODEL_CPU_H */
|
171
src/emu/model_pvt.c
Normal file
171
src/emu/model_pvt.c
Normal file
@ -0,0 +1,171 @@
|
||||
#include "model_pvt.h"
|
||||
|
||||
static const char *pcf_suffix[TRACK_TH_MAX] = {
|
||||
[TRACK_TH_ANY] = "",
|
||||
[TRACK_TH_RUN] = "of the RUNNING thread",
|
||||
[TRACK_TH_ACT] = "of the ACTIVE thread",
|
||||
};
|
||||
|
||||
static int
|
||||
create_values(const struct model_pvt_spec *pvt,
|
||||
struct pcf_type *t, int i)
|
||||
{
|
||||
const struct pcf_value_label(*q)[] = pvt->label[i];
|
||||
|
||||
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(const struct model_pvt_spec *pvt,
|
||||
struct pcf *pcf, int i, int track_mode)
|
||||
{
|
||||
long type = pvt->type[i];
|
||||
|
||||
if (type == -1)
|
||||
return 0;
|
||||
|
||||
/* Compute the label by joining the two parts */
|
||||
const char *prefix = pvt->prefix[i];
|
||||
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);
|
||||
|
||||
if (create_values(pvt, pcftype, i) != 0) {
|
||||
err("create_values failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
init_pcf(const struct model_chan_spec *chan, struct pcf *pcf)
|
||||
{
|
||||
const struct model_pvt_spec *pvt = chan->pvt;
|
||||
|
||||
/* Create default types and values */
|
||||
for (int i = 0; i < chan->nch; i++) {
|
||||
int track_mode = chan->track[i];
|
||||
if (create_type(pvt, pcf, i, track_mode) != 0) {
|
||||
err("create_type failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
connect_cpu_prv(struct emu *emu, struct cpu *scpu, struct prv *prv, int id)
|
||||
{
|
||||
struct model_cpu *cpu = EXT(scpu, id);
|
||||
const struct model_chan_spec *spec = cpu->spec->chan;
|
||||
for (int i = 0; i < spec->nch; i++) {
|
||||
struct chan *out = track_get_default(&cpu->track[i]);
|
||||
long type = spec->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;
|
||||
}
|
||||
|
||||
int
|
||||
model_pvt_connect_cpu(struct emu *emu, const struct model_cpu_spec *spec)
|
||||
{
|
||||
struct system *sys = &emu->system;
|
||||
int id = spec->model->model;
|
||||
|
||||
/* 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, id) != 0) {
|
||||
err("connect_cpu_prv failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Init CPU PCF */
|
||||
struct pcf *pcf = pvt_get_pcf(pvt);
|
||||
if (init_pcf(spec->chan, pcf) != 0) {
|
||||
err("init_pcf failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
connect_thread_prv(struct emu *emu, struct thread *sth, struct prv *prv, int id)
|
||||
{
|
||||
struct model_thread *th = EXT(sth, id);
|
||||
const struct model_chan_spec *spec = th->spec->chan;
|
||||
for (int i = 0; i < spec->nch; i++) {
|
||||
struct chan *out = track_get_default(&th->track[i]);
|
||||
long type = spec->pvt->type[i];
|
||||
long row = sth->gindex;
|
||||
if (prv_register(prv, row, type, &emu->bay, out, PRV_DUP)) {
|
||||
err("prv_register failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
model_pvt_connect_thread(struct emu *emu, const struct model_thread_spec *spec)
|
||||
{
|
||||
struct system *sys = &emu->system;
|
||||
int id = spec->model->model;
|
||||
|
||||
/* Get cpu PRV */
|
||||
struct pvt *pvt = recorder_find_pvt(&emu->recorder, "thread");
|
||||
if (pvt == NULL) {
|
||||
err("cannot find cpu 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, id) != 0) {
|
||||
err("connect_thread_prv failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Init thread PCF */
|
||||
struct pcf *pcf = pvt_get_pcf(pvt);
|
||||
if (init_pcf(spec->chan, pcf) != 0) {
|
||||
err("init_pcf failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
23
src/emu/model_pvt.h
Normal file
23
src/emu/model_pvt.h
Normal file
@ -0,0 +1,23 @@
|
||||
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
|
||||
#ifndef MODEL_PRV_H
|
||||
#define MODEL_PRV_H
|
||||
|
||||
#include "emu.h"
|
||||
#include "pv/pcf.h"
|
||||
|
||||
struct model_pvt_spec {
|
||||
const int *type;
|
||||
const char **prefix;
|
||||
const char **suffix;
|
||||
const struct pcf_value_label (**label)[];
|
||||
};
|
||||
|
||||
#include "model_cpu.h"
|
||||
#include "model_thread.h"
|
||||
|
||||
int model_pvt_connect_cpu(struct emu *emu, const struct model_cpu_spec *spec);
|
||||
int model_pvt_connect_thread(struct emu *emu, const struct model_thread_spec *spec);
|
||||
|
||||
#endif /* MODEL_PRV_H */
|
112
src/emu/model_thread.c
Normal file
112
src/emu/model_thread.c
Normal file
@ -0,0 +1,112 @@
|
||||
#include "model_thread.h"
|
||||
|
||||
#include "model_pvt.h"
|
||||
|
||||
static int
|
||||
init_chan(struct model_thread *th, const struct model_chan_spec *spec, int64_t gindex)
|
||||
{
|
||||
const char *fmt = "%s.thread%ld.%s";
|
||||
const char *prefix = spec->prefix;
|
||||
|
||||
th->ch = calloc(spec->nch, sizeof(struct chan));
|
||||
if (th->ch == NULL) {
|
||||
err("calloc failed:");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < spec->nch; i++) {
|
||||
struct chan *c = &th->ch[i];
|
||||
int type = spec->ch_stack[i];
|
||||
const char *ch_name = spec->ch_names[i];
|
||||
chan_init(c, type, fmt, prefix, gindex, ch_name);
|
||||
|
||||
if (bay_register(th->bay, c) != 0) {
|
||||
err("bay_register failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
th->track = calloc(spec->nch, sizeof(struct track));
|
||||
if (th->track == NULL) {
|
||||
err("calloc failed:");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < spec->nch; i++) {
|
||||
struct track *track = &th->track[i];
|
||||
|
||||
const char *ch_name = spec->ch_names[i];
|
||||
|
||||
if (track_init(track, th->bay, TRACK_TYPE_TH, fmt,
|
||||
prefix, gindex, ch_name) != 0) {
|
||||
err("track_init failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
init_thread(struct thread *systh, struct bay *bay, const struct model_thread_spec *spec)
|
||||
{
|
||||
struct model_thread *th = calloc(1, spec->size);
|
||||
if (th == NULL) {
|
||||
err("calloc failed:");
|
||||
return -1;
|
||||
}
|
||||
|
||||
th->spec = spec;
|
||||
th->bay = bay;
|
||||
|
||||
if (init_chan(th, spec->chan, systh->gindex) != 0) {
|
||||
err("init_chan failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
extend_set(&systh->ext, spec->model->model, th);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
model_thread_create(struct emu *emu, const struct model_thread_spec *spec)
|
||||
{
|
||||
struct system *sys = &emu->system;
|
||||
struct bay *bay = &emu->bay;
|
||||
|
||||
for (struct thread *t = sys->threads; t; t = t->gnext) {
|
||||
if (init_thread(t, bay, spec) != 0) {
|
||||
err("init_thread failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
model_thread_connect(struct emu *emu, const struct model_thread_spec *spec)
|
||||
{
|
||||
int id = spec->model->model;
|
||||
struct system *sys = &emu->system;
|
||||
|
||||
for (struct thread *t = sys->threads; t; t = t->gnext) {
|
||||
struct model_thread *th = EXT(t, id);
|
||||
struct chan *sel = &t->chan[TH_CHAN_STATE];
|
||||
const int *modes = th->spec->chan->track;
|
||||
int nch = th->spec->chan->nch;
|
||||
if (track_connect_thread(th->track, th->ch, modes, sel, nch) != 0) {
|
||||
err("track_thread failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Connect channels to Paraver trace */
|
||||
if (model_pvt_connect_thread(emu, spec) != 0) {
|
||||
err("model_pvt_connect_thread failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
31
src/emu/model_thread.h
Normal file
31
src/emu/model_thread.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
|
||||
#ifndef MODEL_THREAD_H
|
||||
#define MODEL_THREAD_H
|
||||
|
||||
struct model_thread_spec;
|
||||
|
||||
#include "emu.h"
|
||||
#include "bay.h"
|
||||
#include "track.h"
|
||||
#include "model.h"
|
||||
#include "model_chan.h"
|
||||
|
||||
struct model_thread_spec {
|
||||
size_t size;
|
||||
const struct model_chan_spec *chan;
|
||||
const struct model_spec *model;
|
||||
};
|
||||
|
||||
struct model_thread {
|
||||
const struct model_thread_spec *spec;
|
||||
struct bay *bay;
|
||||
struct chan *ch;
|
||||
struct track *track;
|
||||
};
|
||||
|
||||
int model_thread_create(struct emu *emu, const struct model_thread_spec *spec);
|
||||
int model_thread_connect(struct emu *emu, const struct model_thread_spec *spec);
|
||||
|
||||
#endif /* MODEL_THREAD_H */
|
@ -1,95 +0,0 @@
|
||||
#include "nanos6_priv.h"
|
||||
|
||||
static const int th_track[CH_MAX] = {
|
||||
[CH_TASKID] = TRACK_TH_RUN,
|
||||
[CH_TYPE] = TRACK_TH_RUN,
|
||||
[CH_SUBSYSTEM] = TRACK_TH_ACT,
|
||||
[CH_RANK] = TRACK_TH_RUN,
|
||||
[CH_THREAD] = TRACK_TH_ANY,
|
||||
};
|
||||
|
||||
static const int cpu_track[CH_MAX] = {
|
||||
[CH_TASKID] = TRACK_TH_RUN,
|
||||
[CH_TYPE] = TRACK_TH_RUN,
|
||||
[CH_SUBSYSTEM] = TRACK_TH_RUN,
|
||||
[CH_RANK] = TRACK_TH_RUN,
|
||||
[CH_THREAD] = TRACK_TH_RUN,
|
||||
};
|
||||
|
||||
int
|
||||
nanos6_get_track(enum nanos6_chan c, enum nanos6_chan_type type)
|
||||
{
|
||||
if (type == CT_TH)
|
||||
return th_track[c];
|
||||
else
|
||||
return cpu_track[c];
|
||||
}
|
||||
|
||||
static int
|
||||
connect_cpu(struct emu *emu, struct cpu *scpu)
|
||||
{
|
||||
struct nanos6_cpu *cpu = EXT(scpu, '6');
|
||||
for (int i = 0; i < CH_MAX; i++) {
|
||||
struct track *track = &cpu->track[i];
|
||||
|
||||
/* Choose select CPU channel based on tracking mode (only
|
||||
* TRACK_TH_RUN allowed, as active may cause collisions) */
|
||||
int mode = nanos6_get_track(i, CT_CPU);
|
||||
struct chan *sel = cpu_get_th_chan(scpu, mode);
|
||||
if (track_set_select(track, mode, sel, NULL) != 0) {
|
||||
err("track_select failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add each thread as input */
|
||||
for (struct thread *t = emu->system.threads; t; t = t->gnext) {
|
||||
struct nanos6_thread *th = EXT(t, '6');
|
||||
|
||||
/* Choose input channel from the thread output channels
|
||||
* based on CPU tracking mode */
|
||||
struct value key = value_int64(t->gindex);
|
||||
struct chan *inp = track_get_output(&th->track[i], mode);
|
||||
|
||||
if (track_add_input(track, mode, key, inp) != 0) {
|
||||
err("track_add_input failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the PRV output */
|
||||
track_set_default(track, nanos6_get_track(i, CT_CPU));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nanos6_connect(struct emu *emu)
|
||||
{
|
||||
struct system *sys = &emu->system;
|
||||
|
||||
/* threads */
|
||||
for (struct thread *t = sys->threads; t; t = t->gnext) {
|
||||
struct nanos6_thread *th = EXT(t, '6');
|
||||
struct chan *sel = &t->chan[TH_CHAN_STATE];
|
||||
if (track_connect_thread(th->track, th->ch, th_track, sel, CH_MAX) != 0) {
|
||||
err("track_thread failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* cpus */
|
||||
for (struct cpu *c = sys->cpus; c; c = c->next) {
|
||||
if (connect_cpu(emu, c) != 0) {
|
||||
err("connect_cpu failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (nanos6_init_pvt(emu) != 0) {
|
||||
err("init_pvt failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
#include "nanos6_priv.h"
|
||||
|
||||
static const char *chan_name[CH_MAX] = {
|
||||
[CH_TASKID] = "taskid",
|
||||
[CH_TYPE] = "task_type",
|
||||
[CH_SUBSYSTEM] = "subsystem",
|
||||
[CH_RANK] = "rank",
|
||||
[CH_THREAD] = "thread_type",
|
||||
};
|
||||
|
||||
static const int chan_stack[CH_MAX] = {
|
||||
[CH_SUBSYSTEM] = 1,
|
||||
[CH_THREAD] = 1,
|
||||
};
|
||||
|
||||
static int
|
||||
init_chans(struct bay *bay, struct chan *chans, const char *fmt, int64_t gindex)
|
||||
{
|
||||
for (int i = 0; i < CH_MAX; i++) {
|
||||
struct chan *c = &chans[i];
|
||||
int type = chan_stack[i] ? CHAN_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_tracks(struct bay *bay, struct track *tracks, const char *fmt, int64_t gindex)
|
||||
{
|
||||
for (int i = 0; i < CH_MAX; i++) {
|
||||
struct track *track = &tracks[i];
|
||||
|
||||
if (track_init(track, bay, TRACK_TYPE_TH, fmt, gindex, chan_name[i]) != 0) {
|
||||
err("track_init failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
init_cpu(struct bay *bay, struct cpu *syscpu)
|
||||
{
|
||||
struct nanos6_cpu *cpu = calloc(1, sizeof(struct nanos6_cpu));
|
||||
if (cpu == NULL) {
|
||||
err("calloc failed:");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cpu->track = calloc(CH_MAX, sizeof(struct track));
|
||||
if (cpu->track == NULL) {
|
||||
err("calloc failed:");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *fmt = "nanos6.cpu%ld.%s";
|
||||
if (init_tracks(bay, cpu->track, fmt, syscpu->gindex) != 0) {
|
||||
err("init_tracks failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
extend_set(&syscpu->ext, '6', cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
init_thread(struct bay *bay, struct thread *systh)
|
||||
{
|
||||
struct nanos6_thread *th = calloc(1, sizeof(struct nanos6_thread));
|
||||
if (th == NULL) {
|
||||
err("calloc failed:");
|
||||
return -1;
|
||||
}
|
||||
|
||||
th->ch = calloc(CH_MAX, sizeof(struct chan));
|
||||
if (th->ch == NULL) {
|
||||
err("calloc failed:");
|
||||
return -1;
|
||||
}
|
||||
|
||||
th->track = calloc(CH_MAX, sizeof(struct track));
|
||||
if (th->track == NULL) {
|
||||
err("calloc failed:");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *fmt = "nanos6.thread%ld.%s";
|
||||
if (init_chans(bay, th->ch, fmt, systh->gindex) != 0) {
|
||||
err("init_chans failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (init_tracks(bay, th->track, fmt, systh->gindex) != 0) {
|
||||
err("init_tracks failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
th->task_stack.thread = systh;
|
||||
|
||||
extend_set(&systh->ext, '6', th);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
init_proc(struct proc *sysproc)
|
||||
{
|
||||
struct nanos6_proc *proc = calloc(1, sizeof(struct nanos6_proc));
|
||||
if (proc == NULL) {
|
||||
err("calloc failed:");
|
||||
return -1;
|
||||
}
|
||||
|
||||
extend_set(&sysproc->ext, '6', proc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nanos6_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;
|
||||
}
|
@ -95,7 +95,7 @@ simple(struct emu *emu)
|
||||
int st = entry[2];
|
||||
|
||||
struct nanos6_thread *th = EXT(emu->thread, '6');
|
||||
struct chan *ch = &th->ch[chind];
|
||||
struct chan *ch = &th->m.ch[chind];
|
||||
|
||||
if (action == PUSH) {
|
||||
return chan_push(ch, value_int64(st));
|
||||
@ -117,19 +117,19 @@ chan_task_stopped(struct emu *emu)
|
||||
struct nanos6_thread *th = EXT(emu->thread, '6');
|
||||
|
||||
struct value null = value_null();
|
||||
if (chan_set(&th->ch[CH_TASKID], null) != 0) {
|
||||
if (chan_set(&th->m.ch[CH_TASKID], null) != 0) {
|
||||
err("chan_set taskid failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (chan_set(&th->ch[CH_TYPE], null) != 0) {
|
||||
if (chan_set(&th->m.ch[CH_TYPE], null) != 0) {
|
||||
err("chan_set type failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct proc *proc = emu->proc;
|
||||
if (proc->rank >= 0) {
|
||||
if (chan_set(&th->ch[CH_RANK], null) != 0) {
|
||||
if (chan_set(&th->m.ch[CH_RANK], null) != 0) {
|
||||
err("chan_set rank failed");
|
||||
return -1;
|
||||
}
|
||||
@ -153,17 +153,17 @@ chan_task_running(struct emu *emu, struct task *task)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (chan_set(&th->ch[CH_TASKID], value_int64(task->id)) != 0) {
|
||||
if (chan_set(&th->m.ch[CH_TASKID], value_int64(task->id)) != 0) {
|
||||
err("chan_set taskid failed");
|
||||
return -1;
|
||||
}
|
||||
if (chan_set(&th->ch[CH_TYPE], value_int64(task->type->gid)) != 0) {
|
||||
if (chan_set(&th->m.ch[CH_TYPE], value_int64(task->type->gid)) != 0) {
|
||||
err("chan_set type failed");
|
||||
return -1;
|
||||
}
|
||||
if (proc->rank >= 0) {
|
||||
struct value vrank = value_int64(proc->rank + 1);
|
||||
if (chan_set(&th->ch[CH_RANK], vrank) != 0) {
|
||||
if (chan_set(&th->m.ch[CH_RANK], vrank) != 0) {
|
||||
err("chan_set rank failed");
|
||||
return -1;
|
||||
}
|
||||
@ -205,14 +205,14 @@ chan_task_switch(struct emu *emu,
|
||||
|
||||
/* No need to change the rank as we will switch to tasks from
|
||||
* same thread */
|
||||
if (chan_set(&th->ch[CH_TASKID], value_int64(next->id)) != 0) {
|
||||
if (chan_set(&th->m.ch[CH_TASKID], value_int64(next->id)) != 0) {
|
||||
err("chan_set taskid failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO: test when switching to another task with the same type. We
|
||||
* should emit the same type state value as previous task. */
|
||||
if (chan_set(&th->ch[CH_TYPE], value_int64(next->type->gid)) != 0) {
|
||||
if (chan_set(&th->m.ch[CH_TYPE], value_int64(next->type->gid)) != 0) {
|
||||
err("chan_set type failed");
|
||||
return -1;
|
||||
}
|
||||
@ -339,7 +339,7 @@ enforce_task_rules(struct emu *emu, char tr, struct task *next)
|
||||
|
||||
struct nanos6_thread *th = EXT(emu->thread, '6');
|
||||
struct value ss;
|
||||
if (chan_read(&th->ch[CH_SUBSYSTEM], &ss) != 0) {
|
||||
if (chan_read(&th->m.ch[CH_SUBSYSTEM], &ss) != 0) {
|
||||
err("chan_read failed");
|
||||
return -1;
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
#include "nanos6_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 nanos6_thread *th = EXT(t, '6');
|
||||
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 nanos6 subsystems, top=\"%s\"\n",
|
||||
t->tid, stacked, nanos6_ss_name(top.i));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nanos6_finish(struct emu *emu)
|
||||
{
|
||||
if (nanos6_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;
|
||||
}
|
@ -9,15 +9,12 @@
|
||||
#include "mux.h"
|
||||
#include "task.h"
|
||||
#include "track.h"
|
||||
#include "model_cpu.h"
|
||||
#include "model_thread.h"
|
||||
#include "model_pvt.h"
|
||||
|
||||
/* Private enums */
|
||||
|
||||
enum nanos6_chan_type {
|
||||
CT_TH = 0,
|
||||
CT_CPU,
|
||||
CT_MAX
|
||||
};
|
||||
|
||||
enum nanos6_chan {
|
||||
CH_TASKID = 0,
|
||||
CH_TYPE,
|
||||
@ -68,13 +65,12 @@ enum nanos6_thread_type {
|
||||
};
|
||||
|
||||
struct nanos6_thread {
|
||||
struct chan *ch;
|
||||
struct track *track;
|
||||
struct model_thread m;
|
||||
struct task_stack task_stack;
|
||||
};
|
||||
|
||||
struct nanos6_cpu {
|
||||
struct track *track;
|
||||
struct model_cpu m;
|
||||
};
|
||||
|
||||
struct nanos6_proc {
|
||||
@ -87,9 +83,4 @@ int nanos6_connect(struct emu *emu);
|
||||
int nanos6_event(struct emu *emu);
|
||||
int nanos6_finish(struct emu *emu);
|
||||
|
||||
int nanos6_init_pvt(struct emu *emu);
|
||||
int nanos6_finish_pvt(struct emu *emu);
|
||||
const char *nanos6_ss_name(int ss);
|
||||
int nanos6_get_track(enum nanos6_chan c, enum nanos6_chan_type type);
|
||||
|
||||
#endif /* NANOS6_PRIV_H */
|
||||
|
@ -1,20 +0,0 @@
|
||||
#include "nanos6_priv.h"
|
||||
|
||||
struct model_spec model_nanos6 = {
|
||||
.name = "nanos6",
|
||||
.model = '6',
|
||||
.create = nanos6_create,
|
||||
.connect = nanos6_connect,
|
||||
.event = nanos6_event,
|
||||
.probe = nanos6_probe,
|
||||
.finish = nanos6_finish,
|
||||
};
|
||||
|
||||
int
|
||||
nanos6_probe(struct emu *emu)
|
||||
{
|
||||
if (emu->system.nthreads == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,293 +0,0 @@
|
||||
#include "nanos6_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] = 35,
|
||||
[CH_TYPE] = 36,
|
||||
[CH_SUBSYSTEM] = 37,
|
||||
[CH_RANK] = 38,
|
||||
[CH_THREAD] = 39,
|
||||
};
|
||||
|
||||
static const char *pcf_prefix[CH_MAX] = {
|
||||
[CH_TASKID] = "Nanos6 task ID",
|
||||
[CH_TYPE] = "Nanos6 task type",
|
||||
[CH_SUBSYSTEM] = "Nanos6 subsystem",
|
||||
[CH_RANK] = "Nanos6 task MPI rank",
|
||||
[CH_THREAD] = "Nanos6 thread type",
|
||||
};
|
||||
|
||||
static const char *pcf_suffix[TRACK_TH_MAX] = {
|
||||
[TRACK_TH_ANY] = "",
|
||||
[TRACK_TH_RUN] = "of the RUNNING thread",
|
||||
[TRACK_TH_ACT] = "of the ACTIVE thread",
|
||||
};
|
||||
|
||||
static const struct pcf_value_label nanos6_ss_values[] = {
|
||||
{ ST_TASK_BODY, "Task: Running body" },
|
||||
{ ST_TASK_CREATING, "Task: Creating" },
|
||||
{ ST_TASK_SUBMIT, "Task: Submitting" },
|
||||
{ ST_TASK_SPAWNING, "Task: Spawning function" },
|
||||
{ ST_TASK_FOR, "Task: Running task for" },
|
||||
{ ST_SCHED_SERVING, "Scheduler: Serving tasks" },
|
||||
{ ST_SCHED_ADDING, "Scheduler: Adding ready tasks" },
|
||||
{ ST_SCHED_PROCESSING, "Scheduler: Processing ready tasks" },
|
||||
{ ST_DEP_REG, "Dependency: Registering" },
|
||||
{ ST_DEP_UNREG, "Dependency: Unregistering" },
|
||||
{ ST_BLK_TASKWAIT, "Blocking: Taskwait" },
|
||||
{ ST_BLK_BLOCKING, "Blocking: Blocking current task" },
|
||||
{ ST_BLK_UNBLOCKING, "Blocking: Unblocking remote task" },
|
||||
{ ST_BLK_WAITFOR, "Blocking: Wait for deadline" },
|
||||
{ ST_HANDLING_TASK, "Worker: Handling task" },
|
||||
{ ST_WORKER_LOOP, "Worker: Looking for work" },
|
||||
{ ST_SWITCH_TO, "Worker: Switching to another thread" },
|
||||
{ ST_MIGRATE, "Worker: Migrating CPU" },
|
||||
{ ST_SUSPEND, "Worker: Suspending thread" },
|
||||
{ ST_RESUME, "Worker: Resuming another thread" },
|
||||
{ ST_ALLOCATING, "Memory: Allocating" },
|
||||
{ ST_FREEING, "Memory: Freeing" },
|
||||
|
||||
{ EV_SCHED_SEND, "EV Scheduler: Send task" },
|
||||
{ EV_SCHED_RECV, "EV Scheduler: Recv task" },
|
||||
{ EV_SCHED_SELF, "EV Scheduler: Self-assign task" },
|
||||
{ EV_CPU_IDLE, "EV CPU: Becomes idle" },
|
||||
{ EV_CPU_ACTIVE, "EV CPU: Becomes active" },
|
||||
{ EV_SIGNAL, "EV Worker: Wakening another thread" },
|
||||
{ -1, NULL },
|
||||
};
|
||||
|
||||
static const struct pcf_value_label nanos6_thread_type[] = {
|
||||
{ ST_TH_EXTERNAL, "External" },
|
||||
{ ST_TH_WORKER, "Worker" },
|
||||
{ ST_TH_LEADER, "Leader" },
|
||||
{ ST_TH_MAIN, "Main" },
|
||||
{ -1, NULL },
|
||||
};
|
||||
|
||||
static const struct pcf_value_label (*pcf_chan_value_labels[CH_MAX])[] = {
|
||||
[CH_SUBSYSTEM] = &nanos6_ss_values,
|
||||
[CH_THREAD] = &nanos6_thread_type,
|
||||
};
|
||||
|
||||
/* ------------------------------ 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 nanos6_chan c, enum nanos6_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 = nanos6_get_track(c, ct);
|
||||
const char *suffix = pcf_suffix[track_mode];
|
||||
|
||||
char label[MAX_PCF_LABEL];
|
||||
int ret = snprintf(label, MAX_PCF_LABEL, "%s %s",
|
||||
prefix, suffix);
|
||||
|
||||
if (ret >= MAX_PCF_LABEL) {
|
||||
err("computed type label too long");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct pcf_type *pcftype = pcf_add_type(pcf, type, label);
|
||||
|
||||
return create_values(pcftype, c);
|
||||
}
|
||||
|
||||
static int
|
||||
init_pcf(struct pcf *pcf, enum nanos6_chan_type ct)
|
||||
{
|
||||
/* Create default types and values */
|
||||
for (enum nanos6_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 nanos6_thread *th = EXT(thread, '6');
|
||||
for (int i = 0; i < CH_MAX; i++) {
|
||||
struct chan *out = track_get_default(&th->track[i]);
|
||||
long type = pvt_type[i];
|
||||
long row = thread->gindex;
|
||||
if (prv_register(prv, row, type, &emu->bay, out, PRV_DUP)) {
|
||||
err("prv_register failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
connect_cpu_prv(struct emu *emu, struct cpu *scpu, struct prv *prv)
|
||||
{
|
||||
struct nanos6_cpu *cpu = EXT(scpu, '6');
|
||||
for (int i = 0; i < CH_MAX; i++) {
|
||||
struct chan *out = track_get_default(&cpu->track[i]);
|
||||
long type = pvt_type[i];
|
||||
long row = scpu->gindex;
|
||||
if (prv_register(prv, row, type, &emu->bay, out, PRV_DUP)) {
|
||||
err("prv_register failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
connect_threads(struct emu *emu)
|
||||
{
|
||||
struct system *sys = &emu->system;
|
||||
|
||||
/* Get thread PRV */
|
||||
struct pvt *pvt = recorder_find_pvt(&emu->recorder, "thread");
|
||||
if (pvt == NULL) {
|
||||
err("cannot find thread pvt");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Connect thread channels to PRV */
|
||||
struct prv *prv = pvt_get_prv(pvt);
|
||||
for (struct thread *t = sys->threads; t; t = t->gnext) {
|
||||
if (connect_thread_prv(emu, t, prv) != 0) {
|
||||
err("connect_thread_prv failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Init thread PCF */
|
||||
struct pcf *pcf = pvt_get_pcf(pvt);
|
||||
if (init_pcf(pcf, CT_TH) != 0) {
|
||||
err("init_pcf failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
connect_cpus(struct emu *emu)
|
||||
{
|
||||
struct system *sys = &emu->system;
|
||||
|
||||
/* Get cpu PRV */
|
||||
struct pvt *pvt = recorder_find_pvt(&emu->recorder, "cpu");
|
||||
if (pvt == NULL) {
|
||||
err("cannot find cpu pvt");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Connect CPU channels to PRV */
|
||||
struct prv *prv = pvt_get_prv(pvt);
|
||||
for (struct cpu *c = sys->cpus; c; c = c->next) {
|
||||
if (connect_cpu_prv(emu, c, prv) != 0) {
|
||||
err("connect_cpu_prv failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Init CPU PCF */
|
||||
struct pcf *pcf = pvt_get_pcf(pvt);
|
||||
if (init_pcf(pcf, CT_CPU) != 0) {
|
||||
err("init_pcf failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Connect all outputs to the paraver trace and setup PCF types */
|
||||
int
|
||||
nanos6_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
|
||||
nanos6_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 nanos6_proc *nanos6proc = EXT(p, '6');
|
||||
struct task_info *info = &nanos6proc->task_info;
|
||||
if (task_create_pcf_types(pcftype, info->types) != 0) {
|
||||
err("task_create_pcf_types failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
nanos6_ss_name(int ss)
|
||||
{
|
||||
static const char *unknown = "(unknown)";
|
||||
const char *name = unknown;
|
||||
const struct pcf_value_label *pv;
|
||||
for (pv = &nanos6_ss_values[0]; pv->label; pv++) {
|
||||
if (pv->value == ss) {
|
||||
name = pv->label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
307
src/emu/nanos6/setup.c
Normal file
307
src/emu/nanos6/setup.c
Normal file
@ -0,0 +1,307 @@
|
||||
#include "nanos6_priv.h"
|
||||
|
||||
static const char model_name[] = "nanos6";
|
||||
static const int model_id = '6';
|
||||
|
||||
struct model_spec model_nanos6 = {
|
||||
.name = model_name,
|
||||
.model = model_id,
|
||||
.create = nanos6_create,
|
||||
.connect = nanos6_connect,
|
||||
.event = nanos6_event,
|
||||
.probe = nanos6_probe,
|
||||
.finish = nanos6_finish,
|
||||
};
|
||||
|
||||
/* ----------------- channels ------------------ */
|
||||
|
||||
static const char *chan_name[CH_MAX] = {
|
||||
[CH_TASKID] = "taskid",
|
||||
[CH_TYPE] = "task_type",
|
||||
[CH_SUBSYSTEM] = "subsystem",
|
||||
[CH_RANK] = "rank",
|
||||
[CH_THREAD] = "thread_type",
|
||||
};
|
||||
|
||||
static const int chan_stack[CH_MAX] = {
|
||||
[CH_SUBSYSTEM] = 1,
|
||||
[CH_THREAD] = 1,
|
||||
};
|
||||
|
||||
/* ----------------- pvt ------------------ */
|
||||
|
||||
static const int pvt_type[] = {
|
||||
[CH_TASKID] = 35,
|
||||
[CH_TYPE] = 36,
|
||||
[CH_SUBSYSTEM] = 37,
|
||||
[CH_RANK] = 38,
|
||||
[CH_THREAD] = 39,
|
||||
};
|
||||
|
||||
static const char *pcf_prefix[CH_MAX] = {
|
||||
[CH_TASKID] = "Nanos6 task ID",
|
||||
[CH_TYPE] = "Nanos6 task type",
|
||||
[CH_SUBSYSTEM] = "Nanos6 subsystem",
|
||||
[CH_RANK] = "Nanos6 task MPI rank",
|
||||
[CH_THREAD] = "Nanos6 thread type",
|
||||
};
|
||||
|
||||
static const char *pcf_suffix[TRACK_TH_MAX] = {
|
||||
[TRACK_TH_ANY] = "",
|
||||
[TRACK_TH_RUN] = "of the RUNNING thread",
|
||||
[TRACK_TH_ACT] = "of the ACTIVE thread",
|
||||
};
|
||||
|
||||
static const struct pcf_value_label nanos6_ss_values[] = {
|
||||
{ ST_TASK_BODY, "Task: Running body" },
|
||||
{ ST_TASK_CREATING, "Task: Creating" },
|
||||
{ ST_TASK_SUBMIT, "Task: Submitting" },
|
||||
{ ST_TASK_SPAWNING, "Task: Spawning function" },
|
||||
{ ST_TASK_FOR, "Task: Running task for" },
|
||||
{ ST_SCHED_SERVING, "Scheduler: Serving tasks" },
|
||||
{ ST_SCHED_ADDING, "Scheduler: Adding ready tasks" },
|
||||
{ ST_SCHED_PROCESSING, "Scheduler: Processing ready tasks" },
|
||||
{ ST_DEP_REG, "Dependency: Registering" },
|
||||
{ ST_DEP_UNREG, "Dependency: Unregistering" },
|
||||
{ ST_BLK_TASKWAIT, "Blocking: Taskwait" },
|
||||
{ ST_BLK_BLOCKING, "Blocking: Blocking current task" },
|
||||
{ ST_BLK_UNBLOCKING, "Blocking: Unblocking remote task" },
|
||||
{ ST_BLK_WAITFOR, "Blocking: Wait for deadline" },
|
||||
{ ST_HANDLING_TASK, "Worker: Handling task" },
|
||||
{ ST_WORKER_LOOP, "Worker: Looking for work" },
|
||||
{ ST_SWITCH_TO, "Worker: Switching to another thread" },
|
||||
{ ST_MIGRATE, "Worker: Migrating CPU" },
|
||||
{ ST_SUSPEND, "Worker: Suspending thread" },
|
||||
{ ST_RESUME, "Worker: Resuming another thread" },
|
||||
{ ST_ALLOCATING, "Memory: Allocating" },
|
||||
{ ST_FREEING, "Memory: Freeing" },
|
||||
|
||||
{ EV_SCHED_SEND, "EV Scheduler: Send task" },
|
||||
{ EV_SCHED_RECV, "EV Scheduler: Recv task" },
|
||||
{ EV_SCHED_SELF, "EV Scheduler: Self-assign task" },
|
||||
{ EV_CPU_IDLE, "EV CPU: Becomes idle" },
|
||||
{ EV_CPU_ACTIVE, "EV CPU: Becomes active" },
|
||||
{ EV_SIGNAL, "EV Worker: Waking another thread" },
|
||||
{ -1, NULL },
|
||||
};
|
||||
|
||||
static const struct pcf_value_label nanos6_thread_type[] = {
|
||||
{ ST_TH_EXTERNAL, "External" },
|
||||
{ ST_TH_WORKER, "Worker" },
|
||||
{ ST_TH_LEADER, "Leader" },
|
||||
{ ST_TH_MAIN, "Main" },
|
||||
{ -1, NULL },
|
||||
};
|
||||
|
||||
static const struct pcf_value_label (*pcf_labels[CH_MAX])[] = {
|
||||
[CH_SUBSYSTEM] = &nanos6_ss_values,
|
||||
[CH_THREAD] = &nanos6_thread_type,
|
||||
};
|
||||
|
||||
static const struct model_pvt_spec pvt_spec = {
|
||||
.type = pvt_type,
|
||||
.prefix = pcf_prefix,
|
||||
.suffix = pcf_suffix,
|
||||
.label = pcf_labels,
|
||||
};
|
||||
|
||||
/* ----------------- tracking ------------------ */
|
||||
|
||||
static const int th_track[CH_MAX] = {
|
||||
[CH_TASKID] = TRACK_TH_RUN,
|
||||
[CH_TYPE] = TRACK_TH_RUN,
|
||||
[CH_SUBSYSTEM] = TRACK_TH_ACT,
|
||||
[CH_RANK] = TRACK_TH_RUN,
|
||||
[CH_THREAD] = TRACK_TH_ANY,
|
||||
};
|
||||
|
||||
static const int cpu_track[CH_MAX] = {
|
||||
[CH_TASKID] = TRACK_TH_RUN,
|
||||
[CH_TYPE] = TRACK_TH_RUN,
|
||||
[CH_SUBSYSTEM] = TRACK_TH_RUN,
|
||||
[CH_RANK] = TRACK_TH_RUN,
|
||||
[CH_THREAD] = TRACK_TH_RUN,
|
||||
};
|
||||
|
||||
/* ----------------- chan_spec ------------------ */
|
||||
|
||||
static const struct model_chan_spec th_chan = {
|
||||
.nch = CH_MAX,
|
||||
.prefix = model_name,
|
||||
.ch_names = chan_name,
|
||||
.ch_stack = chan_stack,
|
||||
.pvt = &pvt_spec,
|
||||
.track = th_track,
|
||||
};
|
||||
|
||||
static const struct model_chan_spec cpu_chan = {
|
||||
.nch = CH_MAX,
|
||||
.prefix = model_name,
|
||||
.ch_names = chan_name,
|
||||
.ch_stack = chan_stack,
|
||||
.pvt = &pvt_spec,
|
||||
.track = cpu_track,
|
||||
};
|
||||
|
||||
/* ----------------- models ------------------ */
|
||||
|
||||
static const struct model_cpu_spec cpu_spec = {
|
||||
.size = sizeof(struct nanos6_cpu),
|
||||
.chan = &cpu_chan,
|
||||
.model = &model_nanos6,
|
||||
};
|
||||
|
||||
static const struct model_thread_spec th_spec = {
|
||||
.size = sizeof(struct nanos6_thread),
|
||||
.chan = &th_chan,
|
||||
.model = &model_nanos6,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------- */
|
||||
|
||||
int
|
||||
nanos6_probe(struct emu *emu)
|
||||
{
|
||||
if (emu->system.nthreads == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
init_proc(struct proc *sysproc)
|
||||
{
|
||||
struct nanos6_proc *proc = calloc(1, sizeof(struct nanos6_proc));
|
||||
if (proc == NULL) {
|
||||
err("calloc failed:");
|
||||
return -1;
|
||||
}
|
||||
|
||||
extend_set(&sysproc->ext, model_id, proc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nanos6_create(struct emu *emu)
|
||||
{
|
||||
struct system *sys = &emu->system;
|
||||
|
||||
if (model_thread_create(emu, &th_spec) != 0) {
|
||||
err("model_thread_init failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (model_cpu_create(emu, &cpu_spec) != 0) {
|
||||
err("model_cpu_init failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Init task stack thread pointer */
|
||||
for (struct thread *t = sys->threads; t; t = t->gnext) {
|
||||
struct nanos6_thread *th = EXT(t, model_id);
|
||||
th->task_stack.thread = t;
|
||||
}
|
||||
|
||||
for (struct proc *p = sys->procs; p; p = p->gnext) {
|
||||
if (init_proc(p) != 0) {
|
||||
err("init_proc failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nanos6_connect(struct emu *emu)
|
||||
{
|
||||
if (model_thread_connect(emu, &th_spec) != 0) {
|
||||
err("model_thread_connect failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (model_cpu_connect(emu, &cpu_spec) != 0) {
|
||||
err("model_cpu_connect failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: Automatically check all stack channels at the end */
|
||||
static int
|
||||
end_lint(struct emu *emu)
|
||||
{
|
||||
struct system *sys = &emu->system;
|
||||
|
||||
/* Ensure we run out of subsystem states */
|
||||
for (struct thread *t = sys->threads; t; t = t->gnext) {
|
||||
struct nanos6_thread *th = EXT(t, model_id);
|
||||
struct chan *ch = &th->m.ch[CH_SUBSYSTEM];
|
||||
int stacked = ch->data.stack.n;
|
||||
if (stacked > 0) {
|
||||
struct value top;
|
||||
if (chan_read(ch, &top) != 0) {
|
||||
err("chan_read failed for subsystem");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err("thread %d ended with %d stacked nanos6 subsystems\n",
|
||||
t->tid, stacked);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
finish_pvt(struct emu *emu, const char *name)
|
||||
{
|
||||
struct system *sys = &emu->system;
|
||||
|
||||
/* Emit task types for all channel types and processes */
|
||||
struct pvt *pvt = recorder_find_pvt(&emu->recorder, name);
|
||||
if (pvt == NULL) {
|
||||
err("cannot find pvt with name '%s'", name);
|
||||
return -1;
|
||||
}
|
||||
struct pcf *pcf = pvt_get_pcf(pvt);
|
||||
long typeid = pvt_type[CH_TYPE];
|
||||
struct pcf_type *pcftype = pcf_find_type(pcf, typeid);
|
||||
|
||||
for (struct proc *p = sys->procs; p; p = p->gnext) {
|
||||
struct nanos6_proc *proc = EXT(p, model_id);
|
||||
struct task_info *info = &proc->task_info;
|
||||
if (task_create_pcf_types(pcftype, info->types) != 0) {
|
||||
err("task_create_pcf_types failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nanos6_finish(struct emu *emu)
|
||||
{
|
||||
/* Fill task types */
|
||||
if (finish_pvt(emu, "thread") != 0) {
|
||||
err("finish_pvt thread failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (finish_pvt(emu, "cpu") != 0) {
|
||||
err("finish_pvt cpu failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* When running in linter mode perform additional checks */
|
||||
if (emu->args.linter_mode && end_lint(emu) != 0) {
|
||||
err("end_lint failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -7,4 +7,4 @@ ovni_test(nested-tasks-bad.c SHOULD_FAIL
|
||||
ovni_test(task-types.c MP)
|
||||
ovni_test(blocking.c MP)
|
||||
ovni_test(ss-mismatch.c SHOULD_FAIL
|
||||
REGEX "thread [0-9]\\+ ended with 1 stacked nanos6 subsystems, top=\"Worker: Looking for work\"")
|
||||
REGEX "thread [0-9]\\+ ended with 1 stacked nanos6 subsystems")
|
||||
|
Loading…
Reference in New Issue
Block a user