From ac1ae8e69d7deefd3e754421bc19f1f3ac37128a Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Date: Thu, 1 Sep 2022 17:02:02 +0200 Subject: [PATCH] Use one event per blocking type in Nanos6 --- cfg/cpu-kernel-context-switch.cfg | 2 +- cfg/thread-kernel-context-switch.cfg | 2 +- doc/emulation/events.md | 14 +- doc/emulation/nanos6.md | 6 +- emu.h | 75 +++--- emu_nanos6.c | 367 +++++++++++++++------------ emu_nosv.c | 236 ++++++++++------- emu_task.c | 146 +++++------ emu_task.h | 21 +- nix/nanos6.nix | 27 +- ovni.c | 16 +- pcf.c | 27 +- pcf.h | 8 + test/emu/nanos6/CMakeLists.txt | 2 +- test/emu/nanos6/blocking.c | 11 +- test/emu/nanos6/instr_nanos6.h | 51 +--- test/emu/nanos6/subsystems.c | 12 +- test/rt/nanos6/external-thread.c | 3 + 18 files changed, 568 insertions(+), 458 deletions(-) create mode 100644 test/rt/nanos6/external-thread.c diff --git a/cfg/cpu-kernel-context-switch.cfg b/cfg/cpu-kernel-context-switch.cfg index ce0f025..e466e04 100644 --- a/cfg/cpu-kernel-context-switch.cfg +++ b/cfg/cpu-kernel-context-switch.cfg @@ -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 diff --git a/cfg/thread-kernel-context-switch.cfg b/cfg/thread-kernel-context-switch.cfg index 6f521c1..ff3f784 100644 --- a/cfg/thread-kernel-context-switch.cfg +++ b/cfg/thread-kernel-context-switch.cfg @@ -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 diff --git a/doc/emulation/events.md b/doc/emulation/events.md index 91cbecf..01a0760 100644 --- a/doc/emulation/events.md +++ b/doc/emulation/events.md @@ -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() ``` diff --git a/doc/emulation/nanos6.md b/doc/emulation/nanos6.md index e6c78cd..8d7c169 100644 --- a/doc/emulation/nanos6.md +++ b/doc/emulation/nanos6.md @@ -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). diff --git a/emu.h b/emu.h index 488e669..1bb6779 100644 --- a/emu.h +++ b/emu.h @@ -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; }; diff --git a/emu_nanos6.c b/emu_nanos6.c index ff97ca3..31931b7 100644 --- a/emu_nanos6.c +++ b/emu_nanos6.c @@ -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; itotal_nthreads; i++) + for(size_t i=0; itotal_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; itotal_ncpus; i++) + for(size_t i=0; itotal_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; itotal_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); } } } diff --git a/emu_nosv.c b/emu_nosv.c index 2c9ae9a..326e273 100644 --- a/emu_nosv.c +++ b/emu_nosv.c @@ -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; itotal_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); } } } diff --git a/emu_task.c b/emu_task.c index 85f00d5..5fd8bf9 100644 --- a/emu_task.c +++ b/emu_task.c @@ -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; diff --git a/emu_task.h b/emu_task.h index 1f8ce7b..f044317 100644 --- a/emu_task.h +++ b/emu_task.h @@ -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 */ diff --git a/nix/nanos6.nix b/nix/nanos6.nix index 9da14cd..c00cfff 100644 --- a/nix/nanos6.nix +++ b/nix/nanos6.nix @@ -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 diff --git a/ovni.c b/ovni.c index f6b262c..2cacf06 100644 --- a/ovni.c +++ b/ovni.c @@ -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 diff --git a/pcf.c b/pcf.c index cfc8658..5ed71da 100644 --- a/pcf.c +++ b/pcf.c @@ -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" }, diff --git a/pcf.h b/pcf.h index df1fde6..945a12d 100644 --- a/pcf.h +++ b/pcf.h @@ -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); diff --git a/test/emu/nanos6/CMakeLists.txt b/test/emu/nanos6/CMakeLists.txt index 9ff6535..e062f67 100644 --- a/test/emu/nanos6/CMakeLists.txt +++ b/test/emu/nanos6/CMakeLists.txt @@ -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\"") diff --git a/test/emu/nanos6/blocking.c b/test/emu/nanos6/blocking.c index d5dd5ba..c893b60 100644 --- a/test/emu/nanos6/blocking.c +++ b/test/emu/nanos6/blocking.c @@ -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(); diff --git a/test/emu/nanos6/instr_nanos6.h b/test/emu/nanos6/instr_nanos6.h index 28f5863..53048d1 100644 --- a/test/emu/nanos6/instr_nanos6.h +++ b/test/emu/nanos6/instr_nanos6.h @@ -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") diff --git a/test/emu/nanos6/subsystems.c b/test/emu/nanos6/subsystems.c index c23bf58..a223626 100644 --- a/test/emu/nanos6/subsystems.c +++ b/test/emu/nanos6/subsystems.c @@ -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); diff --git a/test/rt/nanos6/external-thread.c b/test/rt/nanos6/external-thread.c new file mode 100644 index 0000000..f3256b0 --- /dev/null +++ b/test/rt/nanos6/external-thread.c @@ -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. */