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
|
# Debug CFLAGS
|
||||||
#CFLAGS+=-fsanitize=address
|
#CFLAGS+=-fsanitize=address
|
||||||
#LDFLAGS+=-fsanitize=address
|
#LDFLAGS+=-fsanitize=address
|
||||||
#CFLAGS+=-g -O0
|
CFLAGS+=-g -O0
|
||||||
|
|
||||||
# Performance CFLAGS
|
# Performance CFLAGS
|
||||||
CFLAGS+=-O3
|
#CFLAGS+=-O3
|
||||||
CFLAGS+=-fstack-protector-explicit
|
#CFLAGS+=-fstack-protector-explicit
|
||||||
CFLAGS+=-flto
|
#CFLAGS+=-flto
|
||||||
|
|
||||||
BIN=dump libovni.a test_speed ovni2prv
|
BIN=dump libovni.a test_speed ovni2prv emu
|
||||||
#BIN=dump libovni.a prvth test_speed emu
|
|
||||||
|
|
||||||
all: $(BIN)
|
all: $(BIN)
|
||||||
|
|
||||||
@ -22,7 +21,7 @@ dump: ovni.o dump.o
|
|||||||
|
|
||||||
test_speed: test_speed.c ovni.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
|
ovni2prv: ovni2prv.c ovni.o
|
||||||
|
|
||||||
|
4
dump.c
4
dump.c
@ -9,6 +9,8 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
#include "ovni.h"
|
#include "ovni.h"
|
||||||
|
#include "ovni_trace.h"
|
||||||
|
#include "emu.h"
|
||||||
|
|
||||||
#define ENABLE_DEBUG
|
#define ENABLE_DEBUG
|
||||||
|
|
||||||
@ -58,7 +60,7 @@ void emit(struct ovni_stream *stream, struct ovni_ev *ev)
|
|||||||
payloadsize = ovni_payload_size(ev);
|
payloadsize = ovni_payload_size(ev);
|
||||||
for(i=0; i<payloadsize; i++)
|
for(i=0; i<payloadsize; i++)
|
||||||
{
|
{
|
||||||
printf("%d ", ev->payload.payload_u8[i]);
|
printf("%02x ", ev->payload.u8[i]);
|
||||||
}
|
}
|
||||||
printf("\n");
|
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 <dirent.h>
|
||||||
|
|
||||||
#include "ovni.h"
|
#include "ovni.h"
|
||||||
|
#include "ovni_trace.h"
|
||||||
|
|
||||||
#define ENABLE_DEBUG
|
#define ENABLE_DEBUG
|
||||||
|
|
||||||
@ -237,9 +238,9 @@ hexdump(uint8_t *buf, size_t size)
|
|||||||
{
|
{
|
||||||
for(j=0; j<16 && i+j < size; j++)
|
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
|
int
|
||||||
ovni_payload_size(struct ovni_ev *ev)
|
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
|
void
|
||||||
ovni_payload_add(struct ovni_ev *ev, uint8_t *buf, int size)
|
ovni_payload_add(struct ovni_ev *ev, uint8_t *buf, int size)
|
||||||
{
|
{
|
||||||
/* Ensure we have room */
|
int payload_size;
|
||||||
assert(ovni_payload_size(ev) + size < 16);
|
|
||||||
|
|
||||||
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
|
int
|
||||||
@ -412,6 +431,7 @@ load_proc(struct ovni_eproc *proc, char *procdir)
|
|||||||
|
|
||||||
sprintf(path, "%s/%s", procdir, dirent->d_name);
|
sprintf(path, "%s/%s", procdir, dirent->d_name);
|
||||||
thread->f = fopen(path, "r");
|
thread->f = fopen(path, "r");
|
||||||
|
thread->state = TH_ST_UNKNOWN;
|
||||||
|
|
||||||
if(thread->f == NULL)
|
if(thread->f == NULL)
|
||||||
{
|
{
|
||||||
|
115
ovni.h
115
ovni.h
@ -1,13 +1,12 @@
|
|||||||
#ifndef OVNI_H
|
#ifndef OVNI_H
|
||||||
#define OVNI_H
|
#define OVNI_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
|
|
||||||
#include "ovni.h"
|
|
||||||
|
|
||||||
#define OVNI_MAX_CPU 256
|
#define OVNI_MAX_CPU 256
|
||||||
#define OVNI_MAX_PROC 32
|
#define OVNI_MAX_PROC 32
|
||||||
#define OVNI_MAX_THR 32
|
#define OVNI_MAX_THR 32
|
||||||
@ -19,6 +18,17 @@
|
|||||||
|
|
||||||
/* ----------------------- common ------------------------ */
|
/* ----------------------- 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 {
|
struct __attribute__((__packed__)) ovni_ev {
|
||||||
/* first 4 bits reserved, last 4 for payload size */
|
/* first 4 bits reserved, last 4 for payload size */
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
@ -27,12 +37,7 @@ struct __attribute__((__packed__)) ovni_ev {
|
|||||||
uint8_t value;
|
uint8_t value;
|
||||||
uint16_t clock_hi;
|
uint16_t clock_hi;
|
||||||
uint32_t clock_lo;
|
uint32_t clock_lo;
|
||||||
union {
|
union ovni_ev_payload payload;
|
||||||
uint8_t payload_u8[16];
|
|
||||||
uint16_t payload_u16[8];
|
|
||||||
uint32_t payload_u32[4];
|
|
||||||
uint64_t payload_u64[2];
|
|
||||||
} payload;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ----------------------- runtime ------------------------ */
|
/* ----------------------- runtime ------------------------ */
|
||||||
@ -75,93 +80,6 @@ struct ovni_rproc {
|
|||||||
int ready;
|
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_proc_init(int loom, int proc);
|
||||||
|
|
||||||
int ovni_thread_init(pid_t tid);
|
int ovni_thread_init(pid_t tid);
|
||||||
@ -185,12 +103,5 @@ void ovni_ev(struct ovni_ev *ev);
|
|||||||
|
|
||||||
int ovni_flush();
|
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 */
|
#endif /* OVNI_H */
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
#include "ovni.h"
|
#include "ovni.h"
|
||||||
|
#include "ovni_trace.h"
|
||||||
|
|
||||||
void emit(struct ovni_stream *stream, struct ovni_ev *ev)
|
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…
Reference in New Issue
Block a user