Introduce channels
This commit is contained in:
parent
13e6eabf33
commit
fbfbb8fc0f
2
Makefile
2
Makefile
@ -24,7 +24,7 @@ dump: ovni.o dump.o parson.o
|
||||
|
||||
test_speed: test_speed.c ovni.o parson.o
|
||||
|
||||
emu: emu.o emu_ovni.o emu_nosv.o emu_nosv_ss.o ovni.o prv.o pcf.o parson.o
|
||||
emu: emu.o emu_ovni.o emu_nosv.o emu_nosv_ss.o ovni.o prv.o pcf.o parson.o chan.o
|
||||
|
||||
libovni.so: ovni.o parson.o
|
||||
$(LINK.c) -shared $^ -o $@
|
||||
|
176
chan.c
Normal file
176
chan.c
Normal file
@ -0,0 +1,176 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include "emu.h"
|
||||
#include "prv.h"
|
||||
|
||||
void
|
||||
chan_init(struct ovni_chan *chan, int row, int type, FILE *prv, int64_t *clock)
|
||||
{
|
||||
chan->n = 0;
|
||||
chan->type = type;
|
||||
chan->enabled = 0;
|
||||
chan->badst = ST_NULL;
|
||||
chan->ev = -1;
|
||||
chan->prv = prv;
|
||||
chan->clock = clock;
|
||||
chan->t = -1;
|
||||
chan->row = row;
|
||||
chan->dirty = 0;
|
||||
}
|
||||
|
||||
void
|
||||
chan_enable(struct ovni_chan *chan, int enabled)
|
||||
{
|
||||
chan->enabled = enabled;
|
||||
}
|
||||
|
||||
int
|
||||
chan_is_enabled(struct ovni_chan *chan)
|
||||
{
|
||||
return chan->enabled;
|
||||
}
|
||||
|
||||
void
|
||||
chan_set(struct ovni_chan *chan, int st)
|
||||
{
|
||||
dbg("chan_set st=%d", st);
|
||||
|
||||
assert(chan->enabled);
|
||||
assert(chan->dirty == 0);
|
||||
|
||||
if(chan->n == 0)
|
||||
chan->n = 1;
|
||||
|
||||
chan->stack[chan->n] = st;
|
||||
chan->t = *chan->clock;
|
||||
chan->dirty = 1;
|
||||
}
|
||||
|
||||
void
|
||||
chan_push(struct ovni_chan *chan, int st)
|
||||
{
|
||||
dbg("chan_push st=%d", st);
|
||||
|
||||
assert(chan->enabled);
|
||||
assert(chan->dirty == 0);
|
||||
|
||||
if(chan->n >= MAX_CHAN_STACK)
|
||||
{
|
||||
err("channel stack full\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
chan->stack[chan->n++] = st;
|
||||
chan->t = *chan->clock;
|
||||
chan->dirty = 1;
|
||||
}
|
||||
|
||||
int
|
||||
chan_pop(struct ovni_chan *chan, int expected_st)
|
||||
{
|
||||
int st;
|
||||
|
||||
dbg("chan_pop expexted_st=%d", expected_st);
|
||||
|
||||
assert(chan->enabled);
|
||||
assert(chan->dirty == 0);
|
||||
|
||||
if(chan->n <= 0)
|
||||
{
|
||||
err("channel empty\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
st = chan->stack[chan->n - 1];
|
||||
|
||||
if(expected_st >= 0 && st != expected_st)
|
||||
{
|
||||
err("unexpected channel state %d (expected %d)\n",
|
||||
st, expected_st);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
chan->n--;
|
||||
chan->t = *chan->clock;
|
||||
chan->dirty = 1;
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
void
|
||||
chan_ev(struct ovni_chan *chan, int ev)
|
||||
{
|
||||
assert(chan->enabled);
|
||||
assert(chan->dirty == 0);
|
||||
assert(ev >= 0);
|
||||
|
||||
chan->ev = ev;
|
||||
chan->t = *chan->clock;
|
||||
chan->dirty = 1;
|
||||
}
|
||||
|
||||
int
|
||||
chan_get_st(struct ovni_chan *chan)
|
||||
{
|
||||
if(chan->enabled == 0)
|
||||
return chan->badst;
|
||||
|
||||
assert(chan->n > 0);
|
||||
return chan->stack[chan->n-1];
|
||||
}
|
||||
|
||||
static void
|
||||
emit_ev(struct ovni_chan *chan)
|
||||
{
|
||||
int new, last;
|
||||
|
||||
assert(chan->enabled);
|
||||
assert(chan->ev != -1);
|
||||
|
||||
new = chan->ev;
|
||||
last = chan_get_st(chan);
|
||||
|
||||
prv_ev(chan->prv, chan->row, chan->t-1, chan->type, new);
|
||||
prv_ev(chan->prv, chan->row, chan->t, chan->type, last);
|
||||
|
||||
chan->ev = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
emit_st(struct ovni_chan *chan)
|
||||
{
|
||||
int st;
|
||||
|
||||
assert(chan->enabled);
|
||||
|
||||
st = chan_get_st(chan);
|
||||
|
||||
prv_ev(chan->prv, chan->row, chan->t, chan->type, st);
|
||||
}
|
||||
|
||||
/* Emits either the current state or punctual event in the PRV file */
|
||||
void
|
||||
chan_emit(struct ovni_chan *chan)
|
||||
{
|
||||
if(chan->dirty == 0)
|
||||
return;
|
||||
|
||||
/* Emit badst if disabled */
|
||||
if(chan->enabled == 0)
|
||||
{
|
||||
/* No punctual events allowed when disabled */
|
||||
assert(chan->ev == -1);
|
||||
|
||||
emit_st(chan);
|
||||
goto shower;
|
||||
}
|
||||
|
||||
/* Otherwise, emit punctual event if any or the state */
|
||||
if(chan->ev != -1)
|
||||
emit_ev(chan);
|
||||
else
|
||||
emit_st(chan);
|
||||
|
||||
shower:
|
||||
chan->dirty = 0;
|
||||
}
|
33
chan.h
Normal file
33
chan.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef OVNI_CHAN_H
|
||||
#define OVNI_CHAN_H
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
void
|
||||
chan_init(struct ovni_chan *chan, int row, int type, FILE *prv, int64_t *clock);
|
||||
|
||||
void
|
||||
chan_enable(struct ovni_chan *chan, int enabled);
|
||||
|
||||
int
|
||||
chan_is_enabled(struct ovni_chan *chan);
|
||||
|
||||
void
|
||||
chan_set(struct ovni_chan *chan, int st);
|
||||
|
||||
void
|
||||
chan_push(struct ovni_chan *chan, int st);
|
||||
|
||||
int
|
||||
chan_pop(struct ovni_chan *chan, int expected_st);
|
||||
|
||||
void
|
||||
chan_ev(struct ovni_chan *chan, int ev);
|
||||
|
||||
int
|
||||
chan_get_st(struct ovni_chan *chan);
|
||||
|
||||
void
|
||||
chan_emit(struct ovni_chan *chan);
|
||||
|
||||
#endif /* OVNI_CHAN_H */
|
55
emu.c
55
emu.c
@ -17,6 +17,7 @@
|
||||
#include "emu.h"
|
||||
#include "prv.h"
|
||||
#include "pcf.h"
|
||||
#include "chan.h"
|
||||
|
||||
/* Obtains the corrected clock of the given event */
|
||||
int64_t
|
||||
@ -75,6 +76,18 @@ find_thread(struct ovni_eproc *proc, pid_t tid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
emit_channels(struct ovni_emu *emu)
|
||||
{
|
||||
struct ovni_ethread *th;
|
||||
int i;
|
||||
|
||||
th = emu->cur_thread;
|
||||
|
||||
for(i=0; i<CHAN_MAX; i++)
|
||||
chan_emit(&th->chan[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
hook_pre(struct ovni_emu *emu)
|
||||
{
|
||||
@ -99,6 +112,8 @@ hook_emit(struct ovni_emu *emu)
|
||||
{
|
||||
//emu_emit(emu);
|
||||
|
||||
emit_channels(emu);
|
||||
|
||||
switch(emu->cur_ev->header.model)
|
||||
{
|
||||
case 'O': hook_emit_ovni(emu);
|
||||
@ -665,6 +680,44 @@ emu_virtual_ev(struct ovni_emu *emu, char *mcv)
|
||||
trace->nvirtual++;
|
||||
}
|
||||
|
||||
static void
|
||||
init_thread(struct ovni_emu *emu, struct ovni_ethread *th)
|
||||
{
|
||||
int i, row;
|
||||
|
||||
row = th->gindex + 1;
|
||||
|
||||
for(i=0; i<CHAN_MAX; i++)
|
||||
{
|
||||
chan_init(&th->chan[i], row, type, emu->prv_thread,
|
||||
&emu->delta_clock);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
init_threads(struct ovni_emu *emu)
|
||||
{
|
||||
struct ovni_loom *loom;
|
||||
struct ovni_eproc *proc;
|
||||
struct ovni_ethread *thread;
|
||||
int i, j, k;
|
||||
|
||||
for(i=0; i<trace->nlooms; i++)
|
||||
{
|
||||
loom = &trace->loom[i];
|
||||
for(j=0; j<loom->nprocs; j++)
|
||||
{
|
||||
proc = &loom->proc[j];
|
||||
for(k=0; k<proc->nthreads; k++)
|
||||
{
|
||||
thread = &proc->thread[k];
|
||||
|
||||
init_thread(emu, thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
emu_init(struct ovni_emu *emu, int argc, char *argv[])
|
||||
{
|
||||
@ -689,6 +742,8 @@ emu_init(struct ovni_emu *emu, int argc, char *argv[])
|
||||
|
||||
open_prvs(emu, emu->tracedir);
|
||||
open_pcfs(emu, emu->tracedir);
|
||||
|
||||
init_threads(emu);
|
||||
}
|
||||
|
||||
static void
|
||||
|
65
emu.h
65
emu.h
@ -64,7 +64,54 @@ struct nosv_task_type {
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
#define MAX_SS_STACK 128
|
||||
#define MAX_CHAN_STACK 128
|
||||
|
||||
struct ovni_chan {
|
||||
/* Number of states in the stack */
|
||||
int n;
|
||||
|
||||
/* Stack of states */
|
||||
int stack[MAX_CHAN_STACK];
|
||||
|
||||
/* 1 if enabled, 0 if not. */
|
||||
int enabled;
|
||||
|
||||
/* What state should be shown in errors */
|
||||
int badst;
|
||||
|
||||
/* Punctual event: -1 if not used */
|
||||
int ev;
|
||||
|
||||
/* Emit events of this type */
|
||||
int type;
|
||||
|
||||
/* A pointer to a clock to sample the time */
|
||||
int64_t *clock;
|
||||
|
||||
/* The time of the last state or event */
|
||||
int64_t t;
|
||||
|
||||
/* Paraver row */
|
||||
int row;
|
||||
|
||||
/* 1 if channel needs flush to PRV */
|
||||
int dirty;
|
||||
|
||||
/* Where should the events be written to? */
|
||||
FILE *prv;
|
||||
};
|
||||
|
||||
enum chan {
|
||||
/* Ovni */
|
||||
CHAN_OVNI_STATE = 0,
|
||||
CHAN_OVNI_TID,
|
||||
CHAN_OVNI_PID,
|
||||
|
||||
/* nOS-V */
|
||||
CHAN_NOSV_TASK_ID,
|
||||
CHAN_NOSV_SS, /* Subsystem */
|
||||
CHAN_MAX
|
||||
};
|
||||
|
||||
/* All PRV event types */
|
||||
enum prv_type {
|
||||
@ -105,22 +152,14 @@ struct ovni_ethread {
|
||||
/* Current cpu */
|
||||
struct ovni_cpu *cpu;
|
||||
|
||||
/* Number of subsystem states in the stack */
|
||||
int nss;
|
||||
|
||||
/* Stack of subsystem states */
|
||||
int ss[MAX_SS_STACK];
|
||||
|
||||
int ss_event;
|
||||
|
||||
/* FIXME: Use a table with registrable pointers to custom data
|
||||
* structures */
|
||||
|
||||
/* nosv task */
|
||||
struct nosv_task *task;
|
||||
|
||||
/* Should we print the subsystem? */
|
||||
int show_ss;
|
||||
/* Channels are used to output the emulator state in PRV */
|
||||
struct ovni_chan chan[CHAN_MAX];
|
||||
};
|
||||
|
||||
/* State of each emulated process */
|
||||
@ -180,10 +219,6 @@ struct ovni_cpu {
|
||||
/* The threads the cpu is currently running */
|
||||
size_t nthreads;
|
||||
struct ovni_ethread *thread[OVNI_MAX_THR];
|
||||
|
||||
///* Each channel emits events in the PRV file */
|
||||
//int nchannels;
|
||||
//struct ovni_channel *channel;
|
||||
};
|
||||
|
||||
/* ----------------------- trace ------------------------ */
|
||||
|
28
emu_nosv.c
28
emu_nosv.c
@ -5,6 +5,7 @@
|
||||
#include "ovni_trace.h"
|
||||
#include "emu.h"
|
||||
#include "prv.h"
|
||||
#include "chan.h"
|
||||
|
||||
enum nosv_prv_type {
|
||||
PRV_TYPE_PROCID
|
||||
@ -15,6 +16,28 @@ struct hook_entry {
|
||||
void (*hook)(struct ovni_emu *);
|
||||
};
|
||||
|
||||
/* --------------------------- init ------------------------------- */
|
||||
|
||||
void
|
||||
hook_nosv_init(struct ovni_emu *emu)
|
||||
{
|
||||
struct ovni_ethread *th;
|
||||
int i, row, type;
|
||||
FILE *prv;
|
||||
int64_t *clock;
|
||||
|
||||
for(i=0; i<emu->total_nthreads; i++)
|
||||
{
|
||||
th = emu->global_thread[i];
|
||||
row = th->gindex + 1;
|
||||
|
||||
//chan_init(struct ovni_chan *chan, int row, int type, FILE *prv, int64_t *clock)
|
||||
|
||||
chan_init(th->chan[CHAN_NOSV_TASK_ID], row, PTT_TASK_ID, prv,
|
||||
clock);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------- pre ------------------------------- */
|
||||
|
||||
static void
|
||||
@ -286,6 +309,11 @@ emit_task(struct ovni_emu *emu)
|
||||
void
|
||||
hook_emit_nosv(struct ovni_emu *emu)
|
||||
{
|
||||
struct ovni_ethread *th;
|
||||
int i;
|
||||
|
||||
th = emu->cur_thread;
|
||||
|
||||
switch(emu->cur_ev->header.class)
|
||||
{
|
||||
case 'T': emit_task(emu); break;
|
||||
|
329
emu_nosv_ss.c
329
emu_nosv_ss.c
@ -5,6 +5,7 @@
|
||||
#include "ovni_trace.h"
|
||||
#include "emu.h"
|
||||
#include "prv.h"
|
||||
#include "chan.h"
|
||||
|
||||
/* This module manages the nos-v subsystem (ss) events, to track which
|
||||
* actions are being performed by each thread at a given time. A stack
|
||||
@ -12,94 +13,34 @@
|
||||
* execution. Events such as task received by a thread are emitted as
|
||||
* fake events with very short period. */
|
||||
|
||||
|
||||
/* --------------------------- ss helpers ------------------------------- */
|
||||
|
||||
static void
|
||||
ss_init(struct ovni_ethread *t)
|
||||
{
|
||||
t->nss = 0;
|
||||
t->show_ss = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ss_push(struct ovni_ethread *t, int st)
|
||||
{
|
||||
if(t->nss >= MAX_SS_STACK)
|
||||
{
|
||||
err("thread %d subsystem stack full\n", t->tid);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
t->ss[t->nss] = st;
|
||||
t->nss++;
|
||||
}
|
||||
|
||||
static int
|
||||
ss_pop(struct ovni_ethread *t, int expected_st)
|
||||
{
|
||||
int st;
|
||||
|
||||
if(t->nss <= 0)
|
||||
{
|
||||
err("thread %d subsystem stack empty\n", t->tid);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
st = t->ss[t->nss - 1];
|
||||
|
||||
if(st > 0 && st != expected_st)
|
||||
{
|
||||
err("thread %d expected subsystem state %d (got %d)\n",
|
||||
t->tid, expected_st, st);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
t->nss--;
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
static void
|
||||
ss_ev(struct ovni_ethread *th, int ev)
|
||||
{
|
||||
th->ss_event = ev;
|
||||
}
|
||||
|
||||
static int
|
||||
ss_last_st(struct ovni_ethread *th)
|
||||
{
|
||||
if(th->nss == 0)
|
||||
return ST_NULL;
|
||||
|
||||
return th->ss[th->nss - 1];
|
||||
}
|
||||
|
||||
/* --------------------------- pre ------------------------------- */
|
||||
|
||||
static void
|
||||
pre_sched(struct ovni_emu *emu)
|
||||
{
|
||||
struct ovni_ethread *th;
|
||||
struct ovni_chan *chan;
|
||||
|
||||
th = emu->cur_thread;
|
||||
chan = &th->chan[CHAN_NOSV_SS];
|
||||
|
||||
switch(emu->cur_ev->header.value)
|
||||
{
|
||||
case 'h':
|
||||
ss_push(th, ST_SCHED_HUNGRY);
|
||||
chan_push(chan, ST_SCHED_HUNGRY);
|
||||
break;
|
||||
case 'f': /* Fill: no longer hungry */
|
||||
ss_pop(th, ST_SCHED_HUNGRY);
|
||||
chan_pop(chan, ST_SCHED_HUNGRY);
|
||||
break;
|
||||
case '[': /* Server enter */
|
||||
ss_push(th, ST_SCHED_SERVING);
|
||||
chan_push(chan, ST_SCHED_SERVING);
|
||||
break;
|
||||
case ']': /* Server exit */
|
||||
ss_pop(th, ST_SCHED_SERVING);
|
||||
chan_pop(chan, ST_SCHED_SERVING);
|
||||
break;
|
||||
case '@': ss_ev(th, EV_SCHED_SELF); break;
|
||||
case 'r': ss_ev(th, EV_SCHED_RECV); break;
|
||||
case 's': ss_ev(th, EV_SCHED_SEND); break;
|
||||
case '@': chan_ev(chan, EV_SCHED_SELF); break;
|
||||
case 'r': chan_ev(chan, EV_SCHED_RECV); break;
|
||||
case 's': chan_ev(chan, EV_SCHED_SEND); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -109,12 +50,15 @@ static void
|
||||
pre_submit(struct ovni_emu *emu)
|
||||
{
|
||||
struct ovni_ethread *th;
|
||||
struct ovni_chan *chan;
|
||||
|
||||
th = emu->cur_thread;
|
||||
chan = &th->chan[CHAN_NOSV_SS];
|
||||
|
||||
switch(emu->cur_ev->header.value)
|
||||
{
|
||||
case '[': ss_push(th, ST_SCHED_SUBMITTING); break;
|
||||
case ']': ss_pop(th, ST_SCHED_SUBMITTING); break;
|
||||
case '[': chan_push(chan, ST_SCHED_SUBMITTING); break;
|
||||
case ']': chan_pop(chan, ST_SCHED_SUBMITTING); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -124,64 +68,15 @@ static void
|
||||
pre_memory(struct ovni_emu *emu)
|
||||
{
|
||||
struct ovni_ethread *th;
|
||||
struct ovni_chan *chan;
|
||||
|
||||
th = emu->cur_thread;
|
||||
chan = &th->chan[CHAN_NOSV_SS];
|
||||
|
||||
switch(emu->cur_ev->header.value)
|
||||
{
|
||||
case '[': ss_push(th, ST_MEM_ALLOCATING); break;
|
||||
case ']': ss_pop(th, ST_MEM_ALLOCATING); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hook for the virtual "thread changed" event */
|
||||
static void
|
||||
pre_thread_change(struct ovni_emu *emu)
|
||||
{
|
||||
struct ovni_ethread *th;
|
||||
|
||||
th = emu->cur_thread;
|
||||
|
||||
/* Only print the subsystem if the thread is running */
|
||||
if(th->state == TH_ST_RUNNING)
|
||||
th->show_ss = 1;
|
||||
else
|
||||
th->show_ss = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pre_thread(struct ovni_emu *emu)
|
||||
{
|
||||
switch(emu->cur_ev->header.value)
|
||||
{
|
||||
case 'c': pre_thread_change(emu); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hook for the virtual "cpu changed" event */
|
||||
static void
|
||||
pre_cpu_change(struct ovni_emu *emu)
|
||||
{
|
||||
struct ovni_ethread *th;
|
||||
|
||||
th = emu->cur_thread;
|
||||
|
||||
/* Only print the subsystem if the thread is running */
|
||||
if(th->state == TH_ST_RUNNING)
|
||||
th->show_ss = 1;
|
||||
else
|
||||
th->show_ss = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pre_cpu(struct ovni_emu *emu)
|
||||
{
|
||||
switch(emu->cur_ev->header.value)
|
||||
{
|
||||
case 'c': pre_thread_change(emu); break;
|
||||
case '[': chan_push(chan, ST_MEM_ALLOCATING); break;
|
||||
case ']': chan_pop(chan, ST_MEM_ALLOCATING); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -190,19 +85,8 @@ pre_cpu(struct ovni_emu *emu)
|
||||
void
|
||||
hook_pre_nosv_ss(struct ovni_emu *emu)
|
||||
{
|
||||
switch(emu->cur_ev->header.model)
|
||||
{
|
||||
/* Listen for virtual events as well */
|
||||
case '*':
|
||||
switch(emu->cur_ev->header.class)
|
||||
{
|
||||
case 'H': pre_thread(emu); break;
|
||||
case 'C': pre_cpu(emu); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'V':
|
||||
assert(emu->cur_ev->header.model == 'V');
|
||||
|
||||
switch(emu->cur_ev->header.class)
|
||||
{
|
||||
case 'S': pre_sched(emu); break;
|
||||
@ -211,181 +95,19 @@ hook_pre_nosv_ss(struct ovni_emu *emu)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------- emit ------------------------------- */
|
||||
|
||||
static void
|
||||
emit_thread_state(struct ovni_emu *emu, struct ovni_ethread *th,
|
||||
int type, int st)
|
||||
{
|
||||
int row;
|
||||
|
||||
row = th->gindex + 1;
|
||||
|
||||
prv_ev_thread(emu, row, type, st);
|
||||
}
|
||||
|
||||
static void
|
||||
emit_cpu_state(struct ovni_emu *emu, struct ovni_ethread *th,
|
||||
int type, int st)
|
||||
{
|
||||
/* Detect multiple threads */
|
||||
if(th->cpu && th->cpu->nthreads > 1)
|
||||
st = ST_BAD;
|
||||
|
||||
prv_ev_autocpu(emu, type, st);
|
||||
}
|
||||
|
||||
static void
|
||||
emit_thread_event(struct ovni_emu *emu, struct ovni_ethread *th,
|
||||
int type, int st)
|
||||
{
|
||||
int64_t t0, t1;
|
||||
int row;
|
||||
int prev_st;
|
||||
|
||||
row = th->gindex + 1;
|
||||
|
||||
t0 = emu->delta_time - 1;
|
||||
t1 = emu->delta_time;
|
||||
|
||||
prev_st = ss_last_st(th);
|
||||
|
||||
/* Fake event using 1 nanosecond in the past */
|
||||
prv_ev_thread_raw(emu, row, t0, type, st);
|
||||
prv_ev_thread_raw(emu, row, t1, type, prev_st);
|
||||
}
|
||||
|
||||
static void
|
||||
emit_cpu_event(struct ovni_emu *emu, struct ovni_ethread *th,
|
||||
int type, int st)
|
||||
{
|
||||
int64_t t0, t1;
|
||||
int row;
|
||||
int prev_st;
|
||||
|
||||
row = th->gindex + 1;
|
||||
|
||||
t0 = emu->delta_time - 1;
|
||||
t1 = emu->delta_time;
|
||||
|
||||
prev_st = ss_last_st(th);
|
||||
|
||||
/* Detect multiple threads */
|
||||
if(th->cpu && th->cpu->nthreads > 1)
|
||||
{
|
||||
st = ST_BAD;
|
||||
prev_st = ST_BAD;
|
||||
}
|
||||
|
||||
/* Fake event using 1 nanosecond in the past */
|
||||
prv_ev_autocpu_raw(emu, t0, type, st);
|
||||
prv_ev_autocpu_raw(emu, t1, type, prev_st);
|
||||
}
|
||||
|
||||
static void
|
||||
emit_thread_changed(struct ovni_emu *emu)
|
||||
{
|
||||
dbg("emit_thread_changed\n")
|
||||
}
|
||||
|
||||
static void
|
||||
emit_cpu_changed(struct ovni_emu *emu)
|
||||
{
|
||||
dbg("emit_cpu_changed\n")
|
||||
//int i;
|
||||
//struct ovni_loom *loom;
|
||||
//struct ovni_cpu *cpu;
|
||||
|
||||
///* Detect multiple threads */
|
||||
//loom = emu->cur_loom;
|
||||
|
||||
//assert(loom->nupdated_cpus > 0);
|
||||
|
||||
//for(i=0; i<loom->nupdated_cpus; i++)
|
||||
//{
|
||||
// cpu = loom->updated_cpu[i];
|
||||
|
||||
// if(cpu->nthreads > 1)
|
||||
// {
|
||||
// prv_stream_disable(cpu->ss_stream);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
void
|
||||
hook_emit_nosv_ss(struct ovni_emu *emu)
|
||||
{
|
||||
/* We need to emit events when a thread notifies us that the subsystem
|
||||
* has changed, but also when the thread is paused, or scheduled to
|
||||
* another CPU, as the CPU view must be updated as well. */
|
||||
|
||||
switch(emu->cur_ev->header.model)
|
||||
{
|
||||
/* Listen for virtual events as well */
|
||||
case '*':
|
||||
switch(emu->cur_ev->header.class)
|
||||
{
|
||||
case 'H':
|
||||
switch(emu->cur_ev->header.value)
|
||||
{
|
||||
case 'c': emit_thread_changed(emu); break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
switch(emu->cur_ev->header.value)
|
||||
{
|
||||
case 'c': emit_cpu_changed(emu); break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case 'V':
|
||||
switch(emu->cur_ev->header.class)
|
||||
{
|
||||
case 'S': pre_sched(emu); break;
|
||||
case 'U': pre_submit(emu); break;
|
||||
case 'M': pre_memory(emu); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
struct ovni_ethread *th;
|
||||
struct ovni_chan *chan;
|
||||
|
||||
th = emu->cur_thread;
|
||||
|
||||
if(th->show_ss == 0)
|
||||
{
|
||||
emit_thread_state(emu, th, PTT_SUBSYSTEM, ST_NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only emit a state if needed */
|
||||
if(th->ss_event != EV_NULL)
|
||||
{
|
||||
emit_thread_event(emu, th, PTT_SUBSYSTEM,
|
||||
th->ss_event);
|
||||
emit_cpu_event(emu, th, PTC_SUBSYSTEM,
|
||||
th->ss_event);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
emit_thread_state(emu, th, PTT_SUBSYSTEM, ss_last_st(th));
|
||||
emit_cpu_state(emu, th, PTC_SUBSYSTEM, ss_last_st(th));
|
||||
chan_emit(&th->chan[CHAN_NOSV_SS]);
|
||||
}
|
||||
|
||||
/* --------------------------- post ------------------------------- */
|
||||
@ -393,5 +115,4 @@ hook_emit_nosv_ss(struct ovni_emu *emu)
|
||||
void
|
||||
hook_post_nosv_ss(struct ovni_emu *emu)
|
||||
{
|
||||
emu->cur_thread->ss_event = EV_NULL;
|
||||
}
|
||||
|
110
emu_ovni.c
110
emu_ovni.c
@ -1,12 +1,35 @@
|
||||
#include "ovni.h"
|
||||
#include "emu.h"
|
||||
#include "prv.h"
|
||||
#include "chan.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* The emulator ovni module provides the execution model by tracking the thread
|
||||
* state and which threads run in each CPU */
|
||||
|
||||
/* --------------------------- pre ------------------------------- */
|
||||
|
||||
static void
|
||||
thread_set_channel_enabled(struct ovni_ethread *th, int enabled)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<CHAN_MAX; i++)
|
||||
chan_enable(&th->chan[i], enabled);
|
||||
}
|
||||
|
||||
static void
|
||||
thread_set_state(struct ovni_ethread *th, int state)
|
||||
{
|
||||
int enabled;
|
||||
|
||||
th->state = state;
|
||||
|
||||
enabled = (state == TH_ST_RUNNING ? 1 : 0);
|
||||
|
||||
thread_set_channel_enabled(th, enabled);
|
||||
}
|
||||
|
||||
void
|
||||
update_cpu(struct ovni_emu *emu, struct ovni_cpu *cpu)
|
||||
{
|
||||
@ -88,7 +111,6 @@ emu_cpu_remove_thread(struct ovni_emu *emu, struct ovni_cpu *cpu, struct ovni_et
|
||||
update_cpu(emu, cpu);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_threads_state(struct ovni_loom *loom)
|
||||
{
|
||||
@ -116,61 +138,64 @@ print_threads_state(struct ovni_loom *loom)
|
||||
}
|
||||
|
||||
static void
|
||||
ev_thread_execute(struct ovni_emu *emu)
|
||||
pre_thread_execute(struct ovni_emu *emu)
|
||||
{
|
||||
struct ovni_cpu *cpu;
|
||||
struct ovni_ethread *th;
|
||||
int cpuid;
|
||||
|
||||
th = emu->cur_thread;
|
||||
|
||||
/* The thread cannot be already running */
|
||||
assert(emu->cur_thread->state != TH_ST_RUNNING);
|
||||
assert(th->state != TH_ST_RUNNING);
|
||||
|
||||
cpuid = emu->cur_ev->payload.i32[0];
|
||||
//dbg("thread %d runs in cpuid %d\n", emu->cur_thread->tid,
|
||||
//dbg("thread %d runs in cpuid %d\n", th->tid,
|
||||
// cpuid);
|
||||
cpu = emu_get_cpu(emu->cur_loom, cpuid);
|
||||
|
||||
emu->cur_thread->state = TH_ST_RUNNING;
|
||||
emu->cur_thread->cpu = cpu;
|
||||
thread_set_state(th, TH_ST_RUNNING);
|
||||
th->cpu = cpu;
|
||||
|
||||
emu_cpu_add_thread(emu, cpu, emu->cur_thread);
|
||||
emu_cpu_add_thread(emu, cpu, th);
|
||||
}
|
||||
|
||||
static void
|
||||
ev_thread_end(struct ovni_emu *emu)
|
||||
pre_thread_end(struct ovni_emu *emu)
|
||||
{
|
||||
assert(emu->cur_thread->state == TH_ST_RUNNING);
|
||||
assert(emu->cur_thread->cpu);
|
||||
|
||||
emu_cpu_remove_thread(emu, emu->cur_thread->cpu, emu->cur_thread);
|
||||
|
||||
emu->cur_thread->state = TH_ST_DEAD;
|
||||
thread_set_state(emu->cur_thread, TH_ST_DEAD);
|
||||
emu->cur_thread->cpu = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
ev_thread_pause(struct ovni_emu *emu)
|
||||
pre_thread_pause(struct ovni_emu *emu)
|
||||
{
|
||||
assert(emu->cur_thread->state == TH_ST_RUNNING);
|
||||
assert(emu->cur_thread->cpu);
|
||||
|
||||
emu_cpu_remove_thread(emu, emu->cur_thread->cpu, emu->cur_thread);
|
||||
|
||||
emu->cur_thread->state = TH_ST_PAUSED;
|
||||
thread_set_state(emu->cur_thread, TH_ST_PAUSED);
|
||||
}
|
||||
|
||||
static void
|
||||
ev_thread_resume(struct ovni_emu *emu)
|
||||
pre_thread_resume(struct ovni_emu *emu)
|
||||
{
|
||||
assert(emu->cur_thread->state == TH_ST_PAUSED);
|
||||
assert(emu->cur_thread->cpu);
|
||||
|
||||
emu_cpu_add_thread(emu, emu->cur_thread->cpu, emu->cur_thread);
|
||||
|
||||
emu->cur_thread->state = TH_ST_RUNNING;
|
||||
thread_set_state(emu->cur_thread, TH_ST_RUNNING);
|
||||
}
|
||||
|
||||
static void
|
||||
ev_thread(struct ovni_emu *emu)
|
||||
pre_thread(struct ovni_emu *emu)
|
||||
{
|
||||
struct ovni_ev *ev;
|
||||
struct ovni_cpu *cpu;
|
||||
@ -193,27 +218,19 @@ ev_thread(struct ovni_emu *emu)
|
||||
ev->payload.u32[2]);
|
||||
|
||||
break;
|
||||
case 'x': ev_thread_execute(emu); break;
|
||||
case 'e': ev_thread_end(emu); break;
|
||||
case 'p': ev_thread_pause(emu); break;
|
||||
case 'r': ev_thread_resume(emu); break;
|
||||
case 'x': pre_thread_execute(emu); break;
|
||||
case 'e': pre_thread_end(emu); break;
|
||||
case 'p': pre_thread_pause(emu); break;
|
||||
case 'r': pre_thread_resume(emu); break;
|
||||
default:
|
||||
err("unknown thread event value %c\n",
|
||||
ev->header.value);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* All but create events change the thread and CPU state: inject two
|
||||
* virtual events to notify other modules. The order is important. */
|
||||
if(ev->header.value != 'c')
|
||||
{
|
||||
emu_virtual_ev(emu, "*Hc");
|
||||
emu_virtual_ev(emu, "*Cc");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ev_affinity_set(struct ovni_emu *emu)
|
||||
pre_affinity_set(struct ovni_emu *emu)
|
||||
{
|
||||
int cpuid;
|
||||
struct ovni_cpu *newcpu;
|
||||
@ -235,7 +252,7 @@ ev_affinity_set(struct ovni_emu *emu)
|
||||
}
|
||||
|
||||
static void
|
||||
ev_affinity_remote(struct ovni_emu *emu)
|
||||
pre_affinity_remote(struct ovni_emu *emu)
|
||||
{
|
||||
int cpuid, tid;
|
||||
struct ovni_cpu *newcpu;
|
||||
@ -279,13 +296,13 @@ ev_affinity_remote(struct ovni_emu *emu)
|
||||
}
|
||||
|
||||
static void
|
||||
ev_affinity(struct ovni_emu *emu)
|
||||
pre_affinity(struct ovni_emu *emu)
|
||||
{
|
||||
//emu_emit(emu);
|
||||
switch(emu->cur_ev->header.value)
|
||||
{
|
||||
case 's': ev_affinity_set(emu); break;
|
||||
case 'r': ev_affinity_remote(emu); break;
|
||||
case 's': pre_affinity_set(emu); break;
|
||||
case 'r': pre_affinity_remote(emu); break;
|
||||
default:
|
||||
dbg("unknown affinity event value %c\n",
|
||||
emu->cur_ev->header.value);
|
||||
@ -303,8 +320,8 @@ hook_pre_ovni(struct ovni_emu *emu)
|
||||
|
||||
switch(emu->cur_ev->header.class)
|
||||
{
|
||||
case 'H': ev_thread(emu); break;
|
||||
case 'A': ev_affinity(emu); break;
|
||||
case 'H': pre_thread(emu); break;
|
||||
case 'A': pre_affinity(emu); break;
|
||||
case 'B':
|
||||
//dbg("burst %c\n", emu->cur_ev->header.value);
|
||||
break;
|
||||
@ -317,21 +334,26 @@ hook_pre_ovni(struct ovni_emu *emu)
|
||||
//print_threads_state(emu);
|
||||
}
|
||||
|
||||
/* --------------------------- emit ------------------------------- */
|
||||
|
||||
static void
|
||||
emit_thread_state(struct ovni_emu *emu)
|
||||
{
|
||||
int row, st, tid;
|
||||
int i, row;
|
||||
struct ovni_ethread *th;
|
||||
|
||||
st = emu->cur_thread->state;
|
||||
row = emu->cur_thread->gindex + 1;
|
||||
tid = emu->cur_thread->tid;
|
||||
th = emu->cur_thread;
|
||||
row = th->gindex + 1;
|
||||
|
||||
prv_ev_thread(emu, row, PTT_THREAD_STATE, st);
|
||||
prv_ev_thread(emu, row, PTT_THREAD_STATE, th->state);
|
||||
|
||||
if(st == TH_ST_RUNNING)
|
||||
prv_ev_thread(emu, row, PTT_THREAD_TID, tid);
|
||||
if(th->state == TH_ST_RUNNING)
|
||||
prv_ev_thread(emu, row, PTT_THREAD_TID, th->tid);
|
||||
else
|
||||
prv_ev_thread(emu, row, PTT_THREAD_TID, 0);
|
||||
|
||||
chan_set(&th->chan[CHAN_OVNI_TID], th->tid);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -390,6 +412,8 @@ emit_current_pid(struct ovni_emu *emu)
|
||||
void
|
||||
hook_emit_ovni(struct ovni_emu *emu)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(emu->cur_ev->header.model != 'O')
|
||||
return;
|
||||
|
||||
@ -405,8 +429,14 @@ hook_emit_ovni(struct ovni_emu *emu)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Emit all enabled channels */
|
||||
for(i=0; i<CHAN_MAX; i++)
|
||||
chan_emit(&emu->cur_thread->chan[i]);
|
||||
}
|
||||
|
||||
/* --------------------------- post ------------------------------- */
|
||||
|
||||
/* Reset thread state */
|
||||
static void
|
||||
post_virtual_thread(struct ovni_emu *emu)
|
||||
|
Loading…
Reference in New Issue
Block a user