Use one event per blocking type in Nanos6

This commit is contained in:
Rodrigo Arias 2022-09-01 17:02:02 +02:00
parent 5c45323354
commit ac1ae8e69d
18 changed files with 568 additions and 458 deletions

View File

@ -37,7 +37,7 @@ window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 40
window_filter_module evt_type 1 45
window_filter_module evt_type_label 1 "CPU: Context switches of the ACTIVE thread"
window_synchronize 1

View File

@ -37,7 +37,7 @@ window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 40
window_filter_module evt_type 1 45
window_filter_module evt_type_label 1 "Thread: Context switches of the CURRENT thread"
window_synchronize 1

View File

@ -162,14 +162,20 @@ KCI Is back in the CPU due to a context switch
6Ha Attaches to Nanos6 as external thread
6HA Detaches from Nanos6 as external thread
6s[ Begins to spawn a function via spawnFunction()
6s] Ends spawning a function
6F[ Begins to spawn a function via spawnFunction()
6F] Ends spawning a function
6Dr Begins the registration of a task's accesses
6DR Ends the registration of a task's accesses
6Du Begins the unregistration of a task's accesses
6DU Ends the unregistration of a task's accesses
6Bu Begins to unblock the given task
6BU Ends unblocking the given task
6Bu Begins to unblock a task
6BU Ends unblocking a task
6Bb Begins to block the current task via blockCurrentTask()
6BB Ends blocking the current task via blockCurrentTask()
6Bw Enters taskWait()
6BW Exits taskWait()
6Bf Enters taskFor()
6BF Exits taskFor()
```

View File

@ -53,6 +53,10 @@ task. It is only shown when the task is in the running state. This view
is specially useful to identify task in a distributed workload, which
spans several nodes.
As the zero value in Paraver gets hidden, we use the rank+1 value
instead. Therefore the rank numeric value go from 1 to the number of
ranks (inclusive).
## Subsystem view
The subsystem view attempts to provide a general overview of what Nanos6
@ -95,7 +99,7 @@ Task subsystem
: The **Task** subsystem contains the code that controls the life cycle
of tasks. It contains the following sections:
- **Running**: Executing the body of the task (user defined code).
- **Body**: Executing the body of the task (user defined code).
- **Spawning function**: Spawning a function as task (it will be
submitted to the scheduler for later execution).

75
emu.h
View File

@ -104,40 +104,30 @@ enum nodes_state {
* CTF implementation. */
enum nanos6_ss_state {
ST_NANOS6_NULL = 0, /* IDLE */
/* RUNTIME */
ST_NANOS6_TASK_BODY = 3, /* TASK */
ST_NANOS6_TASK_CREATING = 8, /* TASK_CREATE */
ST_NANOS6_TASK_SUBMIT = 10, /* TASK_SUBMIT */
ST_NANOS6_TASK_SPAWNING = 18, /* SPAWN_FUNCTION */
ST_NANOS6_SCHED_HUNGRY = 2, /* BUSY_WAIT */
ST_NANOS6_TASK_RUNNING = 3, /* TASK */
ST_NANOS6_SCHED_ADDING = 6, /* SCHEDULER_ADD_TASK */
ST_NANOS6_SCHED_SERVING = 20, /* SCHEDULER_LOCK_SERVING */
ST_NANOS6_DEP_REG = 4, /* DEPENDENCY_REGISTER */
ST_NANOS6_DEP_UNREG = 5, /* DEPENDENCY_UNREGISTER */
ST_NANOS6_SCHED_SUBMITTING = 6, /* SCHEDULER_ADD_TASK */
/* SCHEDULER_GET_TASK */
ST_NANOS6_CREATING = 8, /* TASK_CREATE */
/* TASK_ARGS_INIT */
ST_NANOS6_SUBMIT = 10, /* TASK_SUBMIT */
/* TASKFOR_INIT */
ST_NANOS6_TASKWAIT = 12, /* TASK_WAIT */
ST_NANOS6_WAITFOR = 13, /* WAIT_FOR */
/* LOCK */
/* UNLOCK */
ST_NANOS6_BLOCKING = 16, /* BLOCKING_API_BLOCK */
ST_NANOS6_UNBLOCKING = 17, /* BLOCKING_API_UNBLOCK */
ST_NANOS6_SPAWNING = 18, /* SPAWN_FUNCTION */
/* SCHEDULER_LOCK_ENTER */
ST_NANOS6_SCHED_SERVING = 20, /* SCHEDULER_LOCK_SERVING */
ST_NANOS6_ATTACHED,
ST_NANOS6_BLK_TASKWAIT = 12, /* TASK_WAIT */
ST_NANOS6_BLK_WAITFOR = 13, /* WAIT_FOR */
ST_NANOS6_BLK_BLOCKING = 16, /* BLOCKING_API_BLOCK */
ST_NANOS6_BLK_UNBLOCKING = 17, /* BLOCKING_API_UNBLOCK */
EV_NANOS6_SCHED_RECV,
EV_NANOS6_SCHED_SEND,
EV_NANOS6_SCHED_SELF,
EV_NANOS6_SCHED_RECV = 50,
EV_NANOS6_SCHED_SEND = 51,
EV_NANOS6_SCHED_SELF = 52,
};
/* Possible reasons for Nanos6 tasks becoming running or not running */
enum nanos6_task_run_reason
{
TB_EXEC_OR_END = -1,
TB_BLOCKING_API = 0,
TB_TASKWAIT = 1,
TB_WAITFOR = 2
enum nanos6_thread_state {
ST_NANOS6_TH_EXTERNAL = 1,
ST_NANOS6_TH_WORKER,
ST_NANOS6_TH_LEADER,
ST_NANOS6_TH_MAIN
};
enum kernel_cs_state {
@ -169,6 +159,20 @@ struct task {
struct task *prev;
};
struct task_info {
/* Both hash maps of all known tasks and types */
struct task_type *types;
struct task *tasks;
};
struct task_stack {
union {
struct task *top; /* Synctactic sugar */
struct task *tasks;
};
struct ovni_ethread *thread;
};
#define MAX_CHAN_STACK 128
enum chan_track {
@ -207,6 +211,7 @@ enum chan {
CHAN_NANOS6_TYPE,
CHAN_NANOS6_SUBSYSTEM,
CHAN_NANOS6_RANK,
CHAN_NANOS6_THREAD,
CHAN_KERNEL_CS,
@ -249,7 +254,8 @@ static const int chan_to_prvtype[CHAN_MAX] = {
[CHAN_NANOS6_TYPE] = 36,
[CHAN_NANOS6_SUBSYSTEM] = 37,
[CHAN_NANOS6_RANK] = 38,
[CHAN_KERNEL_CS] = 40,
[CHAN_NANOS6_THREAD] = 39,
[CHAN_KERNEL_CS] = 45,
};
struct ovni_chan {
@ -335,8 +341,8 @@ struct ovni_ethread {
* structures */
/* Task stacks, top ones are the tasks currently runnable. */
struct task *nosv_task_stack;
struct task *nanos6_task_stack;
struct task_stack nosv_task_stack;
struct task_stack nanos6_task_stack;
/* Channels are used to output the emulator state in PRV */
struct ovni_chan chan[CHAN_MAX];
@ -376,11 +382,8 @@ struct ovni_eproc {
/* ------ Subsystem specific data --------*/
/* TODO: Use dynamic allocation */
struct task_type *nosv_types;
struct task *nosv_tasks;
struct task_type *nanos6_types;
struct task *nanos6_tasks;
struct task_info nosv_task_info;
struct task_info nanos6_task_info;
};

View File

@ -30,7 +30,6 @@ hook_init_nanos6(struct ovni_emu *emu)
struct ovni_ethread *th;
struct ovni_cpu *cpu;
struct ovni_chan **uth, **ucpu;
size_t i;
int row;
FILE *prv_th, *prv_cpu;
int64_t *clock;
@ -40,7 +39,7 @@ hook_init_nanos6(struct ovni_emu *emu)
prv_cpu = emu->prv_cpu;
/* Init the channels in all threads */
for(i=0; i<emu->total_nthreads; i++)
for(size_t i=0; i<emu->total_nthreads; i++)
{
th = emu->global_thread[i];
row = th->gindex + 1;
@ -51,10 +50,11 @@ hook_init_nanos6(struct ovni_emu *emu)
chan_th_init(th, uth, CHAN_NANOS6_TYPE, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock);
chan_th_init(th, uth, CHAN_NANOS6_SUBSYSTEM, CHAN_TRACK_TH_ACTIVE, 0, 0, 1, row, prv_th, clock);
chan_th_init(th, uth, CHAN_NANOS6_RANK, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock);
chan_th_init(th, uth, CHAN_NANOS6_THREAD, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock);
}
/* Init the Nanos6 channels in all cpus */
for(i=0; i<emu->total_ncpus; i++)
for(size_t i=0; i<emu->total_ncpus; i++)
{
cpu = emu->global_cpu[i];
row = cpu->gindex + 1;
@ -64,46 +64,38 @@ hook_init_nanos6(struct ovni_emu *emu)
chan_cpu_init(cpu, ucpu, CHAN_NANOS6_TYPE, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
chan_cpu_init(cpu, ucpu, CHAN_NANOS6_SUBSYSTEM, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
chan_cpu_init(cpu, ucpu, CHAN_NANOS6_RANK, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
chan_cpu_init(cpu, ucpu, CHAN_NANOS6_THREAD, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
}
/* Init task stack */
for(size_t i=0; i<emu->total_nthreads; i++)
{
th = emu->global_thread[i];
th->nanos6_task_stack.thread = th;
}
}
/* --------------------------- pre ------------------------------- */
static void
task_not_running(struct ovni_emu *emu, struct task *task, enum nanos6_task_run_reason reason)
chan_task_stopped(struct ovni_emu *emu, char tr)
{
struct ovni_ethread *th;
th = emu->cur_thread;
if(task->state == TASK_ST_RUNNING)
die("task is still running\n");
chan_set(&th->chan[CHAN_NANOS6_TASKID], 0);
chan_set(&th->chan[CHAN_NANOS6_TYPE], 0);
if(emu->cur_loom->rank_enabled)
chan_set(&th->chan[CHAN_NANOS6_RANK], 0);
// Check the reason
switch (reason)
{
case TB_EXEC_OR_END:
chan_pop(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASK_RUNNING);
break;
case TB_BLOCKING_API:
chan_push(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_BLOCKING);
break;
case TB_TASKWAIT:
chan_push(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASKWAIT);
break;
case TB_WAITFOR:
chan_push(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_WAITFOR);
break;
}
/* Only exit the task body when finishing */
if(tr == 'e')
chan_pop(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASK_BODY);
}
static void
task_running(struct ovni_emu *emu, struct task *task, enum nanos6_task_run_reason reason)
chan_task_running(struct ovni_emu *emu, struct task *task, char tr)
{
struct ovni_ethread *th;
struct ovni_eproc *proc;
@ -126,65 +118,150 @@ task_running(struct ovni_emu *emu, struct task *task, enum nanos6_task_run_reaso
if(emu->cur_loom->rank_enabled)
chan_set(&th->chan[CHAN_NANOS6_RANK], proc->rank + 1);
// Check the reason
switch (reason)
{
case TB_EXEC_OR_END:
chan_push(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASK_RUNNING);
break;
case TB_BLOCKING_API:
chan_pop(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_BLOCKING);
break;
case TB_TASKWAIT:
chan_pop(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASKWAIT);
break;
case TB_WAITFOR:
chan_pop(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_WAITFOR);
break;
}
/* Only enter the body of the task when we begin the execution */
if(tr == 'x')
chan_push(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASK_BODY);
}
static void
task_switch(struct ovni_emu *emu, struct task *prev_task,
struct task *next_task, int newtask)
chan_task_switch(struct ovni_emu *emu,
struct task *prev, struct task *next)
{
struct ovni_ethread *th;
struct ovni_ethread *th = emu->cur_thread;
th = emu->cur_thread;
if(!prev_task || !next_task)
if(!prev || !next)
die("cannot switch to or from a NULL task\n");
if(prev_task == next_task)
if(prev == next)
die("cannot switch to the same task\n");
if(newtask && prev_task->state != TASK_ST_RUNNING)
die("previous task must not be no longer running\n");
if(!newtask && prev_task->state != TASK_ST_DEAD)
die("previous task must be dead\n");
if(next_task->state != TASK_ST_RUNNING)
die("next task must be running\n");
if(next_task->id == 0)
if(next->id == 0)
die("next task id cannot be 0\n");
if(next_task->type->gid == 0)
if(next->type->gid == 0)
die("next task type id cannot be 0\n");
if(prev_task->thread != next_task->thread)
if(prev->thread != next->thread)
die("cannot switch to a task of another thread\n");
/* No need to change the rank as we will switch to tasks from same stack */
chan_set(&th->chan[CHAN_NANOS6_TASKID], next_task->id);
/* No need to change the rank as we will switch to tasks from
* same thread */
chan_set(&th->chan[CHAN_NANOS6_TASKID], next->id);
/* FIXME: We should emit a PRV event even if we are switching to
* the same type event, to mark the end of the current task. For
* now we only emit a new type if we switch to a type with a
* different gid. */
if(prev_task->type->gid != next_task->type->gid)
chan_set(&th->chan[CHAN_NANOS6_TYPE], next_task->type->gid);
if(prev->type->gid != next->type->gid)
chan_set(&th->chan[CHAN_NANOS6_TYPE], next->type->gid);
}
static void
update_task_state(struct ovni_emu *emu)
{
if(ovni_payload_size(emu->cur_ev) < 4)
die("missing task id in payload\n");
uint32_t task_id = emu->cur_ev->payload.u32[0];
struct ovni_ethread *th = emu->cur_thread;
struct ovni_eproc *proc = emu->cur_proc;
struct task_info *info = &proc->nanos6_task_info;
struct task_stack *stack = &th->nanos6_task_stack;
struct task *task = task_find(info->tasks, task_id);
if(task == NULL)
die("cannot find task with id %u\n", task_id);
switch(emu->cur_ev->header.value)
{
case 'x': task_execute(stack, task); break;
case 'e': task_end(stack, task); break;
case 'p': task_pause(stack, task); break;
case 'r': task_resume(stack, task); break;
default:
die("unexpected Nanos6 task event value %c\n",
emu->cur_ev->header.value);
}
}
static char
expand_transition_value(struct ovni_emu *emu, int was_running, int runs_now)
{
char tr = emu->cur_ev->header.value;
/* Ensure we don't clobber the value */
if(tr == 'X' || tr == 'E')
die("unexpected event value %c\n", tr);
/* Modify the event value to detect nested transitions */
if(tr == 'x' && was_running)
tr = 'X'; /* Execute a new nested task */
else if(tr == 'e' && runs_now)
tr = 'E'; /* End a nested task */
return tr;
}
static void
update_task_channels(struct ovni_emu *emu,
char tr, struct task *prev, struct task *next)
{
switch(tr)
{
case 'x':
case 'r':
chan_task_running(emu, next, tr);
break;
case 'e':
case 'p':
chan_task_stopped(emu, tr);
break;
/* Additional nested transitions */
case 'X':
case 'E':
chan_task_switch(emu, prev, next);
break;
default:
die("unexpected transition value %c\n", tr);
}
}
static void
update_task(struct ovni_emu *emu)
{
struct ovni_ethread *th = emu->cur_thread;
struct task_stack *stack = &th->nanos6_task_stack;
struct task *prev = task_get_running(stack);
/* Update the emulator state, but don't modify the channels */
update_task_state(emu);
struct task *next = task_get_running(stack);
int was_running = (prev != NULL);
int runs_now = (next != NULL);
char tr = expand_transition_value(emu, was_running, runs_now);
/* Update the channels now */
update_task_channels(emu, tr, prev, next);
}
static void
create_task(struct ovni_emu *emu)
{
if(ovni_payload_size(emu->cur_ev) != 8)
die("cannot create task: unexpected payload size\n");
uint32_t task_id = emu->cur_ev->payload.u32[0];
uint32_t type_id = emu->cur_ev->payload.u32[1];
struct task_info *info = &emu->cur_proc->nanos6_task_info;
task_create(info, type_id, task_id);
}
static void
@ -192,87 +269,53 @@ pre_task(struct ovni_emu *emu)
{
struct ovni_ethread *th;
struct ovni_chan *chan_th;
struct task **task_map = &emu->cur_proc->nanos6_tasks;
struct task_type **type_map = &emu->cur_proc->nanos6_types;
struct task **task_stack = &emu->cur_thread->nanos6_task_stack;
struct task *prev_running = task_get_running(*task_stack);
int was_running_task = (prev_running != NULL);
th = emu->cur_thread;
chan_th = &th->chan[CHAN_NANOS6_SUBSYSTEM];
/* Update the emulator state, but don't modify the channels yet */
switch(emu->cur_ev->header.value)
{
case 'c': task_create(emu->cur_ev->payload.i32[0], emu->cur_ev->payload.i32[1], task_map, type_map); break;
case 'x': task_execute(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break;
case 'e': task_end(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break;
case 'b': task_pause(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break;
case 'u': task_resume(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break;
case 'C': break;
default:
abort();
}
struct task *next_running = task_get_running(*task_stack);
int runs_task_now = (next_running != NULL);
/* Now that we know if the emulator was running a task before
* or if it's running one now, update the channels accordingly. */
switch(emu->cur_ev->header.value)
{
case 'x': /* Execute: either a nested task or a new one */
if(was_running_task)
task_switch(emu, prev_running, next_running, 1);
else
task_running(emu, next_running, TB_EXEC_OR_END);
/* We use the 'c' event to create the task and switch
* the subsystem all in one step because the timing here
* is critical. */
case 'c':
chan_push(chan_th, ST_NANOS6_TASK_CREATING);
create_task(emu);
break;
case 'e': /* End: either a nested task or the last one */
if(runs_task_now)
task_switch(emu, prev_running, next_running, 0);
else
task_not_running(emu, prev_running, TB_EXEC_OR_END);
case 'C':
chan_pop(chan_th, ST_NANOS6_TASK_CREATING);
break;
case 'b': /* Block */
task_not_running(emu, prev_running, emu->cur_ev->payload.i32[1]);
break;
case 'u': /* Unblock */
task_running(emu, next_running, emu->cur_ev->payload.i32[1]);
break;
case 'c': /* Create */
chan_push(chan_th, ST_NANOS6_CREATING);
break;
case 'C': /* Create end */
chan_pop(chan_th, ST_NANOS6_CREATING);
case 'x':
case 'e':
case 'r':
case 'p': /* Wet floor */
update_task(emu);
break;
default:
break;
die("unexpected event value %c\n",
emu->cur_ev->header.value);
}
}
static void
pre_type(struct ovni_emu *emu)
{
uint8_t *data;
if(emu->cur_ev->header.value != 'c')
die("unexpected event value %c\n",
emu->cur_ev->header.value);
switch(emu->cur_ev->header.value)
{
case 'c':
if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0)
{
err("expecting a jumbo event\n");
abort();
}
if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0)
die("expecting a jumbo event\n");
data = &emu->cur_ev->payload.jumbo.data[0];
uint32_t *typeid = (uint32_t *) data;
data += sizeof(*typeid);
const char *label = (const char *) data;
task_type_create(*typeid, label, &emu->cur_proc->nanos6_types);
break;
default:
break;
}
uint8_t *data = &emu->cur_ev->payload.jumbo.data[0];
uint32_t typeid = *(uint32_t *) data;
data += 4;
const char *label = (const char *) data;
struct ovni_eproc *proc = emu->cur_proc;
task_type_create(&proc->nanos6_task_info, typeid, label);
}
static void
@ -287,9 +330,9 @@ pre_deps(struct ovni_emu *emu)
switch(emu->cur_ev->header.value)
{
case 'r': chan_push(chan_th, ST_NANOS6_DEP_REG); break;
case 'R': chan_pop(chan_th, ST_NANOS6_DEP_REG); break;
case 'R': chan_pop (chan_th, ST_NANOS6_DEP_REG); break;
case 'u': chan_push(chan_th, ST_NANOS6_DEP_UNREG); break;
case 'U': chan_pop(chan_th, ST_NANOS6_DEP_UNREG); break;
case 'U': chan_pop (chan_th, ST_NANOS6_DEP_UNREG); break;
default: break;
}
}
@ -305,8 +348,14 @@ pre_blocking(struct ovni_emu *emu)
switch(emu->cur_ev->header.value)
{
case 'u': chan_push(chan_th, ST_NANOS6_UNBLOCKING); break;
case 'U': chan_pop(chan_th, ST_NANOS6_UNBLOCKING); break;
case 'b': chan_push(chan_th, ST_NANOS6_BLK_BLOCKING); break;
case 'B': chan_pop (chan_th, ST_NANOS6_BLK_BLOCKING); break;
case 'u': chan_push(chan_th, ST_NANOS6_BLK_UNBLOCKING); break;
case 'U': chan_pop (chan_th, ST_NANOS6_BLK_UNBLOCKING); break;
case 'w': chan_push(chan_th, ST_NANOS6_BLK_TASKWAIT); break;
case 'W': chan_pop (chan_th, ST_NANOS6_BLK_TASKWAIT); break;
case 'f': chan_push(chan_th, ST_NANOS6_BLK_WAITFOR); break;
case 'F': chan_pop (chan_th, ST_NANOS6_BLK_WAITFOR); break;
default: break;
}
}
@ -334,20 +383,24 @@ pre_sched(struct ovni_emu *emu)
}
static void
pre_thread_type(struct ovni_emu *emu)
pre_thread(struct ovni_emu *emu)
{
struct ovni_ethread *th;
struct ovni_chan *chan_th;
th = emu->cur_thread;
chan_th = &th->chan[CHAN_NANOS6_SUBSYSTEM];
chan_th = &th->chan[CHAN_NANOS6_THREAD];
switch(emu->cur_ev->header.value)
{
case 'a': chan_push(chan_th, ST_NANOS6_ATTACHED); break;
case 'A': chan_pop (chan_th, ST_NANOS6_ATTACHED); break;
case 's': chan_push(chan_th, ST_NANOS6_SPAWNING); break;
case 'S': chan_pop (chan_th, ST_NANOS6_SPAWNING); break;
case 'e': chan_push(chan_th, ST_NANOS6_TH_EXTERNAL); break;
case 'E': chan_pop (chan_th, ST_NANOS6_TH_EXTERNAL); break;
case 'w': chan_push(chan_th, ST_NANOS6_TH_WORKER); break;
case 'W': chan_pop (chan_th, ST_NANOS6_TH_WORKER); break;
case 'l': chan_push(chan_th, ST_NANOS6_TH_LEADER); break;
case 'L': chan_pop (chan_th, ST_NANOS6_TH_LEADER); break;
case 'm': chan_push(chan_th, ST_NANOS6_TH_MAIN); break;
case 'M': chan_pop (chan_th, ST_NANOS6_TH_MAIN); break;
default: break;
}
}
@ -406,8 +459,8 @@ hook_pre_nanos6(struct ovni_emu *emu)
case 'T': pre_task(emu); break;
case 'Y': pre_type(emu); break;
case 'S': pre_sched(emu); break;
case 'U': pre_ss(emu, ST_NANOS6_SUBMIT); break;
case 'H': pre_thread_type(emu); break;
case 'U': pre_ss(emu, ST_NANOS6_TASK_SUBMIT); break;
case 'H': pre_thread(emu); break;
case 'D': pre_deps(emu); break;
case 'B': pre_blocking(emu); break;
default:
@ -417,27 +470,6 @@ hook_pre_nanos6(struct ovni_emu *emu)
check_affinity(emu);
}
char *nanos6_ss_names[] = {
[ST_NANOS6_NULL] = "ST_NANOS6_NULL",
[ST_NANOS6_SCHED_HUNGRY] = "ST_NANOS6_SCHED_HUNGRY",
[ST_NANOS6_TASK_RUNNING] = "ST_NANOS6_TASK_RUNNING",
[ST_NANOS6_DEP_REG] = "ST_NANOS6_DEP_REG",
[ST_NANOS6_DEP_UNREG] = "ST_NANOS6_DEP_UNREG",
[ST_NANOS6_SCHED_SUBMITTING] = "ST_NANOS6_SCHED_SUBMITTING",
[ST_NANOS6_CREATING] = "ST_NANOS6_CREATING",
[ST_NANOS6_SUBMIT] = "ST_NANOS6_SUBMIT",
[ST_NANOS6_TASKWAIT] = "ST_NANOS6_TASKWAIT",
[ST_NANOS6_WAITFOR] = "ST_NANOS6_WAITFOR",
[ST_NANOS6_BLOCKING] = "ST_NANOS6_BLOCKING",
[ST_NANOS6_UNBLOCKING] = "ST_NANOS6_UNBLOCKING",
[ST_NANOS6_SPAWNING] = "ST_NANOS6_SPAWNING",
[ST_NANOS6_SCHED_SERVING] = "ST_NANOS6_SCHED_SERVING",
[ST_NANOS6_ATTACHED] = "ST_NANOS6_ATTACHED",
[EV_NANOS6_SCHED_RECV] = "EV_NANOS6_SCHED_RECV",
[EV_NANOS6_SCHED_SEND] = "EV_NANOS6_SCHED_SEND",
[EV_NANOS6_SCHED_SELF] = "EV_NANOS6_SCHED_SELF",
};
static void
end_lint(struct ovni_emu *emu)
{
@ -449,8 +481,19 @@ end_lint(struct ovni_emu *emu)
if(ch->n != 1)
{
int top = ch->stack[ch->n - 1];
char *name = nanos6_ss_names[top];
die("thread %d ended with %d extra stacked nanos6 subsystems, top=%s\n",
struct pcf_value_label *pv;
char *name = "(unknown)";
for(pv = &nanos6_ss_values[0]; pv->label; pv++)
{
if(pv->value == top)
{
name = pv->label;
break;
}
}
die("thread %d ended with %d extra stacked nanos6 subsystems, top=\"%s\"\n",
th->tid, ch->n - 1, name);
}
}
@ -472,7 +515,7 @@ hook_end_nanos6(struct ovni_emu *emu)
for(size_t j = 0; j < loom->nprocs; j++)
{
struct ovni_eproc *proc = &loom->proc[j];
task_create_pcf_types(pcftype, proc->nanos6_types);
task_create_pcf_types(pcftype, proc->nanos6_task_info.types);
}
}
}

View File

@ -74,18 +74,21 @@ hook_init_nosv(struct ovni_emu *emu)
chan_cpu_init(cpu, ucpu, CHAN_NOSV_RANK, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
chan_cpu_init(cpu, ucpu, CHAN_NOSV_SUBSYSTEM, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
}
/* Init task stack */
for(i=0; i<emu->total_nthreads; i++)
{
th = emu->global_thread[i];
th->nosv_task_stack.thread = th;
}
}
/* --------------------------- pre ------------------------------- */
static void
task_not_running(struct ovni_emu *emu, struct task *task)
chan_task_stopped(struct ovni_emu *emu)
{
struct ovni_ethread *th;
th = emu->cur_thread;
if(task->state == TASK_ST_RUNNING)
die("task is still running\n");
struct ovni_ethread *th = emu->cur_thread;
chan_set(&th->chan[CHAN_NOSV_TASKID], 0);
chan_set(&th->chan[CHAN_NOSV_TYPE], 0);
@ -94,11 +97,12 @@ task_not_running(struct ovni_emu *emu, struct task *task)
if(emu->cur_loom->rank_enabled)
chan_set(&th->chan[CHAN_NOSV_RANK], 0);
/* XXX: Do we need this transition? */
chan_pop(&th->chan[CHAN_NOSV_SUBSYSTEM], ST_NOSV_TASK_RUNNING);
}
static void
task_running(struct ovni_emu *emu, struct task *task)
chan_task_running(struct ovni_emu *emu, struct task *task)
{
struct ovni_ethread *th;
struct ovni_eproc *proc;
@ -126,123 +130,179 @@ task_running(struct ovni_emu *emu, struct task *task)
}
static void
task_switch(struct ovni_emu *emu, struct task *prev_task,
struct task *next_task, int newtask)
chan_task_switch(struct ovni_emu *emu,
struct task *prev, struct task *next)
{
struct ovni_ethread *th;
struct ovni_ethread *th = emu->cur_thread;
th = emu->cur_thread;
if(!prev_task || !next_task)
if(!prev || !next)
die("cannot switch to or from a NULL task\n");
if(prev_task == next_task)
if(prev == next)
die("cannot switch to the same task\n");
if(newtask && prev_task->state != TASK_ST_RUNNING)
die("previous task must not be no longer running\n");
if(!newtask && prev_task->state != TASK_ST_DEAD)
die("previous task must be dead\n");
if(next_task->state != TASK_ST_RUNNING)
die("next task must be running\n");
if(next_task->id == 0)
if(next->id == 0)
die("next task id cannot be 0\n");
if(next_task->type->gid == 0)
if(next->type->gid == 0)
die("next task type id cannot be 0\n");
if(prev_task->thread != next_task->thread)
if(prev->thread != next->thread)
die("cannot switch to a task of another thread\n");
/* No need to change the rank or app ID, as we can only switch
* to tasks of the same thread */
chan_set(&th->chan[CHAN_NOSV_TASKID], next_task->id);
chan_set(&th->chan[CHAN_NOSV_TASKID], next->id);
/* FIXME: We should emit a PRV event even if we are switching to
* the same type event, to mark the end of the current task. For
* now we only emit a new type if we switch to a type with a
* different gid. */
if(prev_task->type->gid != next_task->type->gid)
chan_set(&th->chan[CHAN_NOSV_TYPE], next_task->type->gid);
if(prev->type->gid != next->type->gid)
chan_set(&th->chan[CHAN_NOSV_TYPE], next->type->gid);
}
static void
update_task_state(struct ovni_emu *emu)
{
if(ovni_payload_size(emu->cur_ev) < 4)
die("missing task id in payload\n");
uint32_t task_id = emu->cur_ev->payload.u32[0];
struct ovni_ethread *th = emu->cur_thread;
struct ovni_eproc *proc = emu->cur_proc;
struct task_info *info = &proc->nosv_task_info;
struct task_stack *stack = &th->nosv_task_stack;
struct task *task = task_find(info->tasks, task_id);
if(task == NULL)
die("cannot find task with id %u\n", task_id);
switch(emu->cur_ev->header.value)
{
case 'x': task_execute(stack, task); break;
case 'e': task_end(stack, task); break;
case 'p': task_pause(stack, task); break;
case 'r': task_resume(stack, task); break;
default:
die("unexpected Nanos6 task event value %c\n",
emu->cur_ev->header.value);
}
}
static char
expand_transition_value(struct ovni_emu *emu, int was_running, int runs_now)
{
char tr = emu->cur_ev->header.value;
/* Ensure we don't clobber the value */
if(tr == 'X' || tr == 'E')
die("unexpected event value %c\n", tr);
/* Modify the event value to detect nested transitions */
if(tr == 'x' && was_running)
tr = 'X'; /* Execute a new nested task */
else if(tr == 'e' && runs_now)
tr = 'E'; /* End a nested task */
return tr;
}
static void
update_task_channels(struct ovni_emu *emu,
char tr, struct task *prev, struct task *next)
{
switch(tr)
{
case 'x': chan_task_running(emu, next); break;
case 'r': chan_task_running(emu, next); break;
case 'e': chan_task_stopped(emu); break;
case 'p': chan_task_stopped(emu); break;
/* Additional nested transitions */
case 'X': chan_task_switch(emu, prev, next); break;
case 'E': chan_task_switch(emu, prev, next); break;
default:
die("unexpected transition value %c\n", tr);
}
}
static void
update_task(struct ovni_emu *emu)
{
struct ovni_ethread *th = emu->cur_thread;
struct task_stack *stack = &th->nosv_task_stack;
struct task *prev = task_get_running(stack);
/* Update the emulator state, but don't modify the channels */
update_task_state(emu);
struct task *next = task_get_running(stack);
int was_running = (prev != NULL);
int runs_now = (next != NULL);
char tr = expand_transition_value(emu, was_running, runs_now);
/* Update the channels now */
update_task_channels(emu, tr, prev, next);
}
static void
create_task(struct ovni_emu *emu)
{
if(ovni_payload_size(emu->cur_ev) != 8)
die("cannot create task: unexpected payload size\n");
uint32_t task_id = emu->cur_ev->payload.u32[0];
uint32_t type_id = emu->cur_ev->payload.u32[1];
struct task_info *info = &emu->cur_proc->nosv_task_info;
task_create(info, type_id, task_id);
}
static void
pre_task(struct ovni_emu *emu)
{
struct task **task_map = &emu->cur_proc->nosv_tasks;
struct task_type **type_map = &emu->cur_proc->nosv_types;
struct task **task_stack = &emu->cur_thread->nosv_task_stack;
struct task *prev_running = task_get_running(*task_stack);
int was_running_task = (prev_running != NULL);
/* Update the emulator state, but don't modify the channels yet */
switch(emu->cur_ev->header.value)
{
case 'c': task_create(emu->cur_ev->payload.i32[0], emu->cur_ev->payload.i32[1], task_map, type_map); break;
case 'x': task_execute(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break;
case 'e': task_end(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break;
case 'p': task_pause(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break;
case 'r': task_resume(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break;
default:
abort();
}
struct task *next_running = task_get_running(*task_stack);
int runs_task_now = (next_running != NULL);
/* Now that we know if the emulator was running a task before
* or if it's running one now, update the channels accordingly. */
switch(emu->cur_ev->header.value)
{
case 'x': /* Execute: either a nested task or a new one */
if(was_running_task)
task_switch(emu, prev_running, next_running, 1);
else
task_running(emu, next_running);
case 'c':
create_task(emu);
break;
case 'e': /* End: either a nested task or the last one */
if(runs_task_now)
task_switch(emu, prev_running, next_running, 0);
else
task_not_running(emu, prev_running);
break;
case 'p': /* Pause */
task_not_running(emu, prev_running);
break;
case 'r': /* Resume */
task_running(emu, next_running);
case 'x':
case 'e':
case 'r':
case 'p': /* Wet floor */
update_task(emu);
break;
default:
break;
die("unexpected event value %c\n",
emu->cur_ev->header.value);
}
}
static void
pre_type(struct ovni_emu *emu)
{
uint8_t *data;
if(emu->cur_ev->header.value != 'c')
die("unexpected event value %c\n",
emu->cur_ev->header.value);
switch(emu->cur_ev->header.value)
{
case 'c':
if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0)
{
err("expecting a jumbo event\n");
abort();
}
if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0)
die("expecting a jumbo event\n");
data = &emu->cur_ev->payload.jumbo.data[0];
uint32_t *typeid = (uint32_t *) data;
data += sizeof(*typeid);
const char *label = (const char *) data;
task_type_create(*typeid, label, &emu->cur_proc->nosv_types);
break;
default:
break;
}
uint8_t *data = &emu->cur_ev->payload.jumbo.data[0];
uint32_t typeid = *(uint32_t *) data;
data += 4;
const char *label = (const char *) data;
struct ovni_eproc *proc = emu->cur_proc;
task_type_create(&proc->nosv_task_info, typeid, label);
}
static void
@ -437,7 +497,7 @@ hook_end_nosv(struct ovni_emu *emu)
for(size_t j = 0; j < loom->nprocs; j++)
{
struct ovni_eproc *proc = &loom->proc[j];
task_create_pcf_types(pcftype, proc->nosv_types);
task_create_pcf_types(pcftype, proc->nosv_task_info.types);
}
}
}

View File

@ -24,24 +24,39 @@
#include "prv.h"
#include "chan.h"
struct task *
task_find(struct task *tasks, uint32_t task_id)
{
struct task *task = NULL;
HASH_FIND_INT(tasks, &task_id, task);
return task;
}
struct task_type *
task_type_find(struct task_type *types, uint32_t type_id)
{
struct task_type *type = NULL;
HASH_FIND_INT(types, &type_id, type);
return type;
}
void
task_create(uint32_t task_id, uint32_t type_id, struct task **task_map, struct task_type **type_map)
task_create(struct task_info *info,
uint32_t type_id, uint32_t task_id)
{
/* Ensure the task id is new */
struct task *task = NULL;
HASH_FIND_INT(*task_map, &task_id, task);
if(task != NULL)
die("cannot create a task with id %u: already exists\n", task_id);
if(task_find(info->tasks, task_id) != NULL)
die("cannot create task: task_id %u already exists\n",
task_id);
/* Ensure the type exists */
struct task_type *type = NULL;
HASH_FIND_INT(*type_map, &type_id, type);
struct task_type *type = task_type_find(info->types, type_id);
if(type == NULL)
die("cannot create task: unknown type id %u\n", type_id);
task = calloc(1, sizeof(*task));
struct task *task = calloc(1, sizeof(struct task));
if(task == NULL)
die("calloc failed\n");
@ -52,64 +67,59 @@ task_create(uint32_t task_id, uint32_t type_id, struct task **task_map, struct t
task->thread = NULL;
/* Add the new task to the hash table */
HASH_ADD_INT(*task_map, id, task);
HASH_ADD_INT(info->tasks, id, task);
dbg("new task created id=%d\n", task->id);
}
void
task_execute(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack)
task_execute(struct task_stack *stack, struct task *task)
{
struct task *top = *thread_task_stack;
struct task *task = NULL;
HASH_FIND_INT(*task_map, &task_id, task);
if(task == NULL)
die("cannot find task with id %u\n", task_id);
die("cannot execute: task is NULL\n");
if(task->state != TASK_ST_CREATED)
die("cannot execute task %u: state is not created\n", task_id);
die("cannot execute task %u: state is not created\n", task->id);
if(task->thread != NULL)
die("task already has a thread assigned\n");
if(cur_thread->state != TH_ST_RUNNING)
if(stack->thread->state != TH_ST_RUNNING)
die("thread state is not running\n");
if(top == task)
die("thread already has assigned task %u\n", task_id);
if(stack->top == task)
die("thread already has assigned task %u\n", task->id);
if(top && top->state != TASK_ST_RUNNING)
if(stack->top && stack->top->state != TASK_ST_RUNNING)
die("cannot execute a nested task from a non-running task\n");
task->state = TASK_ST_RUNNING;
task->thread = cur_thread;
task->thread = stack->thread;
DL_PREPEND(*thread_task_stack, task);
DL_PREPEND(stack->tasks, task);
dbg("task id=%u runs now\n", task->id);
}
void
task_pause(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack)
task_pause(struct task_stack *stack, struct task *task)
{
struct task *top = *thread_task_stack;
struct task *task = NULL;
HASH_FIND_INT(*task_map, &task_id, task);
if(task == NULL)
die("cannot find task with id %u\n", task_id);
die("cannot pause: task is NULL\n");
if(task->state != TASK_ST_RUNNING)
die("task state is not running\n");
die("cannot pause: task state is not running\n");
if(cur_thread->state != TH_ST_RUNNING)
die("thread state is not running\n");
if(task->thread == NULL)
die("cannot pause: task has no thread assigned\n");
if(top != task)
if(stack->thread->state != TH_ST_RUNNING)
die("cannot pause: thread state is not running\n");
if(stack->top != task)
die("thread has assigned a different task\n");
if(cur_thread != task->thread)
if(stack->thread != task->thread)
die("task is assigned to a different thread\n");
task->state = TASK_ST_PAUSED;
@ -118,25 +128,24 @@ task_pause(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task
}
void
task_resume(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack)
task_resume(struct task_stack *stack, struct task *task)
{
struct task *top = *thread_task_stack;
struct task *task = NULL;
HASH_FIND_INT(*task_map, &task_id, task);
if(task == NULL)
die("cannot find task with id %u\n", task_id);
die("cannot resume: task is NULL\n");
if(task->state != TASK_ST_PAUSED)
die("task state is not paused\n");
if(cur_thread->state != TH_ST_RUNNING)
if(task->thread == NULL)
die("cannot resume: task has no thread assigned\n");
if(stack->thread->state != TH_ST_RUNNING)
die("thread is not running\n");
if(top != task)
if(stack->top != task)
die("thread has assigned a different task\n");
if(cur_thread != task->thread)
if(stack->thread != task->thread)
die("task is assigned to a different thread\n");
task->state = TASK_ST_RUNNING;
@ -145,25 +154,24 @@ task_resume(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **tas
}
void
task_end(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack)
task_end(struct task_stack *stack, struct task *task)
{
struct task *top = *thread_task_stack;
struct task *task = NULL;
HASH_FIND_INT(*task_map, &task_id, task);
if(task == NULL)
die("cannot find task with id %u\n", task_id);
die("cannot end: task is NULL\n");
if(task->state != TASK_ST_RUNNING)
die("task state is not running\n");
if(cur_thread->state != TH_ST_RUNNING)
die("thread is not running\n");
if(task->thread == NULL)
die("cannot end: task has no thread assigned\n");
if(top != task)
if(stack->thread->state != TH_ST_RUNNING)
die("cannot end task: thread is not running\n");
if(stack->top != task)
die("thread has assigned a different task\n");
if(cur_thread != task->thread)
if(stack->thread != task->thread)
die("task is assigned to a different thread\n");
task->state = TASK_ST_DEAD;
@ -171,7 +179,7 @@ task_end(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_m
/* Don't unset the thread from the task, as it will be used
* later to ensure we switch to tasks of the same thread. */
DL_DELETE(*thread_task_stack, task);
DL_DELETE(stack->tasks, task);
dbg("task id=%d ends\n", task->id);
}
@ -193,27 +201,21 @@ get_task_type_gid(const char *label)
}
void
task_type_create(uint32_t typeid, const char *label, struct task_type **type_map)
task_type_create(struct task_info *info, uint32_t type_id, const char *label)
{
struct task_type *type;
/* Ensure the type id is new */
HASH_FIND_INT(*type_map, &typeid, type);
HASH_FIND_INT(info->types, &type_id, type);
if(type != NULL)
{
err("A task type with id %d already exists\n", typeid);
abort();
}
die("a task type with id %u already exists\n", type_id);
type = calloc(1, sizeof(*type));
if(type == NULL)
{
perror("calloc");
abort();
}
die("calloc failed");
type->id = typeid;
type->id = type_id;
if(type->id == 0)
die("invalid task type id %d\n", type->id);
@ -221,21 +223,21 @@ task_type_create(uint32_t typeid, const char *label, struct task_type **type_map
type->gid = get_task_type_gid(label);
int n = snprintf(type->label, MAX_PCF_LABEL, "%s", label);
if(n >= MAX_PCF_LABEL)
die("task label too long: %s\n", label);
die("task type label too long: %s\n", label);
/* Add the new task type to the hash table */
HASH_ADD_INT(*type_map, id, type);
HASH_ADD_INT(info->types, id, type);
dbg("new task type created id=%d label=%s\n", type->id,
type->label);
}
void
task_create_pcf_types(struct pcf_type *pcftype, struct task_type *type_map)
task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types)
{
/* Emit types for all task types */
struct task_type *tt;
for(tt = type_map; tt != NULL; tt = tt->hh.next)
for(tt = types; tt != NULL; tt = tt->hh.next)
{
struct pcf_value *pcfvalue = pcf_find_value(pcftype, tt->gid);
if(pcfvalue != NULL)
@ -253,9 +255,9 @@ task_create_pcf_types(struct pcf_type *pcftype, struct task_type *type_map)
}
struct task *
task_get_running(struct task *task_stack)
task_get_running(struct task_stack *stack)
{
struct task *task = task_stack;
struct task *task = stack->top;
if(task && task->state == TASK_ST_RUNNING)
return task;

View File

@ -20,13 +20,18 @@
#include "emu.h"
void task_create(uint32_t task_id, uint32_t type_id, struct task **task_map, struct task_type **type_map);
void task_execute(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack);
void task_pause(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack);
void task_resume(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack);
void task_end(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack);
void task_type_create(uint32_t typeid, const char *label, struct task_type **type_map);
void task_create_pcf_types(struct pcf_type *pcftype, struct task_type *type_map);
struct task *task_get_running(struct task *task_stack);
struct task *task_find(struct task *tasks, uint32_t task_id);
void task_create(struct task_info *info, uint32_t type_id, uint32_t task_id);
void task_execute(struct task_stack *stack, struct task *task);
void task_pause(struct task_stack *stack, struct task *task);
void task_resume(struct task_stack *stack, struct task *task);
void task_end(struct task_stack *stack, struct task *task);
struct task_type *task_type_find(struct task_type *types, uint32_t type_id);
void task_type_create(struct task_info *info, uint32_t type_id, const char *label);
void task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types);
struct task *task_get_running(struct task_stack *stack);
#endif /* OVNI_EMU_TASK_H */

View File

@ -11,13 +11,22 @@ let
mpi = last.impi;
#mpi = last.openmpi;
nanos6 = (prev.nanos6Git.override {
gitUrl = "ssh://git@bscpm03.bsc.es/nanos6/forks/nanos6-extern-001.git";
gitBranch = "ovni_instr";
extrae = null;
}).overrideAttrs (old: {
#nanos6 = (prev.nanos6Git.override {
# gitUrl = "ssh://git@bscpm03.bsc.es/nanos6/forks/nanos6-extern-001.git";
# gitBranch = "ovni_instr";
# extrae = null;
#}).overrideAttrs (old: {
# buildInputs = old.buildInputs ++ [ last.ovni ];
# patches = [ ./0001-Emit-a-fill-event-at-shutdown.patch ];
# configureFlags = old.configureFlags ++ [
# "--with-ovni=${last.ovni}"
# ];
#});
nanos6 = prev.nanos6Git.overrideAttrs (old: {
src = ~/bsc/nanos6;
version = "local";
buildInputs = old.buildInputs ++ [ last.ovni ];
patches = [ ./0001-Emit-a-fill-event-at-shutdown.patch ];
configureFlags = old.configureFlags ++ [
"--with-ovni=${last.ovni}"
];
@ -30,7 +39,7 @@ let
clangUnwrapped = prev.clangOmpss2Unwrapped.overrideAttrs (
old:
rec {
src = ../kk/llvm-mono-d3d4f2bf231b9461a5881c5bf56659516d45e670.tar.bz2;
src = ../../ovni-misc/kk2/llvm-mono-d3d4f2bf231b9461a5881c5bf56659516d45e670.tar.bz2;
#src = fetchTarball {
# url = ../kk/llvm-mono-d3d4f2bf231b9461a5881c5bf56659516d45e670.tar.bz2;
#};
@ -89,5 +98,5 @@ let
});
in
bsc.ovni-rt
#bsc.ompss2.clang
#bsc.ovni-rt
bsc.ompss2.clang

16
ovni.c
View File

@ -54,7 +54,7 @@ create_trace_stream(void)
int written = snprintf(path, PATH_MAX, "%s/thread.%d",
rproc.procdir, rthread.tid);
if(written >= PATH_MAX)
if(written >= PATH_MAX)
die("thread trace path too long: %s/thread.%d\n",
rproc.procdir, rthread.tid);
@ -80,7 +80,7 @@ proc_metadata_store(JSON_Value *meta, const char *procdir)
if(meta == NULL)
die("process metadata not initialized\n");
if(snprintf(path, PATH_MAX, "%s/metadata.json", procdir) >= PATH_MAX)
die("metadata path too long: %s/metadata.json\n",
procdir);
@ -111,7 +111,7 @@ ovni_add_cpu(int index, int phyid)
int first_time = 0;
/* Find the CPU array and create it if needed */
/* Find the CPU array and create it if needed */
JSON_Array *cpuarray = json_object_dotget_array(meta, "cpus");
if(cpuarray == NULL)
@ -289,7 +289,7 @@ move_thread_to_final(const char *src, const char *dst)
}
while((bytes = fread(buffer, 1, sizeof(buffer), infile)) > 0)
fwrite(buffer, 1, bytes, outfile);
fwrite(buffer, 1, bytes, outfile);
fclose(outfile);
fclose(infile);
@ -466,11 +466,11 @@ ovni_thread_isready(void)
static inline
uint64_t clock_tsc_now(void)
{
uint32_t lo, hi;
uint32_t lo, hi;
/* RDTSC copies contents of 64-bit TSC into EDX:EAX */
__asm__ volatile("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t) hi << 32 | lo;
/* RDTSC copies contents of 64-bit TSC into EDX:EAX */
__asm__ volatile("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t) hi << 32 | lo;
}
#endif

27
pcf.c
View File

@ -81,12 +81,6 @@ const uint32_t pcf_def_palette[] = {
const uint32_t *pcf_palette = pcf_def_palette;
const int pcf_palette_len = ARRAY_LEN(pcf_def_palette);
/* Only used to generate tables */
struct pcf_value_label {
int value;
char *label;
};
/* ------------------ Value labels --------------------- */
struct pcf_value_label default_values[] = {
@ -181,20 +175,19 @@ struct pcf_value_label kernel_cs_values[] = {
struct pcf_value_label nanos6_ss_values[] = {
{ ST_NULL, "No subsystem" },
{ ST_TOO_MANY_TH, "Unknown: multiple threads running" },
{ ST_NANOS6_TASK_RUNNING, "Task: Running" },
{ ST_NANOS6_SPAWNING, "Task: Spawning function" },
{ ST_NANOS6_CREATING, "Task: Creating" },
{ ST_NANOS6_SUBMIT, "Task: Submitting" },
{ ST_NANOS6_SCHED_HUNGRY, "Scheduler: Waiting for tasks" },
{ ST_NANOS6_TASK_BODY, "Task: Running body" },
{ ST_NANOS6_TASK_CREATING, "Task: Creating" },
{ ST_NANOS6_TASK_SUBMIT, "Task: Submitting" },
{ ST_NANOS6_TASK_SPAWNING, "Task: Spawning function" },
{ ST_NANOS6_SCHED_HUNGRY, "Scheduler: Waiting for ready tasks" },
{ ST_NANOS6_SCHED_SERVING, "Scheduler: Serving tasks" },
{ ST_NANOS6_SCHED_SUBMITTING, "Scheduler: Adding ready tasks" },
{ ST_NANOS6_ATTACHED, "Threading: Attached as external thread" },
{ ST_NANOS6_SCHED_ADDING, "Scheduler: Adding ready tasks" },
{ ST_NANOS6_DEP_REG, "Dependency: Registering" },
{ ST_NANOS6_DEP_UNREG, "Dependency: Unregistering" },
{ ST_NANOS6_TASKWAIT, "Blocking: Taskwait" },
{ ST_NANOS6_BLOCKING, "Blocking: Blocking current task" },
{ ST_NANOS6_UNBLOCKING, "Blocking: Unblocking remote task" },
{ ST_NANOS6_WAITFOR, "Blocking: Wait For" },
{ ST_NANOS6_BLK_TASKWAIT, "Blocking: Taskwait" },
{ ST_NANOS6_BLK_BLOCKING, "Blocking: Blocking current task" },
{ ST_NANOS6_BLK_UNBLOCKING, "Blocking: Unblocking remote task" },
{ ST_NANOS6_BLK_WAITFOR, "Blocking: Wait For" },
{ EV_NANOS6_SCHED_SEND, "EV Scheduler: Send task" },
{ EV_NANOS6_SCHED_RECV, "EV Scheduler: Recv task" },
{ EV_NANOS6_SCHED_SELF, "EV Scheduler: Self-assign task" },

8
pcf.h
View File

@ -50,6 +50,14 @@ struct pcf_file {
struct pcf_type *types;
};
/* Only used to generate tables */
struct pcf_value_label {
int value;
char *label;
};
extern struct pcf_value_label nanos6_ss_values[];
void pcf_open(struct pcf_file *pcf, char *path, int chantype);
void pcf_write(struct pcf_file *pcf);

View File

@ -21,4 +21,4 @@ ovni_test(task-types.c MP)
ovni_test(blocking.c MP)
ovni_test(subsystems.c MP)
ovni_test(ss-mismatch.c SHOULD_FAIL
REGEX "thread [0-9]\\+ ended with 1 extra stacked nanos6 subsystems, top=ST_NANOS6_SCHED_HUNGRY")
REGEX "thread [0-9]\\+ ended with 1 extra stacked nanos6 subsystems, top=\"Scheduler: Waiting for ready tasks\"")

View File

@ -26,16 +26,19 @@ main(void)
int us = 500;
uint32_t typeid = 1;
uint32_t taskid = 1;
instr_nanos6_type_create(typeid);
instr_nanos6_task_create_and_execute(1, typeid);
instr_nanos6_task_create_and_execute(taskid, typeid);
usleep(us);
instr_nanos6_block_enter(1);
instr_nanos6_block_enter();
instr_nanos6_task_pause(taskid);
usleep(us);
instr_nanos6_block_exit(1);
instr_nanos6_task_resume(taskid);
instr_nanos6_block_exit();
usleep(us);
instr_nanos6_task_end(1);
instr_nanos6_task_end(taskid);
instr_end();

View File

@ -45,6 +45,9 @@ instr_nanos6_type_create(int32_t typeid)
INSTR_2ARG(instr_nanos6_task_create, "6Tc", int32_t, id, uint32_t, typeid)
INSTR_0ARG(instr_nanos6_task_create_end, "6TC")
INSTR_1ARG(instr_nanos6_task_execute, "6Tx", int32_t, id)
INSTR_1ARG(instr_nanos6_task_pause, "6Tp", int32_t, id)
INSTR_1ARG(instr_nanos6_task_resume, "6Tr", int32_t, id)
INSTR_1ARG(instr_nanos6_task_end, "6Te", int32_t, id)
static inline void
instr_nanos6_task_create_and_execute(int32_t id, uint32_t typeid)
@ -54,46 +57,14 @@ instr_nanos6_task_create_and_execute(int32_t id, uint32_t typeid)
instr_nanos6_task_execute(id);
}
INSTR_2ARG(instr_nanos6_task_block, "6Tb", int32_t, id, int32_t, reason)
INSTR_2ARG(instr_nanos6_task_unblock, "6Tu", int32_t, id, int32_t, reason)
static inline void
instr_nanos6_block_enter(int32_t id)
{
instr_nanos6_task_block(id, 0);
}
static inline void
instr_nanos6_block_exit(int32_t id)
{
instr_nanos6_task_unblock(id, 0);
}
static inline void
instr_nanos6_task_wait_enter(int32_t id)
{
instr_nanos6_task_block(id, 1);
}
static inline void
instr_nanos6_task_wait_exit(int32_t id)
{
instr_nanos6_task_unblock(id, 1);
}
static inline void
instr_nanos6_waitfor_enter(int32_t id)
{
instr_nanos6_task_block(id, 2);
}
static inline void
instr_nanos6_waitfor_exit(int32_t id)
{
instr_nanos6_task_unblock(id, 2);
}
INSTR_1ARG(instr_nanos6_task_end, "6Te", int32_t, id)
INSTR_0ARG(instr_nanos6_block_enter, "6Bb")
INSTR_0ARG(instr_nanos6_block_exit, "6BB")
INSTR_0ARG(instr_nanos6_unblock_enter, "6Bb")
INSTR_0ARG(instr_nanos6_unblock_exit, "6BB")
INSTR_0ARG(instr_nanos6_taskwait_enter, "6Bw")
INSTR_0ARG(instr_nanos6_taskwait_exit, "6BW")
INSTR_0ARG(instr_nanos6_waitfor_enter, "6Bf")
INSTR_0ARG(instr_nanos6_waitfor_exit, "6BF")
INSTR_0ARG(instr_nanos6_sched_receive_task, "6Sr")
INSTR_0ARG(instr_nanos6_sched_assign_task, "6Ss")

View File

@ -43,16 +43,16 @@ main(void)
instr_nanos6_sched_submit_exit(); usleep(us);
instr_nanos6_enter_submit_task(); usleep(us);
instr_nanos6_exit_submit_task(); usleep(us);
instr_nanos6_block_enter(taskid); usleep(us);
instr_nanos6_block_exit(taskid); usleep(us);
instr_nanos6_waitfor_enter(taskid); usleep(us);
instr_nanos6_waitfor_exit(taskid); usleep(us);
instr_nanos6_block_enter(); usleep(us);
instr_nanos6_block_exit(); usleep(us);
instr_nanos6_waitfor_enter(); usleep(us);
instr_nanos6_waitfor_exit(); usleep(us);
instr_nanos6_register_accesses_enter(); usleep(us);
instr_nanos6_register_accesses_exit(); usleep(us);
instr_nanos6_unregister_accesses_enter(); usleep(us);
instr_nanos6_unregister_accesses_exit(); usleep(us);
instr_nanos6_task_wait_enter(taskid); usleep(us);
instr_nanos6_task_wait_exit(taskid); usleep(us);
instr_nanos6_taskwait_enter(); usleep(us);
instr_nanos6_taskwait_exit(); usleep(us);
instr_nanos6_spawn_function_enter(); usleep(us);
instr_nanos6_spawn_function_exit(); usleep(us);

View File

@ -0,0 +1,3 @@
/* Create a test which unblocks a task from an external thread. This
* should break currently, as the instrumentation attempts to call
* ovni_ev_emit from a thread without initialization. */