ovni/emu_ovni.c

567 lines
12 KiB
C
Raw Normal View History

2021-07-28 11:56:35 +02:00
#include "ovni.h"
#include "emu.h"
2021-08-02 10:08:58 +02:00
#include "prv.h"
2021-10-21 16:15:29 +02:00
#include "chan.h"
2021-07-28 11:56:35 +02:00
#include <assert.h>
/* The emulator ovni module provides the execution model by tracking the thread
* state and which threads run in each CPU */
/* --------------------------- init ------------------------------- */
void
hook_init_ovni(struct ovni_emu *emu)
{
struct ovni_ethread *th;
struct ovni_cpu *cpu;
struct ovni_trace *trace;
int i, row, type;
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; i<emu->total_nthreads; i++)
{
th = emu->global_thread[i];
row = th->gindex + 1;
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);
2021-10-11 11:12:26 +02:00
/* All threads begin in unknown state */
chan_enable(&th->chan[CHAN_OVNI_STATE], 1);
chan_set(&th->chan[CHAN_OVNI_STATE], TH_ST_UNKNOWN);
}
/* Init the ovni channels in all cpus */
for(i=0; i<emu->total_ncpus; i++)
{
cpu = emu->global_cpu[i];
row = cpu->gindex + 1;
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_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]);
}
}
2021-10-21 16:15:29 +02:00
/* --------------------------- pre ------------------------------- */
static void
2021-10-11 11:12:26 +02:00
thread_update_channels(struct ovni_ethread *th)
2021-10-21 16:15:29 +02:00
{
struct ovni_chan *chan;
2021-10-11 11:12:26 +02:00
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);
2021-10-21 16:15:29 +02:00
for(i=0; i<CHAN_MAX; i++)
{
chan = &th->chan[i];
2021-10-11 11:12:26 +02:00
switch (chan->track)
{
2021-10-11 11:12:26 +02:00
case CHAN_TRACK_TH_RUNNING:
enabled = is_running ? 1 : 0;
break;
case CHAN_TRACK_TH_UNPAUSED:
enabled = is_unpaused ? 1 : 0;
break;
default:
continue;
}
2021-10-11 11:12:26 +02:00
/* 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);
}
2021-10-21 16:15:29 +02:00
}
static void
thread_set_state(struct ovni_ethread *th, int state)
{
int enabled;
th->state = state;
2021-10-11 11:12:26 +02:00
chan_set(&th->chan[CHAN_OVNI_STATE], th->state);
/* Enable or disable the thread channels that track the thread state */
thread_update_channels(th);
2021-10-21 16:15:29 +02:00
}
void
update_cpu(struct ovni_emu *emu, struct ovni_cpu *cpu)
{
2021-10-11 11:12:26 +02:00
int i, tid, pid, enabled, nrunning;
struct ovni_loom *loom;
2021-10-11 11:12:26 +02:00
struct ovni_ethread *th, *last_th;
struct ovni_chan *chan;
loom = emu->cur_loom;
2021-10-11 11:12:26 +02:00
/* Count running threads */
for(i=0, nrunning=0; i<cpu->nthreads; i++)
{
th = cpu->thread[i];
if(th->state == TH_ST_RUNNING)
{
last_th = th;
nrunning++;
}
}
chan_set(&cpu->chan[CHAN_OVNI_NTHREADS], nrunning);
th = NULL;
2021-10-11 11:12:26 +02:00
if(nrunning == 0)
{
/* No thread running */
tid = pid = 0;
}
2021-10-11 11:12:26 +02:00
else if(nrunning == 1)
{
2021-10-11 11:12:26 +02:00
/* 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;
}
chan_set(&cpu->chan[CHAN_OVNI_TID], tid);
chan_set(&cpu->chan[CHAN_OVNI_PID], pid);
// enabled = (th != NULL && th->state == TH_ST_RUNNING ? 1 : 0);
//
// /* Update all channels that need to follow the running thread */
// for(i=0; i<CHAN_MAX; i++)
// {
// chan = &cpu->chan[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);
// }
// }
}
2021-07-28 19:12:20 +02:00
struct ovni_cpu *
2021-08-02 21:13:03 +02:00
emu_get_cpu(struct ovni_loom *loom, int cpuid)
2021-07-28 19:12:20 +02:00
{
assert(cpuid < OVNI_MAX_CPU);
if(cpuid < 0)
{
2021-08-02 21:13:03 +02:00
return &loom->vcpu;
2021-07-28 19:12:20 +02:00
}
2021-08-02 21:13:03 +02:00
return &loom->cpu[cpuid];
2021-07-28 19:12:20 +02:00
}
int
emu_cpu_find_thread(struct ovni_cpu *cpu, struct ovni_ethread *thread)
{
int i;
for(i=0; i<cpu->nthreads; i++)
if(cpu->thread[i] == thread)
break;
/* Not found */
if(i >= cpu->nthreads)
return -1;
return i;
}
2021-10-11 11:12:26 +02:00
static void
cpu_add_thread(struct ovni_emu *emu, struct ovni_cpu *cpu, struct ovni_ethread *thread)
2021-07-28 19:12:20 +02:00
{
/* Found, abort */
if(emu_cpu_find_thread(cpu, thread) >= 0)
abort();
assert(cpu->nthreads < OVNI_MAX_THR);
cpu->thread[cpu->nthreads++] = thread;
update_cpu(emu, cpu);
2021-07-28 19:12:20 +02:00
}
2021-10-11 11:12:26 +02:00
static void
cpu_remove_thread(struct ovni_emu *emu, struct ovni_cpu *cpu, struct ovni_ethread *thread)
2021-07-28 19:12:20 +02:00
{
int i, j;
i = emu_cpu_find_thread(cpu, thread);
/* Not found, abort */
if(i < 0)
abort();
for(j=i; j+1 < cpu->nthreads; j++)
cpu->thread[i] = cpu->thread[j+1];
cpu->nthreads--;
update_cpu(emu, cpu);
2021-07-28 19:12:20 +02:00
}
2021-10-11 11:12:26 +02:00
void
cpu_migrate_thread(struct ovni_emu *emu,
struct ovni_cpu *cpu,
struct ovni_ethread *thread,
struct ovni_cpu *newcpu)
{
cpu_remove_thread(emu, cpu, thread);
cpu_add_thread(emu, newcpu, thread);
}
/* Sets the thread assigned CPU to the given one.
* Precondition: the thread CPU must be null */
void
thread_set_cpu(struct ovni_ethread *th, struct ovni_cpu *cpu)
{
assert(th->cpu == NULL);
th->cpu = cpu;
chan_enable(&th->chan[CHAN_OVNI_CPU], 1);
chan_set(&th->chan[CHAN_OVNI_CPU], cpu->gindex + 1);
}
/* Unsets the thread assigned CPU.
* Precondition: the thread CPU must be not null */
void
thread_unset_cpu(struct ovni_ethread *th)
{
assert(th->cpu != NULL);
th->cpu = NULL;
chan_enable(&th->chan[CHAN_OVNI_CPU], 0);
}
/* Migrates the thread assigned CPU to the given one.
* Precondition: the thread CPU must be not null */
void
thread_migrate_cpu(struct ovni_ethread *th, struct ovni_cpu *cpu)
{
assert(th->cpu != NULL);
th->cpu = cpu;
assert(chan_is_enabled(&th->chan[CHAN_OVNI_CPU]));
chan_set(&th->chan[CHAN_OVNI_CPU], cpu->gindex + 1);
}
2021-07-28 11:56:35 +02:00
static void
2021-08-02 21:13:03 +02:00
print_threads_state(struct ovni_loom *loom)
2021-07-28 11:56:35 +02:00
{
struct ovni_cpu *cpu;
int i, j;
2021-08-02 21:13:03 +02:00
for(i=0; i<loom->ncpus; i++)
2021-07-28 11:56:35 +02:00
{
2021-08-02 21:13:03 +02:00
cpu = &loom->cpu[i];
2021-07-28 11:56:35 +02:00
dbg("-- cpu %d runs %lu threads:", i, cpu->nthreads);
2021-07-28 11:56:35 +02:00
for(j=0; j<cpu->nthreads; j++)
{
dbg(" %d", cpu->thread[j]->tid);
}
dbg("\n");
}
dbg("-- vcpu runs %lu threads:", loom->vcpu.nthreads);
2021-08-02 21:13:03 +02:00
for(j=0; j<loom->vcpu.nthreads; j++)
2021-07-28 11:56:35 +02:00
{
2021-08-02 21:13:03 +02:00
dbg(" %d", loom->vcpu.thread[j]->tid);
2021-07-28 11:56:35 +02:00
}
dbg("\n");
}
static void
2021-10-11 11:12:26 +02:00
pre_thread_execute(struct ovni_emu *emu, struct ovni_ethread *th)
2021-07-28 11:56:35 +02:00
{
struct ovni_cpu *cpu;
int cpuid;
/* The thread cannot be already running */
2021-10-21 16:15:29 +02:00
assert(th->state != TH_ST_RUNNING);
2021-07-28 11:56:35 +02:00
cpuid = emu->cur_ev->payload.i32[0];
2021-10-21 16:15:29 +02:00
//dbg("thread %d runs in cpuid %d\n", th->tid,
2021-07-29 17:46:25 +02:00
// cpuid);
2021-08-02 21:13:03 +02:00
cpu = emu_get_cpu(emu->cur_loom, cpuid);
2021-07-28 11:56:35 +02:00
2021-10-21 16:15:29 +02:00
thread_set_state(th, TH_ST_RUNNING);
2021-10-11 11:12:26 +02:00
thread_set_cpu(th, cpu);
2021-10-11 11:12:26 +02:00
cpu_add_thread(emu, cpu, th);
/* Enable thread TID and PID */
chan_enable(&th->chan[CHAN_OVNI_TID], 1);
chan_enable(&th->chan[CHAN_OVNI_PID], 1);
2021-07-28 11:56:35 +02:00
}
static void
2021-10-11 11:12:26 +02:00
pre_thread_end(struct ovni_emu *emu, struct ovni_ethread *th)
2021-07-28 11:56:35 +02:00
{
assert(th->state == TH_ST_RUNNING);
assert(th->cpu);
2021-10-11 11:12:26 +02:00
cpu_remove_thread(emu, th->cpu, th);
thread_set_state(th, TH_ST_DEAD);
2021-10-11 11:12:26 +02:00
thread_unset_cpu(th);
2021-07-28 11:56:35 +02:00
/* Disable thread TID and PID */
chan_enable(&th->chan[CHAN_OVNI_TID], 0);
chan_enable(&th->chan[CHAN_OVNI_PID], 0);
2021-07-28 11:56:35 +02:00
}
static void
2021-10-11 11:12:26 +02:00
pre_thread_pause(struct ovni_emu *emu, struct ovni_ethread *th)
2021-07-28 11:56:35 +02:00
{
2021-10-11 11:12:26 +02:00
assert(th->state == TH_ST_RUNNING || th->state == TH_ST_COOLING);
assert(th->cpu);
2021-07-28 11:56:35 +02:00
2021-10-11 11:12:26 +02:00
thread_set_state(th, TH_ST_PAUSED);
}
2021-07-28 11:56:35 +02:00
2021-10-11 11:12:26 +02:00
static void
pre_thread_resume(struct ovni_emu *emu, 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);
2021-07-28 11:56:35 +02:00
}
static void
2021-10-11 11:12:26 +02:00
pre_thread_cool(struct ovni_emu *emu, struct ovni_ethread *th)
2021-07-28 11:56:35 +02:00
{
2021-10-11 11:12:26 +02:00
assert(th->state == TH_ST_RUNNING);
assert(th->cpu);
thread_set_state(th, TH_ST_COOLING);
}
2021-07-28 11:56:35 +02:00
2021-10-11 11:12:26 +02:00
static void
pre_thread_warm(struct ovni_emu *emu, struct ovni_ethread *th)
{
assert(th->state == TH_ST_PAUSED);
assert(th->cpu);
2021-07-28 11:56:35 +02:00
2021-10-11 11:12:26 +02:00
thread_set_state(th, TH_ST_WARMING);
2021-07-28 11:56:35 +02:00
}
static void
2021-10-21 16:15:29 +02:00
pre_thread(struct ovni_emu *emu)
2021-07-28 11:56:35 +02:00
{
struct ovni_ev *ev;
struct ovni_cpu *cpu;
2021-10-11 11:12:26 +02:00
struct ovni_ethread *th, *remote_thread;
2021-07-28 11:56:35 +02:00
int i;
2021-07-29 17:46:25 +02:00
//emu_emit(emu);
2021-07-28 11:56:35 +02:00
2021-10-11 11:12:26 +02:00
th = emu->cur_thread;
cpu = th->cpu;
2021-07-28 11:56:35 +02:00
ev = emu->cur_ev;
2021-07-30 20:08:40 +02:00
switch(ev->header.value)
2021-07-28 11:56:35 +02:00
{
2021-10-11 11:12:26 +02:00
case 'C': /* create */
2021-07-28 11:56:35 +02:00
dbg("thread %d creates a new thread at cpu=%d with args=%x %x\n",
2021-10-11 11:12:26 +02:00
th->tid,
2021-07-28 11:56:35 +02:00
ev->payload.u32[0],
ev->payload.u32[1],
ev->payload.u32[2]);
break;
2021-10-11 11:12:26 +02:00
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;
2021-07-28 11:56:35 +02:00
default:
2021-09-27 17:42:14 +02:00
err("unknown thread event value %c\n",
ev->header.value);
exit(EXIT_FAILURE);
2021-07-28 11:56:35 +02:00
}
}
static void
2021-10-21 16:15:29 +02:00
pre_affinity_set(struct ovni_emu *emu)
2021-07-28 11:56:35 +02:00
{
int cpuid;
struct ovni_cpu *newcpu;
2021-10-11 11:12:26 +02:00
struct ovni_ethread *th;
2021-07-28 11:56:35 +02:00
2021-10-11 11:12:26 +02:00
th = emu->cur_thread;
2021-07-28 11:56:35 +02:00
cpuid = emu->cur_ev->payload.i32[0];
2021-10-11 11:12:26 +02:00
assert(th->cpu);
assert(th->state == TH_ST_RUNNING
|| th->state == TH_ST_COOLING
|| th->state == TH_ST_WARMING);
2021-07-28 11:56:35 +02:00
/* Migrate current cpu to the one at cpuid */
2021-08-02 21:13:03 +02:00
newcpu = emu_get_cpu(emu->cur_loom, cpuid);
2021-07-28 11:56:35 +02:00
2021-10-11 11:12:26 +02:00
if(th->cpu == newcpu)
{
err("warning: thread %d affinity already set to cpu %d\n",
2021-10-11 11:12:26 +02:00
th->tid,
th->cpu->gindex);
return;
}
2021-10-11 11:12:26 +02:00
cpu_migrate_thread(emu, th->cpu, th, newcpu);
thread_migrate_cpu(th, newcpu);
2021-10-11 11:12:26 +02:00
//dbg("cpu %d now runs %d\n", cpuid, th->tid);
2021-07-28 11:56:35 +02:00
}
static void
2021-10-21 16:15:29 +02:00
pre_affinity_remote(struct ovni_emu *emu)
2021-07-28 11:56:35 +02:00
{
int cpuid, tid;
struct ovni_cpu *newcpu;
2021-10-11 11:12:26 +02:00
struct ovni_ethread *remote_th;
2021-07-28 11:56:35 +02:00
cpuid = emu->cur_ev->payload.i32[0];
tid = emu->cur_ev->payload.i32[1];
2021-10-11 11:12:26 +02:00
remote_th = emu_get_thread(emu->cur_proc, tid);
2021-07-28 11:56:35 +02:00
2021-10-11 11:12:26 +02:00
assert(remote_th);
2021-10-11 11:12:26 +02:00
/* The remote_th cannot be in states dead or unknown */
assert(remote_th->state != TH_ST_DEAD
&& remote_th->state != TH_ST_UNKNOWN);
/* It must have an assigned CPU */
2021-10-11 11:12:26 +02:00
assert(remote_th->cpu);
2021-07-28 11:56:35 +02:00
/* Migrate current cpu to the one at cpuid */
2021-08-02 21:13:03 +02:00
newcpu = emu_get_cpu(emu->cur_loom, cpuid);
2021-07-28 11:56:35 +02:00
2021-10-11 11:12:26 +02:00
cpu_migrate_thread(emu, remote_th->cpu, remote_th, newcpu);
thread_migrate_cpu(remote_th, newcpu);
2021-07-28 11:56:35 +02:00
2021-10-11 11:12:26 +02:00
//dbg("remote_th %d switches to cpu %d by remote petition\n", tid,
2021-07-29 17:46:25 +02:00
// cpuid);
2021-07-28 11:56:35 +02:00
}
static void
2021-10-21 16:15:29 +02:00
pre_affinity(struct ovni_emu *emu)
2021-07-28 11:56:35 +02:00
{
2021-07-29 17:46:25 +02:00
//emu_emit(emu);
2021-07-30 20:08:40 +02:00
switch(emu->cur_ev->header.value)
2021-07-28 11:56:35 +02:00
{
2021-10-21 16:15:29 +02:00
case 's': pre_affinity_set(emu); break;
case 'r': pre_affinity_remote(emu); break;
2021-07-28 11:56:35 +02:00
default:
dbg("unknown affinity event value %c\n",
2021-07-30 20:08:40 +02:00
emu->cur_ev->header.value);
2021-07-28 11:56:35 +02:00
break;
}
}
2021-10-11 11:12:26 +02:00
void
pre_burst(struct ovni_emu *emu)
{
int64_t dt;
if(emu->nbursts >= MAX_BURSTS)
{
err("too many bursts\n");
abort();
}
emu->burst_time[emu->nbursts] = emu->delta_time;
if(emu->nbursts > 0)
{
dt = emu->burst_time[emu->nbursts] -
emu->burst_time[emu->nbursts - 1];
err("burst delta time %ld ns\n", dt);
}
emu->nbursts++;
}
2021-07-28 11:56:35 +02:00
void
2021-07-28 19:12:20 +02:00
hook_pre_ovni(struct ovni_emu *emu)
2021-07-28 11:56:35 +02:00
{
//emu_emit(emu);
if(emu->cur_ev->header.model != 'O')
return;
2021-07-30 20:08:40 +02:00
switch(emu->cur_ev->header.class)
2021-07-28 11:56:35 +02:00
{
2021-10-21 16:15:29 +02:00
case 'H': pre_thread(emu); break;
case 'A': pre_affinity(emu); break;
2021-10-11 11:12:26 +02:00
case 'B': pre_burst(emu); break;
2021-07-28 11:56:35 +02:00
default:
dbg("unknown ovni event class %c\n",
2021-07-30 20:08:40 +02:00
emu->cur_ev->header.class);
2021-07-28 11:56:35 +02:00
break;
}
2021-07-29 17:46:25 +02:00
//print_threads_state(emu);
2021-07-28 11:56:35 +02:00
}
2021-07-28 19:12:20 +02:00
2021-10-21 16:15:29 +02:00
/* --------------------------- post ------------------------------- */
void
hook_post_ovni(struct ovni_emu *emu)
{
2021-07-28 19:12:20 +02:00
}