Add preliminar nosv CPU subsystem support

This commit is contained in:
Rodrigo Arias 2021-10-21 16:05:01 +02:00
parent e8f4060370
commit 28fa152169
6 changed files with 276 additions and 22 deletions

6
emu.c
View File

@ -39,7 +39,7 @@ emit_ev(struct ovni_stream *stream, struct ovni_ev *ev)
delta = clock - stream->lastclock; 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, stream->loom, stream->proc, stream->tid,
ev->header.model, ev->header.class, ev->header.value, clock, delta); 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); case 'V': hook_pre_nosv(emu);
break; break;
case '*': hook_pre_nosv(emu); case '*': hook_pre_nosv(emu);
hook_pre_ovni(emu);
break; break;
default: default:
break; break;
@ -105,6 +106,7 @@ hook_emit(struct ovni_emu *emu)
case 'V': hook_emit_nosv(emu); case 'V': hook_emit_nosv(emu);
break; break;
case '*': hook_emit_nosv(emu); case '*': hook_emit_nosv(emu);
hook_emit_ovni(emu);
break; break;
default: default:
//dbg("unknown model %c\n", emu->cur_ev->model); //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); case 'V': hook_post_nosv(emu);
break; break;
case '*': hook_post_nosv(emu); case '*': hook_post_nosv(emu);
hook_post_ovni(emu);
break; break;
default: default:
//dbg("unknown model %c\n", emu->cur_ev->model); //dbg("unknown model %c\n", emu->cur_ev->model);
@ -240,6 +243,7 @@ emulate(struct ovni_emu *emu)
while(next_event(emu) == 0) while(next_event(emu) == 0)
{ {
//fprintf(stdout, "step %i\n", i); //fprintf(stdout, "step %i\n", i);
emu_emit(emu);
hook_pre(emu); hook_pre(emu);
hook_emit(emu); hook_emit(emu);
hook_post(emu); hook_post(emu);

14
emu.h
View File

@ -14,7 +14,7 @@
# define dbg(...) # define dbg(...)
#endif #endif
#define err(...) fprintf(stderr, "error: " __VA_ARGS__); #define err(...) fprintf(stderr, __VA_ARGS__);
/* Emulated thread runtime status */ /* Emulated thread runtime status */
enum ethread_state { enum ethread_state {
@ -33,6 +33,7 @@ enum nosv_task_state {
enum nosv_thread_ss_state { enum nosv_thread_ss_state {
ST_NULL = 0, ST_NULL = 0,
ST_BAD = 3,
ST_SCHED_HUNGRY = 6, ST_SCHED_HUNGRY = 6,
ST_SCHED_SERVING = 7, ST_SCHED_SERVING = 7,
ST_SCHED_SUBMITTING = 8, ST_SCHED_SUBMITTING = 8,
@ -156,9 +157,16 @@ struct ovni_cpu {
size_t last_nthreads; size_t last_nthreads;
/* 1 if the cpu has updated is threads, 0 if not */
int updated;
/* The threads the cpu is currently running */ /* The threads the cpu is currently running */
size_t nthreads; size_t nthreads;
struct ovni_ethread *thread[OVNI_MAX_THR]; struct ovni_ethread *thread[OVNI_MAX_THR];
///* Each channel emits events in the PRV file */
//int nchannels;
//struct ovni_channel *channel;
}; };
/* ----------------------- trace ------------------------ */ /* ----------------------- trace ------------------------ */
@ -180,6 +188,10 @@ struct ovni_loom {
struct ovni_cpu vcpu; struct ovni_cpu vcpu;
struct ovni_eproc proc[OVNI_MAX_PROC]; 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 #define MAX_VIRTUAL_EVENTS 16

View File

@ -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 void
hook_pre_nosv_ss(struct ovni_emu *emu) 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) switch(emu->cur_ev->header.class)
{ {
case 'H': pre_thread(emu); break; case 'H': pre_thread(emu); break;
case 'C': pre_cpu(emu); break;
default: default:
break; break;
} }
@ -203,6 +230,17 @@ emit_thread_state(struct ovni_emu *emu, struct ovni_ethread *th,
prv_ev_thread(emu, row, type, st); 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 static void
emit_thread_event(struct ovni_emu *emu, struct ovni_ethread *th, emit_thread_event(struct ovni_emu *emu, struct ovni_ethread *th,
int type, int st) 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); 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; i<loom->nupdated_cpus; i++)
//{
// cpu = loom->updated_cpu[i];
// if(cpu->nthreads > 1)
// {
// prv_stream_disable(cpu->ss_stream);
// }
//}
}
void void
hook_emit_nosv_ss(struct ovni_emu *emu) 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; struct ovni_ethread *th;
th = emu->cur_thread; th = emu->cur_thread;
@ -241,11 +378,14 @@ hook_emit_nosv_ss(struct ovni_emu *emu)
{ {
emit_thread_event(emu, th, PTT_SUBSYSTEM, emit_thread_event(emu, th, PTT_SUBSYSTEM,
th->ss_event); th->ss_event);
emit_cpu_event(emu, th, PTC_SUBSYSTEM,
th->ss_event);
return; return;
} }
emit_thread_state(emu, th, PTT_SUBSYSTEM, ss_last_st(th)); emit_thread_state(emu, th, PTT_SUBSYSTEM, ss_last_st(th));
emit_cpu_state(emu, th, PTC_SUBSYSTEM, ss_last_st(th));
} }
/* --------------------------- post ------------------------------- */ /* --------------------------- post ------------------------------- */

View File

@ -4,6 +4,26 @@
#include <assert.h> #include <assert.h>
/* 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 * struct ovni_cpu *
emu_get_cpu(struct ovni_loom *loom, int cpuid) 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 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 */ /* Found, abort */
if(emu_cpu_find_thread(cpu, thread) >= 0) 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); assert(cpu->nthreads < OVNI_MAX_THR);
cpu->thread[cpu->nthreads++] = thread; cpu->thread[cpu->nthreads++] = thread;
update_cpu(emu, cpu);
} }
void 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; int i, j;
@ -62,6 +84,8 @@ emu_cpu_remove_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread)
} }
cpu->nthreads--; cpu->nthreads--;
update_cpu(emu, cpu);
} }
@ -75,7 +99,7 @@ print_threads_state(struct ovni_loom *loom)
{ {
cpu = &loom->cpu[i]; 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; j<cpu->nthreads; j++) for(j=0; j<cpu->nthreads; j++)
{ {
dbg(" %d", cpu->thread[j]->tid); dbg(" %d", cpu->thread[j]->tid);
@ -83,7 +107,7 @@ print_threads_state(struct ovni_loom *loom)
dbg("\n"); dbg("\n");
} }
dbg("-- vcpu runs %d threads:", loom->vcpu.nthreads); dbg("-- vcpu runs %lu threads:", loom->vcpu.nthreads);
for(j=0; j<loom->vcpu.nthreads; j++) for(j=0; j<loom->vcpu.nthreads; j++)
{ {
dbg(" %d", loom->vcpu.thread[j]->tid); 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->state = TH_ST_RUNNING;
emu->cur_thread->cpu = cpu; emu->cur_thread->cpu = cpu;
emu_cpu_add_thread(cpu, emu->cur_thread); emu_cpu_add_thread(emu, cpu, emu->cur_thread);
} }
static void 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->state == TH_ST_RUNNING);
assert(emu->cur_thread->cpu); 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->state = TH_ST_DEAD;
emu->cur_thread->cpu = NULL; 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->state == TH_ST_RUNNING);
assert(emu->cur_thread->cpu); 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; 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->state == TH_ST_PAUSED);
assert(emu->cur_thread->cpu); 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; emu->cur_thread->state = TH_ST_RUNNING;
} }
@ -179,9 +203,13 @@ ev_thread(struct ovni_emu *emu)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* All events change the thread state: inject a virtual event to /* All but create events change the thread and CPU state: inject two
* notify other modules */ * virtual events to notify other modules. The order is important. */
emu_virtual_ev(emu, "*Hc"); if(ev->header.value != 'c')
{
emu_virtual_ev(emu, "*Hc");
emu_virtual_ev(emu, "*Cc");
}
} }
static void static void
@ -198,8 +226,8 @@ ev_affinity_set(struct ovni_emu *emu)
/* Migrate current cpu to the one at cpuid */ /* Migrate current cpu to the one at cpuid */
newcpu = emu_get_cpu(emu->cur_loom, cpuid); newcpu = emu_get_cpu(emu->cur_loom, cpuid);
emu_cpu_remove_thread(emu->cur_thread->cpu, emu->cur_thread); emu_cpu_remove_thread(emu, emu->cur_thread->cpu, emu->cur_thread);
emu_cpu_add_thread(newcpu, emu->cur_thread); emu_cpu_add_thread(emu, newcpu, emu->cur_thread);
emu->cur_thread->cpu = newcpu; emu->cur_thread->cpu = newcpu;
@ -233,8 +261,8 @@ ev_affinity_remote(struct ovni_emu *emu)
/* If running, update the CPU thread lists */ /* If running, update the CPU thread lists */
if(thread->state == TH_ST_RUNNING) if(thread->state == TH_ST_RUNNING)
{ {
emu_cpu_remove_thread(thread->cpu, thread); emu_cpu_remove_thread(emu, thread->cpu, thread);
emu_cpu_add_thread(newcpu, thread); emu_cpu_add_thread(emu, newcpu, thread);
} }
else else
{ {
@ -270,6 +298,9 @@ hook_pre_ovni(struct ovni_emu *emu)
{ {
//emu_emit(emu); //emu_emit(emu);
if(emu->cur_ev->header.model != 'O')
return;
switch(emu->cur_ev->header.class) switch(emu->cur_ev->header.class)
{ {
case 'H': ev_thread(emu); break; case 'H': ev_thread(emu); break;
@ -359,6 +390,9 @@ emit_current_pid(struct ovni_emu *emu)
void void
hook_emit_ovni(struct ovni_emu *emu) hook_emit_ovni(struct ovni_emu *emu)
{ {
if(emu->cur_ev->header.model != 'O')
return;
switch(emu->cur_ev->header.class) switch(emu->cur_ev->header.class)
{ {
case 'H': case 'H':
@ -373,18 +407,74 @@ hook_emit_ovni(struct ovni_emu *emu)
} }
} }
void /* Reset thread state */
hook_post_ovni(struct ovni_emu *emu) static void
post_virtual_thread(struct ovni_emu *emu)
{ {
int i; int i;
struct ovni_loom *loom; struct ovni_loom *loom;
loom = emu->cur_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; i<loom->ncpus; i++) for(i=0; i<loom->ncpus; i++)
loom->cpu[i].last_nthreads = loom->cpu[i].nthreads; loom->cpu[i].last_nthreads = loom->cpu[i].nthreads;
/* Fix the virtual CPU as well */
loom->vcpu.last_nthreads = loom->vcpu.nthreads; 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; i<loom->nupdated_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;
}
}

11
pcf.c
View File

@ -114,8 +114,9 @@ struct event_type thread_tid = {
thread_tid_values thread_tid_values
}; };
struct event_value thread_ss_values[] = { struct event_value ss_values[] = {
{ ST_NULL, "NULL" }, { ST_NULL, "NULL" },
{ ST_BAD, "Unknown subsystem: multiple threads" },
{ ST_SCHED_HUNGRY, "Scheduler: Hungry" }, { ST_SCHED_HUNGRY, "Scheduler: Hungry" },
{ ST_SCHED_SERVING, "Scheduler: Serving" }, { ST_SCHED_SERVING, "Scheduler: Serving" },
{ ST_SCHED_SUBMITTING, "Scheduler: Submitting" }, { ST_SCHED_SUBMITTING, "Scheduler: Submitting" },
@ -128,7 +129,12 @@ struct event_value thread_ss_values[] = {
struct event_type thread_ss = { struct event_type thread_ss = {
0, PTT_SUBSYSTEM, "Thread: Subsystem", 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 static void
@ -194,6 +200,7 @@ write_events(FILE *f)
write_event_type(f, &thread_state); write_event_type(f, &thread_state);
write_event_type(f, &thread_tid); write_event_type(f, &thread_tid);
write_event_type(f, &thread_ss); write_event_type(f, &thread_ss);
write_event_type(f, &cpu_ss);
} }
int int

1
prv.h
View File

@ -14,6 +14,7 @@ enum prv_type {
PTC_TASK_ID = 20, PTC_TASK_ID = 20,
PTC_TASK_TYPE_ID = 21, PTC_TASK_TYPE_ID = 21,
PTC_APP_ID = 30, PTC_APP_ID = 30,
PTC_SUBSYSTEM = 31,
/* Rows are threads */ /* Rows are threads */
PTT_THREAD_STATE = 60, PTT_THREAD_STATE = 60,