Add preliminar nosv CPU subsystem support
This commit is contained in:
parent
e8f4060370
commit
28fa152169
6
emu.c
6
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);
|
||||
|
14
emu.h
14
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
|
||||
|
140
emu_nosv_ss.c
140
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; i<loom->nupdated_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 ------------------------------- */
|
||||
|
126
emu_ovni.c
126
emu_ovni.c
@ -4,6 +4,26 @@
|
||||
|
||||
#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 *
|
||||
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; j<cpu->nthreads; 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; j<loom->vcpu.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; i<loom->ncpus; 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; 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
11
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
|
||||
|
Loading…
Reference in New Issue
Block a user