#include #include #include #include #include #include #include #include #include #include #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; ipayload.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; inthreads; 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; instreams; 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; instreams; 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; inthreads; 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; itrace.nlooms; i++) { loom = &emu->trace.loom[i]; for(j=0; jnprocs; j++) { proc = &loom->proc[j]; for(k=0; knthreads; 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; }