Distribute emulator into modules
This commit is contained in:
		
							parent
							
								
									cfc4eb7527
								
							
						
					
					
						commit
						d25bbed350
					
				
							
								
								
									
										13
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								Makefile
									
									
									
									
									
								
							| @ -3,15 +3,14 @@ CFLAGS=-fPIC | ||||
| # Debug CFLAGS
 | ||||
| #CFLAGS+=-fsanitize=address
 | ||||
| #LDFLAGS+=-fsanitize=address
 | ||||
| #CFLAGS+=-g -O0
 | ||||
| CFLAGS+=-g -O0 | ||||
| 
 | ||||
| # Performance CFLAGS
 | ||||
| CFLAGS+=-O3 | ||||
| CFLAGS+=-fstack-protector-explicit | ||||
| CFLAGS+=-flto | ||||
| #CFLAGS+=-O3
 | ||||
| #CFLAGS+=-fstack-protector-explicit
 | ||||
| #CFLAGS+=-flto
 | ||||
| 
 | ||||
| BIN=dump libovni.a test_speed ovni2prv | ||||
| #BIN=dump libovni.a prvth test_speed emu
 | ||||
| BIN=dump libovni.a test_speed ovni2prv emu | ||||
| 
 | ||||
| all: $(BIN) | ||||
| 
 | ||||
| @ -22,7 +21,7 @@ dump: ovni.o dump.o | ||||
| 
 | ||||
| test_speed: test_speed.c ovni.o | ||||
| 
 | ||||
| emu: emu.c ovni.o | ||||
| emu: emu.o emu_ovni.o emu_nosv.o ovni.o | ||||
| 
 | ||||
| ovni2prv: ovni2prv.c ovni.o | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										4
									
								
								dump.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								dump.c
									
									
									
									
									
								
							| @ -9,6 +9,8 @@ | ||||
| #include <dirent.h>  | ||||
| 
 | ||||
| #include "ovni.h" | ||||
| #include "ovni_trace.h" | ||||
| #include "emu.h" | ||||
| 
 | ||||
| #define ENABLE_DEBUG | ||||
| 
 | ||||
| @ -58,7 +60,7 @@ void emit(struct ovni_stream *stream, struct ovni_ev *ev) | ||||
| 	payloadsize = ovni_payload_size(ev); | ||||
| 	for(i=0; i<payloadsize; i++) | ||||
| 	{ | ||||
| 		printf("%d ", ev->payload.payload_u8[i]); | ||||
| 		printf("%02x ", ev->payload.u8[i]); | ||||
| 	} | ||||
| 	printf("\n"); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										312
									
								
								emu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										312
									
								
								emu.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,312 @@ | ||||
| #include <stdio.h> | ||||
| #include <stdint.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <linux/limits.h> | ||||
| #include <errno.h> | ||||
| #include <sys/stat.h> | ||||
| #include <stdatomic.h> | ||||
| #include <dirent.h>  | ||||
| #include <assert.h>  | ||||
| 
 | ||||
| #include "ovni.h" | ||||
| #include "ovni_trace.h" | ||||
| #include "emu.h" | ||||
| 
 | ||||
| static void | ||||
| emit_ev(struct ovni_stream *stream, struct ovni_ev *ev) | ||||
| { | ||||
| 	int64_t delta; | ||||
| 	uint64_t clock; | ||||
| 	int i, payloadsize; | ||||
| 
 | ||||
| 	//dbg("sizeof(*ev) = %d\n", sizeof(*ev));
 | ||||
| 	//hexdump((uint8_t *) ev, sizeof(*ev));
 | ||||
| 
 | ||||
| 	clock = ovni_ev_get_clock(ev); | ||||
| 
 | ||||
| 	delta = clock - stream->lastclock; | ||||
| 
 | ||||
| 	dbg("%d.%d.%d %c %c %c % 20lu % 15ld ", | ||||
| 			stream->loom, stream->proc, stream->tid, | ||||
| 			ev->model, ev->class, ev->value, clock, delta); | ||||
| 
 | ||||
| 	payloadsize = ovni_payload_size(ev); | ||||
| 	for(i=0; i<payloadsize; i++) | ||||
| 	{ | ||||
| 		dbg("%d ", ev->payload.u8[i]); | ||||
| 	} | ||||
| 	dbg("\n"); | ||||
| 
 | ||||
| 	stream->lastclock = clock; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| emu_emit(struct ovni_emu *emu) | ||||
| { | ||||
| 	emit_ev(emu->cur_stream, emu->cur_ev); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| load_first_event(struct ovni_stream *stream) | ||||
| { | ||||
| 	int i; | ||||
| 	size_t n; | ||||
| 	struct ovni_ev *ev; | ||||
| 
 | ||||
| 	if(!stream->active) | ||||
| 		return; | ||||
| 
 | ||||
| 	ev = &stream->last; | ||||
| 	if((n = fread(ev, sizeof(*ev), 1, stream->f)) != 1) | ||||
| 	{ | ||||
| 		//fprintf(stderr, "failed to read an event, n=%ld\n", n);
 | ||||
| 		stream->active = 0; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	stream->active = 1; | ||||
| } | ||||
| 
 | ||||
| struct ovni_ethread * | ||||
| find_thread(struct ovni_eproc *proc, pid_t tid) | ||||
| { | ||||
| 	int i; | ||||
| 	struct ovni_ethread *thread; | ||||
| 
 | ||||
| 	for(i=0; i<proc->nthreads; i++) | ||||
| 	{ | ||||
| 		thread = &proc->thread[i]; | ||||
| 		if(thread->tid == tid) | ||||
| 			return thread; | ||||
| 	} | ||||
| 
 | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| step_emulator(struct ovni_emu *emu) | ||||
| { | ||||
| 	//emu_emit(emu);
 | ||||
| 
 | ||||
| 	switch(emu->cur_ev->model) | ||||
| 	{ | ||||
| 		case 'O': emu_process_ovni_ev(emu); break; | ||||
| 		//case 'V': emu_process_nosv_ev(emu); break;
 | ||||
| 		//case 'M': emu_process_tampi_ev(emu); break;
 | ||||
| 		default: | ||||
| 			  //dbg("unknown model %c\n", emu->cur_ev->model);
 | ||||
| 			  break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| set_current(struct ovni_emu *emu, struct ovni_stream *stream) | ||||
| { | ||||
| 	emu->cur_stream = stream; | ||||
| 	emu->cur_ev = &stream->last; | ||||
| 	emu->cur_loom = &emu->trace.loom[stream->loom]; | ||||
| 	emu->cur_proc = &emu->cur_loom->proc[stream->proc]; | ||||
| 	emu->cur_thread = &emu->cur_proc->thread[stream->thread]; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| next_event(struct ovni_emu *emu) | ||||
| { | ||||
| 	int i, f; | ||||
| 	uint64_t minclock; | ||||
| 	struct ovni_ev *ev; | ||||
| 	struct ovni_stream *stream; | ||||
| 	struct ovni_trace *trace; | ||||
| 
 | ||||
| 	trace = &emu->trace; | ||||
| 
 | ||||
| 	f = -1; | ||||
| 	minclock = 0; | ||||
| 
 | ||||
| 	/* TODO: use a heap */ | ||||
| 
 | ||||
| 	/* Select next event based on the clock */ | ||||
| 	for(i=0; i<trace->nstreams; i++) | ||||
| 	{ | ||||
| 		stream = &trace->stream[i]; | ||||
| 
 | ||||
| 		if(!stream->active) | ||||
| 			continue; | ||||
| 
 | ||||
| 		ev = &stream->last; | ||||
| 		if(f < 0 || ovni_ev_get_clock(ev) < minclock) | ||||
| 		{ | ||||
| 			f = i; | ||||
| 			minclock = ovni_ev_get_clock(ev); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if(f < 0) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	/* We have a valid stream with a new event */ | ||||
| 	stream = &trace->stream[f]; | ||||
| 
 | ||||
| 	set_current(emu, stream); | ||||
| 
 | ||||
| 	if(emu->lastclock > ovni_ev_get_clock(&stream->last)) | ||||
| 	{ | ||||
| 		fprintf(stdout, "warning: backwards jump in time %lu -> %lu\n", | ||||
| 				emu->lastclock, ovni_ev_get_clock(&stream->last)); | ||||
| 	} | ||||
| 
 | ||||
| 	emu->lastclock = ovni_ev_get_clock(&stream->last); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| emulate(struct ovni_emu *emu) | ||||
| { | ||||
| 	int i; | ||||
| 	struct ovni_ev ev; | ||||
| 	struct ovni_stream *stream; | ||||
| 	struct ovni_trace *trace; | ||||
| 
 | ||||
| 	/* Load events */ | ||||
| 	trace = &emu->trace; | ||||
| 	for(i=0; i<trace->nstreams; i++) | ||||
| 	{ | ||||
| 		stream = &trace->stream[i]; | ||||
| 		ovni_load_next_event(stream); | ||||
| 	} | ||||
| 
 | ||||
| 	emu->lastclock = 0; | ||||
| 
 | ||||
| 	/* Then process all events */ | ||||
| 	while(next_event(emu) == 0) | ||||
| 	{ | ||||
| 		//fprintf(stdout, "step %i\n", i);
 | ||||
| 		step_emulator(emu); | ||||
| 
 | ||||
| 		/* Read the next event */ | ||||
| 		ovni_load_next_event(emu->cur_stream); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int | ||||
| emu_cpu_find_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for(i=0; i<cpu->nthreads; i++) | ||||
| 		if(cpu->thread[i] == thread) | ||||
| 			break; | ||||
| 
 | ||||
| 	/* Not found */ | ||||
| 	if(i >= cpu->nthreads) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	return i; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| emu_cpu_remove_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread) | ||||
| { | ||||
| 	int i, j; | ||||
| 
 | ||||
| 	i = emu_cpu_find_thread(cpu, thread); | ||||
| 
 | ||||
| 	/* Not found, abort */ | ||||
| 	if(i < 0) | ||||
| 		abort(); | ||||
| 
 | ||||
| 	for(j=i; j+1 < cpu->nthreads; j++) | ||||
| 	{ | ||||
| 		cpu->thread[i] = cpu->thread[j+1]; | ||||
| 	} | ||||
| 
 | ||||
| 	cpu->nthreads--; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| emu_cpu_add_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread) | ||||
| { | ||||
| 	/* Found, abort */ | ||||
| 	if(emu_cpu_find_thread(cpu, thread) >= 0) | ||||
| 		abort(); | ||||
| 
 | ||||
| 	assert(cpu->nthreads < OVNI_MAX_THR); | ||||
| 
 | ||||
| 	cpu->thread[cpu->nthreads++] = thread; | ||||
| } | ||||
| 
 | ||||
| struct ovni_cpu * | ||||
| emu_get_cpu(struct ovni_emu *emu, int cpuid) | ||||
| { | ||||
| 	assert(cpuid < OVNI_MAX_CPU); | ||||
| 
 | ||||
| 	if(cpuid < 0) | ||||
| 	{ | ||||
| 		return &emu->vcpu; | ||||
| 	} | ||||
| 
 | ||||
| 	return &emu->cpu[emu->cpuind[cpuid]]; | ||||
| } | ||||
| 
 | ||||
| struct ovni_ethread * | ||||
| emu_get_thread(struct ovni_emu *emu, int tid) | ||||
| { | ||||
| 	int i, j, k; | ||||
| 	struct ovni_loom *loom; | ||||
| 	struct ovni_eproc *proc; | ||||
| 	struct ovni_ethread *thread; | ||||
| 
 | ||||
| 	for(i=0; i<emu->trace.nlooms; i++) | ||||
| 	{ | ||||
| 		loom = &emu->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]; | ||||
| 				if(thread->tid == tid) | ||||
| 				{ | ||||
| 					/* Only same process threads can
 | ||||
| 					 * change the affinity to each | ||||
| 					 * others */ | ||||
| 					assert(emu->cur_proc == proc); | ||||
| 					return thread; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return thread; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	char *tracedir; | ||||
| 	struct ovni_emu emu; | ||||
| 
 | ||||
| 	if(argc != 2) | ||||
| 	{ | ||||
| 		fprintf(stderr, "missing tracedir\n"); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
| 
 | ||||
| 	tracedir = argv[1]; | ||||
| 
 | ||||
| 	memset(&emu, 0, sizeof(emu)); | ||||
| 
 | ||||
| 	if(ovni_load_trace(&emu.trace, tracedir)) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	if(ovni_load_streams(&emu.trace)) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	emulate(&emu); | ||||
| 
 | ||||
| 	ovni_free_streams(&emu.trace); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										151
									
								
								emu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								emu.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,151 @@ | ||||
| #ifndef OVNI_EMU_H | ||||
| #define OVNI_EMU_H | ||||
| 
 | ||||
| #include "ovni.h" | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| /* Debug macros */ | ||||
| 
 | ||||
| #define ENABLE_DEBUG | ||||
| 
 | ||||
| #ifdef ENABLE_DEBUG | ||||
| # define dbg(...) fprintf(stderr, __VA_ARGS__); | ||||
| #else | ||||
| # define dbg(...) | ||||
| #endif | ||||
| 
 | ||||
| #define err(...) fprintf(stderr, __VA_ARGS__); | ||||
| 
 | ||||
| /* Emulated thread runtime status */ | ||||
| enum ethread_state { | ||||
| 	TH_ST_UNKNOWN, | ||||
| 	TH_ST_RUNNING, | ||||
| 	TH_ST_PAUSED, | ||||
| 	TH_ST_DEAD, | ||||
| }; | ||||
| 
 | ||||
| /* State of each emulated thread */ | ||||
| struct ovni_ethread { | ||||
| 	/* Emulated thread tid */ | ||||
| 	pid_t tid; | ||||
| 
 | ||||
| 	/* Stream file */ | ||||
| 	FILE *f; | ||||
| 
 | ||||
| 	enum ethread_state state; | ||||
| 
 | ||||
| 	/* Thread stream */ | ||||
| 	struct ovni_stream *stream; | ||||
| 
 | ||||
| 	/* Current cpu */ | ||||
| 	struct ovni_cpu *cpu; | ||||
| }; | ||||
| 
 | ||||
| /* State of each emulated process */ | ||||
| struct ovni_eproc { | ||||
| 	/* Monotonic counter for process index */ | ||||
| 	/* TODO: Use pid? */ | ||||
| 	int proc; | ||||
| 
 | ||||
| 	/* Path of the process tracedir */ | ||||
| 	char dir[PATH_MAX]; | ||||
| 
 | ||||
| 	/* Threads */ | ||||
| 	size_t nthreads; | ||||
| 	struct ovni_ethread thread[OVNI_MAX_THR]; | ||||
| }; | ||||
| 
 | ||||
| /* ----------------------- trace ------------------------ */ | ||||
| 
 | ||||
| /* State of each loom on post-process */ | ||||
| struct ovni_loom { | ||||
| 	size_t nprocs; | ||||
| 	struct ovni_eproc proc[OVNI_MAX_PROC]; | ||||
| }; | ||||
| 
 | ||||
| struct ovni_stream { | ||||
| 	FILE *f; | ||||
| 	int tid; | ||||
| 	int thread; | ||||
| 	int proc; | ||||
| 	int loom; | ||||
| 	int loaded; | ||||
| 	int active; | ||||
| 	struct ovni_ev last; | ||||
| 	uint64_t lastclock; | ||||
| }; | ||||
| 
 | ||||
| struct ovni_trace { | ||||
| 	int nlooms; | ||||
| 	struct ovni_loom loom[OVNI_MAX_LOOM]; | ||||
| 	int nstreams; | ||||
| 	struct ovni_stream *stream; | ||||
| }; | ||||
| 
 | ||||
| /* ------------------ emulation ---------------- */ | ||||
| 
 | ||||
| enum ovni_cpu_type { | ||||
| 	CPU_REAL, | ||||
| 	CPU_VIRTUAL, | ||||
| }; | ||||
| 
 | ||||
| enum ovni_cpu_state { | ||||
| 	CPU_ST_UNKNOWN, | ||||
| 	CPU_ST_READY, | ||||
| }; | ||||
| 
 | ||||
| struct ovni_cpu { | ||||
| 	/* Physical id */ | ||||
| 	int cpu_id; | ||||
| 
 | ||||
| 	/* Position in emu->cpu */ | ||||
| 	int index; | ||||
| 
 | ||||
| 	enum ovni_cpu_state state; | ||||
| 	enum ovni_cpu_type type; | ||||
| 
 | ||||
| 	/* The threads the cpu is currently running */ | ||||
| 	size_t nthreads; | ||||
| 	struct ovni_ethread *thread[OVNI_MAX_THR]; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| struct ovni_emu { | ||||
| 	struct ovni_trace trace; | ||||
| 
 | ||||
| 	/* Physical CPUs */ | ||||
| 	int max_ncpus; | ||||
| 	int ncpus; | ||||
| 	struct ovni_cpu cpu[OVNI_MAX_CPU]; | ||||
| 	int cpuind[OVNI_MAX_CPU]; | ||||
| 
 | ||||
| 	/* Virtual CPU */ | ||||
| 	struct ovni_cpu vcpu; | ||||
| 
 | ||||
| 	struct ovni_stream *cur_stream; | ||||
| 	struct ovni_ev *cur_ev; | ||||
| 
 | ||||
| 	struct ovni_loom *cur_loom; | ||||
| 	struct ovni_eproc *cur_proc; | ||||
| 	struct ovni_ethread *cur_thread; | ||||
| 
 | ||||
| 	uint64_t lastclock; | ||||
| }; | ||||
| 
 | ||||
| /* Emulator function declaration */ | ||||
| 
 | ||||
| void emu_emit(struct ovni_emu *emu); | ||||
| void emu_process_ovni_ev(struct ovni_emu *emu); | ||||
| 
 | ||||
| 
 | ||||
| int emu_cpu_find_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread); | ||||
| 
 | ||||
| void emu_cpu_remove_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread); | ||||
| 
 | ||||
| void emu_cpu_add_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread); | ||||
| 
 | ||||
| struct ovni_cpu *emu_get_cpu(struct ovni_emu *emu, int cpuid); | ||||
| 
 | ||||
| struct ovni_ethread *emu_get_thread(struct ovni_emu *emu, int tid); | ||||
| 
 | ||||
| #endif /* OVNI_EMU_H */ | ||||
							
								
								
									
										13
									
								
								emu_nosv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								emu_nosv.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| #include "ovni.h" | ||||
| #include "ovni_trace.h" | ||||
| #include "emu.h" | ||||
| 
 | ||||
| int | ||||
| emu_nosv_thread_init(struct ovni_emu *emu, struct ovni_ethread *thread) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| int | ||||
| emu_nosv_process_ev(struct ovni_emu *emu) | ||||
| { | ||||
| } | ||||
							
								
								
									
										265
									
								
								emu_ovni.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								emu_ovni.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,265 @@ | ||||
| #include "ovni.h" | ||||
| #include "emu.h" | ||||
| 
 | ||||
| #include <assert.h> | ||||
| 
 | ||||
| static void | ||||
| print_threads_state(struct ovni_emu *emu) | ||||
| { | ||||
| 	struct ovni_cpu *cpu; | ||||
| 	int i, j; | ||||
| 
 | ||||
| 	for(i=0; i<emu->ncpus; i++) | ||||
| 	{ | ||||
| 		cpu = &emu->cpu[i]; | ||||
| 
 | ||||
| 		dbg("-- cpu %d runs %d threads:", i, cpu->nthreads); | ||||
| 		for(j=0; j<cpu->nthreads; j++) | ||||
| 		{ | ||||
| 			dbg(" %d", cpu->thread[j]->tid); | ||||
| 		} | ||||
| 		dbg("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	dbg("-- vcpu runs %d threads:", emu->vcpu.nthreads); | ||||
| 	for(j=0; j<emu->vcpu.nthreads; j++) | ||||
| 	{ | ||||
| 		dbg(" %d", emu->vcpu.thread[j]->tid); | ||||
| 	} | ||||
| 	dbg("\n"); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| ev_thread_execute(struct ovni_emu *emu) | ||||
| { | ||||
| 	struct ovni_cpu *cpu; | ||||
| 	int cpuid; | ||||
| 
 | ||||
| 	/* The thread cannot be already running */ | ||||
| 	assert(emu->cur_thread->state != TH_ST_RUNNING); | ||||
| 
 | ||||
| 	cpuid = emu->cur_ev->payload.i32[0]; | ||||
| 	dbg("thread %d runs in cpuid %d\n", emu->cur_thread->tid, | ||||
| 			cpuid); | ||||
| 	cpu = emu_get_cpu(emu, cpuid); | ||||
| 
 | ||||
| 	emu->cur_thread->state = TH_ST_RUNNING; | ||||
| 	emu->cur_thread->cpu = cpu; | ||||
| 
 | ||||
| 	emu_cpu_add_thread(cpu, emu->cur_thread); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| ev_thread_end(struct ovni_emu *emu) | ||||
| { | ||||
| 	assert(emu->cur_thread->state == TH_ST_RUNNING); | ||||
| 	assert(emu->cur_thread->cpu); | ||||
| 
 | ||||
| 	emu_cpu_remove_thread(emu->cur_thread->cpu, emu->cur_thread); | ||||
| 
 | ||||
| 	emu->cur_thread->state = TH_ST_DEAD; | ||||
| 	emu->cur_thread->cpu = NULL; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| ev_thread_pause(struct ovni_emu *emu) | ||||
| { | ||||
| 	assert(emu->cur_thread->state == TH_ST_RUNNING); | ||||
| 	assert(emu->cur_thread->cpu); | ||||
| 
 | ||||
| 	emu_cpu_remove_thread(emu->cur_thread->cpu, emu->cur_thread); | ||||
| 
 | ||||
| 	emu->cur_thread->state = TH_ST_PAUSED; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| ev_thread_resume(struct ovni_emu *emu) | ||||
| { | ||||
| 	assert(emu->cur_thread->state == TH_ST_PAUSED); | ||||
| 	assert(emu->cur_thread->cpu); | ||||
| 
 | ||||
| 	emu_cpu_add_thread(emu->cur_thread->cpu, emu->cur_thread); | ||||
| 
 | ||||
| 	emu->cur_thread->state = TH_ST_RUNNING; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| ev_thread(struct ovni_emu *emu) | ||||
| { | ||||
| 	struct ovni_ev *ev; | ||||
| 	struct ovni_cpu *cpu; | ||||
| 	struct ovni_ethread *thread, *remote_thread; | ||||
| 	int i; | ||||
| 
 | ||||
| 	emu_emit(emu); | ||||
| 
 | ||||
| 	thread = emu->cur_thread; | ||||
| 	cpu = thread->cpu; | ||||
| 	ev = emu->cur_ev; | ||||
| 
 | ||||
| 	switch(ev->value) | ||||
| 	{ | ||||
| 		case 'c': /* create */ | ||||
| 			dbg("thread %d creates a new thread at cpu=%d with args=%x %x\n", | ||||
| 					thread->tid, | ||||
| 					ev->payload.u32[0], | ||||
| 					ev->payload.u32[1], | ||||
| 					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; | ||||
| 		default: | ||||
| 			break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| ev_affinity_set(struct ovni_emu *emu) | ||||
| { | ||||
| 	int cpuid; | ||||
| 	struct ovni_cpu *newcpu; | ||||
| 
 | ||||
| 	cpuid = emu->cur_ev->payload.i32[0]; | ||||
| 
 | ||||
| 	assert(emu->cur_thread->state == TH_ST_RUNNING); | ||||
| 	assert(emu->cur_thread->cpu); | ||||
| 
 | ||||
| 	/* Migrate current cpu to the one at cpuid */ | ||||
| 	newcpu = emu_get_cpu(emu, cpuid); | ||||
| 
 | ||||
| 	emu_cpu_remove_thread(emu->cur_thread->cpu, emu->cur_thread); | ||||
| 	emu_cpu_add_thread(newcpu, emu->cur_thread); | ||||
| 
 | ||||
| 	emu->cur_thread->cpu = newcpu; | ||||
| 
 | ||||
| 	dbg("cpu %d now runs %d\n", cpuid, emu->cur_thread->tid); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| ev_affinity_remote(struct ovni_emu *emu) | ||||
| { | ||||
| 	int cpuid, tid; | ||||
| 	struct ovni_cpu *newcpu; | ||||
| 	struct ovni_ethread *thread; | ||||
| 
 | ||||
| 	cpuid = emu->cur_ev->payload.i32[0]; | ||||
| 	tid = emu->cur_ev->payload.i32[1]; | ||||
| 
 | ||||
| 	thread = emu_get_thread(emu, tid); | ||||
| 
 | ||||
| 	assert(thread); | ||||
| 	assert(thread->state == TH_ST_PAUSED); | ||||
| 	assert(thread->cpu); | ||||
| 
 | ||||
| 	newcpu = emu_get_cpu(emu, cpuid); | ||||
| 
 | ||||
| 	/* It must not be running in any of the cpus */ | ||||
| 	assert(emu_cpu_find_thread(thread->cpu, thread) == -1); | ||||
| 	assert(emu_cpu_find_thread(newcpu, thread) == -1); | ||||
| 
 | ||||
| 	thread->cpu = newcpu; | ||||
| 
 | ||||
| 	dbg("thread %d switches to cpu %d by remote petition\n", tid, | ||||
| 			cpuid); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| ev_affinity(struct ovni_emu *emu) | ||||
| { | ||||
| 	emu_emit(emu); | ||||
| 	switch(emu->cur_ev->value) | ||||
| 	{ | ||||
| 		case 's': ev_affinity_set(emu); break; | ||||
| 		case 'r': ev_affinity_remote(emu); break; | ||||
| 		default: | ||||
| 			dbg("unknown affinity event value %c\n", | ||||
| 					emu->cur_ev->value); | ||||
| 			break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| ev_cpu_count(struct ovni_emu *emu) | ||||
| { | ||||
| 	int i, ncpus, maxcpu; | ||||
| 
 | ||||
| 	ncpus = emu->cur_ev->payload.i32[0]; | ||||
| 	maxcpu = emu->cur_ev->payload.i32[1]; | ||||
| 
 | ||||
| 	assert(ncpus < OVNI_MAX_CPU); | ||||
| 	assert(maxcpu < OVNI_MAX_CPU); | ||||
| 
 | ||||
| 	for(i=0; i<OVNI_MAX_CPU; i++) | ||||
| 	{ | ||||
| 		emu->cpu[i].state = CPU_ST_UNKNOWN; | ||||
| 		emu->cpu[i].cpu_id = -1; | ||||
| 		emu->cpuind[i] = -1; | ||||
| 	} | ||||
| 
 | ||||
| 	emu->ncpus = 0; | ||||
| 	emu->max_ncpus = ncpus; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| ev_cpu_id(struct ovni_emu *emu) | ||||
| { | ||||
| 	int cpuid; | ||||
| 
 | ||||
| 	cpuid = emu->cur_ev->payload.i32[0]; | ||||
| 
 | ||||
| 	assert(cpuid < emu->max_ncpus); | ||||
| 	assert(emu->ncpus < emu->max_ncpus); | ||||
| 	assert(emu->ncpus < OVNI_MAX_CPU); | ||||
| 
 | ||||
| 	assert(emu->cpu[emu->ncpus].state == CPU_ST_UNKNOWN); | ||||
| 
 | ||||
| 	emu->cpu[emu->ncpus].state = CPU_ST_READY; | ||||
| 	emu->cpu[emu->ncpus].cpu_id = cpuid; | ||||
| 	emu->cpu[emu->ncpus].index = emu->ncpus; | ||||
| 
 | ||||
| 	/* Fill the translation to cpu index too */ | ||||
| 	assert(emu->cpuind[cpuid] == -1); | ||||
| 	emu->cpuind[cpuid] = emu->ncpus; | ||||
| 
 | ||||
| 	dbg("new cpu id=%d at %d\n", cpuid, emu->ncpus); | ||||
| 
 | ||||
| 	emu->ncpus++; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void | ||||
| ev_cpu(struct ovni_emu *emu) | ||||
| { | ||||
| 	switch(emu->cur_ev->value) | ||||
| 	{ | ||||
| 		case 'n': ev_cpu_count(emu); break; | ||||
| 		case 'i': ev_cpu_id(emu); break; | ||||
| 		default: | ||||
| 			dbg("unknown cpu event value %c\n", | ||||
| 					emu->cur_ev->value); | ||||
| 			break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void | ||||
| emu_process_ovni_ev(struct ovni_emu *emu) | ||||
| { | ||||
| 	//emu_emit(emu);
 | ||||
| 
 | ||||
| 	switch(emu->cur_ev->class) | ||||
| 	{ | ||||
| 		case 'H': ev_thread(emu); break; | ||||
| 		case 'A': ev_affinity(emu); break; | ||||
| 		case 'C': ev_cpu(emu); break; | ||||
| 		case 'B': dbg("burst %c\n", emu->cur_ev->value); break; | ||||
| 		default: | ||||
| 			dbg("unknown ovni event class %c\n", | ||||
| 					emu->cur_ev->class); | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	print_threads_state(emu); | ||||
| } | ||||
							
								
								
									
										32
									
								
								ovni.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								ovni.c
									
									
									
									
									
								
							| @ -17,6 +17,7 @@ | ||||
| #include <dirent.h> | ||||
| 
 | ||||
| #include "ovni.h" | ||||
| #include "ovni_trace.h" | ||||
| 
 | ||||
| #define ENABLE_DEBUG | ||||
| 
 | ||||
| @ -237,9 +238,9 @@ hexdump(uint8_t *buf, size_t size) | ||||
| 	{ | ||||
| 		for(j=0; j<16 && i+j < size; j++) | ||||
| 		{ | ||||
| 			printf("%02x ", buf[i+j]); | ||||
| 			dbg("%02x ", buf[i+j]); | ||||
| 		} | ||||
| 		printf("\n"); | ||||
| 		dbg("\n"); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -307,16 +308,34 @@ ovni_ev_set_mcv(struct ovni_ev *ev, char *mcv) | ||||
| int | ||||
| ovni_payload_size(struct ovni_ev *ev) | ||||
| { | ||||
| 	return ev->flags & 0x0f; | ||||
| 	int size; | ||||
| 
 | ||||
| 	size = ev->flags & 0x0f; | ||||
| 
 | ||||
| 	if(size == 0) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* The minimum size is 2 bytes, so we can encode a length of 16
 | ||||
| 	 * bytes using 4 bits (0x0f) */ | ||||
| 	size++; | ||||
| 
 | ||||
| 	return size; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| ovni_payload_add(struct ovni_ev *ev, uint8_t *buf, int size) | ||||
| { | ||||
| 	/* Ensure we have room */ | ||||
| 	assert(ovni_payload_size(ev) + size < 16); | ||||
| 	int payload_size; | ||||
| 
 | ||||
| 	ev->flags = ev->flags & 0xf0 | size & 0x0f; | ||||
| 	payload_size = ovni_payload_size(ev); | ||||
| 
 | ||||
| 	/* Ensure we have room */ | ||||
| 	assert(payload_size + size <= sizeof(ev->payload)); | ||||
| 
 | ||||
| 	memcpy(&ev->payload.u8[payload_size], buf, size); | ||||
| 	payload_size += size; | ||||
| 
 | ||||
| 	ev->flags = ev->flags & 0xf0 | (payload_size-1) & 0x0f; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| @ -412,6 +431,7 @@ load_proc(struct ovni_eproc *proc, char *procdir) | ||||
| 
 | ||||
| 		sprintf(path, "%s/%s", procdir, dirent->d_name); | ||||
| 		thread->f = fopen(path, "r"); | ||||
| 		thread->state = TH_ST_UNKNOWN; | ||||
| 
 | ||||
| 		if(thread->f == NULL) | ||||
| 		{ | ||||
|  | ||||
							
								
								
									
										115
									
								
								ovni.h
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								ovni.h
									
									
									
									
									
								
							| @ -1,13 +1,12 @@ | ||||
| #ifndef OVNI_H | ||||
| #define OVNI_H | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <stdint.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <linux/limits.h> | ||||
| 
 | ||||
| #include "ovni.h" | ||||
| 
 | ||||
| #define OVNI_MAX_CPU 256 | ||||
| #define OVNI_MAX_PROC 32 | ||||
| #define OVNI_MAX_THR 32 | ||||
| @ -19,6 +18,17 @@ | ||||
| 
 | ||||
| /* ----------------------- common ------------------------ */ | ||||
| 
 | ||||
| union __attribute__((__packed__)) ovni_ev_payload { | ||||
| 	uint8_t u8[16]; | ||||
| 	int8_t i8[16]; | ||||
| 	uint16_t u16[8]; | ||||
| 	int16_t i16[8]; | ||||
| 	uint32_t u32[4]; | ||||
| 	int32_t i32[4]; | ||||
| 	uint64_t u64[2]; | ||||
| 	int64_t i64[2]; | ||||
| }; | ||||
| 
 | ||||
| struct __attribute__((__packed__)) ovni_ev { | ||||
| 	/* first 4 bits reserved, last 4 for payload size */ | ||||
| 	uint8_t flags; | ||||
| @ -27,12 +37,7 @@ struct __attribute__((__packed__)) ovni_ev { | ||||
| 	uint8_t value; | ||||
| 	uint16_t clock_hi; | ||||
| 	uint32_t clock_lo; | ||||
| 	union { | ||||
| 		uint8_t payload_u8[16]; | ||||
| 		uint16_t payload_u16[8]; | ||||
| 		uint32_t payload_u32[4]; | ||||
| 		uint64_t payload_u64[2]; | ||||
| 	} payload; | ||||
| 	union ovni_ev_payload payload; | ||||
| }; | ||||
| 
 | ||||
| /* ----------------------- runtime ------------------------ */ | ||||
| @ -75,93 +80,6 @@ struct ovni_rproc { | ||||
| 	int ready; | ||||
| }; | ||||
| 
 | ||||
| /* ----------------------- emulated ------------------------ */ | ||||
| 
 | ||||
| struct ovni_cpu; | ||||
| 
 | ||||
| /* State of each thread on post-process */ | ||||
| struct ovni_ethread { | ||||
| 	/* Emulated thread tid */ | ||||
| 	pid_t tid; | ||||
| 
 | ||||
| 	/* Stream file */ | ||||
| 	FILE *f; | ||||
| 
 | ||||
| 	/* Thread stream */ | ||||
| 	struct ovni_stream *stream; | ||||
| 
 | ||||
| 	/* Current cpu */ | ||||
| 	struct ovni_cpu *cpu; | ||||
| }; | ||||
| 
 | ||||
| /* State of each process on post-process */ | ||||
| struct ovni_eproc { | ||||
| 	/* Monotonic counter for process index */ | ||||
| 	/* TODO: Use pid? */ | ||||
| 	int proc; | ||||
| 
 | ||||
| 	/* Path of the process tracedir */ | ||||
| 	char dir[PATH_MAX]; | ||||
| 
 | ||||
| 	/* Threads */ | ||||
| 	size_t nthreads; | ||||
| 	struct ovni_ethread thread[OVNI_MAX_THR]; | ||||
| }; | ||||
| 
 | ||||
| /* ----------------------- trace ------------------------ */ | ||||
| 
 | ||||
| /* State of each loom on post-process */ | ||||
| struct ovni_loom { | ||||
| 	size_t nprocs; | ||||
| 	struct ovni_eproc proc[OVNI_MAX_PROC]; | ||||
| }; | ||||
| 
 | ||||
| struct ovni_stream { | ||||
| 	FILE *f; | ||||
| 	int tid; | ||||
| 	int thread; | ||||
| 	int proc; | ||||
| 	int loom; | ||||
| 	int loaded; | ||||
| 	int active; | ||||
| 	struct ovni_ev last; | ||||
| 	uint64_t lastclock; | ||||
| }; | ||||
| 
 | ||||
| struct ovni_trace { | ||||
| 	int nlooms; | ||||
| 	struct ovni_loom loom[OVNI_MAX_LOOM]; | ||||
| 	int nstreams; | ||||
| 	struct ovni_stream *stream; | ||||
| }; | ||||
| 
 | ||||
| struct ovni_cpu { | ||||
| 	/* The thread the cpu is currently running */ | ||||
| 	struct ovni_ethread *thread; | ||||
| }; | ||||
| 
 | ||||
| struct ovni_evhead { | ||||
| 	struct ovni_stream *stream; | ||||
| 
 | ||||
| 	struct ovni_loom *loom; | ||||
| 	struct ovni_eproc *proc; | ||||
| 	struct ovni_ethread *thread; | ||||
| }; | ||||
| 
 | ||||
| struct ovni_emulator { | ||||
| 	struct ovni_trace trace; | ||||
| 	struct ovni_cpu cpu[OVNI_MAX_CPU]; | ||||
| 
 | ||||
| 	struct ovni_evhead head; | ||||
| 	uint64_t lastclock; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int ovni_proc_init(int loom, int proc); | ||||
| 
 | ||||
| int ovni_thread_init(pid_t tid); | ||||
| @ -185,12 +103,5 @@ void ovni_ev(struct ovni_ev *ev); | ||||
| 
 | ||||
| int ovni_flush(); | ||||
| 
 | ||||
| int ovni_load_trace(struct ovni_trace *trace, char *tracedir); | ||||
| 
 | ||||
| int ovni_load_streams(struct ovni_trace *trace); | ||||
| 
 | ||||
| void ovni_free_streams(struct ovni_trace *trace); | ||||
| 
 | ||||
| void ovni_load_next_event(struct ovni_stream *stream); | ||||
| 
 | ||||
| #endif /* OVNI_H */ | ||||
|  | ||||
| @ -9,6 +9,7 @@ | ||||
| #include <dirent.h>  | ||||
| 
 | ||||
| #include "ovni.h" | ||||
| #include "ovni_trace.h" | ||||
| 
 | ||||
| void emit(struct ovni_stream *stream, struct ovni_ev *ev) | ||||
| { | ||||
|  | ||||
							
								
								
									
										15
									
								
								ovni_trace.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								ovni_trace.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| #ifndef OVNI_TRACE_H | ||||
| #define OVNI_TRACE_H | ||||
| 
 | ||||
| #include "ovni.h" | ||||
| #include "emu.h" | ||||
| 
 | ||||
| void ovni_load_next_event(struct ovni_stream *stream); | ||||
| 
 | ||||
| int ovni_load_trace(struct ovni_trace *trace, char *tracedir); | ||||
| 
 | ||||
| int ovni_load_streams(struct ovni_trace *trace); | ||||
| 
 | ||||
| void ovni_free_streams(struct ovni_trace *trace); | ||||
| 
 | ||||
| #endif /* OVNI_TRACE_H */ | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user