diff --git a/dump.c b/dump.c index 51506ae..2fcc349 100644 --- a/dump.c +++ b/dump.c @@ -55,7 +55,7 @@ void emit(struct ovni_stream *stream, struct ovni_ev *ev) printf("%d.%d.%d %c %c %c % 20lu % 15ld ", stream->loom, stream->proc, stream->tid, - ev->model, ev->class, ev->value, clock, delta); + ev->header.model, ev->header.class, ev->header.value, clock, delta); payloadsize = ovni_payload_size(ev); for(i=0; iactive) continue; - ev = &stream->last; + ev = stream->cur_ev; if(f < 0 || ovni_ev_get_clock(ev) < minclock) { f = i; @@ -112,16 +112,16 @@ void dump_events(struct ovni_trace *trace) stream = &trace->stream[f]; - if(lastclock > ovni_ev_get_clock(&stream->last)) + if(lastclock > ovni_ev_get_clock(stream->cur_ev)) { fprintf(stdout, "warning: backwards jump in time %lu -> %lu\n", - lastclock, ovni_ev_get_clock(&stream->last)); + lastclock, ovni_ev_get_clock(stream->cur_ev)); } /* Emit current event */ - emit(stream, &stream->last); + emit(stream, stream->cur_ev); - lastclock = ovni_ev_get_clock(&stream->last); + lastclock = ovni_ev_get_clock(stream->cur_ev); /* Read the next one */ ovni_load_next_event(stream); diff --git a/emu.c b/emu.c index 73ea644..3fbc77a 100644 --- a/emu.c +++ b/emu.c @@ -29,7 +29,7 @@ emit_ev(struct ovni_stream *stream, struct ovni_ev *ev) dbg("%d.%d.%d %c %c %c % 20lu % 15ld ", stream->loom, stream->proc, stream->tid, - ev->model, ev->class, ev->value, clock, delta); + ev->header.model, ev->header.class, ev->header.value, clock, delta); payloadsize = ovni_payload_size(ev); for(i=0; icur_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) { @@ -89,7 +68,7 @@ hook_pre(struct ovni_emu *emu) { //emu_emit(emu); - switch(emu->cur_ev->model) + switch(emu->cur_ev->header.model) { case 'O': hook_pre_ovni(emu); break; case 'V': hook_pre_nosv(emu); break; @@ -104,7 +83,7 @@ hook_view(struct ovni_emu *emu) { //emu_emit(emu); - switch(emu->cur_ev->model) + switch(emu->cur_ev->header.model) { case 'O': hook_view_ovni(emu); break; case 'V': hook_view_nosv(emu); break; @@ -119,7 +98,7 @@ hook_post(struct ovni_emu *emu) { //emu_emit(emu); - switch(emu->cur_ev->model) + switch(emu->cur_ev->header.model) { case 'O': hook_post_ovni(emu); break; default: @@ -132,7 +111,7 @@ static void set_current(struct ovni_emu *emu, struct ovni_stream *stream) { emu->cur_stream = stream; - emu->cur_ev = &stream->last; + emu->cur_ev = stream->cur_ev; 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]; @@ -163,7 +142,7 @@ next_event(struct ovni_emu *emu) if(!stream->active) continue; - ev = &stream->last; + ev = stream->cur_ev; if(f < 0 || ovni_ev_get_clock(ev) < minclock) { f = i; @@ -179,13 +158,13 @@ next_event(struct ovni_emu *emu) set_current(emu, stream); - if(emu->lastclock > ovni_ev_get_clock(&stream->last)) + if(emu->lastclock > ovni_ev_get_clock(stream->cur_ev)) { 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->cur_ev)); } - emu->lastclock = ovni_ev_get_clock(&stream->last); + emu->lastclock = ovni_ev_get_clock(stream->cur_ev); if(t0 < 0) t0 = emu->lastclock; diff --git a/emu.h b/emu.h index efee92c..777f87e 100644 --- a/emu.h +++ b/emu.h @@ -25,7 +25,6 @@ enum ethread_state { TH_ST_DEAD, }; - enum nosv_task_state { TASK_ST_CREATED, TASK_ST_RUNNING, @@ -45,17 +44,17 @@ struct nosv_task { struct nosv_task_type { int id; + const char *label; UT_hash_handle hh; }; - /* State of each emulated thread */ struct ovni_ethread { /* Emulated thread tid */ pid_t tid; - /* Stream file */ - FILE *f; + /* Stream fd */ + int stream_fd; enum ethread_state state; @@ -95,14 +94,17 @@ struct ovni_loom { }; struct ovni_stream { - FILE *f; + uint8_t *buf; + size_t size; + size_t offset; + int tid; int thread; int proc; int loom; int loaded; int active; - struct ovni_ev last; + struct ovni_ev *cur_ev; uint64_t lastclock; }; @@ -142,7 +144,6 @@ struct ovni_cpu { struct ovni_ethread *thread[OVNI_MAX_THR]; }; - struct ovni_emu { struct ovni_trace trace; diff --git a/emu_nosv.c b/emu_nosv.c index ffb7ef8..1b63609 100644 --- a/emu_nosv.c +++ b/emu_nosv.c @@ -148,7 +148,7 @@ static void pre_task(struct ovni_emu *emu) { emu_emit(emu); - switch(emu->cur_ev->value) + switch(emu->cur_ev->header.value) { case 'c': pre_task_create(emu); break; case 'x': pre_task_execute(emu); break; @@ -165,16 +165,27 @@ static void pre_type_create(struct ovni_emu *emu) { struct nosv_task_type *type, *p = NULL; - int typeid; + uint8_t *data; + uint32_t *typeid; + const char *label; - typeid = emu->cur_ev->payload.i32[0]; + if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0) + { + err("expecting a jumbo event\n"); + abort(); + } + + data = &emu->cur_ev->payload.jumbo.data[0]; + typeid = (uint32_t *) data; + data += sizeof(*typeid); + label = (const char *) data; /* Ensure the type id is new */ - HASH_FIND_INT(types, &typeid, type); + HASH_FIND_INT(types, typeid, type); if(type != NULL) { - err("A task type with id %d already exists\n", p->id); + err("A task type with id %d already exists\n", *typeid); abort(); } @@ -186,18 +197,20 @@ pre_type_create(struct ovni_emu *emu) abort(); } - type->id = typeid; + type->id = *typeid; + type->label = label; /* Add the new task type to the hash table */ HASH_ADD_INT(types, id, type); - dbg("new task type created id=%d\n", type->id); + dbg("new task type created id=%d label=%s\n", type->id, + type->label); } static void pre_type(struct ovni_emu *emu) { - switch(emu->cur_ev->value) + switch(emu->cur_ev->header.value) { case 'c': pre_type_create(emu); break; default: @@ -209,7 +222,7 @@ void hook_pre_nosv(struct ovni_emu *emu) { dbg("pre nosv\n"); - switch(emu->cur_ev->class) + switch(emu->cur_ev->header.class) { case 'T': pre_task(emu); break; case 'Y': pre_type(emu); break; @@ -266,7 +279,7 @@ emit_task_end(struct ovni_emu *emu) static void emit_task(struct ovni_emu *emu) { - switch(emu->cur_ev->value) + switch(emu->cur_ev->header.value) { case 'c': emit_task_create(emu); break; case 'x': emit_task_execute(emu); break; @@ -282,7 +295,7 @@ void hook_view_nosv(struct ovni_emu *emu) { dbg("pre nosv\n"); - switch(emu->cur_ev->class) + switch(emu->cur_ev->header.class) { case 'T': emit_task(emu); break; default: diff --git a/emu_ovni.c b/emu_ovni.c index 222da97..5d88d7f 100644 --- a/emu_ovni.c +++ b/emu_ovni.c @@ -158,7 +158,7 @@ ev_thread(struct ovni_emu *emu) cpu = thread->cpu; ev = emu->cur_ev; - switch(ev->value) + switch(ev->header.value) { case 'c': /* create */ dbg("thread %d creates a new thread at cpu=%d with args=%x %x\n", @@ -231,13 +231,13 @@ static void ev_affinity(struct ovni_emu *emu) { //emu_emit(emu); - switch(emu->cur_ev->value) + switch(emu->cur_ev->header.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); + emu->cur_ev->header.value); break; } } @@ -294,13 +294,13 @@ ev_cpu_id(struct ovni_emu *emu) static void ev_cpu(struct ovni_emu *emu) { - switch(emu->cur_ev->value) + switch(emu->cur_ev->header.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); + emu->cur_ev->header.value); break; } } @@ -310,15 +310,15 @@ hook_pre_ovni(struct ovni_emu *emu) { //emu_emit(emu); - switch(emu->cur_ev->class) + switch(emu->cur_ev->header.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; + case 'B': dbg("burst %c\n", emu->cur_ev->header.value); break; default: dbg("unknown ovni event class %c\n", - emu->cur_ev->class); + emu->cur_ev->header.class); break; } @@ -367,7 +367,7 @@ emit: void hook_view_ovni(struct ovni_emu *emu) { - switch(emu->cur_ev->class) + switch(emu->cur_ev->header.class) { case 'H': case 'A': diff --git a/ovni.c b/ovni.c index eda549e..4aff761 100644 --- a/ovni.c +++ b/ovni.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -284,8 +285,8 @@ flush_evbuf() static void ovni_ev_set_clock(struct ovni_ev *ev) { - ev->clock_lo = (uint32_t) (rthread.clockvalue & 0xffffffff); - ev->clock_hi = (uint16_t) ((rthread.clockvalue >> 32) & 0xffff); + ev->header.clock_lo = (uint32_t) (rthread.clockvalue & 0xffffffff); + ev->header.clock_hi = (uint16_t) ((rthread.clockvalue >> 32) & 0xffff); } uint64_t @@ -293,16 +294,22 @@ ovni_ev_get_clock(struct ovni_ev *ev) { uint64_t clock; - clock = ((uint64_t) ev->clock_hi) << 32 | ((uint64_t) ev->clock_lo); + clock = ((uint64_t) ev->header.clock_hi) << 32 | ((uint64_t) ev->header.clock_lo); return clock; } void ovni_ev_set_mcv(struct ovni_ev *ev, char *mcv) { - ev->model = mcv[0]; - ev->class = mcv[1]; - ev->value = mcv[2]; + ev->header.model = mcv[0]; + ev->header.class = mcv[1]; + ev->header.value = mcv[2]; +} + +static size_t +get_jumbo_payload_size(struct ovni_ev *ev) +{ + return sizeof(ev->payload.jumbo.size) + ev->payload.jumbo.size; } int @@ -310,7 +317,10 @@ ovni_payload_size(struct ovni_ev *ev) { int size; - size = ev->flags & 0x0f; + if(ev->header.flags & OVNI_EV_JUMBO) + return get_jumbo_payload_size(ev); + + size = ev->header.flags & 0x0f; if(size == 0) return 0; @@ -327,6 +337,9 @@ ovni_payload_add(struct ovni_ev *ev, uint8_t *buf, int size) { int payload_size; + assert((ev->header.flags & OVNI_EV_JUMBO) == 0); + assert(size >= 2); + payload_size = ovni_payload_size(ev); /* Ensure we have room */ @@ -335,37 +348,17 @@ ovni_payload_add(struct ovni_ev *ev, uint8_t *buf, int size) memcpy(&ev->payload.u8[payload_size], buf, size); payload_size += size; - ev->flags = ev->flags & 0xf0 | (payload_size-1) & 0x0f; + ev->header.flags = ev->header.flags & 0xf0 | (payload_size-1) & 0x0f; } int ovni_ev_size(struct ovni_ev *ev) { - return sizeof(*ev) - sizeof(ev->payload) + - ovni_payload_size(ev); + return sizeof(ev->header) + ovni_payload_size(ev); } - static void -ovni_ev_add(struct ovni_ev *ev) -{ - int size; - - ovni_ev_set_clock(ev); - - size = ovni_ev_size(ev); - - - memcpy(&rthread.evbuf[rthread.evlen], ev, size); - rthread.evlen += size; -} - -void -ovni_ev(struct ovni_ev *ev) -{ - ovni_ev_set_clock(ev); - ovni_ev_add(ev); -} +ovni_ev_add(struct ovni_ev *ev); int ovni_flush() @@ -393,6 +386,79 @@ ovni_flush() return ret; } +void +ovni_ev_add_jumbo(struct ovni_ev *ev, uint8_t *buf, uint32_t bufsize) +{ + size_t evsize, totalsize; + + assert(ovni_payload_size(ev) == 0); + + ovni_payload_add(ev, (uint8_t *) &bufsize, sizeof(bufsize)); + evsize = ovni_ev_size(ev); + + totalsize = evsize + bufsize; + + /* Check if the event fits or flush first otherwise */ + if(rthread.evlen + totalsize >= OVNI_MAX_EV_BUF) + ovni_flush(); + + /* Se the jumbo flag here, so we capture the previous evsize + * properly, ignoring the jumbo buffer */ + ev->header.flags |= OVNI_EV_JUMBO; + + memcpy(&rthread.evbuf[rthread.evlen], ev, evsize); + rthread.evlen += evsize; + memcpy(&rthread.evbuf[rthread.evlen], buf, bufsize); + rthread.evlen += bufsize; + + assert(rthread.evlen < OVNI_MAX_EV_BUF); +} + + +static void +ovni_ev_add(struct ovni_ev *ev) +{ + int size; + + size = ovni_ev_size(ev); + + /* Check if the event fits or flush first otherwise */ + if(rthread.evlen + size >= OVNI_MAX_EV_BUF) + ovni_flush(); + + memcpy(&rthread.evbuf[rthread.evlen], ev, size); + rthread.evlen += size; +} + +void +ovni_ev_jumbo(struct ovni_ev *ev, uint8_t *buf, uint32_t bufsize) +{ + ovni_ev_set_clock(ev); + ovni_ev_add_jumbo(ev, buf, bufsize); +} + +void +ovni_ev(struct ovni_ev *ev) +{ + ovni_ev_set_clock(ev); + ovni_ev_add(ev); +} + +static int +load_thread(struct ovni_ethread *thread, int tid, char *filepath) +{ + thread->tid = tid; + thread->stream_fd = open(filepath, O_RDONLY); + + if(thread->stream_fd == -1) + { + perror("open"); + return -1; + } + + thread->state = TH_ST_UNKNOWN; + return 0; +} static int load_proc(struct ovni_eproc *proc, char *procdir) @@ -425,20 +491,12 @@ load_proc(struct ovni_eproc *proc, char *procdir) return -1; } + sprintf(path, "%s/%s", procdir, dirent->d_name); thread = &proc->thread[proc->nthreads++]; - thread->tid = atoi(p); - sprintf(path, "%s/%s", procdir, dirent->d_name); - thread->f = fopen(path, "r"); - thread->state = TH_ST_UNKNOWN; - - if(thread->f == NULL) - { - fprintf(stderr, "fopen %s failed: %s\n", - path, strerror(errno)); + if(load_thread(thread, atoi(p), path) != 0) return -1; - } } closedir(dir); @@ -503,6 +561,30 @@ ovni_load_trace(struct ovni_trace *trace, char *tracedir) return 0; } +static int +load_stream_buf(struct ovni_stream *stream, struct ovni_ethread *thread) +{ + struct stat st; + + if(fstat(thread->stream_fd, &st) < 0) + { + perror("fstat"); + return -1; + } + + stream->size = st.st_size; + stream->buf = mmap(NULL, stream->size, PROT_READ, MAP_SHARED, + thread->stream_fd, 0); + + if(stream->buf == MAP_FAILED) + { + perror("mmap"); + return -1; + } + + return 0; +} + /* Populates the streams in a single array */ int ovni_load_streams(struct ovni_trace *trace) @@ -549,13 +631,20 @@ ovni_load_streams(struct ovni_trace *trace) thread = &proc->thread[k]; stream = &trace->stream[s++]; - stream->f = thread->f; + if(load_stream_buf(stream, thread) != 0) + { + err("load_stream_buf failed\n"); + return -1; + } + stream->tid = thread->tid; stream->thread = k; stream->proc = j; stream->loom = i; stream->active = 1; stream->lastclock = 0; + stream->offset = 0; + stream->cur_ev = NULL; } } } @@ -569,45 +658,51 @@ ovni_free_streams(struct ovni_trace *trace) free(trace->stream); } -void +int ovni_load_next_event(struct ovni_stream *stream) { int i; size_t n, size; - struct ovni_ev *ev; uint8_t flags; - if(!stream->active) - return; - - ev = &stream->last; - if((n = fread(&ev->flags, sizeof(ev->flags), 1, stream->f)) != 1) + if(stream->active == 0) { - dbg("stream is empty\n"); - stream->active = 0; - return; + dbg("stream is inactive, cannot load more events\n"); + return -1; } - //dbg("flags = %d\n", ev->flags); - - size = ovni_ev_size(ev) - sizeof(ev->flags); - //dbg("ev size = %d\n", size); - - - /* Clean payload from previous event */ - memset(&ev->payload, 0, sizeof(ev->payload)); - - if((n = fread(((uint8_t *) ev) + sizeof(ev->flags), 1, size, stream->f)) != size) + if(stream->cur_ev == NULL) { - err("warning: garbage found at the end of the stream\n"); - stream->active = 0; - return; + stream->cur_ev = (struct ovni_ev *) stream->buf; + stream->offset = 0; + dbg("first event\n"); + goto out; } + //printf("advancing offset %ld bytes\n", ovni_ev_size(stream->cur_ev)); + stream->offset += ovni_ev_size(stream->cur_ev); + + /* We have reached the end */ + if(stream->offset == stream->size) + { + stream->active = 0; + dbg("stream runs out of events\n"); + return -1; + } + + /* It cannot overflow, otherwise we are reading garbage */ + assert(stream->offset < stream->size); + + stream->cur_ev = (struct ovni_ev *) &stream->buf[stream->offset]; + +out: + + //dbg("---------\n"); + //dbg("ev size = %d\n", ovni_ev_size(stream->cur_ev)); + //dbg("ev flags = %02x\n", stream->cur_ev->header.flags); //dbg("loaded next event:\n"); - //hexdump((uint8_t *) ev, ovni_ev_size(ev)); + //hexdump((uint8_t *) stream->cur_ev, ovni_ev_size(stream->cur_ev)); //dbg("---------\n"); - stream->active = 1; - + return 0; } diff --git a/ovni.h b/ovni.h index 9318bbb..71452fc 100644 --- a/ovni.h +++ b/ovni.h @@ -18,25 +18,46 @@ /* ----------------------- 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]; +enum ovni_ev_flags { + OVNI_EV_JUMBO = 0x10, }; -struct __attribute__((__packed__)) ovni_ev { +struct __attribute__((__packed__)) ovni_jumbo_payload { + uint32_t size; + uint8_t data[1]; +}; + +union __attribute__((__packed__)) ovni_ev_payload { + + int8_t i8[16]; + int16_t i16[8]; + int32_t i32[4]; + int64_t i64[2]; + + uint8_t u8[16]; + uint16_t u16[8]; + uint32_t u32[4]; + uint64_t u64[2]; + + struct ovni_jumbo_payload jumbo; +}; + +struct __attribute__((__packed__)) ovni_ev_header { /* first 4 bits reserved, last 4 for payload size */ uint8_t flags; uint8_t model; uint8_t class; uint8_t value; - uint16_t clock_hi; uint32_t clock_lo; + uint16_t clock_hi; +}; + +struct __attribute__((__packed__)) ovni_ev { + struct ovni_ev_header header; + + /* The payload size may vary depending on the ev type: + * - normal: 0, or 2 to 16 bytes + * - jumbo: 0 to 2^32 - 1 bytes */ union ovni_ev_payload payload; }; @@ -100,6 +121,7 @@ int ovni_payload_size(struct ovni_ev *ev); /* Set the current clock in the event and queue it */ void ovni_ev(struct ovni_ev *ev); +void ovni_ev_jumbo(struct ovni_ev *ev, uint8_t *buf, uint32_t bufsize); int ovni_flush(); diff --git a/ovni2prv.c b/ovni2prv.c index ed89246..d589bcb 100644 --- a/ovni2prv.c +++ b/ovni2prv.c @@ -31,7 +31,7 @@ void emit(struct ovni_stream *stream, struct ovni_ev *ev) //2:0:1:1:7:1542091:6400025:1 //2:0:1:1:7:1542091:6400017:0 - printf("2:0:1:1:%d:%ld:%d:%d\n", stream->thread+1, delta, ev->class, ev->value); + printf("2:0:1:1:%d:%ld:%d:%d\n", stream->thread+1, delta, ev->header.class, ev->header.value); } void dump_events(struct ovni_trace *trace) @@ -63,7 +63,7 @@ void dump_events(struct ovni_trace *trace) if(!stream->active) continue; - ev = &stream->last; + ev = stream->cur_ev; if(f < 0 || ovni_ev_get_clock(ev) < minclock) { f = i; @@ -78,15 +78,15 @@ void dump_events(struct ovni_trace *trace) stream = &trace->stream[f]; - if(lastclock >= ovni_ev_get_clock(&stream->last)) + if(lastclock >= ovni_ev_get_clock(stream->cur_ev)) { fprintf(stderr, "warning: backwards jump in time\n"); } /* Emit current event */ - emit(stream, &stream->last); + emit(stream, stream->cur_ev); - lastclock = ovni_ev_get_clock(&stream->last); + lastclock = ovni_ev_get_clock(stream->cur_ev); /* Read the next one */ ovni_load_next_event(stream); diff --git a/ovni_trace.h b/ovni_trace.h index 59990b9..9606d84 100644 --- a/ovni_trace.h +++ b/ovni_trace.h @@ -4,7 +4,7 @@ #include "ovni.h" #include "emu.h" -void ovni_load_next_event(struct ovni_stream *stream); +int ovni_load_next_event(struct ovni_stream *stream); int ovni_load_trace(struct ovni_trace *trace, char *tracedir);