From 5a940540d3da99878f763e078aae87554023eb89 Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Date: Mon, 18 Oct 2021 12:47:51 +0200 Subject: [PATCH] Use priority queue for streams and fast channels A priority queue (in heap.h) is used to keep the next event ready in the emulator loop. Additionally, a list of dirty channels is keept to limit the complexity of the propagation and emit phases. --- chan.c | 141 ++++++++++-- chan.h | 22 +- emu.c | 636 +++++++++++++++++++++++++++++++++------------------ emu.h | 201 +++++++++------- emu_nosv.c | 38 +-- emu_openmp.c | 15 +- emu_ovni.c | 387 +++++++++++++++---------------- emu_tampi.c | 15 +- heap.h | 296 ++++++++++++++++++++++++ ovni.c | 143 ++++++------ ovni.h | 12 +- ovni2prv.c | 15 +- pcf.c | 214 ++++++++++++++--- prv.c | 2 +- 14 files changed, 1462 insertions(+), 675 deletions(-) create mode 100644 heap.h diff --git a/chan.c b/chan.c index e86f9eb..4b07790 100644 --- a/chan.c +++ b/chan.c @@ -1,9 +1,12 @@ +#include "chan.h" + #include #include "emu.h" #include "prv.h" +#include "utlist.h" -void +static void chan_init(struct ovni_chan *chan, int track, int row, int type, FILE *prv, int64_t *clock) { chan->n = 0; @@ -19,36 +22,89 @@ chan_init(struct ovni_chan *chan, int track, int row, int type, FILE *prv, int64 chan->track = track; } +static void +mark_dirty(struct ovni_chan *chan) +{ + assert(chan->dirty == 0); + + dbg("adding dirty chan %d to list\n", chan->id); + chan->dirty = 1; + DL_APPEND(*chan->update_list, chan); +} + void -chan_th_init(struct ovni_ethread *th, int chan_index, int track, int row, FILE *prv, int64_t *clock) +chan_th_init(struct ovni_ethread *th, + struct ovni_chan **update_list, + enum chan id, + int track, + int init_st, + int enabled, + int dirty, + int row, + FILE *prv, + int64_t *clock) { struct ovni_chan *chan; int prvth; - chan = &th->chan[chan_index]; - prvth = chan_to_prvtype[chan_index][1]; + chan = &th->chan[id]; + assert(chan_to_prvtype[id][0] == (int) id); + prvth = chan_to_prvtype[id][1]; chan_init(chan, track, row, prvth, prv, clock); + + chan->id = id; + chan->thread = th; + chan->update_list = update_list; + chan->enabled = enabled; + chan->stack[chan->n++] = init_st; + if(dirty) + mark_dirty(chan); } void -chan_cpu_init(struct ovni_cpu *cpu, int chan_index, int track, int row, FILE *prv, int64_t *clock) +chan_cpu_init(struct ovni_cpu *cpu, + struct ovni_chan **update_list, + enum chan id, + int track, +// int init_st, +// int enabled, + int row, + FILE *prv, + int64_t *clock) { struct ovni_chan *chan; int prvcpu; - chan = &cpu->chan[chan_index]; - prvcpu = chan_to_prvtype[chan_index][2]; + chan = &cpu->chan[id]; + assert(chan_to_prvtype[id][0] == (int) id); + prvcpu = chan_to_prvtype[id][2]; + chan->id = id; + chan->cpu = cpu; + chan->update_list = update_list; chan_init(chan, track, row, prvcpu, prv, clock); } +static void +chan_dump_update_list(struct ovni_chan *chan) +{ + struct ovni_chan *c; + + dbg("update list for chan %d at %p:\n", + chan->id, (void *) chan); + for(c = *chan->update_list; c; c = c->next) + { + dbg(" chan %d at %p\n", c->id, (void *) c); + } +} + void chan_enable(struct ovni_chan *chan, int enabled) { /* Can be dirty */ - dbg("chan_enable chan=%p enabled=%d\n", (void*) chan, enabled); + dbg("chan_enable chan=%d enabled=%d\n", chan->id, enabled); if(chan->enabled == enabled) { @@ -58,7 +114,24 @@ chan_enable(struct ovni_chan *chan, int enabled) chan->enabled = enabled; chan->t = *chan->clock; - chan->dirty = 1; + + /* Only append if not dirty */ + if(!chan->dirty) + { + mark_dirty(chan); + } + else + { + dbg("already dirty chan %d: skip update list\n", + chan->id); + chan_dump_update_list(chan); + } +} + +void +chan_disable(struct ovni_chan *chan) +{ + chan_enable(chan, 0); } int @@ -70,25 +143,46 @@ chan_is_enabled(struct ovni_chan *chan) void chan_set(struct ovni_chan *chan, int st) { - //dbg("chan_set chan=%p st=%d\n", (void*) chan, st); + /* Can be dirty */ + + dbg("chan_set chan %d st=%d\n", chan->id, st); assert(chan->enabled); - //assert(chan->dirty == 0); if(chan->n == 0) chan->n = 1; chan->stack[chan->n - 1] = st; chan->t = *chan->clock; - chan->dirty = 1; + + /* Only append if not dirty */ + if(!chan->dirty) + { + mark_dirty(chan); + } + else + { + dbg("already dirty chan %d: skip update list\n", + chan->id); + chan_dump_update_list(chan); + } +} + +void +chan_enable_and_set(struct ovni_chan *chan, int st) +{ + chan_enable(chan, 1); + chan_set(chan, st); } void chan_push(struct ovni_chan *chan, int st) { - //dbg("chan_push chan=%p st=%d\n", (void*) chan, st); + dbg("chan_push chan %d st=%d\n", chan->id, st); assert(chan->enabled); + + /* Cannot be dirty */ assert(chan->dirty == 0); if(chan->n >= MAX_CHAN_STACK) @@ -99,7 +193,8 @@ chan_push(struct ovni_chan *chan, int st) chan->stack[chan->n++] = st; chan->t = *chan->clock; - chan->dirty = 1; + + mark_dirty(chan); } int @@ -107,9 +202,11 @@ chan_pop(struct ovni_chan *chan, int expected_st) { int st; - //dbg("chan_pop chan=%p expected_st=%d\n", (void*) chan, expected_st); + dbg("chan_pop chan %d expected_st=%d\n", chan->id, expected_st); assert(chan->enabled); + + /* Cannot be dirty */ assert(chan->dirty == 0); if(chan->n <= 0) @@ -129,7 +226,8 @@ chan_pop(struct ovni_chan *chan, int expected_st) chan->n--; chan->t = *chan->clock; - chan->dirty = 1; + + mark_dirty(chan); return st; } @@ -137,15 +235,18 @@ chan_pop(struct ovni_chan *chan, int expected_st) void chan_ev(struct ovni_chan *chan, int ev) { - dbg("chan_ev chan=%p ev=%d\n", (void*) chan, ev); + dbg("chan_ev chan %d ev=%d\n", chan->id, ev); assert(chan->enabled); + + /* Cannot be dirty */ assert(chan->dirty == 0); assert(ev >= 0); chan->ev = ev; chan->t = *chan->clock; - chan->dirty = 1; + + mark_dirty(chan); } int @@ -192,10 +293,10 @@ emit_st(struct ovni_chan *chan) void chan_emit(struct ovni_chan *chan) { - if(chan->dirty == 0) + if(likely(chan->dirty == 0)) return; - //dbg("chan_emit chan=%p\n", (void*) chan); + dbg("chan_emit chan %d\n", chan->id); /* Emit badst if disabled */ if(chan->enabled == 0) diff --git a/chan.h b/chan.h index 3c4cbd8..2408aca 100644 --- a/chan.h +++ b/chan.h @@ -4,23 +4,35 @@ #include "emu.h" void -chan_init(struct ovni_chan *chan, int track, int row, int type, FILE *prv, int64_t *clock); +chan_th_init(struct ovni_ethread *th, + struct ovni_chan **update_list, + enum chan id, + int track, + int init_st, + int enabled, + int dirty, + int row, + FILE *prv, + int64_t *clock); void -chan_th_init(struct ovni_ethread *th, int chan_index, int track, int row, FILE *prv, int64_t *clock); - -void -chan_cpu_init(struct ovni_cpu *cpu, int chan_index, int track, int row, FILE *prv, int64_t *clock); +chan_cpu_init(struct ovni_cpu *cpu, struct ovni_chan **update_list, enum chan id, int track, int row, FILE *prv, int64_t *clock); void chan_enable(struct ovni_chan *chan, int enabled); +void +chan_disable(struct ovni_chan *chan); + int chan_is_enabled(struct ovni_chan *chan); void chan_set(struct ovni_chan *chan, int st); +void +chan_enable_and_set(struct ovni_chan *chan, int st); + void chan_push(struct ovni_chan *chan, int st); diff --git a/emu.c b/emu.c index 6908812..3c95e66 100644 --- a/emu.c +++ b/emu.c @@ -8,9 +8,10 @@ #include #include #include -#include -#include +#include +#include #include +#include #include "ovni.h" #include "ovni_trace.h" @@ -18,21 +19,23 @@ #include "prv.h" #include "pcf.h" #include "chan.h" +#include "utlist.h" /* Obtains the corrected clock of the given event */ -int64_t +static int64_t evclock(struct ovni_stream *stream, struct ovni_ev *ev) { return (int64_t) ovni_ev_get_clock(ev) + stream->clock_offset; } static void -emit_ev(struct ovni_stream *stream, struct ovni_ev *ev) +print_ev(struct ovni_stream *stream, struct ovni_ev *ev) { - int64_t delta; - uint64_t clock; + int64_t clock, delta; int i, payloadsize; + UNUSED(delta); + //dbg("sizeof(*ev) = %d\n", sizeof(*ev)); //hexdump((uint8_t *) ev, sizeof(*ev)); @@ -50,112 +53,189 @@ emit_ev(struct ovni_stream *stream, struct ovni_ev *ev) dbg("%d ", ev->payload.u8[i]); } dbg("\n"); +} + +static void +print_cur_ev(struct ovni_emu *emu) +{ + print_ev(emu->cur_stream, emu->cur_ev); +} + +/* Update the tracking channel if needed */ +static void +cpu_update_tracking_chan(struct ovni_chan *cpu_chan, struct ovni_ethread *th) +{ + int th_enabled, cpu_enabled; + struct ovni_chan *th_chan; + + assert(th); + + switch (cpu_chan->track) + { + case CHAN_TRACK_TH_RUNNING: + cpu_enabled = th->is_running; + break; + case CHAN_TRACK_TH_ACTIVE: + cpu_enabled = th->is_active; + break; + default: + dbg("ignoring thread %d chan %d with track=%d\n", + th->tid, cpu_chan->id, cpu_chan->track); + return; + } + + th_chan = &th->chan[cpu_chan->id]; + th_enabled = chan_is_enabled(th_chan); + + /* Enable the cpu channel if needed */ + if(cpu_enabled && !chan_is_enabled(cpu_chan)) + chan_enable(cpu_chan, cpu_enabled); + + /* Copy the state from the thread channel if needed */ + if(th_enabled && cpu_enabled) + { + /* Both enabled: simply follow the same value */ + chan_set(cpu_chan, chan_get_st(th_chan)); + } + else if(th_enabled && !cpu_enabled) + { + /* Only thread enabled: disable CPU */ + if(chan_is_enabled(cpu_chan)) + chan_disable(cpu_chan); + } + else if(!th_enabled && cpu_enabled) + { + /* Only CPU enabled: is this possible? Set to bad */ + chan_set(cpu_chan, ST_BAD); + err("warning: cpu %s chan %d enabled but tracked thread %d chan disabled\n", + cpu_chan->cpu->name, + cpu_chan->id, + th->tid); + } + else + { + /* Both disabled: disable CPU channel if needed */ + if(chan_is_enabled(cpu_chan)) + chan_disable(cpu_chan); + } + + dbg("cpu %s chan %d enabled=%d state=%d\n", + cpu_chan->cpu->name, cpu_chan->id, + chan_is_enabled(cpu_chan), + chan_get_st(cpu_chan)); - stream->lastclock = clock; } void -emu_emit(struct ovni_emu *emu) +emu_cpu_update_chan(struct ovni_cpu *cpu, struct ovni_chan *cpu_chan) { - emit_ev(emu->cur_stream, emu->cur_ev); -} + int count; + struct ovni_ethread *th; -struct ovni_ethread * -find_thread(struct ovni_eproc *proc, pid_t tid) -{ - int i; - struct ovni_ethread *thread; + /* Determine the source of tracking */ - for(i=0; inthreads; i++) + switch (cpu_chan->track) { - thread = &proc->thread[i]; - if(thread->tid == tid) - return thread; + case CHAN_TRACK_TH_RUNNING: + count = cpu->nrunning_threads; + th = cpu->th_running; + break; + case CHAN_TRACK_TH_ACTIVE: + count = cpu->nactive_threads; + th = cpu->th_active; + break; + default: + dbg("ignoring %s chan %d with track=%d\n", + cpu->name, cpu_chan->id, cpu_chan->track); + return; } - return NULL; + /* Based on how many threads, determine the state */ + if(count == 0) + { + /* The channel can be already disabled (migration of paused + * thread) so only disable it if needed. */ + if(chan_is_enabled(cpu_chan)) + chan_disable(cpu_chan); + } + else if(count == 1) + { + assert(th); + + /* A unique thread found: copy the state */ + dbg("cpu_update_chan: unique thread %d found, updating chan %d\n", + th->tid, cpu_chan->id); + + cpu_update_tracking_chan(cpu_chan, th); + } + else + { + /* More than one thread: enable the channel and set it to a + * error value */ + if(!chan_is_enabled(cpu_chan)) + chan_enable(cpu_chan, 1); + + chan_set(cpu_chan, ST_TOO_MANY_TH); + } +} + +static void +propagate_channels(struct ovni_emu *emu) +{ + struct ovni_cpu *cpu; + struct ovni_chan *cpu_chan, *th_chan, *tmp; + struct ovni_ethread *thread; + + /* Only propagate thread channels to their corresponding CPU */ + + DL_FOREACH_SAFE(emu->th_chan, th_chan, tmp) + { + assert(th_chan->thread); + + thread = th_chan->thread; + + /* No CPU in the thread */ + if(thread->cpu == NULL) + continue; + + cpu = thread->cpu; + + cpu_chan = &cpu->chan[th_chan->id]; + + dbg("propagate thread %d chan %d in cpu %s\n", + thread->tid, th_chan->id, cpu->name); + + emu_cpu_update_chan(cpu, cpu_chan); + } } static void emit_channels(struct ovni_emu *emu) { - struct ovni_cpu *cpu; - struct ovni_chan *chan_cpu, *chan_th; - struct ovni_ethread *th, *last_th; - int i, j, k, nrunning, st; + struct ovni_chan *cpu_chan, *th_chan; - /* Compute the CPU derived channels from the threads */ - for(i=0; itotal_ncpus; j++) - { - cpu = emu->global_cpu[j]; - chan_cpu = &cpu->chan[i]; - - /* Not implemented */ - assert(chan_cpu->track != CHAN_TRACK_TH_UNPAUSED); - - if(chan_cpu->track != CHAN_TRACK_TH_RUNNING) - { - //dbg("cpu chan %d not tracking threads\n", i); - break; - } - - /* Count running threads */ - for(k=0, nrunning=0; knthreads; k++) - { - th = cpu->thread[k]; - if(th->state == TH_ST_RUNNING) - { - last_th = th; - nrunning++; - } - } - - if(nrunning == 0) - { - //dbg("cpu chan %d disabled: no running threads\n", i); - if(chan_is_enabled(chan_cpu)) - chan_enable(chan_cpu, 0); - } - else if(nrunning > 1) - { - //dbg("cpu chan %d bad: multiple threads\n", i); - if(!chan_is_enabled(chan_cpu)) - chan_enable(chan_cpu, 1); - chan_set(chan_cpu, ST_BAD); - } - else - { - th = last_th; - chan_th = &th->chan[i]; - - //dbg("cpu chan %d good: one thread\n", i); - if(!chan_is_enabled(chan_cpu)) - chan_enable(chan_cpu, 1); - - if(chan_is_enabled(chan_th)) - st = chan_get_st(&last_th->chan[i]); - else - st = ST_BAD; - - /* Only update the CPU chan if needed */ - if(chan_get_st(chan_cpu) != st) - chan_set(chan_cpu, st); - } - } - } + dbg("emu enters emit_channels -------------------\n"); /* Emit only the channels that have been updated. We need a list * of updated channels */ - for(i=0; itotal_nthreads; i++) - for(j=0; jglobal_thread[i]->chan[j]); + DL_FOREACH(emu->th_chan, th_chan) + { + dbg("emu emits th chan %d\n", th_chan->id); + //assert(th_chan->dirty); + chan_emit(th_chan); + } - for(i=0; itotal_ncpus; i++) - for(j=0; jglobal_cpu[i]->chan[j]); + DL_FOREACH(emu->cpu_chan, cpu_chan) + { + dbg("emu emits cpu chan %d\n", cpu_chan->id); + //assert(cpu_chan->dirty); + chan_emit(cpu_chan); + } + /* Reset the list of updated channels */ + dbg("emu resets the list of dirty channels -------------------\n"); + emu->th_chan = NULL; + emu->cpu_chan = NULL; } static void @@ -170,43 +250,20 @@ hook_init(struct ovni_emu *emu) static void hook_pre(struct ovni_emu *emu) { - //emu_emit(emu); - switch(emu->cur_ev->header.model) { - case 'O': hook_pre_ovni(emu); - break; - case 'V': hook_pre_nosv(emu); - break; - case 'T': hook_pre_tampi(emu); - break; - case 'M': hook_pre_openmp(emu); - break; + case 'O': hook_pre_ovni(emu); break; + case 'V': hook_pre_nosv(emu); break; + case 'T': hook_pre_tampi(emu); break; + case 'M': hook_pre_openmp(emu); break; default: break; } } -static void -hook_emit(struct ovni_emu *emu) -{ - //emu_emit(emu); - - emit_channels(emu); - - switch(emu->cur_ev->header.model) - { - default: - //dbg("unknown model %c\n", emu->cur_ev->model); - break; - } -} - static void hook_post(struct ovni_emu *emu) { - //emu_emit(emu); - switch(emu->cur_ev->header.model) { default: @@ -225,70 +282,134 @@ set_current(struct ovni_emu *emu, struct ovni_stream *stream) emu->cur_thread = &emu->cur_proc->thread[stream->thread]; } +/* + * heap_node_compare_t - comparison function, returns: + + * > 0 if a > b + * < 0 if a < b + * = 0 if a == b + * + * Invert the comparison function to get a min-heap instead + */ +static inline int stream_cmp(heap_node_t *a, heap_node_t *b) +{ + struct ovni_stream *sa, *sb; + + sa = heap_elem(a, struct ovni_stream, hh); + sb = heap_elem(b, struct ovni_stream, hh); + + if(sb->lastclock < sa->lastclock) + return -1; + else if(sb->lastclock > sa->lastclock) + return +1; + else + return 0; +} + +static double +get_time(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (double)ts.tv_sec + (double)ts.tv_nsec * 1.0e-9; +} + +static void +print_progress(struct ovni_emu *emu) +{ + double progress, time_now, time_elapsed, time_total, time_left; + double speed_in, speed_out; + double cpu_written, th_written, written; + int min, sec; + + cpu_written = (double) ftell(emu->prv_cpu); + th_written = (double) ftell(emu->prv_thread); + + written = cpu_written + th_written; + + progress = ((double) emu->global_offset) / + ((double) emu->global_size); + + time_now = get_time(); + time_elapsed = time_now - emu->start_emulation_time; + time_total = time_elapsed / progress; + time_left = time_total - time_elapsed; + + speed_in = (double) emu->nev_processed / time_elapsed; + speed_out = written / time_elapsed; + + min = (int) (time_left / 60.0); + sec = (int) ((time_left / 60.0 - min) * 60); + + err("%.1f%% done at %.0f Kev/s, out %.1f GB CPU / %.1f GB TH at %.1f MB/s (%d min %d s left)\n", + 100.0 * progress, + speed_in / 1024.0, + cpu_written / (1024.0 * 1024.0 * 1024.0), + th_written / (1024.0 * 1024.0 * 1024.0), + speed_out / (1024.0 * 1024), + min, sec); +} + +/* Loads the next event and sets the lastclock in the stream. + * Returns -1 if the stream has no more events. */ +static int +emu_step_stream(struct ovni_emu *emu, struct ovni_stream *stream) +{ + if(ovni_load_next_event(stream) < 0) + return -1; + + stream->lastclock = evclock(stream, stream->cur_ev); + + heap_insert(&emu->sorted_stream, &stream->hh, &stream_cmp); + + return 0; +} + 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; + heap_node_t *node; static int done_first = 0; - trace = &emu->trace; + /* Extract the next stream based on the event clock */ + node = heap_pop_max(&emu->sorted_stream, stream_cmp); - /* Look for virtual events first */ - - if(trace->ivirtual < trace->nvirtual) - { - emu->cur_ev = &trace->virtual_events[trace->ivirtual]; - trace->ivirtual++; - return 0; - } - else - { - /* Reset virtual events to 0 */ - trace->ivirtual = 0; - trace->nvirtual = 0; - } - - 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->cur_ev; - if(f < 0 || evclock(stream, ev) < minclock) - { - f = i; - minclock = evclock(stream, ev); - } - } - - if(f < 0) + /* No more streams */ + if(node == NULL) return -1; - /* We have a valid stream with a new event */ - stream = &trace->stream[f]; + stream = heap_elem(node, struct ovni_stream, hh); + + assert(stream); set_current(emu, stream); - if(emu->lastclock > evclock(stream, stream->cur_ev)) + emu->global_offset += ovni_ev_size(stream->cur_ev); + + //err("stream %d clock at %ld\n", stream->tid, stream->lastclock); + + /* This can happen if two events are not ordered in the stream, but the + * emulator picks other events in the middle. Example: + * + * Stream A: 10 3 ... + * Stream B: 5 12 + * + * emulator output: + * 5 + * 10 + * 3 -> warning! + * 12 + * ... + * */ + if(emu->lastclock > stream->lastclock) { - fprintf(stdout, "warning: backwards jump in time %lu -> %lu\n", - emu->lastclock, evclock(stream, stream->cur_ev)); + err("warning: backwards jump in time %lu -> %lu for tid %d\n", + emu->lastclock, stream->lastclock, stream->tid); } - emu->lastclock = evclock(stream, stream->cur_ev); + emu->lastclock = stream->lastclock; if(!done_first) { @@ -302,45 +423,81 @@ next_event(struct ovni_emu *emu) } static void -emulate(struct ovni_emu *emu) +emu_load_first_events(struct ovni_emu *emu) { - int i; - struct ovni_ev ev; - struct ovni_stream *stream; + size_t i; struct ovni_trace *trace; + struct ovni_stream *stream; - /* Load events */ + /* Prepare the stream heap */ + heap_init(&emu->sorted_stream); + + emu->lastclock = 0; + + /* Load initial streams and events */ trace = &emu->trace; for(i=0; instreams; i++) { stream = &trace->stream[i]; - ovni_load_next_event(stream); + emu->global_size += stream->size; + + if(emu_step_stream(emu, stream) < 0) + { + dbg("warning: empty stream for tid %d\n", stream->tid); + continue; + } + + assert(stream->active); } +} +static void +emulate(struct ovni_emu *emu) +{ + size_t i; - emu->lastclock = 0; + emu->nev_processed = 0; + + err("loading first events\n"); + emu_load_first_events(emu); + + err("emulation starts\n"); + emu->start_emulation_time = get_time(); hook_init(emu); + emit_channels(emu); + /* Then process all events */ - while(next_event(emu) == 0) + for(i=0; next_event(emu) == 0; i++) { - //fprintf(stdout, "step %i\n", i); - emu_emit(emu); + print_cur_ev(emu); + hook_pre(emu); - hook_emit(emu); + + propagate_channels(emu); + emit_channels(emu); + hook_post(emu); - /* Read the next event if no virtual events exist */ - if(emu->trace.ivirtual == emu->trace.nvirtual) - ovni_load_next_event(emu->cur_stream); + if(i >= 50000) + { + print_progress(emu); + i = 0; + } + + emu->nev_processed++; + + emu_step_stream(emu, emu->cur_stream); } + + print_progress(emu); } struct ovni_ethread * emu_get_thread(struct ovni_eproc *proc, int tid) { - int i; + size_t i; struct ovni_ethread *thread; for(i=0; inthreads; i++) @@ -359,7 +516,7 @@ add_new_cpu(struct ovni_emu *emu, struct ovni_loom *loom, int i, int phyid) struct ovni_cpu *cpu; /* The logical id must match our index */ - assert(i == loom->ncpus); + assert((size_t) i == loom->ncpus); cpu = &loom->cpu[i]; @@ -376,13 +533,13 @@ add_new_cpu(struct ovni_emu *emu, struct ovni_loom *loom, int i, int phyid) loom->ncpus++; } -void +static void proc_load_cpus(struct ovni_emu *emu, struct ovni_loom *loom, struct ovni_eproc *proc) { JSON_Array *cpuarray; JSON_Object *cpu; JSON_Object *meta; - int i, index, phyid; + size_t i, index, phyid; struct ovni_cpu *vcpu; meta = json_value_get_object(proc->meta); @@ -421,14 +578,12 @@ proc_load_cpus(struct ovni_emu *emu, struct ovni_loom *loom, struct ovni_eproc * } /* Obtain CPUs in the metadata files and other data */ -static int +static void load_metadata(struct ovni_emu *emu) { - int i, j, k, s; + size_t i, j; struct ovni_loom *loom; struct ovni_eproc *proc; - struct ovni_ethread *thread; - struct ovni_stream *stream; struct ovni_trace *trace; trace = &emu->trace; @@ -449,18 +604,14 @@ load_metadata(struct ovni_emu *emu) /* FIXME: The CPU list should be at the loom dir */ assert(loom->ncpus > 0); } - - return 0; } static int destroy_metadata(struct ovni_emu *emu) { - int i, j, k, s; + size_t i, j; struct ovni_loom *loom; struct ovni_eproc *proc; - struct ovni_ethread *thread; - struct ovni_stream *stream; struct ovni_trace *trace; trace = &emu->trace; @@ -490,14 +641,22 @@ open_prvs(struct ovni_emu *emu, char *tracedir) emu->prv_thread = fopen(path, "w"); if(emu->prv_thread == NULL) - abort(); + { + err("error opening thread PRV file %s: %s\n", path, + strerror(errno)); + exit(EXIT_FAILURE); + } sprintf(path, "%s/%s", tracedir, "cpu.prv"); emu->prv_cpu = fopen(path, "w"); if(emu->prv_cpu == NULL) - abort(); + { + err("error opening cpu PRV file %s: %s\n", path, + strerror(errno)); + exit(EXIT_FAILURE); + } prv_header(emu->prv_thread, emu->total_nthreads); prv_header(emu->prv_cpu, emu->total_ncpus); @@ -513,14 +672,22 @@ open_pcfs(struct ovni_emu *emu, char *tracedir) emu->pcf_thread = fopen(path, "w"); if(emu->pcf_thread == NULL) - abort(); + { + err("error opening thread PCF file %s: %s\n", path, + strerror(errno)); + exit(EXIT_FAILURE); + } sprintf(path, "%s/%s", tracedir, "cpu.pcf"); emu->pcf_cpu = fopen(path, "w"); if(emu->pcf_cpu == NULL) - abort(); + { + err("error opening cpu PCF file %s: %s\n", path, + strerror(errno)); + exit(EXIT_FAILURE); + } } static void @@ -540,6 +707,9 @@ close_pcfs(struct ovni_emu *emu) static void usage(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + err("Usage: emu [-c offsetfile] tracedir\n"); err("\n"); err("Options:\n"); @@ -583,7 +753,7 @@ parse_args(struct ovni_emu *emu, int argc, char *argv[]) static struct ovni_loom * find_loom_by_hostname(struct ovni_emu *emu, char *host) { - int i; + size_t i; struct ovni_loom *loom; for(i=0; itrace.nlooms; i++) @@ -602,19 +772,22 @@ load_clock_offsets(struct ovni_emu *emu) { FILE *f; char buf[1024]; - int i, rank, ret; + size_t i; + int rank, ret; double offset, mean, std; char host[OVNI_MAX_HOSTNAME]; struct ovni_loom *loom; struct ovni_trace *trace; struct ovni_stream *stream; - + f = fopen(emu->clock_offset_file, "r"); if(f == NULL) { - perror("fopen clock offset file failed\n"); - abort(); + err("error opening clock offset file %s: %s\n", + emu->clock_offset_file, + strerror(errno)); + exit(EXIT_FAILURE); } /* Ignore header line */ @@ -652,7 +825,7 @@ load_clock_offsets(struct ovni_emu *emu) if(loom == NULL) { err("No loom has hostname %s\n", host); - abort(); + exit(EXIT_FAILURE); } if(loom->clock_offset != 0) @@ -682,7 +855,7 @@ static void write_row_cpu(struct ovni_emu *emu) { FILE *f; - int i, j; + size_t i; char path[PATH_MAX]; struct ovni_cpu *cpu; @@ -700,7 +873,7 @@ write_row_cpu(struct ovni_emu *emu) fprintf(f, "hostname\n"); fprintf(f, "\n"); - fprintf(f, "LEVEL THREAD SIZE %d\n", emu->total_ncpus); + fprintf(f, "LEVEL THREAD SIZE %ld\n", emu->total_ncpus); for(i=0; itotal_ncpus; i++) { @@ -715,7 +888,7 @@ static void write_row_thread(struct ovni_emu *emu) { FILE *f; - int i, j; + size_t i; char path[PATH_MAX]; struct ovni_ethread *th; @@ -733,7 +906,7 @@ write_row_thread(struct ovni_emu *emu) fprintf(f, "hostname\n"); fprintf(f, "\n"); - fprintf(f, "LEVEL THREAD SIZE %d\n", emu->total_nthreads); + fprintf(f, "LEVEL THREAD SIZE %ld\n", emu->total_nthreads); for(i=0; itotal_nthreads; i++) { @@ -744,7 +917,7 @@ write_row_thread(struct ovni_emu *emu) fclose(f); } -static int +static void emu_virtual_init(struct ovni_emu *emu) { struct ovni_trace *trace; @@ -762,8 +935,6 @@ emu_virtual_init(struct ovni_emu *emu) perror("calloc"); exit(EXIT_FAILURE); } - - return 0; } void @@ -798,7 +969,7 @@ init_threads(struct ovni_emu *emu) struct ovni_loom *loom; struct ovni_eproc *proc; struct ovni_ethread *thread; - int i, j, k, gi; + size_t i, j, k, gi; emu->total_nthreads = 0; @@ -824,8 +995,8 @@ init_threads(struct ovni_emu *emu) if(emu->global_thread == NULL) { - perror("calloc"); - abort(); + perror("calloc failed"); + exit(EXIT_FAILURE); } for(gi=0, i=0; inlooms; i++) @@ -850,7 +1021,7 @@ init_cpus(struct ovni_emu *emu) struct ovni_trace *trace; struct ovni_loom *loom; struct ovni_cpu *cpu; - int i, j, gi; + size_t i, j; trace = &emu->trace; @@ -860,10 +1031,10 @@ init_cpus(struct ovni_emu *emu) if(emu->global_cpu == NULL) { perror("calloc"); - abort(); + exit(EXIT_FAILURE); } - for(gi=0, i=0; inlooms; i++) + for(i=0; inlooms; i++) { loom = &trace->loom[i]; for(j=0; jncpus; j++) @@ -871,18 +1042,20 @@ init_cpus(struct ovni_emu *emu) cpu = &loom->cpu[j]; emu->global_cpu[cpu->gindex] = cpu; - if(snprintf(cpu->name, MAX_CPU_NAME, "CPU %d.%d", + if(snprintf(cpu->name, MAX_CPU_NAME, "CPU %ld.%ld", i, j) >= MAX_CPU_NAME) { - abort(); + err("error cpu %ld.%ld name too long\n", i, j); + exit(EXIT_FAILURE); } } emu->global_cpu[loom->vcpu.gindex] = &loom->vcpu; - if(snprintf(loom->vcpu.name, MAX_CPU_NAME, "CPU %d.*", + if(snprintf(loom->vcpu.name, MAX_CPU_NAME, "CPU %ld.*", i) >= MAX_CPU_NAME) { - abort(); + err("error cpu %ld.* name too long\n", i); + exit(EXIT_FAILURE); } } } @@ -895,16 +1068,20 @@ emu_init(struct ovni_emu *emu, int argc, char *argv[]) parse_args(emu, argc, argv); if(ovni_load_trace(&emu->trace, emu->tracedir)) - abort(); + { + err("error loading ovni trace\n"); + exit(EXIT_FAILURE); + } - if(emu_virtual_init(emu)) - abort(); + emu_virtual_init(emu); if(ovni_load_streams(&emu->trace)) - abort(); + { + err("error loading streams\n"); + exit(EXIT_FAILURE); + } - if(load_metadata(emu) != 0) - abort(); + load_metadata(emu); if(emu->clock_offset_file != NULL) load_clock_offsets(emu); @@ -915,7 +1092,10 @@ emu_init(struct ovni_emu *emu, int argc, char *argv[]) open_prvs(emu, emu->tracedir); open_pcfs(emu, emu->tracedir); - err("loaded %d cpus and %d threads\n", + emu->global_size = 0; + emu->global_offset = 0; + + err("loaded %ld cpus and %ld threads\n", emu->total_ncpus, emu->total_nthreads); } @@ -944,7 +1124,7 @@ int main(int argc, char *argv[]) { struct ovni_emu *emu; - + emu = malloc(sizeof(struct ovni_emu)); if(emu == NULL) diff --git a/emu.h b/emu.h index a17e100..d4b85bb 100644 --- a/emu.h +++ b/emu.h @@ -4,6 +4,7 @@ #include "ovni.h" #include "uthash.h" #include "parson.h" +#include "heap.h" #include /* Debug macros */ @@ -16,6 +17,10 @@ #define err(...) fprintf(stderr, __VA_ARGS__); +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#define UNUSED(x) (void)(x) + /* Emulated thread runtime status */ enum ethread_state { TH_ST_UNKNOWN, @@ -33,6 +38,10 @@ enum nosv_task_state { TASK_ST_DEAD, }; +enum cpu_st { + ST_TOO_MANY_TH = 777, +}; + enum nosv_ss_values { ST_NULL = 0, ST_NOSV_SCHED_HUNGRY = 6, @@ -88,12 +97,67 @@ struct nosv_task_type { #define MAX_CHAN_STACK 128 enum chan_track { + /* The channel is manually controlled. */ CHAN_TRACK_NONE = 0, + + /* Enables the channel when the thread is running only. */ CHAN_TRACK_TH_RUNNING, - CHAN_TRACK_TH_UNPAUSED, + + /* The thread active tracking mode a enables the channel when + * the thread is running, cooling or warming. Otherwise the + * channel is disabled. */ + CHAN_TRACK_TH_ACTIVE, +}; + +enum chan { + CHAN_OVNI_PID, + CHAN_OVNI_TID, + CHAN_OVNI_NTHREADS, + CHAN_OVNI_STATE, + CHAN_OVNI_APPID, + CHAN_OVNI_CPU, + + CHAN_NOSV_TASKID, + CHAN_NOSV_TYPEID, + CHAN_NOSV_APPID, + CHAN_NOSV_SUBSYSTEM, + + CHAN_TAMPI_MODE, + CHAN_OPENMP_MODE, + + CHAN_MAX +}; + +enum chan_to_prv_type { + CHAN_ID = 0, + CHAN_TH = 1, + CHAN_CPU = 2, +}; + +/* Same order as `enum chan` */ +static const int chan_to_prvtype[CHAN_MAX][3] = { + /* Channel TH CPU */ + { CHAN_OVNI_PID, 10, 60 }, + { CHAN_OVNI_TID, 11, 61 }, + { CHAN_OVNI_NTHREADS, -1, 62 }, + { CHAN_OVNI_STATE, 13, -1 }, + { CHAN_OVNI_APPID, 14, 64 }, /* Not used */ + { CHAN_OVNI_CPU, 15, -1 }, + + { CHAN_NOSV_TASKID, 20, 70 }, + { CHAN_NOSV_TYPEID, 21, 71 }, + { CHAN_NOSV_APPID, 22, 72 }, + { CHAN_NOSV_SUBSYSTEM, 23, 73 }, + + { CHAN_TAMPI_MODE, 30, 80 }, + + { CHAN_OPENMP_MODE, 40, 90 }, }; struct ovni_chan { + /* Channel id */ + enum chan id; + /* Number of states in the stack */ int n; @@ -129,68 +193,20 @@ struct ovni_chan { /* What should cause the channel to become disabled? */ enum chan_track track; + + /* The thread associated with the channel if any */ + struct ovni_ethread *thread; + + /* The CPU associated with the channel if any */ + struct ovni_cpu *cpu; + + struct ovni_chan **update_list; + + /* Used when the channel is a list */ + struct ovni_chan *prev; + struct ovni_chan *next; }; -enum chan { - CHAN_OVNI_PID, - CHAN_OVNI_TID, - CHAN_OVNI_NTHREADS, - CHAN_OVNI_STATE, - CHAN_OVNI_APPID, - CHAN_OVNI_CPU, - - CHAN_NOSV_TASKID, - CHAN_NOSV_TYPEID, - CHAN_NOSV_APPID, - CHAN_NOSV_SUBSYSTEM, - - CHAN_TAMPI_MODE, - CHAN_OPENMP_MODE, - - CHAN_MAX -}; - -/* Same order as `enum chan` */ -const static int chan_to_prvtype[CHAN_MAX][3] = { - /* Channel TH CPU */ - { CHAN_OVNI_PID, 10, 60 }, - { CHAN_OVNI_TID, 11, 61 }, - { CHAN_OVNI_NTHREADS, -1, 62 }, - { CHAN_OVNI_STATE, 13, 63 }, - { CHAN_OVNI_APPID, 14, 64 }, - { CHAN_OVNI_CPU, 15, -1 }, - - { CHAN_NOSV_TASKID, 20, 70 }, - { CHAN_NOSV_TYPEID, 21, 71 }, - { CHAN_NOSV_APPID, 22, 72 }, - { CHAN_NOSV_SUBSYSTEM, 23, 73 }, - - { CHAN_TAMPI_MODE, 30, 80 }, - - { CHAN_OPENMP_MODE, 40, 90 }, -}; - -///* All PRV event types */ -//enum prv_type { -// /* Rows are CPUs */ -// PTC_PROC_PID = 10, -// PTC_THREAD_TID = 11, -// PTC_NTHREADS = 12, -// PTC_TASK_ID = 20, -// PTC_TASK_TYPE_ID = 21, -// PTC_APP_ID = 30, -// PTC_SUBSYSTEM = 31, -// -// /* Rows are threads */ -// PTT_THREAD_STATE = 60, -// PTT_THREAD_TID = 61, -// PTT_SUBSYSTEM = 62, -// -// PTT_TASK_ID = 63, -// PTT_TASK_TYPE_ID = 64, -// PTT_TASK_APP_ID = 65, -//}; - #define MAX_BURSTS 100 /* State of each emulated thread */ @@ -208,6 +224,8 @@ struct ovni_ethread { int stream_fd; enum ethread_state state; + int is_running; + int is_active; /* Thread stream */ struct ovni_stream *stream; @@ -294,10 +312,18 @@ struct ovni_cpu { /* 1 if the cpu has updated is threads, 0 if not */ int updated; - /* The threads the cpu is currently running */ + /* The threads with affinity set to this CPU */ size_t nthreads; struct ovni_ethread *thread[OVNI_MAX_THR]; + /* From the assigned threads, how many running */ + size_t nrunning_threads; + struct ovni_ethread *th_running; + + /* Number of assigned threads active */ + size_t nactive_threads; + struct ovni_ethread *th_active; + /* Cpu name as shown in paraver row */ char name[MAX_CPU_NAME]; }; @@ -309,10 +335,10 @@ struct ovni_loom { size_t nprocs; char hostname[OVNI_MAX_HOSTNAME]; - int max_ncpus; - int max_phyid; - int ncpus; - int offset_ncpus; + size_t max_ncpus; + size_t max_phyid; + size_t ncpus; + size_t offset_ncpus; struct ovni_cpu cpu[OVNI_MAX_CPU]; int64_t clock_offset; @@ -330,19 +356,19 @@ struct ovni_loom { #define MAX_VIRTUAL_EVENTS 16 struct ovni_trace { - int nlooms; + size_t nlooms; struct ovni_loom loom[OVNI_MAX_LOOM]; /* Index of next virtual event */ - int ivirtual; + size_t ivirtual; /* Number of virtual events stored */ - int nvirtual; + size_t nvirtual; /* The virtual events are generated by the emulator */ struct ovni_ev *virtual_events; - int nstreams; + size_t nstreams; struct ovni_stream *stream; }; @@ -357,9 +383,14 @@ struct ovni_stream { int loom; int loaded; int active; + + double progress; + struct ovni_ev *cur_ev; - uint64_t lastclock; + int64_t lastclock; int64_t clock_offset; + + heap_node_t hh; }; struct ovni_emu { @@ -378,10 +409,18 @@ struct ovni_emu { struct nosv_task *cur_task; + /* Global processed size and offset of all streams */ + size_t global_size; + size_t global_offset; + double start_emulation_time; + int64_t firstclock; int64_t lastclock; int64_t delta_time; + /* Counters for statistics */ + int64_t nev_processed; + FILE *prv_thread; FILE *prv_cpu; FILE *pcf_thread; @@ -391,24 +430,24 @@ struct ovni_emu { char *tracedir; /* Total counters */ - int total_nthreads; - int total_proc; - int total_ncpus; + size_t total_nthreads; + size_t total_proc; + size_t total_ncpus; + + /* Keep a list of dirty channels for the CPUs and threads */ + struct ovni_chan *cpu_chan; + struct ovni_chan *th_chan; + + heap_head_t sorted_stream; }; /* Emulator function declaration */ -void emu_emit(struct ovni_emu *emu); - void hook_init_ovni(struct ovni_emu *emu); void hook_pre_ovni(struct ovni_emu *emu); -void hook_emit_ovni(struct ovni_emu *emu); -void hook_post_ovni(struct ovni_emu *emu); void hook_init_nosv(struct ovni_emu *emu); void hook_pre_nosv(struct ovni_emu *emu); -void hook_emit_nosv(struct ovni_emu *emu); -void hook_post_nosv(struct ovni_emu *emu); void hook_init_tampi(struct ovni_emu *emu); void hook_pre_tampi(struct ovni_emu *emu); @@ -420,7 +459,7 @@ struct ovni_cpu *emu_get_cpu(struct ovni_loom *loom, int cpuid); struct ovni_ethread *emu_get_thread(struct ovni_eproc *proc, int tid); -void emu_emit_prv(struct ovni_emu *emu, int type, int val); +void emu_cpu_update_chan(struct ovni_cpu *cpu, struct ovni_chan *cpu_chan); void emu_virtual_ev(struct ovni_emu *emu, char *mcv); diff --git a/emu_nosv.c b/emu_nosv.c index 946fc8f..c6affb3 100644 --- a/emu_nosv.c +++ b/emu_nosv.c @@ -14,15 +14,15 @@ hook_init_nosv(struct ovni_emu *emu) { struct ovni_ethread *th; struct ovni_cpu *cpu; - struct ovni_trace *trace; - int i, row, type; + struct ovni_chan **uth, **ucpu; + size_t i; + int row; FILE *prv_th, *prv_cpu; int64_t *clock; clock = &emu->delta_time; prv_th = emu->prv_thread; prv_cpu = emu->prv_cpu; - trace = &emu->trace; /* Init the channels in all threads */ for(i=0; itotal_nthreads; i++) @@ -30,19 +30,17 @@ hook_init_nosv(struct ovni_emu *emu) th = emu->global_thread[i]; row = th->gindex + 1; - chan_th_init(th, CHAN_NOSV_TASKID, CHAN_TRACK_TH_RUNNING, row, prv_th, clock); - chan_enable(&th->chan[CHAN_NOSV_TASKID], 1); - chan_set(&th->chan[CHAN_NOSV_TASKID], 0); - chan_enable(&th->chan[CHAN_NOSV_TASKID], 0); + uth = &emu->th_chan; - chan_th_init(th, CHAN_NOSV_TYPEID, CHAN_TRACK_TH_RUNNING, row, prv_th, clock); - chan_th_init(th, CHAN_NOSV_APPID, CHAN_TRACK_TH_RUNNING, row, prv_th, clock); + chan_th_init(th, uth, CHAN_NOSV_TASKID, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock); + chan_th_init(th, uth, CHAN_NOSV_TYPEID, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock); + chan_th_init(th, uth, CHAN_NOSV_APPID, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock); /* We allow threads to emit subsystem events in cooling and * warming states as well, as they may be allocating memory. * However, these information won't be presented in the CPU * channel, as it only shows the thread in the running state */ - chan_th_init(th, CHAN_NOSV_SUBSYSTEM, CHAN_TRACK_TH_UNPAUSED, row, prv_th, clock); + chan_th_init(th, uth, CHAN_NOSV_SUBSYSTEM, CHAN_TRACK_TH_ACTIVE, 0, 0, 1, row, prv_th, clock); } /* Init the nosv channels in all cpus */ @@ -50,15 +48,17 @@ hook_init_nosv(struct ovni_emu *emu) { cpu = emu->global_cpu[i]; row = cpu->gindex + 1; + ucpu = &emu->cpu_chan; + + chan_cpu_init(cpu, ucpu, CHAN_NOSV_TASKID, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); - chan_cpu_init(cpu, CHAN_NOSV_TASKID, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); chan_enable(&cpu->chan[CHAN_NOSV_TASKID], 1); chan_set(&cpu->chan[CHAN_NOSV_TASKID], 0); chan_enable(&cpu->chan[CHAN_NOSV_TASKID], 0); - chan_cpu_init(cpu, CHAN_NOSV_TYPEID, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); - chan_cpu_init(cpu, CHAN_NOSV_APPID, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); - chan_cpu_init(cpu, CHAN_NOSV_SUBSYSTEM, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); + chan_cpu_init(cpu, ucpu, CHAN_NOSV_TYPEID, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); + chan_cpu_init(cpu, ucpu, CHAN_NOSV_APPID, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); + chan_cpu_init(cpu, ucpu, CHAN_NOSV_SUBSYSTEM, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); } } @@ -210,7 +210,7 @@ pre_task_running(struct ovni_emu *emu, struct nosv_task *task) } static void -pre_task_not_running(struct ovni_emu *emu, struct nosv_task *task) +pre_task_not_running(struct ovni_emu *emu) { struct ovni_ethread *th; @@ -249,7 +249,7 @@ pre_task(struct ovni_emu *emu) break; case 'p': case 'e': - pre_task_not_running(emu, task); + pre_task_not_running(emu); break; case 'c': default: @@ -406,6 +406,9 @@ pre_ss(struct ovni_emu *emu, int st) th = emu->cur_thread; chan_th = &th->chan[CHAN_NOSV_SUBSYSTEM]; + assert(chan_th->id == CHAN_NOSV_SUBSYSTEM); + dbg("pre_ss chan id %d st=%d\n", chan_th->id, st); + switch(emu->cur_ev->header.value) { case '[': @@ -426,6 +429,9 @@ hook_pre_nosv(struct ovni_emu *emu) { assert(emu->cur_ev->header.model == 'V'); + /* Ensure the thread is active */ + assert(emu->cur_thread->is_active); + switch(emu->cur_ev->header.category) { case 'T': pre_task(emu); break; diff --git a/emu_openmp.c b/emu_openmp.c index 7514612..49a54ad 100644 --- a/emu_openmp.c +++ b/emu_openmp.c @@ -14,26 +14,24 @@ hook_init_openmp(struct ovni_emu *emu) { struct ovni_ethread *th; struct ovni_cpu *cpu; - struct ovni_trace *trace; - int i, row, type; + size_t i; + int row; FILE *prv_th, *prv_cpu; int64_t *clock; + struct ovni_chan **uth, **ucpu; clock = &emu->delta_time; prv_th = emu->prv_thread; prv_cpu = emu->prv_cpu; - trace = &emu->trace; /* Init the channels in all threads */ for(i=0; itotal_nthreads; i++) { th = emu->global_thread[i]; row = th->gindex + 1; + uth = &emu->th_chan; - chan_th_init(th, CHAN_OPENMP_MODE, CHAN_TRACK_TH_RUNNING, row, prv_th, clock); - chan_enable(&th->chan[CHAN_OPENMP_MODE], 1); - chan_set(&th->chan[CHAN_OPENMP_MODE], ST_NULL); - chan_enable(&th->chan[CHAN_OPENMP_MODE], 0); + chan_th_init(th, uth, CHAN_OPENMP_MODE, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock); } /* Init the channels in all cpus */ @@ -41,8 +39,9 @@ hook_init_openmp(struct ovni_emu *emu) { cpu = emu->global_cpu[i]; row = cpu->gindex + 1; + ucpu = &emu->cpu_chan; - chan_cpu_init(cpu, CHAN_OPENMP_MODE, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); + chan_cpu_init(cpu, ucpu, CHAN_OPENMP_MODE, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); } } diff --git a/emu_ovni.c b/emu_ovni.c index f133b9d..b94e9a8 100644 --- a/emu_ovni.c +++ b/emu_ovni.c @@ -15,38 +15,27 @@ hook_init_ovni(struct ovni_emu *emu) { struct ovni_ethread *th; struct ovni_cpu *cpu; - struct ovni_trace *trace; - int i, row, type; + struct ovni_chan **uth, **ucpu; + size_t i; + int row; FILE *prv_th, *prv_cpu; int64_t *clock; clock = &emu->delta_time; prv_th = emu->prv_thread; prv_cpu = emu->prv_cpu; - trace = &emu->trace; /* Init the ovni channels in all threads */ for(i=0; itotal_nthreads; i++) { th = emu->global_thread[i]; row = th->gindex + 1; + uth = &emu->th_chan; - chan_th_init(th, CHAN_OVNI_TID, CHAN_TRACK_NONE, row, prv_th, clock); - chan_th_init(th, CHAN_OVNI_PID, CHAN_TRACK_NONE, row, prv_th, clock); - chan_th_init(th, CHAN_OVNI_CPU, CHAN_TRACK_NONE, row, prv_th, clock); - chan_th_init(th, CHAN_OVNI_STATE, CHAN_TRACK_NONE, row, prv_th, clock); - - chan_enable(&th->chan[CHAN_OVNI_TID], 1); - chan_set(&th->chan[CHAN_OVNI_TID], th->tid); - chan_enable(&th->chan[CHAN_OVNI_TID], 0); - - chan_enable(&th->chan[CHAN_OVNI_PID], 1); - chan_set(&th->chan[CHAN_OVNI_PID], th->proc->pid); - chan_enable(&th->chan[CHAN_OVNI_PID], 0); - - /* All threads begin in unknown state */ - chan_enable(&th->chan[CHAN_OVNI_STATE], 1); - chan_set(&th->chan[CHAN_OVNI_STATE], TH_ST_UNKNOWN); + chan_th_init(th, uth, CHAN_OVNI_TID, CHAN_TRACK_TH_RUNNING, th->tid, 0, 1, row, prv_th, clock); + chan_th_init(th, uth, CHAN_OVNI_PID, CHAN_TRACK_TH_RUNNING, th->proc->pid, 0, 1, row, prv_th, clock); + chan_th_init(th, uth, CHAN_OVNI_CPU, CHAN_TRACK_NONE, -1, 0, 1, row, prv_th, clock); + chan_th_init(th, uth, CHAN_OVNI_STATE, CHAN_TRACK_NONE, TH_ST_UNKNOWN, 1, 1, row, prv_th, clock); } /* Init the ovni channels in all cpus */ @@ -54,140 +43,137 @@ hook_init_ovni(struct ovni_emu *emu) { cpu = emu->global_cpu[i]; row = cpu->gindex + 1; + ucpu = &emu->cpu_chan; - chan_cpu_init(cpu, CHAN_OVNI_TID, CHAN_TRACK_NONE, row, prv_cpu, clock); - chan_cpu_init(cpu, CHAN_OVNI_PID, CHAN_TRACK_NONE, row, prv_cpu, clock); - chan_cpu_init(cpu, CHAN_OVNI_NTHREADS, CHAN_TRACK_NONE, row, prv_cpu, clock); + chan_cpu_init(cpu, ucpu, CHAN_OVNI_TID, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); + chan_cpu_init(cpu, ucpu, CHAN_OVNI_PID, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); + chan_cpu_init(cpu, ucpu, CHAN_OVNI_NTHREADS, CHAN_TRACK_NONE, row, prv_cpu, clock); + /* FIXME: Use extended initialization for CPUs too */ chan_enable(&cpu->chan[CHAN_OVNI_TID], 1); chan_set(&cpu->chan[CHAN_OVNI_TID], 0); - chan_emit(&cpu->chan[CHAN_OVNI_TID]); chan_enable(&cpu->chan[CHAN_OVNI_PID], 1); chan_set(&cpu->chan[CHAN_OVNI_PID], 0); - chan_emit(&cpu->chan[CHAN_OVNI_PID]); chan_enable(&cpu->chan[CHAN_OVNI_NTHREADS], 1); - chan_set(&cpu->chan[CHAN_OVNI_NTHREADS], cpu->nthreads); - chan_emit(&cpu->chan[CHAN_OVNI_NTHREADS]); + chan_set(&cpu->chan[CHAN_OVNI_NTHREADS], 0); } } /* --------------------------- pre ------------------------------- */ +/* Update the tracking channel if needed */ static void -thread_update_channels(struct ovni_ethread *th) -{ - struct ovni_chan *chan; - int i, st, enabled, is_running, is_unpaused; - - st = th->state; - is_running = (st == TH_ST_RUNNING); - is_unpaused = (st == TH_ST_RUNNING - || st == TH_ST_COOLING - || st == TH_ST_WARMING); - - for(i=0; ichan[i]; - - switch (chan->track) - { - case CHAN_TRACK_TH_RUNNING: - enabled = is_running ? 1 : 0; - break; - case CHAN_TRACK_TH_UNPAUSED: - enabled = is_unpaused ? 1 : 0; - break; - default: - continue; - } - - /* The channel is already in the proper state */ - if(chan_is_enabled(chan) == enabled) - continue; - - dbg("thread %d changes state to %d: chan %d enabled=%d\n", - th->tid, th->state, i, enabled); - chan_enable(chan, enabled); - } -} - -static void -thread_set_state(struct ovni_ethread *th, int state) +chan_tracking_update(struct ovni_chan *chan, struct ovni_ethread *th) { int enabled; + assert(th); + + switch (chan->track) + { + case CHAN_TRACK_TH_RUNNING: + enabled = th->is_running; + break; + case CHAN_TRACK_TH_ACTIVE: + enabled = th->is_active; + break; + default: + dbg("ignoring thread %d chan %d with track=%d\n", + th->tid, chan->id, chan->track); + return; + } + + /* The channel is already in the proper state */ + if(chan_is_enabled(chan) == enabled) + return; + + dbg("thread %d changes state to %d: chan %d enabled=%d\n", + th->tid, th->state, chan->id, enabled); + + chan_enable(chan, enabled); +} + +/* Sets the state of the thread and updates the thread tracking channels */ +static void +thread_set_state(struct ovni_ethread *th, int state) +{ + int i; + + /* The state must be updated when a cpu is set */ + assert(th->cpu); + + dbg("thread_set_state: setting thread %d state %d\n", + th->tid, state); + th->state = state; + th->is_running = (state == TH_ST_RUNNING) ? 1 : 0; + + th->is_active = (state == TH_ST_RUNNING + || state == TH_ST_COOLING + || state == TH_ST_WARMING) ? 1 : 0; + chan_set(&th->chan[CHAN_OVNI_STATE], th->state); /* Enable or disable the thread channels that track the thread state */ - thread_update_channels(th); + for(i=0; ichan[i], th); + + dbg("thread_set_state: done\n"); } -void -update_cpu(struct ovni_emu *emu, struct ovni_cpu *cpu) +static void +cpu_update_th_stats(struct ovni_cpu *cpu) { - int i, tid, pid, enabled, nrunning; - struct ovni_loom *loom; - struct ovni_ethread *th, *last_th; - struct ovni_chan *chan; + struct ovni_ethread *th, *th_running = NULL, *th_active = NULL; + size_t i; + int active = 0, running = 0; - loom = emu->cur_loom; - - /* Count running threads */ - for(i=0, nrunning=0; inthreads; i++) + for(i=0; inthreads; i++) { th = cpu->thread[i]; if(th->state == TH_ST_RUNNING) { - last_th = th; - nrunning++; + th_running = th; + running++; + th_active = th; + active++; + } + else if(th->state == TH_ST_COOLING || th->state == TH_ST_WARMING) + { + th_active = th; + active++; } } - chan_set(&cpu->chan[CHAN_OVNI_NTHREADS], nrunning); + cpu->nrunning_threads = running; + cpu->nactive_threads = active; + cpu->th_running = th_running; + cpu->th_active = th_active; +} - th = NULL; +static void +update_cpu(struct ovni_cpu *cpu) +{ + int i; - if(nrunning == 0) - { - /* No thread running */ - tid = pid = 0; - } - else if(nrunning == 1) - { - /* Take the info from the running thread */ - tid = last_th->tid; - pid = last_th->proc->pid; - th = last_th; - } - else - { - /* Multiple threads */ - tid = pid = 1; - } + dbg("updating cpu %s\n", cpu->name); - chan_set(&cpu->chan[CHAN_OVNI_TID], tid); - chan_set(&cpu->chan[CHAN_OVNI_PID], pid); + /* Update the running and active threads first */ + cpu_update_th_stats(cpu); -// enabled = (th != NULL && th->state == TH_ST_RUNNING ? 1 : 0); -// -// /* Update all channels that need to follow the running thread */ -// for(i=0; ichan[i]; -// -// if(chan->track == CHAN_TRACK_TH_RUNNING) -// { -// chan_enable(chan, enabled); -// dbg("cpu thread %d: %s chan %d\n", -// tid, -// enabled ? "enable" : "disable", -// i); -// } -// } + /* From the CPU channels we only need to manually update the number of + * threads running in the CPU */ + if(chan_get_st(&cpu->chan[CHAN_OVNI_NTHREADS]) != (int) cpu->nrunning_threads) + chan_set(&cpu->chan[CHAN_OVNI_NTHREADS], (int) cpu->nrunning_threads); + + /* Update all tracking channels */ + for(i=0; ichan[i]); + + dbg("updating cpu %s complete!\n", cpu->name); } struct ovni_cpu * @@ -203,10 +189,10 @@ emu_get_cpu(struct ovni_loom *loom, int cpuid) return &loom->cpu[cpuid]; } -int +static int emu_cpu_find_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread) { - int i; + size_t i; for(i=0; inthreads; i++) if(cpu->thread[i] == thread) @@ -219,22 +205,28 @@ emu_cpu_find_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread) return i; } +/* Add the given thread to the list of threads assigned to the CPU */ static void -cpu_add_thread(struct ovni_emu *emu, struct ovni_cpu *cpu, struct ovni_ethread *thread) +cpu_add_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread) { /* Found, abort */ if(emu_cpu_find_thread(cpu, thread) >= 0) + { + err("The thread %d is already assigned to %s\n", + thread->tid, cpu->name); abort(); + } + /* Ensure that we have room for another thread */ assert(cpu->nthreads < OVNI_MAX_THR); cpu->thread[cpu->nthreads++] = thread; - update_cpu(emu, cpu); + update_cpu(cpu); } static void -cpu_remove_thread(struct ovni_emu *emu, struct ovni_cpu *cpu, struct ovni_ethread *thread) +cpu_remove_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread) { int i, j; @@ -244,31 +236,32 @@ cpu_remove_thread(struct ovni_emu *emu, struct ovni_cpu *cpu, struct ovni_ethrea if(i < 0) abort(); - for(j=i; j+1 < cpu->nthreads; j++) + for(j=i; j+1 < (int)cpu->nthreads; j++) cpu->thread[i] = cpu->thread[j+1]; cpu->nthreads--; - update_cpu(emu, cpu); + update_cpu(cpu); } -void -cpu_migrate_thread(struct ovni_emu *emu, - struct ovni_cpu *cpu, +static void +cpu_migrate_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread, struct ovni_cpu *newcpu) { - cpu_remove_thread(emu, cpu, thread); - cpu_add_thread(emu, newcpu, thread); + cpu_remove_thread(cpu, thread); + cpu_add_thread(newcpu, thread); } /* Sets the thread assigned CPU to the given one. * Precondition: the thread CPU must be null */ -void +static void thread_set_cpu(struct ovni_ethread *th, struct ovni_cpu *cpu) { assert(th->cpu == NULL); + dbg("thread_set_cpu: setting thread %d cpu to %s\n", + th->tid, cpu->name); th->cpu = cpu; chan_enable(&th->chan[CHAN_OVNI_CPU], 1); @@ -277,7 +270,7 @@ thread_set_cpu(struct ovni_ethread *th, struct ovni_cpu *cpu) /* Unsets the thread assigned CPU. * Precondition: the thread CPU must be not null */ -void +static void thread_unset_cpu(struct ovni_ethread *th) { assert(th->cpu != NULL); @@ -288,7 +281,7 @@ thread_unset_cpu(struct ovni_ethread *th) /* Migrates the thread assigned CPU to the given one. * Precondition: the thread CPU must be not null */ -void +static void thread_migrate_cpu(struct ovni_ethread *th, struct ovni_cpu *cpu) { assert(th->cpu != NULL); @@ -298,31 +291,31 @@ thread_migrate_cpu(struct ovni_ethread *th, struct ovni_cpu *cpu) chan_set(&th->chan[CHAN_OVNI_CPU], cpu->gindex + 1); } -static void -print_threads_state(struct ovni_loom *loom) -{ - struct ovni_cpu *cpu; - int i, j; - - for(i=0; incpus; i++) - { - cpu = &loom->cpu[i]; - - dbg("-- cpu %d runs %lu threads:", i, cpu->nthreads); - for(j=0; jnthreads; j++) - { - dbg(" %d", cpu->thread[j]->tid); - } - dbg("\n"); - } - - dbg("-- vcpu runs %lu threads:", loom->vcpu.nthreads); - for(j=0; jvcpu.nthreads; j++) - { - dbg(" %d", loom->vcpu.thread[j]->tid); - } - dbg("\n"); -} +//static void +//print_threads_state(struct ovni_loom *loom) +//{ +// struct ovni_cpu *cpu; +// size_t i, j; +// +// for(i=0; incpus; i++) +// { +// cpu = &loom->cpu[i]; +// +// dbg("-- cpu %ld runs %lu threads:", i, cpu->nthreads); +// for(j=0; jnthreads; j++) +// { +// dbg(" %ld", cpu->thread[j]->tid); +// } +// dbg("\n"); +// } +// +// dbg("-- vcpu runs %lu threads:", loom->vcpu.nthreads); +// for(j=0; jvcpu.nthreads; j++) +// { +// dbg(" %ld", loom->vcpu.thread[j]->tid); +// } +// dbg("\n"); +//} static void pre_thread_execute(struct ovni_emu *emu, struct ovni_ethread *th) @@ -334,84 +327,85 @@ pre_thread_execute(struct ovni_emu *emu, struct ovni_ethread *th) assert(th->state != TH_ST_RUNNING); cpuid = emu->cur_ev->payload.i32[0]; - //dbg("thread %d runs in cpuid %d\n", th->tid, - // cpuid); - cpu = emu_get_cpu(emu->cur_loom, cpuid); - thread_set_state(th, TH_ST_RUNNING); + cpu = emu_get_cpu(emu->cur_loom, cpuid); + dbg("pre_thread_execute: thread %d runs in CPU %s\n", th->tid, cpu->name); + + /* First set the CPU in the thread */ thread_set_cpu(th, cpu); - cpu_add_thread(emu, cpu, th); + /* Then set the thread to running state */ + thread_set_state(th, TH_ST_RUNNING); - /* Enable thread TID and PID */ - chan_enable(&th->chan[CHAN_OVNI_TID], 1); - chan_enable(&th->chan[CHAN_OVNI_PID], 1); + /* And then add the thread to the CPU, so tracking channels see the + * updated thread state */ + cpu_add_thread(cpu, th); } static void -pre_thread_end(struct ovni_emu *emu, struct ovni_ethread *th) +pre_thread_end(struct ovni_ethread *th) { assert(th->state == TH_ST_RUNNING); assert(th->cpu); - cpu_remove_thread(emu, th->cpu, th); - + /* First update the thread state */ thread_set_state(th, TH_ST_DEAD); - thread_unset_cpu(th); - /* Disable thread TID and PID */ - chan_enable(&th->chan[CHAN_OVNI_TID], 0); - chan_enable(&th->chan[CHAN_OVNI_PID], 0); + /* Then remove it from the cpu, so channels are properly updated */ + cpu_remove_thread(th->cpu, th); + + thread_unset_cpu(th); } static void -pre_thread_pause(struct ovni_emu *emu, struct ovni_ethread *th) +pre_thread_pause(struct ovni_ethread *th) { assert(th->state == TH_ST_RUNNING || th->state == TH_ST_COOLING); assert(th->cpu); thread_set_state(th, TH_ST_PAUSED); + update_cpu(th->cpu); } static void -pre_thread_resume(struct ovni_emu *emu, struct ovni_ethread *th) +pre_thread_resume(struct ovni_ethread *th) { assert(th->state == TH_ST_PAUSED || th->state == TH_ST_WARMING); assert(th->cpu); thread_set_state(th, TH_ST_RUNNING); + update_cpu(th->cpu); } static void -pre_thread_cool(struct ovni_emu *emu, struct ovni_ethread *th) +pre_thread_cool(struct ovni_ethread *th) { assert(th->state == TH_ST_RUNNING); assert(th->cpu); thread_set_state(th, TH_ST_COOLING); + update_cpu(th->cpu); } static void -pre_thread_warm(struct ovni_emu *emu, struct ovni_ethread *th) +pre_thread_warm(struct ovni_ethread *th) { assert(th->state == TH_ST_PAUSED); assert(th->cpu); thread_set_state(th, TH_ST_WARMING); + update_cpu(th->cpu); } static void pre_thread(struct ovni_emu *emu) { struct ovni_ev *ev; - struct ovni_cpu *cpu; - struct ovni_ethread *th, *remote_thread; - int i; + struct ovni_ethread *th; //emu_emit(emu); th = emu->cur_thread; - cpu = th->cpu; ev = emu->cur_ev; switch(ev->header.value) @@ -425,11 +419,11 @@ pre_thread(struct ovni_emu *emu) break; case 'x': pre_thread_execute(emu, th); break; - case 'e': pre_thread_end(emu, th); break; - case 'p': pre_thread_pause(emu, th); break; - case 'r': pre_thread_resume(emu, th); break; - case 'c': pre_thread_cool(emu, th); break; - case 'w': pre_thread_warm(emu, th); break; + case 'e': pre_thread_end(th); break; + case 'p': pre_thread_pause(th); break; + case 'r': pre_thread_resume(th); break; + case 'c': pre_thread_cool(th); break; + case 'w': pre_thread_warm(th); break; default: err("unknown thread event value %c\n", ev->header.value); @@ -457,13 +451,14 @@ pre_affinity_set(struct ovni_emu *emu) if(th->cpu == newcpu) { - err("warning: thread %d affinity already set to cpu %d\n", - th->tid, - th->cpu->gindex); + /* No need to warn the user */ + //err("warning: thread %d affinity already set to cpu %d\n", + // th->tid, + // th->cpu->gindex); return; } - cpu_migrate_thread(emu, th->cpu, th, newcpu); + cpu_migrate_thread(th->cpu, th, newcpu); thread_migrate_cpu(th, newcpu); //dbg("cpu %d now runs %d\n", cpuid, th->tid); @@ -472,7 +467,8 @@ pre_affinity_set(struct ovni_emu *emu) static void pre_affinity_remote(struct ovni_emu *emu) { - int i, cpuid, tid; + size_t i; + int32_t cpuid, tid; struct ovni_cpu *newcpu; struct ovni_ethread *remote_th; struct ovni_loom *loom; @@ -521,7 +517,7 @@ pre_affinity_remote(struct ovni_emu *emu) /* Migrate current cpu to the one at cpuid */ newcpu = emu_get_cpu(emu->cur_loom, cpuid); - cpu_migrate_thread(emu, remote_th->cpu, remote_th, newcpu); + cpu_migrate_thread(remote_th->cpu, remote_th, newcpu); thread_migrate_cpu(remote_th, newcpu); //dbg("remote_th %d switches to cpu %d by remote petition\n", tid, @@ -543,12 +539,14 @@ pre_affinity(struct ovni_emu *emu) } } -void +static void pre_burst(struct ovni_emu *emu) { struct ovni_ethread *th; int64_t dt; + UNUSED(dt); + th = emu->cur_thread; if(th->nbursts >= MAX_BURSTS) @@ -563,7 +561,7 @@ pre_burst(struct ovni_emu *emu) dt = th->burst_time[th->nbursts] - th->burst_time[th->nbursts - 1]; - err("burst delta time %ld ns\n", dt); + dbg("burst delta time %ld ns\n", dt); } th->nbursts++; @@ -590,10 +588,3 @@ hook_pre_ovni(struct ovni_emu *emu) //print_threads_state(emu); } - -/* --------------------------- post ------------------------------- */ - -void -hook_post_ovni(struct ovni_emu *emu) -{ -} diff --git a/emu_tampi.c b/emu_tampi.c index 5f563da..4167a7a 100644 --- a/emu_tampi.c +++ b/emu_tampi.c @@ -14,26 +14,24 @@ hook_init_tampi(struct ovni_emu *emu) { struct ovni_ethread *th; struct ovni_cpu *cpu; - struct ovni_trace *trace; - int i, row, type; + size_t i; + int row; FILE *prv_th, *prv_cpu; int64_t *clock; + struct ovni_chan **uth, **ucpu; clock = &emu->delta_time; prv_th = emu->prv_thread; prv_cpu = emu->prv_cpu; - trace = &emu->trace; /* Init the channels in all threads */ for(i=0; itotal_nthreads; i++) { th = emu->global_thread[i]; row = th->gindex + 1; + uth = &emu->th_chan; - chan_th_init(th, CHAN_TAMPI_MODE, CHAN_TRACK_TH_RUNNING, row, prv_th, clock); - chan_enable(&th->chan[CHAN_TAMPI_MODE], 1); - chan_set(&th->chan[CHAN_TAMPI_MODE], ST_NULL); - chan_enable(&th->chan[CHAN_TAMPI_MODE], 0); + chan_th_init(th, uth, CHAN_TAMPI_MODE, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock); } /* Init the channels in all cpus */ @@ -41,8 +39,9 @@ hook_init_tampi(struct ovni_emu *emu) { cpu = emu->global_cpu[i]; row = cpu->gindex + 1; + ucpu = &emu->cpu_chan; - chan_cpu_init(cpu, CHAN_TAMPI_MODE, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); + chan_cpu_init(cpu, ucpu, CHAN_TAMPI_MODE, CHAN_TRACK_TH_RUNNING, row, prv_cpu, clock); } } diff --git a/heap.h b/heap.h new file mode 100644 index 0000000..b3586dc --- /dev/null +++ b/heap.h @@ -0,0 +1,296 @@ +/* + * heap.h - basic heap with intrusive structures. + * Copyright (C) 2021 Barcelona Supercomputing Center (BSC) + * Author: David Alvarez + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#ifndef HEAP_H +#define HEAP_H + +#include +#include + +typedef struct heap_node { + struct heap_node *parent; + struct heap_node *left; + struct heap_node *right; +} heap_node_t; + +typedef struct head_head { + struct heap_node *root; + size_t size; +} heap_head_t; + +#define heap_elem(head, type, name) \ + ((type *) (((char *) head) - offsetof(type, name))) + +#define heap_swap(a, b) \ + do { heap_node_t *aux = (a); (a) = (b); (b) = aux; } while(0) + +/* heap_node_compare_t - comparison function. + * The comparison function cmp(a, b) shall return an integer: + * > 0 if a > b + * < 0 if a < b + * = 0 if a == b + * + * Invert the comparison function to get a min-heap instead */ +typedef int (*heap_node_compare_t)(heap_node_t *a, heap_node_t *b); + +static inline void +heap_init(heap_head_t *head) +{ + head->root = NULL; + head->size = 0; +} + +/* max_heapify maintains the max-heap property + * When it is called for a node "a", a->left and a->right are max-heaps, but "a" + * may be smaller than a->left or a->right, violating the max-heap property + * max_heapify will float "a" down in the max-heap */ +static inline void +heap_max_heapify(heap_head_t *head, heap_node_t *a, heap_node_compare_t cmp) +{ + heap_node_t *largest = a; + + if (a->left && cmp(a->left, largest) > 0) + largest = a->left; + if (a->right && cmp(a->right, largest) > 0) + largest = a->right; + + if (largest == a) + return; + + // Exchange + largest->parent = a->parent; + + if (a->parent) { + if (a->parent->left == a) + a->parent->left = largest; + else + a->parent->right = largest; + } + a->parent = largest; + + if (head) + head->root = largest; + + if (a->left == largest) { + a->left = largest->left; + if (a->left) + a->left->parent = a; + largest->left = a; + + heap_swap(a->right, largest->right); + if (a->right) + a->right->parent = a; + if (largest->right) + largest->right->parent = largest; + } else { + // Right + a->right = largest->right; + if (a->right) + a->right->parent = a; + + largest->right = a; + heap_swap(a->left, largest->left); + if (a->left) + a->left->parent = a; + if (largest->left) + largest->left->parent = largest; + } + + heap_max_heapify(NULL, a, cmp); +} + +static inline heap_node_t * +heap_max(heap_head_t *head) +{ + return head->root; +} + +/* Get a move to reach a leaf */ +static inline int +heap_get_move(size_t *node /*out*/) +{ + size_t aux_node = *node; + + // Round to previous po2 + size_t base = (1ULL) << (sizeof(size_t) * 8 + - __builtin_clzll(aux_node) - 1); + + aux_node -= base / 2; + + if (aux_node < base) { + // Left + *node = aux_node; + return 0; + } else { + // Right + *node = aux_node - base / 2; + return 1; + } +} + +/* Travel down the heap to find the correct node */ +static inline heap_node_t * +heap_get(heap_head_t *head, size_t node) +{ + heap_node_t *current = head->root; + + while (node != 1) { + if (heap_get_move(&node)) + current = current->right; + else + current = current->left; + } + + return current; +} + +static inline heap_node_t * +heap_pop_max(heap_head_t *head, heap_node_compare_t cmp) +{ + heap_node_t *max = head->root; + + if (!max) + return NULL; + + size_t size = head->size; + heap_node_t *change = heap_get(head, size); + assert(change); + + head->size--; + + // Special case + if (!change->parent) { + head->root = NULL; + return max; + } + + if (change->parent == max) { + // Right child + if (size % 2) { + change->left = max->left; + if (change->left) + change->left->parent = change; + } else { + change->right = max->right; + if (change->right) + change->right->parent = change; + } + + change->parent = NULL; + head->root = change; + } else { + // Right child + if (size % 2) + change->parent->right = NULL; + else + change->parent->left = NULL; + + assert(!change->left); + assert(!change->right); + + change->left = max->left; + if (change->left) + change->left->parent = change; + change->right = max->right; + if (change->right) + change->right->parent = change; + + change->parent = NULL; + head->root = change; + } + + heap_max_heapify(head, change, cmp); + return max; +} + +static inline void +heap_insert(heap_head_t *head, heap_node_t *node, heap_node_compare_t cmp) +{ + node->left = NULL; + node->right = NULL; + node->parent = NULL; + head->size++; + + if (!head->root) { + // Easy + head->root = node; + return; + } + + // Insert on size's parent + size_t insert = head->size / 2; + heap_node_t *parent = heap_get(head, insert); + + // Right child + if (head->size % 2) { + assert(!parent->right); + parent->right = node; + } else { + assert(!parent->left); + parent->left = node; + } + + node->parent = parent; + + // Equivalent of HEAP-INCREASE-KEY + while (parent && cmp(node, parent) > 0) { + // Bubble up + node->parent = parent->parent; + parent->parent = node; + + if (node->parent) { + if (node->parent->left == parent) + node->parent->left = node; + else + node->parent->right = node; + } + + if (parent->left == node) { + parent->left = node->left; + if (parent->left) + parent->left->parent = parent; + + node->left = parent; + + heap_swap(node->right, parent->right); + if (node->right) + node->right->parent = node; + if (parent->right) + parent->right->parent = parent; + } else { + parent->right = node->right; + if (parent->right) + parent->right->parent = parent; + + node->right = parent; + heap_swap(node->left, parent->left); + if (node->left) + node->left->parent = node; + if (parent->left) + parent->left->parent = parent; + } + + parent = node->parent; + } + + if (!parent) + head->root = node; +} + +#endif // HEAP_H diff --git a/ovni.c b/ovni.c index db68afb..152fce8 100644 --- a/ovni.c +++ b/ovni.c @@ -67,9 +67,8 @@ create_trace_dirs(char *tracedir, char *loom, int proc) } static int -create_trace_stream() +create_trace_stream(void) { - int fd; char path[PATH_MAX]; fprintf(stderr, "create thread stream tid=%d gettid=%d rproc.proc=%d rproc.ready=%d\n", @@ -96,8 +95,6 @@ create_trace_stream() static int proc_metadata_init(struct ovni_rproc *proc) { - JSON_Value *meta; - proc->meta = json_value_init_object(); if(proc->meta == NULL) @@ -200,8 +197,6 @@ proc_set_app(int appid) int ovni_proc_init(int app, char *loom, int proc) { - int i; - assert(rproc.ready == 0); memset(&rproc, 0, sizeof(rproc)); @@ -228,7 +223,7 @@ ovni_proc_init(int app, char *loom, int proc) } int -ovni_proc_fini() +ovni_proc_fini(void) { if(proc_metadata_store(&rproc) != 0) abort(); @@ -239,8 +234,6 @@ ovni_proc_fini() int ovni_thread_init(pid_t tid) { - int i; - assert(tid != 0); if(rthread.ready) @@ -270,7 +263,7 @@ ovni_thread_init(pid_t tid) abort(); } - if(create_trace_stream(tid)) + if(create_trace_stream()) abort(); rthread.ready = 1; @@ -278,25 +271,19 @@ ovni_thread_init(pid_t tid) return 0; } -int -ovni_thread_free() +void +ovni_thread_free(void) { assert(rthread.ready); free(rthread.evbuf); } int -ovni_thread_isready() +ovni_thread_isready(void) { return rthread.ready; } -void -ovni_cpu_set(int cpu) -{ - rthread.cpu = cpu; -} - static inline uint64_t rdtsc(void) { @@ -308,21 +295,21 @@ uint64_t rdtsc(void) } uint64_t -ovni_get_clock() +ovni_get_clock(void) { struct timespec tp; uint64_t ns = 1000LL * 1000LL * 1000LL; uint64_t raw; - int ret; #ifdef USE_RDTSC raw = rdtsc(); #else - ret = clock_gettime(rproc.clockid, &tp); - #ifdef ENABLE_SLOW_CHECKS + int ret = clock_gettime(rproc.clockid, &tp); if(ret) abort(); +#else + clock_gettime(rproc.clockid, &tp); #endif /* ENABLE_SLOW_CHECKS */ raw = tp.tv_sec * ns + tp.tv_nsec; @@ -336,27 +323,27 @@ ovni_get_clock() /* Sets the current time so that all subsequent events have the new * timestamp */ void -ovni_clock_update() +ovni_clock_update(void) { rthread.clockvalue = ovni_get_clock(); } -static void -hexdump(uint8_t *buf, size_t size) -{ - int i, j; - - //printf("writing %ld bytes in cpu=%d\n", size, rthread.cpu); - - for(i=0; iheader.flags & OVNI_EV_JUMBO) == 0); assert(size >= 2); @@ -457,7 +444,7 @@ ovni_payload_add(struct ovni_ev *ev, uint8_t *buf, int size) memcpy(&ev->payload.u8[payload_size], buf, size); payload_size += size; - ev->header.flags = ev->header.flags & 0xf0 | (payload_size-1) & 0x0f; + ev->header.flags = (ev->header.flags & 0xf0) | ((payload_size-1) & 0x0f); } int @@ -470,7 +457,7 @@ static void ovni_ev_add(struct ovni_ev *ev); int -ovni_flush() +ovni_flush(void) { int ret = 0; struct ovni_ev pre={0}, post={0}; @@ -495,7 +482,7 @@ ovni_flush() return ret; } -void +static void ovni_ev_add_jumbo(struct ovni_ev *ev, uint8_t *buf, uint32_t bufsize) { size_t evsize, totalsize; @@ -639,9 +626,19 @@ load_proc(struct ovni_eproc *proc, struct ovni_loom *loom, int index, int pid, c proc->gindex = total_procs++; proc->loom = loom; - sprintf(path, "%s/%s", procdir, "metadata.json"); + if(snprintf(path, PATH_MAX, "%s/%s", procdir, "metadata.json") >= + PATH_MAX) + { + err("snprintf: path too large: %s\n", procdir); + abort(); + } + proc->meta = json_parse_file_with_comments(path); - assert(proc->meta); + if(proc->meta == NULL) + { + err("error loading metadata from %s\n", path); + return -1; + } /* The appid is populated from the metadata */ load_proc_metadata(proc); @@ -658,7 +655,12 @@ load_proc(struct ovni_eproc *proc, struct ovni_loom *loom, int index, int pid, c if(find_dir_prefix_int(dirent, "thread", &tid) != 0) continue; - sprintf(path, "%s/%s", procdir, dirent->d_name); + if(snprintf(path, PATH_MAX, "%s/%s", procdir, dirent->d_name) >= + PATH_MAX) + { + err("snprintf: path too large: %s\n", procdir); + abort(); + } if(proc->nthreads >= OVNI_MAX_THR) { @@ -686,7 +688,6 @@ load_loom(struct ovni_loom *loom, int loomid, char *loomdir) { int pid; char path[PATH_MAX]; - struct stat st; DIR *dir; struct dirent *dirent; struct ovni_eproc *proc; @@ -734,13 +735,12 @@ compare_alph(const void* a, const void* b) int ovni_load_trace(struct ovni_trace *trace, char *tracedir) { - int i; - char path[PATH_MAX]; + char *looms[OVNI_MAX_LOOM]; + char *hosts[OVNI_MAX_LOOM]; const char *loom_name; - struct stat st; DIR *dir; struct dirent *dirent; - struct ovni_loom *loom; + size_t l; trace->nlooms = 0; @@ -751,11 +751,10 @@ ovni_load_trace(struct ovni_trace *trace, char *tracedir) return -1; } - char *looms[OVNI_MAX_LOOM]; - char *hosts[OVNI_MAX_LOOM]; - for (int l = 0; l < OVNI_MAX_LOOM; ++l) { - looms[l] = malloc(PATH_MAX*sizeof(char)); - hosts[l] = malloc(PATH_MAX*sizeof(char)); + for(l=0; lnlooms, sizeof(const char*), compare_alph); qsort((const char **) looms, trace->nlooms, sizeof(const char*), compare_alph); - for (int l = 0; l < trace->nlooms; ++l) { - /* FIXME: Unsafe */ + for(l=0; lnlooms; l++) + { + if(strlen(hosts[l]) >= PATH_MAX) + { + err("error hostname too long: %s\n", hosts[l]); + exit(EXIT_FAILURE); + } + + /* Safe */ strcpy(trace->loom[l].hostname, hosts[l]); if(load_loom(&trace->loom[l], l, looms[l]) != 0) @@ -793,7 +799,8 @@ ovni_load_trace(struct ovni_trace *trace, char *tracedir) closedir(dir); - for (int l = 0; l < OVNI_MAX_LOOM; ++l) { + for(l=0; lnstreams); + err("loaded %ld streams\n", trace->nstreams); for(s=0, i=0; inlooms; i++) { @@ -913,9 +920,7 @@ ovni_free_streams(struct ovni_trace *trace) int ovni_load_next_event(struct ovni_stream *stream) { - int i; - size_t n, size; - uint8_t flags; + size_t size; if(stream->active == 0) { @@ -927,11 +932,13 @@ ovni_load_next_event(struct ovni_stream *stream) { stream->cur_ev = (struct ovni_ev *) stream->buf; stream->offset = 0; + size = 0; goto out; } //printf("advancing offset %ld bytes\n", ovni_ev_size(stream->cur_ev)); - stream->offset += ovni_ev_size(stream->cur_ev); + size = ovni_ev_size(stream->cur_ev); + stream->offset += size; /* We have reached the end */ if(stream->offset == stream->size) @@ -955,5 +962,5 @@ out: //hexdump((uint8_t *) stream->cur_ev, ovni_ev_size(stream->cur_ev)); //dbg("---------\n"); - return 0; + return (int) size; } diff --git a/ovni.h b/ovni.h index 2f348d0..685896f 100644 --- a/ovni.h +++ b/ovni.h @@ -114,18 +114,22 @@ struct ovni_rproc { int ovni_proc_init(int app, char *loom, int proc); -int ovni_proc_fini(); +int ovni_proc_fini(void); int ovni_thread_init(pid_t tid); -int ovni_thread_isready(); +void ovni_thread_free(void); -void ovni_clock_update(); +int ovni_thread_isready(void); + +void ovni_clock_update(void); void ovni_ev_set_mcv(struct ovni_ev *ev, char *mcv); uint64_t ovni_ev_get_clock(struct ovni_ev *ev); +uint64_t ovni_get_clock(void); + void ovni_payload_add(struct ovni_ev *ev, uint8_t *buf, int size); int ovni_ev_size(struct ovni_ev *ev); @@ -138,7 +142,7 @@ void ovni_add_cpu(int index, int phyid); void ovni_ev(struct ovni_ev *ev); void ovni_ev_jumbo(struct ovni_ev *ev, uint8_t *buf, uint32_t bufsize); -int ovni_flush(); +int ovni_flush(void); #ifdef __cplusplus } diff --git a/ovni2prv.c b/ovni2prv.c index ad29587..32c42df 100644 --- a/ovni2prv.c +++ b/ovni2prv.c @@ -11,11 +11,11 @@ #include "ovni.h" #include "ovni_trace.h" -void emit(struct ovni_stream *stream, struct ovni_ev *ev, int row) +static void +emit(struct ovni_ev *ev, int row) { static uint64_t firstclock = 0; int64_t delta; - int task; if(firstclock == 0) firstclock = ovni_ev_get_clock(ev); @@ -34,9 +34,11 @@ void emit(struct ovni_stream *stream, struct ovni_ev *ev, int row) printf("2:0:1:1:%d:%ld:%d:%d\n", row, delta, ev->header.category, ev->header.value); } -void dump_events(struct ovni_trace *trace) +static void +dump_events(struct ovni_trace *trace) { - int i, f, row; + size_t i; + int f, row; uint64_t minclock, lastclock; struct ovni_ev *ev; struct ovni_stream *stream; @@ -85,7 +87,7 @@ void dump_events(struct ovni_trace *trace) /* Emit current event */ row = f + 1; - emit(stream, stream->cur_ev, row); + emit(stream->cur_ev, row); lastclock = ovni_ev_get_clock(stream->cur_ev); @@ -124,7 +126,8 @@ int main(int argc, char *argv[]) if(ovni_load_streams(trace)) return 1; - printf("#Paraver (19/01/38 at 03:14):00000000000000000000_ns:0:1:1(%d:1)\n", trace->nstreams); + printf("#Paraver (19/01/38 at 03:14):00000000000000000000_ns:0:1:1(%ld:1)\n", + trace->nstreams); dump_events(trace); diff --git a/pcf.c b/pcf.c index ce25e1b..5f8f55b 100644 --- a/pcf.c +++ b/pcf.c @@ -90,7 +90,63 @@ struct event_type { struct event_value *values; }; -struct event_value thread_state_values[] = { +/* ---------------- CHAN_OVNI_PID ---------------- */ + +struct event_value ovni_pid_values[] = { + { 0, "None" }, + { ST_TOO_MANY_TH, "Unknown PID: Multiple threads running" }, + /* FIXME: PID values may collide with error code values */ + { -1, NULL }, +}; + +struct event_type thread_ovni_pid = { + 0, chan_to_prvtype[CHAN_OVNI_PID][CHAN_TH], + "Thread: PID of the RUNNING thread", + ovni_pid_values +}; + +struct event_type cpu_ovni_pid = { + 0, chan_to_prvtype[CHAN_OVNI_PID][CHAN_CPU], + "CPU: PID of the RUNNING thread", + ovni_pid_values +}; + +/* ---------------- CHAN_OVNI_TID ---------------- */ + +struct event_value ovni_tid_values[] = { + { 0, "None" }, + { ST_TOO_MANY_TH, "Unknown TID: Multiple threads running" }, + /* FIXME: TID values may collide with error code values */ + { -1, NULL }, +}; + +struct event_type thread_ovni_tid = { + 0, chan_to_prvtype[CHAN_OVNI_TID][CHAN_TH], + "Thread: TID of the RUNNING thread", + ovni_tid_values +}; + +struct event_type cpu_ovni_tid = { + 0, chan_to_prvtype[CHAN_OVNI_TID][CHAN_CPU], + "CPU: TID of the RUNNING thread", + ovni_tid_values +}; + +/* ---------------- CHAN_OVNI_NTHREADS ---------------- */ + +struct event_value ovni_nthreads_values[] = { + { -1, NULL }, +}; + +struct event_type cpu_ovni_nthreads = { + 0, chan_to_prvtype[CHAN_OVNI_NTHREADS][CHAN_CPU], + "CPU: Number of RUNNING threads", + ovni_nthreads_values +}; + +/* ---------------- CHAN_OVNI_STATE ---------------- */ + +struct event_value ovni_state_values[] = { { TH_ST_UNKNOWN, "Unknown" }, { TH_ST_RUNNING, "Running" }, { TH_ST_PAUSED, "Paused" }, @@ -100,26 +156,94 @@ struct event_value thread_state_values[] = { { -1, NULL }, }; -/* FIXME: Use enum */ -struct event_type thread_state = { - 0, 13, "Thread: State", - thread_state_values +struct event_type thread_ovni_state = { + 0, chan_to_prvtype[CHAN_OVNI_STATE][CHAN_TH], + "Thread: State of the CURRENT thread", + ovni_state_values }; -struct event_value thread_tid_values[] = { - { 0, "None" }, - { 1, "Multiple threads" }, +/* PRV CPU not used for the state */ + +/* ---------------- CHAN_OVNI_APPID ---------------- */ + +/* Not used */ + +/* ---------------- CHAN_OVNI_CPU ---------------- */ + +struct event_type thread_cpu_affinity = { + 0, chan_to_prvtype[CHAN_OVNI_CPU][CHAN_TH], + "Thread: CPU affinity of the CURRENT thread", + /* Ignored */ NULL +}; + +/* ---------------- CHAN_NOSV_TASKID ---------------- */ + +struct event_value nosv_taskid_values[] = { + { ST_TOO_MANY_TH, "Unknown TaskID: Multiple threads running" }, + /* FIXME: Task ID values may collide with error code values */ { -1, NULL }, }; -struct event_type thread_tid = { - 0, 61, "CPU: Thread TID", - thread_tid_values +struct event_type thread_nosv_taskid = { + 0, chan_to_prvtype[CHAN_NOSV_TASKID][CHAN_TH], + "Thread: nOS-V TaskID of the RUNNING thread", + nosv_taskid_values }; +struct event_type cpu_nosv_taskid = { + 0, chan_to_prvtype[CHAN_NOSV_TASKID][CHAN_CPU], + "CPU: nOS-V TaskID of the RUNNING thread", + nosv_taskid_values +}; + +/* ---------------- CHAN_NOSV_TYPEID ---------------- */ + +struct event_value nosv_typeid_values[] = { + { ST_TOO_MANY_TH, "Unknown Task TypeID: Multiple threads running" }, + /* FIXME: Task ID values may collide with error code values */ + { -1, NULL }, +}; + +struct event_type thread_nosv_typeid = { + 0, chan_to_prvtype[CHAN_NOSV_TYPEID][CHAN_TH], + "Thread: nOS-V task TypeID of the RUNNING thread", + nosv_typeid_values +}; + +struct event_type cpu_nosv_typeid = { + 0, chan_to_prvtype[CHAN_NOSV_TYPEID][CHAN_CPU], + "CPU: nOS-V task TypeID of the RUNNING thread", + nosv_typeid_values +}; + +/* ---------------- CHAN_NOSV_APPID ---------------- */ + +struct event_value nosv_appid_values[] = { + { ST_TOO_MANY_TH, "Unknown Task AppID: Multiple threads running" }, + /* FIXME: Task ID values may collide with error code values */ + { -1, NULL }, +}; + +struct event_type thread_nosv_appid = { + 0, chan_to_prvtype[CHAN_NOSV_APPID][CHAN_TH], + "Thread: nOS-V task AppID of the RUNNING thread", + nosv_appid_values +}; + +struct event_type cpu_nosv_appid = { + 0, chan_to_prvtype[CHAN_NOSV_APPID][CHAN_CPU], + "CPU: nOS-V task AppID of the RUNNING thread", + nosv_appid_values +}; + +/* ---------------- CHAN_NOSV_SUBSYSTEM ---------------- */ + struct event_value nosv_ss_values[] = { - { ST_NULL, "NULL" }, - { ST_BAD, "Unknown subsystem: multiple threads" }, + /* Errors */ + { ST_BAD, "Unknown subsystem: Bad happened (report bug)" }, + { ST_TOO_MANY_TH, "Unknown subsystem: Multiple threads running" }, + /* Good values */ + { ST_NULL, "No subsystem" }, { ST_NOSV_SCHED_HUNGRY, "Scheduler: Hungry" }, { ST_NOSV_SCHED_SERVING, "Scheduler: Serving" }, { ST_NOSV_SCHED_SUBMITTING, "Scheduler: Submitting" }, @@ -138,17 +262,22 @@ struct event_value nosv_ss_values[] = { }; struct event_type thread_nosv_ss = { - 0, 23, "Thread: Subsystem", + 0, chan_to_prvtype[CHAN_NOSV_SUBSYSTEM][CHAN_TH], + "Thread: nOS-V subsystem of the ACTIVE thread", nosv_ss_values }; struct event_type cpu_nosv_ss = { - 0, 73, "CPU: Current thread subsystem", + 0, chan_to_prvtype[CHAN_NOSV_SUBSYSTEM][CHAN_CPU], + "CPU: nOS-V subsystem of the RUNNING thread", nosv_ss_values }; +/* ---------------- CHAN_TAMPI_MODE ---------------- */ + struct event_value tampi_mode_values[] = { { ST_NULL, "NULL" }, + { ST_TOO_MANY_TH, "TAMPI: Unknown, multiple threads running" }, { ST_TAMPI_SEND, "TAMPI: Send" }, { ST_TAMPI_RECV, "TAMPI: Recv" }, { ST_TAMPI_ISEND, "TAMPI: Isend" }, @@ -159,36 +288,40 @@ struct event_value tampi_mode_values[] = { }; struct event_type cpu_tampi_mode = { - 0, 80, "CPU: TAMPI running thread mode", + 0, chan_to_prvtype[CHAN_TAMPI_MODE][CHAN_CPU], + "CPU: TAMPI mode of the RUNNING thread", tampi_mode_values }; struct event_type thread_tampi_mode = { - 0, 30, "Thread: TAMPI mode", + 0, chan_to_prvtype[CHAN_TAMPI_MODE][CHAN_TH], + "Thread: TAMPI mode of the RUNNING thread", tampi_mode_values }; +/* ---------------- CHAN_OPENMP_MODE ---------------- */ + struct event_value openmp_mode_values[] = { { ST_NULL, "NULL" }, + { ST_TOO_MANY_TH, "OpenMP: Unknown, multiple threads running" }, { ST_OPENMP_TASK, "OpenMP: Task" }, { ST_OPENMP_PARALLEL, "OpenMP: Parallel" }, { -1, NULL }, }; struct event_type cpu_openmp_mode = { - 0, 90, "CPU: OpenMP running thread mode", + 0, chan_to_prvtype[CHAN_OPENMP_MODE][CHAN_CPU], + "CPU: OpenMP mode of the RUNNING thread", openmp_mode_values }; struct event_type thread_openmp_mode = { - 0, 40, "Thread: OpenMP mode", + 0, chan_to_prvtype[CHAN_OPENMP_MODE][CHAN_TH], + "Thread: OpenMP mode of the RUNNING thread", openmp_mode_values }; -struct event_type thread_cpu_affinity = { - 0, chan_to_prvtype[CHAN_OVNI_CPU][1], "Thread: current CPU affinity", - /* Ignored */ NULL -}; +/* ----------------------------------------------- */ static void decompose_rgb(uint32_t col, uint8_t *r, uint8_t *g, uint8_t *b) @@ -208,7 +341,6 @@ static void write_colors(FILE *f, const uint32_t *palette, int n) { int i; - uint32_t col; uint8_t r, g, b; fprintf(f, "\n\n"); @@ -216,7 +348,6 @@ write_colors(FILE *f, const uint32_t *palette, int n) for(i=0; iindex, ev->type, ev->label); @@ -258,22 +389,41 @@ write_cpu_type(FILE *f, struct event_type *ev, struct ovni_emu *emu) for(i=0; itotal_ncpus; i++) { - fprintf(f, "%-4d %s\n", i+1, emu->global_cpu[i]->name); + fprintf(f, "%-4ld %s\n", i+1, emu->global_cpu[i]->name); } } static void write_events(FILE *f, struct ovni_emu *emu) { - write_event_type(f, &thread_state); - write_event_type(f, &thread_tid); + /* Threads */ + write_event_type(f, &thread_ovni_pid); + write_event_type(f, &thread_ovni_tid); + /* thread_ovni_nthreads not needed */ + write_event_type(f, &thread_ovni_state); + /* thread_ovni_appid not needed */ + write_event_type(f, &thread_nosv_taskid); + write_event_type(f, &thread_nosv_typeid); + write_event_type(f, &thread_nosv_appid); write_event_type(f, &thread_nosv_ss); - write_event_type(f, &cpu_nosv_ss); - write_event_type(f, &cpu_tampi_mode); write_event_type(f, &thread_tampi_mode); - write_event_type(f, &cpu_openmp_mode); write_event_type(f, &thread_openmp_mode); + /* CPU */ + write_event_type(f, &cpu_ovni_pid); + write_event_type(f, &cpu_ovni_tid); + /* cpu_ovni_nthreads not needed */ + /* cpu_ovni_state not needed */ + /* cpu_ovni_appid not needed */ + /* cpu_ovni_cpu not needed */ + write_event_type(f, &cpu_nosv_taskid); + write_event_type(f, &cpu_nosv_typeid); + write_event_type(f, &cpu_nosv_appid); + write_event_type(f, &cpu_nosv_ss); + write_event_type(f, &cpu_tampi_mode); + write_event_type(f, &cpu_openmp_mode); + + /* Custom */ write_cpu_type(f, &thread_cpu_affinity, emu); } diff --git a/prv.c b/prv.c index 5e6b96a..1b269c8 100644 --- a/prv.c +++ b/prv.c @@ -24,7 +24,7 @@ prv_ev_thread(struct ovni_emu *emu, int row, int type, int val) prv_ev_thread_raw(emu, row, emu->delta_time, type, val); } -void +static void prv_ev_cpu_raw(struct ovni_emu *emu, int row, int64_t time, int type, int val) { prv_ev(emu->prv_cpu, row, time, type, val);