Only allow and emit state transitions

Fixes the ghost events shown in the PRV trace. Only transitions to a
different state are allowed now.
This commit is contained in:
Rodrigo Arias 2021-11-17 12:08:25 +01:00
parent 78f5db4bce
commit 557371e836
3 changed files with 62 additions and 18 deletions

54
chan.c
View File

@ -37,15 +37,17 @@ chan_init(struct ovni_chan *chan, enum chan_track track, int row, int type, FILE
chan->row = row; chan->row = row;
chan->dirty = 0; chan->dirty = 0;
chan->track = track; chan->track = track;
chan->lastst = -1;
} }
static void static void
mark_dirty(struct ovni_chan *chan) mark_dirty(struct ovni_chan *chan, enum chan_dirty dirty)
{ {
assert(chan->dirty == 0); assert(chan->dirty == CHAN_CLEAN);
assert(dirty != CHAN_CLEAN);
dbg("adding dirty chan %d to list\n", chan->id); dbg("adding dirty chan %d to list\n", chan->id);
chan->dirty = 1; chan->dirty = dirty;
DL_APPEND(*chan->update_list, chan); DL_APPEND(*chan->update_list, chan);
} }
@ -75,7 +77,7 @@ chan_th_init(struct ovni_ethread *th,
chan->enabled = enabled; chan->enabled = enabled;
chan->stack[chan->n++] = init_st; chan->stack[chan->n++] = init_st;
if(dirty) if(dirty)
mark_dirty(chan); mark_dirty(chan, CHAN_DIRTY_ACTIVE);
} }
void void
@ -104,7 +106,7 @@ chan_cpu_init(struct ovni_cpu *cpu,
chan->enabled = enabled; chan->enabled = enabled;
chan->stack[chan->n++] = init_st; chan->stack[chan->n++] = init_st;
if(dirty) if(dirty)
mark_dirty(chan); mark_dirty(chan, CHAN_DIRTY_ACTIVE);
} }
static void static void
@ -139,7 +141,7 @@ chan_enable(struct ovni_chan *chan, int enabled)
/* Only append if not dirty */ /* Only append if not dirty */
if(!chan->dirty) if(!chan->dirty)
{ {
mark_dirty(chan); mark_dirty(chan, CHAN_DIRTY_ACTIVE);
} }
else else
{ {
@ -179,7 +181,7 @@ chan_set(struct ovni_chan *chan, int st)
/* Only append if not dirty */ /* Only append if not dirty */
if(!chan->dirty) if(!chan->dirty)
{ {
mark_dirty(chan); mark_dirty(chan, CHAN_DIRTY_VALUE);
} }
else else
{ {
@ -215,7 +217,7 @@ chan_push(struct ovni_chan *chan, int st)
chan->stack[chan->n++] = st; chan->stack[chan->n++] = st;
chan->t = *chan->clock; chan->t = *chan->clock;
mark_dirty(chan); mark_dirty(chan, CHAN_DIRTY_VALUE);
} }
int int
@ -248,7 +250,7 @@ chan_pop(struct ovni_chan *chan, int expected_st)
chan->n--; chan->n--;
chan->t = *chan->clock; chan->t = *chan->clock;
mark_dirty(chan); mark_dirty(chan, CHAN_DIRTY_VALUE);
return st; return st;
} }
@ -267,7 +269,7 @@ chan_ev(struct ovni_chan *chan, int ev)
chan->ev = ev; chan->ev = ev;
chan->t = *chan->clock; chan->t = *chan->clock;
mark_dirty(chan); mark_dirty(chan, CHAN_DIRTY_VALUE);
} }
int int
@ -283,6 +285,32 @@ chan_get_st(struct ovni_chan *chan)
return chan->stack[chan->n-1]; return chan->stack[chan->n-1];
} }
static void
emit(struct ovni_chan *chan, int64_t t, int state)
{
assert(chan->dirty != CHAN_CLEAN);
/* A channel can only emit the same state as lastst if is dirty because
* it has been enabled or disabled. Otherwise is a bug (ie. you have two
* consecutive ovni events?) */
if(chan->lastst != -1
&& chan->dirty == CHAN_DIRTY_VALUE
&& chan->lastst == state)
{
/* TODO: Print the raw clock of the offending event */
err("chan: id=%d cannot emit the same state %d twice\n",
chan->id, state);
abort();
}
if(chan->lastst != state)
{
prv_ev(chan->prv, chan->row, t, chan->type, state);
chan->lastst = state;
}
}
static void static void
emit_ev(struct ovni_chan *chan) emit_ev(struct ovni_chan *chan)
{ {
@ -294,8 +322,8 @@ emit_ev(struct ovni_chan *chan)
new = chan->ev; new = chan->ev;
last = chan_get_st(chan); last = chan_get_st(chan);
prv_ev(chan->prv, chan->row, chan->t-1, chan->type, new); emit(chan, chan->t-1, new);
prv_ev(chan->prv, chan->row, chan->t, chan->type, last); emit(chan, chan->t, last);
chan->ev = -1; chan->ev = -1;
} }
@ -307,7 +335,7 @@ emit_st(struct ovni_chan *chan)
st = chan_get_st(chan); st = chan_get_st(chan);
prv_ev(chan->prv, chan->row, chan->t, chan->type, st); emit(chan, chan->t, st);
} }
/* Emits either the current state or punctual event in the PRV file */ /* Emits either the current state or punctual event in the PRV file */

7
emu.c
View File

@ -82,7 +82,7 @@ print_cur_ev(struct ovni_emu *emu)
static void static void
cpu_update_tracking_chan(struct ovni_chan *cpu_chan, struct ovni_ethread *th) cpu_update_tracking_chan(struct ovni_chan *cpu_chan, struct ovni_ethread *th)
{ {
int th_enabled, cpu_enabled; int th_enabled, cpu_enabled, st;
struct ovni_chan *th_chan; struct ovni_chan *th_chan;
assert(th); assert(th);
@ -112,7 +112,9 @@ cpu_update_tracking_chan(struct ovni_chan *cpu_chan, struct ovni_ethread *th)
if(th_enabled && cpu_enabled) if(th_enabled && cpu_enabled)
{ {
/* Both enabled: simply follow the same value */ /* Both enabled: simply follow the same value */
chan_set(cpu_chan, chan_get_st(th_chan)); st = chan_get_st(th_chan);
if(chan_get_st(cpu_chan) != st)
chan_set(cpu_chan, st);
} }
else if(th_enabled && !cpu_enabled) else if(th_enabled && !cpu_enabled)
{ {
@ -192,6 +194,7 @@ emu_cpu_update_chan(struct ovni_cpu *cpu, struct ovni_chan *cpu_chan)
if(!chan_is_enabled(cpu_chan)) if(!chan_is_enabled(cpu_chan))
chan_enable(cpu_chan, 1); chan_enable(cpu_chan, 1);
if(chan_get_st(cpu_chan) != ST_TOO_MANY_TH)
chan_set(cpu_chan, ST_TOO_MANY_TH); chan_set(cpu_chan, ST_TOO_MANY_TH);
} }
} }

17
emu.h
View File

@ -170,6 +170,16 @@ enum chan_to_prv_type {
CHAN_CPU = 2, CHAN_CPU = 2,
}; };
enum chan_dirty {
CHAN_CLEAN = 0,
/* The channel is dirty because it has been enabled or disabled */
CHAN_DIRTY_ACTIVE = 1,
/* The channel is dirty because it changed the state */
CHAN_DIRTY_VALUE = 2,
};
/* Same order as `enum chan` */ /* Same order as `enum chan` */
static const int chan_to_prvtype[CHAN_MAX][3] = { static const int chan_to_prvtype[CHAN_MAX][3] = {
/* Channel TH CPU */ /* Channel TH CPU */
@ -212,6 +222,9 @@ struct ovni_chan {
/* What state should be shown in errors */ /* What state should be shown in errors */
int badst; int badst;
/* Last state emitted (-1 otherwise) */
int lastst;
/* Punctual event: -1 if not used */ /* Punctual event: -1 if not used */
int ev; int ev;
@ -227,8 +240,8 @@ struct ovni_chan {
/* Paraver row */ /* Paraver row */
int row; int row;
/* 1 if channel needs flush to PRV */ /* Type of dirty */
int dirty; enum chan_dirty dirty;
/* Where should the events be written to? */ /* Where should the events be written to? */
FILE *prv; FILE *prv;