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; | ||||
|  | ||||
							
								
								
									
										337
									
								
								emu_nosv_ss.c
									
									
									
									
									
								
							
							
						
						
									
										337
									
								
								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,94 +68,30 @@ 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; | ||||
| 		case '[': chan_push(chan, ST_MEM_ALLOCATING); break; | ||||
| 		case ']': chan_pop(chan, 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; | ||||
| 		default: | ||||
| 			break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void | ||||
| hook_pre_nosv_ss(struct ovni_emu *emu) | ||||
| { | ||||
| 	switch(emu->cur_ev->header.model) | ||||
| 	assert(emu->cur_ev->header.model == 'V'); | ||||
| 
 | ||||
| 	switch(emu->cur_ev->header.class) | ||||
| 	{ | ||||
| 		/* 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': | ||||
| 			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; | ||||
| 		case 'S': pre_sched(emu); break; | ||||
| 		case 'U': pre_submit(emu); break; | ||||
| 		case 'M': pre_memory(emu); break; | ||||
| 		default: | ||||
| 			break; | ||||
| 	} | ||||
| @ -219,173 +99,15 @@ hook_pre_nosv_ss(struct ovni_emu *emu) | ||||
| 
 | ||||
| /* --------------------------- 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; | ||||
| } | ||||
|  | ||||
							
								
								
									
										112
									
								
								emu_ovni.c
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								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; | ||||
| 	 | ||||
| 	st = emu->cur_thread->state; | ||||
| 	row = emu->cur_thread->gindex + 1; | ||||
| 	tid = emu->cur_thread->tid; | ||||
| 	int i, row; | ||||
| 	struct ovni_ethread *th; | ||||
| 
 | ||||
| 	prv_ev_thread(emu, row, PTT_THREAD_STATE, st); | ||||
| 	th = emu->cur_thread; | ||||
| 	row = th->gindex + 1; | ||||
| 
 | ||||
| 	if(st == TH_ST_RUNNING) | ||||
| 		prv_ev_thread(emu, row, PTT_THREAD_TID, tid); | ||||
| 	prv_ev_thread(emu, row, PTT_THREAD_STATE, th->state); | ||||
| 
 | ||||
| 	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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user