From 28fa152169fb1c2e35aaab7199c16ea760d5986e Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Date: Thu, 21 Oct 2021 16:05:01 +0200 Subject: [PATCH] Add preliminar nosv CPU subsystem support --- emu.c | 6 ++- emu.h | 14 ++++- emu_nosv_ss.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++ emu_ovni.c | 126 ++++++++++++++++++++++++++++++++++++++------- pcf.c | 11 +++- prv.h | 1 + 6 files changed, 276 insertions(+), 22 deletions(-) diff --git a/emu.c b/emu.c index 1e067f9..2b97c07 100644 --- a/emu.c +++ b/emu.c @@ -39,7 +39,7 @@ emit_ev(struct ovni_stream *stream, struct ovni_ev *ev) delta = clock - stream->lastclock; - dbg("%d.%d.%d %c %c %c % 20lu % 15ld ", + dbg("%d.%d.%d %c %c %c % 20ld % 15ld ", stream->loom, stream->proc, stream->tid, ev->header.model, ev->header.class, ev->header.value, clock, delta); @@ -87,6 +87,7 @@ hook_pre(struct ovni_emu *emu) case 'V': hook_pre_nosv(emu); break; case '*': hook_pre_nosv(emu); + hook_pre_ovni(emu); break; default: break; @@ -105,6 +106,7 @@ hook_emit(struct ovni_emu *emu) case 'V': hook_emit_nosv(emu); break; case '*': hook_emit_nosv(emu); + hook_emit_ovni(emu); break; default: //dbg("unknown model %c\n", emu->cur_ev->model); @@ -124,6 +126,7 @@ hook_post(struct ovni_emu *emu) case 'V': hook_post_nosv(emu); break; case '*': hook_post_nosv(emu); + hook_post_ovni(emu); break; default: //dbg("unknown model %c\n", emu->cur_ev->model); @@ -240,6 +243,7 @@ emulate(struct ovni_emu *emu) while(next_event(emu) == 0) { //fprintf(stdout, "step %i\n", i); + emu_emit(emu); hook_pre(emu); hook_emit(emu); hook_post(emu); diff --git a/emu.h b/emu.h index 1a6294c..7aafe41 100644 --- a/emu.h +++ b/emu.h @@ -14,7 +14,7 @@ # define dbg(...) #endif -#define err(...) fprintf(stderr, "error: " __VA_ARGS__); +#define err(...) fprintf(stderr, __VA_ARGS__); /* Emulated thread runtime status */ enum ethread_state { @@ -33,6 +33,7 @@ enum nosv_task_state { enum nosv_thread_ss_state { ST_NULL = 0, + ST_BAD = 3, ST_SCHED_HUNGRY = 6, ST_SCHED_SERVING = 7, ST_SCHED_SUBMITTING = 8, @@ -156,9 +157,16 @@ struct ovni_cpu { size_t last_nthreads; + /* 1 if the cpu has updated is threads, 0 if not */ + int updated; + /* The threads the cpu is currently running */ size_t nthreads; struct ovni_ethread *thread[OVNI_MAX_THR]; + + ///* Each channel emits events in the PRV file */ + //int nchannels; + //struct ovni_channel *channel; }; /* ----------------------- trace ------------------------ */ @@ -180,6 +188,10 @@ struct ovni_loom { struct ovni_cpu vcpu; struct ovni_eproc proc[OVNI_MAX_PROC]; + + /* Keep a list of updated cpus */ + int nupdated_cpus; + struct ovni_cpu *updated_cpu[OVNI_MAX_CPU]; }; #define MAX_VIRTUAL_EVENTS 16 diff --git a/emu_nosv_ss.c b/emu_nosv_ss.c index bf400f5..1a8b101 100644 --- a/emu_nosv_ss.c +++ b/emu_nosv_ss.c @@ -161,6 +161,32 @@ pre_thread(struct ovni_emu *emu) } } +/* Hook for the virtual "cpu changed" event */ +static void +pre_cpu_change(struct ovni_emu *emu) +{ + struct ovni_ethread *th; + + th = emu->cur_thread; + + /* Only print the subsystem if the thread is running */ + if(th->state == TH_ST_RUNNING) + th->show_ss = 1; + else + th->show_ss = 0; +} + +static void +pre_cpu(struct ovni_emu *emu) +{ + switch(emu->cur_ev->header.value) + { + case 'c': pre_thread_change(emu); break; + default: + break; + } +} + void hook_pre_nosv_ss(struct ovni_emu *emu) { @@ -171,6 +197,7 @@ hook_pre_nosv_ss(struct ovni_emu *emu) switch(emu->cur_ev->header.class) { case 'H': pre_thread(emu); break; + case 'C': pre_cpu(emu); break; default: break; } @@ -203,6 +230,17 @@ emit_thread_state(struct ovni_emu *emu, struct ovni_ethread *th, prv_ev_thread(emu, row, type, st); } +static void +emit_cpu_state(struct ovni_emu *emu, struct ovni_ethread *th, + int type, int st) +{ + /* Detect multiple threads */ + if(th->cpu && th->cpu->nthreads > 1) + st = ST_BAD; + + prv_ev_autocpu(emu, type, st); +} + static void emit_thread_event(struct ovni_emu *emu, struct ovni_ethread *th, int type, int st) @@ -223,9 +261,108 @@ emit_thread_event(struct ovni_emu *emu, struct ovni_ethread *th, prv_ev_thread_raw(emu, row, t1, type, prev_st); } +static void +emit_cpu_event(struct ovni_emu *emu, struct ovni_ethread *th, + int type, int st) +{ + int64_t t0, t1; + int row; + int prev_st; + + row = th->gindex + 1; + + t0 = emu->delta_time - 1; + t1 = emu->delta_time; + + prev_st = ss_last_st(th); + + /* Detect multiple threads */ + if(th->cpu && th->cpu->nthreads > 1) + { + st = ST_BAD; + prev_st = ST_BAD; + } + + /* Fake event using 1 nanosecond in the past */ + prv_ev_autocpu_raw(emu, t0, type, st); + prv_ev_autocpu_raw(emu, t1, type, prev_st); +} + +static void +emit_thread_changed(struct ovni_emu *emu) +{ + dbg("emit_thread_changed\n") +} + +static void +emit_cpu_changed(struct ovni_emu *emu) +{ + dbg("emit_cpu_changed\n") + //int i; + //struct ovni_loom *loom; + //struct ovni_cpu *cpu; + + ///* Detect multiple threads */ + //loom = emu->cur_loom; + + //assert(loom->nupdated_cpus > 0); + + //for(i=0; inupdated_cpus; i++) + //{ + // cpu = loom->updated_cpu[i]; + + // if(cpu->nthreads > 1) + // { + // prv_stream_disable(cpu->ss_stream); + // } + //} +} + void hook_emit_nosv_ss(struct ovni_emu *emu) { + /* We need to emit events when a thread notifies us that the subsystem + * has changed, but also when the thread is paused, or scheduled to + * another CPU, as the CPU view must be updated as well. */ + + switch(emu->cur_ev->header.model) + { + /* Listen for virtual events as well */ + case '*': + switch(emu->cur_ev->header.class) + { + case 'H': + switch(emu->cur_ev->header.value) + { + case 'c': emit_thread_changed(emu); break; + default: break; + } + break; + case 'C': + switch(emu->cur_ev->header.value) + { + case 'c': emit_cpu_changed(emu); break; + default: break; + } + break; + default: break; + } + break; + case 'V': + switch(emu->cur_ev->header.class) + { + case 'S': pre_sched(emu); break; + case 'U': pre_submit(emu); break; + case 'M': pre_memory(emu); break; + default: + break; + } + break; + default: + break; + } + + struct ovni_ethread *th; th = emu->cur_thread; @@ -241,11 +378,14 @@ hook_emit_nosv_ss(struct ovni_emu *emu) { emit_thread_event(emu, th, PTT_SUBSYSTEM, th->ss_event); + emit_cpu_event(emu, th, PTC_SUBSYSTEM, + th->ss_event); return; } emit_thread_state(emu, th, PTT_SUBSYSTEM, ss_last_st(th)); + emit_cpu_state(emu, th, PTC_SUBSYSTEM, ss_last_st(th)); } /* --------------------------- post ------------------------------- */ diff --git a/emu_ovni.c b/emu_ovni.c index 32bc1c7..e380e72 100644 --- a/emu_ovni.c +++ b/emu_ovni.c @@ -4,6 +4,26 @@ #include +/* The emulator ovni module provides the execution model by tracking the thread + * state and which threads run in each CPU */ + +void +update_cpu(struct ovni_emu *emu, struct ovni_cpu *cpu) +{ + struct ovni_loom *loom; + + loom = emu->cur_loom; + + if(loom->nupdated_cpus >= OVNI_MAX_CPU) + abort(); + + if(cpu->updated) + return; + + cpu->updated = 1; + loom->updated_cpu[loom->nupdated_cpus++] = cpu; +} + struct ovni_cpu * emu_get_cpu(struct ovni_loom *loom, int cpuid) { @@ -34,7 +54,7 @@ emu_cpu_find_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread) } void -emu_cpu_add_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread) +emu_cpu_add_thread(struct ovni_emu *emu, struct ovni_cpu *cpu, struct ovni_ethread *thread) { /* Found, abort */ if(emu_cpu_find_thread(cpu, thread) >= 0) @@ -43,10 +63,12 @@ emu_cpu_add_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread) assert(cpu->nthreads < OVNI_MAX_THR); cpu->thread[cpu->nthreads++] = thread; + + update_cpu(emu, cpu); } void -emu_cpu_remove_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread) +emu_cpu_remove_thread(struct ovni_emu *emu, struct ovni_cpu *cpu, struct ovni_ethread *thread) { int i, j; @@ -62,6 +84,8 @@ emu_cpu_remove_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread) } cpu->nthreads--; + + update_cpu(emu, cpu); } @@ -75,7 +99,7 @@ print_threads_state(struct ovni_loom *loom) { cpu = &loom->cpu[i]; - dbg("-- cpu %d runs %d threads:", i, cpu->nthreads); + dbg("-- cpu %d runs %lu threads:", i, cpu->nthreads); for(j=0; jnthreads; j++) { dbg(" %d", cpu->thread[j]->tid); @@ -83,7 +107,7 @@ print_threads_state(struct ovni_loom *loom) dbg("\n"); } - dbg("-- vcpu runs %d threads:", loom->vcpu.nthreads); + dbg("-- vcpu runs %lu threads:", loom->vcpu.nthreads); for(j=0; jvcpu.nthreads; j++) { dbg(" %d", loom->vcpu.thread[j]->tid); @@ -108,7 +132,7 @@ ev_thread_execute(struct ovni_emu *emu) emu->cur_thread->state = TH_ST_RUNNING; emu->cur_thread->cpu = cpu; - emu_cpu_add_thread(cpu, emu->cur_thread); + emu_cpu_add_thread(emu, cpu, emu->cur_thread); } static void @@ -117,7 +141,7 @@ ev_thread_end(struct ovni_emu *emu) assert(emu->cur_thread->state == TH_ST_RUNNING); assert(emu->cur_thread->cpu); - emu_cpu_remove_thread(emu->cur_thread->cpu, emu->cur_thread); + emu_cpu_remove_thread(emu, emu->cur_thread->cpu, emu->cur_thread); emu->cur_thread->state = TH_ST_DEAD; emu->cur_thread->cpu = NULL; @@ -129,7 +153,7 @@ ev_thread_pause(struct ovni_emu *emu) assert(emu->cur_thread->state == TH_ST_RUNNING); assert(emu->cur_thread->cpu); - emu_cpu_remove_thread(emu->cur_thread->cpu, emu->cur_thread); + emu_cpu_remove_thread(emu, emu->cur_thread->cpu, emu->cur_thread); emu->cur_thread->state = TH_ST_PAUSED; } @@ -140,7 +164,7 @@ ev_thread_resume(struct ovni_emu *emu) assert(emu->cur_thread->state == TH_ST_PAUSED); assert(emu->cur_thread->cpu); - emu_cpu_add_thread(emu->cur_thread->cpu, emu->cur_thread); + emu_cpu_add_thread(emu, emu->cur_thread->cpu, emu->cur_thread); emu->cur_thread->state = TH_ST_RUNNING; } @@ -179,9 +203,13 @@ ev_thread(struct ovni_emu *emu) exit(EXIT_FAILURE); } - /* All events change the thread state: inject a virtual event to - * notify other modules */ - emu_virtual_ev(emu, "*Hc"); + /* All but create events change the thread and CPU state: inject two + * virtual events to notify other modules. The order is important. */ + if(ev->header.value != 'c') + { + emu_virtual_ev(emu, "*Hc"); + emu_virtual_ev(emu, "*Cc"); + } } static void @@ -198,8 +226,8 @@ ev_affinity_set(struct ovni_emu *emu) /* Migrate current cpu to the one at cpuid */ newcpu = emu_get_cpu(emu->cur_loom, cpuid); - emu_cpu_remove_thread(emu->cur_thread->cpu, emu->cur_thread); - emu_cpu_add_thread(newcpu, emu->cur_thread); + emu_cpu_remove_thread(emu, emu->cur_thread->cpu, emu->cur_thread); + emu_cpu_add_thread(emu, newcpu, emu->cur_thread); emu->cur_thread->cpu = newcpu; @@ -233,8 +261,8 @@ ev_affinity_remote(struct ovni_emu *emu) /* If running, update the CPU thread lists */ if(thread->state == TH_ST_RUNNING) { - emu_cpu_remove_thread(thread->cpu, thread); - emu_cpu_add_thread(newcpu, thread); + emu_cpu_remove_thread(emu, thread->cpu, thread); + emu_cpu_add_thread(emu, newcpu, thread); } else { @@ -270,6 +298,9 @@ hook_pre_ovni(struct ovni_emu *emu) { //emu_emit(emu); + if(emu->cur_ev->header.model != 'O') + return; + switch(emu->cur_ev->header.class) { case 'H': ev_thread(emu); break; @@ -359,6 +390,9 @@ emit_current_pid(struct ovni_emu *emu) void hook_emit_ovni(struct ovni_emu *emu) { + if(emu->cur_ev->header.model != 'O') + return; + switch(emu->cur_ev->header.class) { case 'H': @@ -373,18 +407,74 @@ hook_emit_ovni(struct ovni_emu *emu) } } -void -hook_post_ovni(struct ovni_emu *emu) +/* Reset thread state */ +static void +post_virtual_thread(struct ovni_emu *emu) { int i; struct ovni_loom *loom; loom = emu->cur_loom; - /* Update last_nthreads in the CPUs */ + /* Should be executed *before* we reset the CPUs updated flags */ + assert(loom->nupdated_cpus > 0); + /* Update last_nthreads in the CPUs */ for(i=0; incpus; i++) loom->cpu[i].last_nthreads = loom->cpu[i].nthreads; + /* Fix the virtual CPU as well */ loom->vcpu.last_nthreads = loom->vcpu.nthreads; } + +/* Reset CPU state */ +static void +post_virtual_cpu(struct ovni_emu *emu) +{ + int i; + struct ovni_loom *loom; + + loom = emu->cur_loom; + + for(i=0; inupdated_cpus; i++) + { + /* Remove the update flags */ + assert(loom->updated_cpu[i]->updated == 1); + loom->updated_cpu[i]->updated = 0; + } + + /* Fix the virtual CPU as well */ + loom->vcpu.last_nthreads = loom->vcpu.nthreads; + + /* Restore 0 updated CPUs */ + loom->nupdated_cpus = 0; +} + +static void +post_virtual(struct ovni_emu *emu) +{ + switch(emu->cur_ev->header.class) + { + case 'H': + post_virtual_thread(emu); + break; + case 'C': + post_virtual_cpu(emu); + break; + default: + break; + } +} + +void +hook_post_ovni(struct ovni_emu *emu) +{ + switch(emu->cur_ev->header.model) + { + case '*': + post_virtual(emu); + break; + default: + break; + } +} diff --git a/pcf.c b/pcf.c index 48c7930..c85a59b 100644 --- a/pcf.c +++ b/pcf.c @@ -114,8 +114,9 @@ struct event_type thread_tid = { thread_tid_values }; -struct event_value thread_ss_values[] = { +struct event_value ss_values[] = { { ST_NULL, "NULL" }, + { ST_BAD, "Unknown subsystem: multiple threads" }, { ST_SCHED_HUNGRY, "Scheduler: Hungry" }, { ST_SCHED_SERVING, "Scheduler: Serving" }, { ST_SCHED_SUBMITTING, "Scheduler: Submitting" }, @@ -128,7 +129,12 @@ struct event_value thread_ss_values[] = { struct event_type thread_ss = { 0, PTT_SUBSYSTEM, "Thread: Subsystem", - thread_ss_values + ss_values +}; + +struct event_type cpu_ss = { + 0, PTC_SUBSYSTEM, "CPU: Current thread subsystem", + ss_values }; static void @@ -194,6 +200,7 @@ write_events(FILE *f) write_event_type(f, &thread_state); write_event_type(f, &thread_tid); write_event_type(f, &thread_ss); + write_event_type(f, &cpu_ss); } int diff --git a/prv.h b/prv.h index 565911e..dc77c15 100644 --- a/prv.h +++ b/prv.h @@ -14,6 +14,7 @@ enum prv_type { PTC_TASK_ID = 20, PTC_TASK_TYPE_ID = 21, PTC_APP_ID = 30, + PTC_SUBSYSTEM = 31, /* Rows are threads */ PTT_THREAD_STATE = 60,