From 7de874e54424ffa2995e4cacc36c29ebc1d621d6 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Mon, 26 Jun 2023 17:15:55 +0800 Subject: [PATCH 01/80] Bring in the FS scheduler from the manual example. --- core/threaded/CMakeLists.txt | 1 + core/threaded/scheduler_FS.c | 614 ++++++++++++++++++ include/core/lf_types.h | 4 + include/core/threaded/scheduler_instance.h | 64 ++ .../core/threaded/scheduler_instructions.h | 38 ++ 5 files changed, 721 insertions(+) create mode 100644 core/threaded/scheduler_FS.c create mode 100644 include/core/threaded/scheduler_instructions.h diff --git a/core/threaded/CMakeLists.txt b/core/threaded/CMakeLists.txt index 7c48d8ded..9468c3dfd 100644 --- a/core/threaded/CMakeLists.txt +++ b/core/threaded/CMakeLists.txt @@ -2,6 +2,7 @@ set( THREADED_SOURCES reactor_threaded.c scheduler_adaptive.c + scheduler_FS.c scheduler_GEDF_NP_CI.c scheduler_GEDF_NP.c scheduler_NP.c diff --git a/core/threaded/scheduler_FS.c b/core/threaded/scheduler_FS.c new file mode 100644 index 000000000..89088a82a --- /dev/null +++ b/core/threaded/scheduler_FS.c @@ -0,0 +1,614 @@ +#if defined(LF_THREADED) +/* Fully-static scheduler for the threaded runtime of the C target of Lingua +Franca. */ + +/************* +Copyright (c) 2022, The University of Texas at Dallas. Copyright (c) 2022, The +University of California at Berkeley. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***************/ + +/** + * A fully static (FS) scheduler for the threaded runtime of the C target of + * Lingua Franca. + * + * @author{Shaokai Lin } + */ +#include "lf_types.h" +#if SCHEDULER == FS || (!defined(SCHEDULER) && defined(LF_THREADED)) +#ifndef NUMBER_OF_WORKERS +#define NUMBER_OF_WORKERS 1 +#endif // NUMBER_OF_WORKERS + +#include + +#include "platform.h" +#include "reactor_common.h" +#include "scheduler_instance.h" +#include "scheduler_sync_tag_advance.h" +#include "scheduler.h" +#include "semaphore.h" +#include "trace.h" +#include "util.h" + +/////////////////// External Variables ///////////////////////// +// Global variable defined in tag.c: +extern instant_t start_time; + +// Global variables defined in schedule.c: +extern const inst_t* static_schedules[]; +extern volatile uint32_t hyperperiod_iterations[]; +extern volatile uint32_t counters[]; +extern const size_t num_counters; + +/////////////////// Scheduler Private API ///////////////////////// +/** + * @brief If there is work to be done, notify workers individually. + * + * This assumes that the caller is not holding any thread mutexes. + */ +void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { + // Note: All threads are idle. Therefore, there is no need to lock the mutex + // while accessing the executing queue (which is pointing to one of the + // reaction queues). + size_t workers_to_awaken = + scheduler->number_of_idle_workers; + //LF_PRINT_DEBUG("Scheduler: Notifying %zu workers.", workers_to_awaken); + scheduler->number_of_idle_workers -= workers_to_awaken; + //LF_PRINT_DEBUG("Scheduler: New number of idle workers: %zu.", + //scheduler->number_of_idle_workers); + if (workers_to_awaken > 1) { + // Notify all the workers except the worker thread that has called this + // function. + lf_semaphore_release(scheduler->semaphore, + (workers_to_awaken - 1)); + } +} + +/** + * @brief Wait until the scheduler assigns work. + * + * If the calling worker thread is the last to become idle, it will call on the + * scheduler to distribute work. Otherwise, it will wait on + * 'scheduler->semaphore'. + * + * @param worker_number The worker number of the worker thread asking for work + * to be assigned to it. + */ +void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_number) { + // Increment the number of idle workers by 1 and + // check if this is the last worker thread to become idle. + if (lf_atomic_add_fetch(&scheduler->number_of_idle_workers, + 1) == + scheduler->number_of_workers) { + // Last thread to go idle + //LF_PRINT_DEBUG("Scheduler: Worker %zu is the last idle thread.", + //worker_number); + // Clear all the counters. + for (int i = 0; i < num_counters; i++) { + counters[i] = 0; + } + // Call on the scheduler to distribute work or advance tag. + _lf_sched_notify_workers(scheduler); + } else { + // Not the last thread to become idle. + // Wait for work to be released. + lf_semaphore_acquire(scheduler->semaphore); + } +} + +/** + * @brief BIT: Branch If Timeout + * Check if timeout is reached. If not, don't do anything. + * If so, jump to a specified location (rs1). + * + * FIXME: Should the timeout value be an operand? + * FIXME: Use a global variable num_active_reactors instead of iterating over + * a for loop. + */ +void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + bool stop = true; + for (int i = 0; i < scheduler->num_reactor_self_instances; i++) { + if (!scheduler->reactor_reached_stop_tag[i]) { + stop = false; + break; + } + } + + //LF_PRINT_DEBUG("Start time is %ld. Current tag is (%ld, %d). Stop tag is (%ld, %d). Stop array: ", start_time, current_tag.time, current_tag.microstep, stop_tag.time, stop_tag.microstep); + for (int i = 0; i < scheduler->num_reactor_self_instances; i++) { + //LF_PRINT_DEBUG("(%ld, %d)", + //scheduler->reactor_self_instances[i]->tag.time, + //scheduler->reactor_self_instances[i]->tag.microstep); + //LF_PRINT_DEBUG("%d", scheduler->reactor_reached_stop_tag[i]); + } + + if (stop) *pc = rs1; // Jump to a specified location. + else *pc += 1; // Increment pc. +} + +/** + * @brief EIT: "Execute-If-Triggered" + * Check if the reaction status is "queued." + * If so, return the reaction pointer and advance pc. + * + * @param rs1 + * @param rs2 + * @param pc + * @param returned_reaction + * @param exit_loop + */ +void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t* reaction = scheduler->reaction_instances[rs1]; + if (reaction->status == queued) { + *returned_reaction = reaction; + *exit_loop = true; + } else + //LF_PRINT_DEBUG("*** Worker %zu skip execution", worker_number); + *pc += 1; // Increment pc. +} + +/** + * @brief EXE: Execute a reaction + * + * @param rs1 + * @param rs2 + * @param pc + * @param returned_reaction + * @param exit_loop + */ +void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t* reaction = scheduler->reaction_instances[rs1]; + *returned_reaction = reaction; + *exit_loop = true; + *pc += 1; // Increment pc. +} + +/** + * @brief DU: Delay Until a physical timepoint (rs1) plus an offset (rs2) is reached. + * + * @param worker_number + * @param rs1 + * @param rs2 + * @param pc + * @param returned_reaction + * @param exit_loop + */ +void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + // FIXME: There seems to be an overflow problem. + // When wakeup_time overflows but lf_time_physical() doesn't, + // _lf_interruptable_sleep_until_locked() terminates immediately. + instant_t wakeup_time = start_time + rs1 * (*iteration + 1); + //LF_PRINT_DEBUG("start_time: %ld, wakeup_time: %ld, rs1: %lld, iteration+1: %d, current_physical_time: %ld\n", start_time, wakeup_time, rs1, (*iteration + 1), lf_time_physical()); + //LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); + _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); + //LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); + *pc += 1; // Increment pc. +} + +/** + * @brief WU: Wait until a counting variable reaches a specified value. + * + * @param rs1 + * @param rs2 + * @param pc + * @param returned_reaction + * @param exit_loop + */ +void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + //LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); + while(scheduler->counters[rs1] < rs2); + //LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); + *pc += 1; // Increment pc. +} + +/** + * @brief ADV: Advance time for a particular reactor. + * + * @param rs1 + * @param rs2 + * @param pc + * @param returned_reaction + * @param exit_loop + */ +void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + + // This mutex is quite expensive. + lf_mutex_lock(&(scheduler->env->mutex)); + + self_base_t* reactor = + scheduler->reactor_self_instances[rs1]; + reactor->tag.time += rs2; + reactor->tag.microstep = 0; + + if (_lf_is_tag_after_stop_tag(scheduler->env, reactor->tag)) { + scheduler->reactor_reached_stop_tag[rs1] = true; + } + + lf_mutex_unlock(&(scheduler->env->mutex)); + + *pc += 1; // Increment pc. +} + +/** + * @brief ADV: Advance time for a particular reactor. + * + * @param rs1 + * @param rs2 + * @param pc + * @param returned_reaction + * @param exit_loop + */ +void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + + self_base_t* reactor = + scheduler->reactor_self_instances[rs1]; + reactor->tag.time += rs2; + reactor->tag.microstep = 0; + + if (_lf_is_tag_after_stop_tag(scheduler->env, reactor->tag)) { + scheduler->reactor_reached_stop_tag[rs1] = true; + } + + *pc += 1; // Increment pc. +} + +/** + * @brief JMP: Jump to a particular line in the schedule. + * + * @param rs1 + * @param rs2 + * @param pc + * @param returned_reaction + * @param exit_loop + */ +void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + if (rs2 != -1) *iteration += 1; + *pc = rs1; +} + +/** + * @brief SAC: (Sync-And-Clear) synchronize all workers until all execute SAC + * and let the last idle worker reset all counters to 0. + * + * @param rs1 + * @param rs2 + * @param pc + * @param returned_reaction + * @param exit_loop + */ +void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + tracepoint_worker_wait_starts(worker_number); + _lf_sched_wait_for_work(scheduler, worker_number); + tracepoint_worker_wait_ends(worker_number); + *pc += 1; // Increment pc. +} + +/** + * @brief INC: INCrement a counter (rs1) by an amount (rs2). + * + * @param rs1 + * @param rs2 + * @param pc + * @param returned_reaction + * @param exit_loop + */ +void execute_inst_INC(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + lf_mutex_lock(&(scheduler->env->mutex)); + scheduler->counters[rs1] += rs2; + lf_mutex_unlock(&(scheduler->env->mutex)); + *pc += 1; // Increment pc. +} + +/** + * @brief INC2: [Lock-free] INCrement a counter (rs1) by an amount (rs2). + * The compiler needs to guarantee a single writer. + * + * @param rs1 + * @param rs2 + * @param pc + * @param returned_reaction + * @param exit_loop + */ +void execute_inst_INC2(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + scheduler->counters[rs1] += rs2; + *pc += 1; // Increment pc. +} + +/** + * @brief STP: SToP the execution. + * + */ +void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + *exit_loop = true; +} + +/** + * @brief Execute an instruction + * + * @param op the opcode + * @param rs1 the first operand + * @param rs2 the second operand + * @param pc a pointer to the program counter + * @param returned_reaction a pointer to a reaction to be executed + * + * FIXME: This feels like a bad design in the abstraction. + * @param exit_loop a pointer to a boolean indicating whether + * the outer while loop should be exited + */ +void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t op, long long int rs1, long long int rs2, + size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile volatile int* iteration) { + char* op_str = NULL; + switch (op) { + case ADV: + op_str = "ADV"; + //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", + //worker_number, *pc, op_str, rs1, rs2); + execute_inst_ADV(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + break; + case ADV2: + op_str = "ADV2"; + //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", + //worker_number, *pc, op_str, rs1, rs2); + execute_inst_ADV2(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + break; + case BIT: + op_str = "BIT"; + //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", + //worker_number, *pc, op_str, rs1, rs2); + execute_inst_BIT(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + break; + case DU: + op_str = "DU"; + //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", + //worker_number, *pc, op_str, rs1, rs2); + execute_inst_DU(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + break; + case EIT: + op_str = "EIT"; + //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", + //worker_number, *pc, op_str, rs1, rs2); + execute_inst_EIT(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + break; + case EXE: + op_str = "EXE"; + //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", + //worker_number, *pc, op_str, rs1, rs2); + execute_inst_EXE(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + break; + case INC: + op_str = "INC"; + //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", + //worker_number, *pc, op_str, rs1, rs2); + execute_inst_INC(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + break; + case INC2: + op_str = "INC2"; + //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", + //worker_number, *pc, op_str, rs1, rs2); + execute_inst_INC2(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + break; + case JMP: + op_str = "JMP"; + //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", + //worker_number, *pc, op_str, rs1, rs2); + execute_inst_JMP(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + break; + case SAC: + op_str = "SAC"; + //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", + //worker_number, *pc, op_str, rs1, rs2); + execute_inst_SAC(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + break; + case STP: + op_str = "STP"; + //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", + //worker_number, *pc, op_str, rs1, rs2); + execute_inst_STP(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + break; + case WU: + op_str = "WU"; + //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", + //worker_number, *pc, op_str, rs1, rs2); + execute_inst_WU(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + break; + default: + lf_print_error_and_exit("Invalid instruction: %d", op); + } +} + +///////////////////// Scheduler Init and Destroy API ///////////////////////// +/** + * @brief Initialize the scheduler. + * + * This has to be called before other functions of the scheduler can be used. + * If the scheduler is already initialized, this will be a no-op. + * + * @param number_of_workers Indicate how many workers this scheduler will be + * managing. + * @param option Pointer to a `sched_params_t` struct containing additional + * scheduler parameters. + */ +void lf_sched_init( + environment_t *env, + size_t number_of_workers, + sched_params_t* params +) { + //LF_PRINT_DEBUG("Scheduler: Initializing with %zu workers", number_of_workers); + + // Scheduler already initialized + if (!init_sched_instance(env, &env->scheduler, number_of_workers, params)) { + // FIXME: This is not the best practice and seems to take advantage of a + // bug in the runtime. + // lf_sched_init() is for some reason called twice. + // Once in lf_reactor_c_main() in reactor_threaded.c. + // Another in initialize() -> _lf_initialize_trigger_objects() + // -> lf_sched_init(), also in reactor_threaded.c. + // This implementation takes advantage of the fact that when + // lf_sched_init() is called the second time, start_time is set + // to a meaningful value. When the first time lf_sched_init() is + // called, start_time has not been set. + + // Initialize the local tags for the FS scheduler. + for (int i = 0; i < env->scheduler->num_reactor_self_instances; i++) { + env->scheduler->reactor_self_instances[i]->tag.time = start_time; + env->scheduler->reactor_self_instances[i]->tag.microstep = 0; + //LF_PRINT_DEBUG("(%ld, %d)", + //env->scheduler->reactor_self_instances[i]->tag.time, + //env->scheduler->reactor_self_instances[i]->tag.microstep); + } + + // Already initialized + return; + } + + env->scheduler->pc = calloc(number_of_workers, sizeof(size_t)); + env->scheduler->static_schedules = &static_schedules[0]; + env->scheduler->reaction_instances = params->reaction_instances; + env->scheduler->reactor_self_instances = params->reactor_self_instances; + env->scheduler->num_reactor_self_instances = params->num_reactor_self_instances; + env->scheduler->reactor_reached_stop_tag = params->reactor_reached_stop_tag; + env->scheduler->counters = counters; +} + +/** + * @brief Free the memory used by the scheduler. + * + * This must be called when the scheduler is no longer needed. + */ +void lf_sched_free(lf_scheduler_t* scheduler) { + //LF_PRINT_DEBUG("Freeing the pointers in the scheduler struct."); + free(scheduler->pc); + free(scheduler->reactor_self_instances); + free(scheduler->reaction_instances); +} + +///////////////////// Scheduler Worker API (public) ///////////////////////// +/** + * @brief Ask the scheduler for one more reaction. + * + * This function blocks until it can return a ready reaction for worker thread + * 'worker_number' or it is time for the worker thread to stop and exit (where a + * NULL value would be returned). + * + * @param worker_number + * @return reaction_t* A reaction for the worker to execute. NULL if the calling + * worker thread should exit. + */ +reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_number) { + //LF_PRINT_DEBUG("Worker %d inside lf_sched_get_ready_reaction", worker_number); + + const inst_t* current_schedule = scheduler->static_schedules[worker_number]; + reaction_t* returned_reaction = NULL; + bool exit_loop = false; + size_t* pc = &scheduler->pc[worker_number]; + opcode_t op; + long long int rs1; + long long int rs2; + volatile uint32_t* iteration = &hyperperiod_iterations[worker_number]; + + while (!exit_loop) { + op = current_schedule[*pc].op; + rs1 = current_schedule[*pc].rs1; + rs2 = current_schedule[*pc].rs2; + + // Execute the current instruction + execute_inst(scheduler, worker_number, op, rs1, rs2, pc, + &returned_reaction, &exit_loop, iteration); + + //LF_PRINT_DEBUG("Worker %d: returned_reaction = %p, exit_loop = %d", + //worker_number, returned_reaction, exit_loop); + } + + //LF_PRINT_DEBUG("Worker %d leaves lf_sched_get_ready_reaction", worker_number); + return returned_reaction; +} + +/** + * @brief Inform the scheduler that worker thread 'worker_number' is done + * executing the 'done_reaction'. + * + * @param worker_number The worker number for the worker thread that has + * finished executing 'done_reaction'. + * @param done_reaction The reaction that is done. + */ +void lf_sched_done_with_reaction(size_t worker_number, + reaction_t* done_reaction) { + //LF_PRINT_DEBUG("*** Worker %zu inside lf_sched_done_with_reaction, done with %s", worker_number, done_reaction->name); + // If the reaction status is queued, change it back to inactive. + // We do not check for error here because the EXE instruction + // can execute a reaction with an "inactive" status. + // The reason is that since runtime does not advance + // global time, the next timer events will not be + // scheduled and put onto the event queue. The next + // timer events are encoded directly into the schedule + // using the EXE instructions. + lf_bool_compare_and_swap(&done_reaction->status, queued, inactive); + + //LF_PRINT_DEBUG("*** Worker %zu reports updated status for %s: %u", worker_number, done_reaction->name, done_reaction->status); +} + +/** + * @brief Inform the scheduler that worker thread 'worker_number' would like to + * trigger 'reaction' at the current tag. + * + * If a worker number is not available (e.g., this function is not called by a + * worker thread), -1 should be passed as the 'worker_number'. + * + * This scheduler ignores the worker number. + * + * The scheduler will ensure that the same reaction is not triggered twice in + * the same tag. + * + * @param reaction The reaction to trigger at the current tag. + * @param worker_number The ID of the worker that is making this call. 0 should + * be used if there is only one worker (e.g., when the program is using the + * unthreaded C runtime). -1 is used for an anonymous call in a context where a + * worker number does not make sense (e.g., the caller is not a worker thread). + * + */ +void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { + //LF_PRINT_DEBUG("*** Inside lf_sched_trigger_reaction"); + //LF_PRINT_DEBUG("*** Worker %d triggering reaction %s", worker_number, reaction->name); + // Mark a reaction as queued, so that it will be executed when workers do work. + if (!lf_bool_compare_and_swap(&reaction->status, inactive, queued)) { + // FIXME: Uncommenting the code below yields weird exception. + // lf_print_error_and_exit("Worker %d reports unexpected reaction status for reaction %s: %d. Expected %d.", + // worker_number, reaction->name, + // reaction->status, inactive); + } +} +#endif +#endif diff --git a/include/core/lf_types.h b/include/core/lf_types.h index ddaa70d1c..2f7d4f541 100644 --- a/include/core/lf_types.h +++ b/include/core/lf_types.h @@ -379,6 +379,10 @@ typedef struct self_base_t { #ifdef MODAL_REACTORS reactor_mode_state_t _lf__mode_state; // The current mode (for modal models). #endif +// FIXME: use a LOCAL_TIME macro instead. +#if SCHEDULER == FS + tag_t tag; // The current tag of the reactor instance. +#endif } self_base_t; /** diff --git a/include/core/threaded/scheduler_instance.h b/include/core/threaded/scheduler_instance.h index 5ecb356b1..8ddaa846f 100644 --- a/include/core/threaded/scheduler_instance.h +++ b/include/core/threaded/scheduler_instance.h @@ -45,6 +45,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "semaphore.h" #include +#if SCHEDULER == FS +#include "lf_types.h" +#include "scheduler_instructions.h" +#endif + #define DEFAULT_MAX_REACTION_LEVEL 100 // Forward declarations @@ -58,7 +63,12 @@ typedef struct custom_scheduler_data_t custom_scheduler_data_t; * These should be expanded to accommodate new schedulers. */ typedef struct lf_scheduler_t { + /** + * @brief Environment which the scheduler has access to. + * + */ struct environment_t * env; + /** * @brief Maximum number of levels for reactions in the program. * @@ -135,6 +145,54 @@ typedef struct lf_scheduler_t { // The type is forward declared here and must be declared again in the scheduler source file // Is not touched by `init_sched_instance` and must be initialized by each scheduler that needs it custom_scheduler_data_t * custom_data; + +#if SCHEDULER == FS + + /** + * @brief Points to an array of program counters for each worker. + * + */ + size_t* pc; + + /** + * @brief Points to a read-only array of static schedules. + * + */ + const inst_t** static_schedules; + + /** + * @brief Points to an array of pointers to reactor self instances. + * + */ + self_base_t** reactor_self_instances; + + /** + * @brief The total number of reactor self instances. + * + */ + size_t num_reactor_self_instances; + + /** + * @brief Points to an array of bools indicating whether + * a reactor reaches stop. + * + */ + bool* reactor_reached_stop_tag; + + /** + * @brief Points to an array of pointers to reaction instances. + * + */ + reaction_t** reaction_instances; + + /** + * @brief Points to an array of integer counters. + * + */ + volatile uint32_t* counters; + +#endif + } lf_scheduler_t; /** @@ -155,6 +213,12 @@ typedef struct lf_scheduler_t { typedef struct { size_t* num_reactions_per_level; size_t num_reactions_per_level_size; +#if SCHEDULER == FS + struct self_base_t** reactor_self_instances; + size_t num_reactor_self_instances; + bool* reactor_reached_stop_tag; + reaction_t** reaction_instances; +#endif } sched_params_t; /** diff --git a/include/core/threaded/scheduler_instructions.h b/include/core/threaded/scheduler_instructions.h new file mode 100644 index 000000000..4ea8772bb --- /dev/null +++ b/include/core/threaded/scheduler_instructions.h @@ -0,0 +1,38 @@ +/** + * @author Shaokai Lin + * @brief Format of the instruction set + * + * VM Instruction Set + * - ADV rs1, rs2 : ADVance the logical time of a reactor (rs1) by a specified amount (rs2). Add a delay_until here. + * - ADV2 rs1, rs2 : Lock-free version of ADV. The compiler needs to guarantee only a single thread can update a reactor's tag. + * - BIT rs1, : (Branch-If-Timeout) Branch to a location (rs1) if all reactors reach timeout. + * - DU rs1, rs2 : Delay Until a physical timepoint (rs1) plus an offset (rs2) is reached. + * - EIT rs1 : Execute a reaction (rs1) If Triggered. FIXME: Combine with a branch. + * - EXE rs1 : EXEcute a reaction (rs1) (used for known triggers such as startup, shutdown, and timers). + * - INC rs1, rs2 : INCrement a counter (rs1) by an amount (rs2). + * - INC2 rs1, rs2 : Lock-free version of INC. The compiler needs to guarantee single writer. + * - JMP rs1 : JuMP to a location (rs1). + * - SAC : (Sync-And-Clear) synchronize all workers until all execute SAC and let the last idle worker reset all counters to 0. + * - STP : SToP the execution. + * - WU rs1, rs2 : Wait Until a counting variable (rs1) to reach a desired value (rs2). + */ +typedef enum { + ADV, + ADV2, + BIT, + DU, + EIT, + EXE, + INC, + INC2, + JMP, + SAC, + STP, + WU, +} opcode_t; + +typedef struct inst_t { + opcode_t op; + long long int rs1; + long long int rs2; +} inst_t; \ No newline at end of file From 0a76f87753c6302d8a11bf0357b139c461d312ea Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Wed, 28 Jun 2023 17:30:18 +0800 Subject: [PATCH 02/80] Implement DU using a hyperperiod-based semantics. --- core/threaded/scheduler_FS.c | 33 ++++++++++--------- .../core/threaded/scheduler_instructions.h | 2 +- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/core/threaded/scheduler_FS.c b/core/threaded/scheduler_FS.c index 89088a82a..bc5c6a876 100644 --- a/core/threaded/scheduler_FS.c +++ b/core/threaded/scheduler_FS.c @@ -57,6 +57,7 @@ extern instant_t start_time; // Global variables defined in schedule.c: extern const inst_t* static_schedules[]; +extern const long long int hyperperiod; extern volatile uint32_t hyperperiod_iterations[]; extern volatile uint32_t counters[]; extern const size_t num_counters; @@ -127,7 +128,7 @@ void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_number) { * a for loop. */ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { bool stop = true; for (int i = 0; i < scheduler->num_reactor_self_instances; i++) { if (!scheduler->reactor_reached_stop_tag[i]) { @@ -160,7 +161,7 @@ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, long long * @param exit_loop */ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { reaction_t* reaction = scheduler->reaction_instances[rs1]; if (reaction->status == queued) { *returned_reaction = reaction; @@ -180,7 +181,7 @@ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, long long * @param exit_loop */ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { reaction_t* reaction = scheduler->reaction_instances[rs1]; *returned_reaction = reaction; *exit_loop = true; @@ -188,7 +189,7 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, long long } /** - * @brief DU: Delay Until a physical timepoint (rs1) plus an offset (rs2) is reached. + * @brief DU: Delay Until a physical time offset (rs1) wrt the current hyperperiod is reached. * * @param worker_number * @param rs1 @@ -198,12 +199,12 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, long long * @param exit_loop */ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { // FIXME: There seems to be an overflow problem. // When wakeup_time overflows but lf_time_physical() doesn't, // _lf_interruptable_sleep_until_locked() terminates immediately. - instant_t wakeup_time = start_time + rs1 * (*iteration + 1); - //LF_PRINT_DEBUG("start_time: %ld, wakeup_time: %ld, rs1: %lld, iteration+1: %d, current_physical_time: %ld\n", start_time, wakeup_time, rs1, (*iteration + 1), lf_time_physical()); + instant_t wakeup_time = start_time + hyperperiod * (*iteration) + rs1; + LF_PRINT_DEBUG("start_time: %lld, wakeup_time: %lld, rs1: %lld, iteration: %d, current_physical_time: %lld, hyperperiod: %lld\n", start_time, wakeup_time, rs1, (*iteration), lf_time_physical(), hyperperiod); //LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); //LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); @@ -220,7 +221,7 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, long long * @param exit_loop */ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { //LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); while(scheduler->counters[rs1] < rs2); //LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); @@ -237,7 +238,7 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, long long * @param exit_loop */ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { // This mutex is quite expensive. lf_mutex_lock(&(scheduler->env->mutex)); @@ -266,7 +267,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, long long * @param exit_loop */ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { self_base_t* reactor = scheduler->reactor_self_instances[rs1]; @@ -290,7 +291,7 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, long lon * @param exit_loop */ void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { if (rs2 != -1) *iteration += 1; *pc = rs1; } @@ -306,7 +307,7 @@ void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, long long * @param exit_loop */ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { tracepoint_worker_wait_starts(worker_number); _lf_sched_wait_for_work(scheduler, worker_number); tracepoint_worker_wait_ends(worker_number); @@ -323,7 +324,7 @@ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, long long * @param exit_loop */ void execute_inst_INC(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { lf_mutex_lock(&(scheduler->env->mutex)); scheduler->counters[rs1] += rs2; lf_mutex_unlock(&(scheduler->env->mutex)); @@ -341,7 +342,7 @@ void execute_inst_INC(lf_scheduler_t* scheduler, size_t worker_number, long long * @param exit_loop */ void execute_inst_INC2(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { scheduler->counters[rs1] += rs2; *pc += 1; // Increment pc. } @@ -351,7 +352,7 @@ void execute_inst_INC2(lf_scheduler_t* scheduler, size_t worker_number, long lon * */ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile int* iteration) { + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { *exit_loop = true; } @@ -369,7 +370,7 @@ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, long long * the outer while loop should be exited */ void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t op, long long int rs1, long long int rs2, - size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile volatile int* iteration) { + size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { char* op_str = NULL; switch (op) { case ADV: diff --git a/include/core/threaded/scheduler_instructions.h b/include/core/threaded/scheduler_instructions.h index 4ea8772bb..e5ed58fac 100644 --- a/include/core/threaded/scheduler_instructions.h +++ b/include/core/threaded/scheduler_instructions.h @@ -6,7 +6,7 @@ * - ADV rs1, rs2 : ADVance the logical time of a reactor (rs1) by a specified amount (rs2). Add a delay_until here. * - ADV2 rs1, rs2 : Lock-free version of ADV. The compiler needs to guarantee only a single thread can update a reactor's tag. * - BIT rs1, : (Branch-If-Timeout) Branch to a location (rs1) if all reactors reach timeout. - * - DU rs1, rs2 : Delay Until a physical timepoint (rs1) plus an offset (rs2) is reached. + * - DU rs1, rs2 : Delay Until a physical time offset (rs1) wrt the current hyperperiod is reached. * - EIT rs1 : Execute a reaction (rs1) If Triggered. FIXME: Combine with a branch. * - EXE rs1 : EXEcute a reaction (rs1) (used for known triggers such as startup, shutdown, and timers). * - INC rs1, rs2 : INCrement a counter (rs1) by an amount (rs2). From 2015f097c841ec8d3e88ecb7e3b663e420680fde Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 30 Jun 2023 20:19:45 +0200 Subject: [PATCH 03/80] Support reactor-local time --- include/api/set.h | 24 ++++++++++++++++++++---- include/core/lf_types.h | 16 ++++++++++++---- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/include/api/set.h b/include/api/set.h index d0615eaae..86752830b 100644 --- a/include/api/set.h +++ b/include/api/set.h @@ -215,13 +215,29 @@ do { \ // For simplicity and backward compatability, dont require the environment-pointer when calling the timing API. // Since this is always done from the context of a reaction `self` is in scope and is a pointer to the self-struct // of the current reactor. + +// The fully static (FS) runtime, uses time local to each reactor. If this is the case +// then we defined these macros to acces that timestamp rather than using the standard API +// FIXME (erj): I am not really stoked about this added complexity +#if defined REACTOR_LOCAL_TIME +#define lf_tag() self->base.tag +#define get_current_tag() self->base.tag +#define lf_time_logical() self->base.tag.time +#define lf_time_logical_elapsed() (self->base.tag.time - lf_time_start()) +#define get_logical_elapsed() (self->base.tag.time - lf_time_start()) +#define get_logical_time() self->base.tag +#define get_microstep() self->base.tag.microstep + +#else #define lf_tag() lf_tag(self->base.environment) #define get_current_tag() get_current_tag(self->base.environment) -#define get_microstep() get_microstep(self->base.environment) - -#define lf_request_stop() _lf_request_stop(self->base.environment) - #define lf_time_logical() lf_time_logical(self->base.environment) #define lf_time_logical_elapsed() lf_time_logical_elapsed(self->base.environment) #define get_elapsed_logical_time() get_elapsed_logical_time(self->base.environment) #define get_logical_time() get_logical_time(self->base.environment) +#define get_microstep() get_microstep(self->base.environment) +#endif + +// FIXME: How should this be implemented for the FS scheduler? +#define lf_request_stop() _lf_request_stop(self->base.environment) + diff --git a/include/core/lf_types.h b/include/core/lf_types.h index 553c2c6fd..38fc6a0d9 100644 --- a/include/core/lf_types.h +++ b/include/core/lf_types.h @@ -73,6 +73,14 @@ typedef unsigned short int ushort; #define LET 4 #define NP 5 #define PEDF_NP 6 +#define FS 7 + +// If we use the fully static scheduler, then we want local time at each reactor +#if SCHEDULER == FS + #ifndef REACTOR_LOCAL_TIME + #define REACTOR_LOCAL_TIME + #endif +#endif /* * A struct representing a barrier in threaded @@ -305,15 +313,15 @@ typedef struct self_base_t { struct allocation_record_t *allocations; struct reaction_t *executing_reaction; // The currently executing reaction of the reactor. environment_t * environment; -#ifdef LF_THREADED +#if defined LF_THREADED void* reactor_mutex; // If not null, this is expected to point to an lf_mutex_t. // It is not declared as such to avoid a dependence on platform.h. #endif -#ifdef MODAL_REACTORS +#if defined MODAL_REACTORS reactor_mode_state_t _lf__mode_state; // The current mode (for modal models). #endif -// FIXME: use a LOCAL_TIME macro instead. -#if SCHEDULER == FS +// This is used by e.g. the fully static scheduler (FS) +#if defined REACTOR_LOCAL_TIME tag_t tag; // The current tag of the reactor instance. #endif } self_base_t; From 05622fdc2f6b7120c47263be15c7af6ab6f9fff7 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 30 Jun 2023 20:20:01 +0200 Subject: [PATCH 04/80] Hide chain optimization for the FS scheduler --- core/reactor_common.c | 6 ++++++ include/core/reactor_common.h | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/core/reactor_common.c b/core/reactor_common.c index c43ec6392..5227bd454 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1391,6 +1391,8 @@ void schedule_output_reactions(environment_t *env, reaction_t* reaction, int wor downstream_reaction->is_STP_violated, downstream_reaction->name); } #endif +// FIXME (erj): This is super hacky and only a temporary fix. +#if defined REACTION_CHAIN_OPTIMIZATION if (downstream_reaction != NULL && downstream_reaction != downstream_to_execute_now) { num_downstream_reactions++; // If there is exactly one downstream reaction that is enabled by this @@ -1419,6 +1421,10 @@ void schedule_output_reactions(environment_t *env, reaction_t* reaction, int wor _lf_trigger_reaction(env, downstream_reaction, worker); } } +#else + // Queue the reaction. + _lf_trigger_reaction(env, downstream_reaction, worker); +#endif } } } diff --git a/include/core/reactor_common.h b/include/core/reactor_common.h index 551cb5b7c..4b1034d36 100644 --- a/include/core/reactor_common.h +++ b/include/core/reactor_common.h @@ -10,6 +10,11 @@ #include "modes.h" #include "port.h" +// FIXME (erj): Super hack to disable chain optimzation when we are using the FS runtime. +#if SCHEDULER == FS +#else +#define REACTION_CHAIN_OPTIMIZATION +#endif // ******** Global Variables :( ******** // extern unsigned int _lf_number_of_workers; From 4616369c3999218e5ec5648f84069734fec89fda Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 3 Jul 2023 18:51:28 +0200 Subject: [PATCH 05/80] Add the infrastructure for resetting is_present of ports on a per-reactor basis --- core/threaded/scheduler_FS.c | 16 ++++++++++++++++ include/core/lf_types.h | 5 ++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/core/threaded/scheduler_FS.c b/core/threaded/scheduler_FS.c index bc5c6a876..e4a002e5f 100644 --- a/core/threaded/scheduler_FS.c +++ b/core/threaded/scheduler_FS.c @@ -248,6 +248,14 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, long long reactor->tag.time += rs2; reactor->tag.microstep = 0; + // Reset all "is_present" fields of the output ports of the reactor + // Doing this here has the major implicatio that ADV has to execute AFTER + // all downstream reactions have finished. Since it is modifying state that is + // visible to thos reactions. + for (int i = 0; inum_output_ports; i++) { + reactor->output_ports[i]->is_present = false; + } + if (_lf_is_tag_after_stop_tag(scheduler->env, reactor->tag)) { scheduler->reactor_reached_stop_tag[rs1] = true; } @@ -273,6 +281,14 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, long lon scheduler->reactor_self_instances[rs1]; reactor->tag.time += rs2; reactor->tag.microstep = 0; + + // Reset all "is_present" fields of the output ports of the reactor + // Doing this here has the major implicatio that ADV has to execute AFTER + // all downstream reactions have finished. Since it is modifying state that is + // visible to thos reactions. + for (int i = 0; inum_output_ports; i++) { + reactor->output_ports[i]->is_present = false; + } if (_lf_is_tag_after_stop_tag(scheduler->env, reactor->tag)) { scheduler->reactor_reached_stop_tag[rs1] = true; diff --git a/include/core/lf_types.h b/include/core/lf_types.h index 38fc6a0d9..cd85ea37c 100644 --- a/include/core/lf_types.h +++ b/include/core/lf_types.h @@ -321,8 +321,11 @@ typedef struct self_base_t { reactor_mode_state_t _lf__mode_state; // The current mode (for modal models). #endif // This is used by e.g. the fully static scheduler (FS) -#if defined REACTOR_LOCAL_TIME +#if defined REACTOR_LOCAL_TIME // FIXME: The output_ports pointers isnt obviously related to local time tag_t tag; // The current tag of the reactor instance. + lf_port_base_t **output_ports; // An array of pointers to output ports of this reactor. + // Used to reset the is_present fields + int num_output_ports; #endif } self_base_t; From bfe021d2332252a096b375e30d8c59020808adbe Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Mon, 10 Jul 2023 16:03:07 +0200 Subject: [PATCH 06/80] Comment out lf_request_stop() macro --- include/api/set.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/api/set.h b/include/api/set.h index d340adaa5..bcda87fce 100644 --- a/include/api/set.h +++ b/include/api/set.h @@ -239,5 +239,5 @@ do { \ #endif // FIXME: How should this be implemented for the FS scheduler? -#define lf_request_stop() _lf_request_stop(self->base.environment) +// #define lf_request_stop() _lf_request_stop(self->base.environment) From 3e4bd005cfb966b536249112f0a26b3d8b0a568a Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Mon, 10 Jul 2023 17:35:24 +0200 Subject: [PATCH 07/80] Change ADV to advance to absolute time wrt hyperperiod; change sync-and-clear to sync-advance-clear to advance time at the end of the hyperperiod --- core/threaded/scheduler_FS.c | 51 ++++++++++++++----- .../core/threaded/scheduler_instructions.h | 2 +- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/core/threaded/scheduler_FS.c b/core/threaded/scheduler_FS.c index e4a002e5f..c9463764d 100644 --- a/core/threaded/scheduler_FS.c +++ b/core/threaded/scheduler_FS.c @@ -92,25 +92,42 @@ void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { * If the calling worker thread is the last to become idle, it will call on the * scheduler to distribute work. Otherwise, it will wait on * 'scheduler->semaphore'. + * This implementation of _lf_sched_wait_for_work also takes on the role of + * advancing time for all reactors at the end of the hyperperiod. * * @param worker_number The worker number of the worker thread asking for work * to be assigned to it. + * @param next_timestamp The next timestamp all reactors advance to. */ -void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_number) { +void _lf_sched_wait_for_work( + lf_scheduler_t* scheduler, + size_t worker_number, + instant_t next_timestamp +) { // Increment the number of idle workers by 1 and // check if this is the last worker thread to become idle. if (lf_atomic_add_fetch(&scheduler->number_of_idle_workers, 1) == scheduler->number_of_workers) { + // Last thread to go idle //LF_PRINT_DEBUG("Scheduler: Worker %zu is the last idle thread.", //worker_number); - // Clear all the counters. + + // The last worker advances all reactors to the next tag. + for (int j = 0; j < scheduler->num_reactor_self_instances; j++) { + scheduler->reactor_self_instances[j]->tag.time = next_timestamp; + scheduler->reactor_self_instances[j]->tag.microstep = 0; + } + + // The last worker clears all the counters. for (int i = 0; i < num_counters; i++) { counters[i] = 0; } - // Call on the scheduler to distribute work or advance tag. + + // The last worker calls on the scheduler to distribute work or advance tag. _lf_sched_notify_workers(scheduler); + } else { // Not the last thread to become idle. // Wait for work to be released. @@ -137,13 +154,15 @@ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, long long } } - //LF_PRINT_DEBUG("Start time is %ld. Current tag is (%ld, %d). Stop tag is (%ld, %d). Stop array: ", start_time, current_tag.time, current_tag.microstep, stop_tag.time, stop_tag.microstep); + /* + LF_PRINT_DEBUG("Start time is %ld. Current tag is (%ld, %d). Stop tag is (%ld, %d). Stop array: ", start_time, current_tag.time, current_tag.microstep, stop_tag.time, stop_tag.microstep); for (int i = 0; i < scheduler->num_reactor_self_instances; i++) { - //LF_PRINT_DEBUG("(%ld, %d)", - //scheduler->reactor_self_instances[i]->tag.time, - //scheduler->reactor_self_instances[i]->tag.microstep); - //LF_PRINT_DEBUG("%d", scheduler->reactor_reached_stop_tag[i]); + LF_PRINT_DEBUG("(%ld, %d)", + scheduler->reactor_self_instances[i]->tag.time, + scheduler->reactor_self_instances[i]->tag.microstep); + LF_PRINT_DEBUG("%d", scheduler->reactor_reached_stop_tag[i]); } + */ if (stop) *pc = rs1; // Jump to a specified location. else *pc += 1; // Increment pc. @@ -229,7 +248,7 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, long long } /** - * @brief ADV: Advance time for a particular reactor. + * @brief ADV: Advance time for a reactor up to a tag (relative to the current hyperperiod). * * @param rs1 * @param rs2 @@ -245,7 +264,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, long long self_base_t* reactor = scheduler->reactor_self_instances[rs1]; - reactor->tag.time += rs2; + reactor->tag.time = hyperperiod * (*iteration) + rs2; reactor->tag.microstep = 0; // Reset all "is_present" fields of the output ports of the reactor @@ -266,7 +285,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, long long } /** - * @brief ADV: Advance time for a particular reactor. + * @brief ADV: Advance time for a reactor up to a tag (relative to the current hyperperiod). * * @param rs1 * @param rs2 @@ -279,7 +298,7 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, long lon self_base_t* reactor = scheduler->reactor_self_instances[rs1]; - reactor->tag.time += rs2; + reactor->tag.time = hyperperiod * (*iteration) + rs2; reactor->tag.microstep = 0; // Reset all "is_present" fields of the output ports of the reactor @@ -313,7 +332,7 @@ void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, long long } /** - * @brief SAC: (Sync-And-Clear) synchronize all workers until all execute SAC + * @brief SAC: (Sync-Advance-Clear) synchronize all workers until all execute SAC * and let the last idle worker reset all counters to 0. * * @param rs1 @@ -324,8 +343,12 @@ void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + + // Compute the next tag for all reactors. + instant_t next_timestamp = hyperperiod * (*iteration) + rs1; + tracepoint_worker_wait_starts(worker_number); - _lf_sched_wait_for_work(scheduler, worker_number); + _lf_sched_wait_for_work(scheduler, worker_number, next_timestamp); tracepoint_worker_wait_ends(worker_number); *pc += 1; // Increment pc. } diff --git a/include/core/threaded/scheduler_instructions.h b/include/core/threaded/scheduler_instructions.h index e5ed58fac..e9deb431d 100644 --- a/include/core/threaded/scheduler_instructions.h +++ b/include/core/threaded/scheduler_instructions.h @@ -12,7 +12,7 @@ * - INC rs1, rs2 : INCrement a counter (rs1) by an amount (rs2). * - INC2 rs1, rs2 : Lock-free version of INC. The compiler needs to guarantee single writer. * - JMP rs1 : JuMP to a location (rs1). - * - SAC : (Sync-And-Clear) synchronize all workers until all execute SAC and let the last idle worker reset all counters to 0. + * - SAC : (Sync-Advance-Clear) synchronize all workers until all execute SAC and let the last idle worker reset all counters to 0. * - STP : SToP the execution. * - WU rs1, rs2 : Wait Until a counting variable (rs1) to reach a desired value (rs2). */ From edcae4fb1434194d23a709554d9947ff2bddb37b Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Tue, 18 Jul 2023 13:58:53 +0200 Subject: [PATCH 08/80] Support lf_schedule --- core/reactor_common.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/reactor_common.c b/core/reactor_common.c index 43ccb14d7..4f40d019d 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -875,6 +875,7 @@ int _lf_schedule_at_tag(environment_t* env, trigger_t* trigger, tag_t tag, lf_to * @param token The token wrapping the payload or NULL for no payload. * @return A handle to the event, or 0 if no new event was scheduled, or -1 for error. */ +#if SCHEDULER != FS trigger_handle_t _lf_schedule(environment_t *env, trigger_t* trigger, interval_t extra_delay, lf_token_t* token) { assert(env != GLOBAL_ENVIRONMENT); if (_lf_is_tag_after_stop_tag(env, env->current_tag)) { @@ -1117,6 +1118,16 @@ trigger_handle_t _lf_schedule(environment_t *env, trigger_t* trigger, interval_t } return return_value; } +#else +trigger_handle_t _lf_schedule(environment_t *env, trigger_t* trigger, interval_t extra_delay, lf_token_t* token) { + // Put the corresponding reactions onto the reaction queue. + for (int i = 0; i < trigger->number_of_reactions; i++) { + reaction_t *reaction = trigger->reactions[i]; + reaction->status = queued; + } + return 0; +} +#endif /** * Insert reactions triggered by trigger to the reaction queue... From a6e08b31a6d88c206ab9dea0f97e716b272cbca8 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Tue, 18 Jul 2023 15:18:32 +0200 Subject: [PATCH 09/80] Support lf_schedule with payloads, given limitations --- core/reactor_common.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/core/reactor_common.c b/core/reactor_common.c index 4f40d019d..13b4bd6a3 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -842,6 +842,7 @@ int _lf_schedule_at_tag(environment_t* env, trigger_t* trigger, tag_t tag, lf_to return 1; } +#if SCHEDULER != FS /** * Schedule the specified trigger at env->current_tag.time plus the offset of the * specified trigger plus the delay. See schedule_token() in reactor.h for details. @@ -875,7 +876,6 @@ int _lf_schedule_at_tag(environment_t* env, trigger_t* trigger, tag_t tag, lf_to * @param token The token wrapping the payload or NULL for no payload. * @return A handle to the event, or 0 if no new event was scheduled, or -1 for error. */ -#if SCHEDULER != FS trigger_handle_t _lf_schedule(environment_t *env, trigger_t* trigger, interval_t extra_delay, lf_token_t* token) { assert(env != GLOBAL_ENVIRONMENT); if (_lf_is_tag_after_stop_tag(env, env->current_tag)) { @@ -1119,9 +1119,34 @@ trigger_handle_t _lf_schedule(environment_t *env, trigger_t* trigger, interval_t return return_value; } #else +/** + * @brief Implementation of _lf_schedule for the static scheduler. + * FIXME: This implementation cannot handle the scenario when a reaction invocation + * is scheduled at time t but the same reaction is invoked at an earlier t' < t. + * In this case, the token for t is erased by the earlier invocation at t'. + * To solve this issue, we need a multi-slot buffer storing multiple tokens, or + * design instructions for declaring trigger variables in the Embedded VM program. + * Currently, it is the compiler's responsibility to make the above scenario happen. + * + * @param env Environment in which we are executing. + * @param trigger The trigger to be invoked at a later logical time. + * @param extra_delay The logical time delay, which gets added to the + * trigger's minimum delay, if it has one. If this number is negative, + * then zero is used instead. + * @param token The token wrapping the payload or NULL for no payload. + * @return A handle to the event. Currently, always return 0. + */ trigger_handle_t _lf_schedule(environment_t *env, trigger_t* trigger, interval_t extra_delay, lf_token_t* token) { - // Put the corresponding reactions onto the reaction queue. + // Copy the token pointer into the trigger struct so that the + // reactions can access it. + _lf_replace_template_token((token_template_t*)trigger, token); + + // Decrement the reference count because the event queue no longer needs this token. + _lf_done_using(token); + + // Iterate over all triggered reactions. for (int i = 0; i < trigger->number_of_reactions; i++) { + // Mark reactions to be triggered by the scheduled action as queued. reaction_t *reaction = trigger->reactions[i]; reaction->status = queued; } From 42cad3573e33dbf9cd4e5a52df0ffb334ac70174 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Tue, 18 Jul 2023 15:27:51 +0200 Subject: [PATCH 10/80] Rename FS to STATIC --- core/reactor_common.c | 2 +- core/threaded/CMakeLists.txt | 2 +- core/threaded/{scheduler_FS.c => scheduler_static.c} | 7 +++---- include/api/set.h | 4 ++-- include/core/lf_types.h | 6 +++--- include/core/reactor_common.h | 4 ++-- include/core/threaded/scheduler_instance.h | 6 +++--- 7 files changed, 15 insertions(+), 16 deletions(-) rename core/threaded/{scheduler_FS.c => scheduler_static.c} (99%) diff --git a/core/reactor_common.c b/core/reactor_common.c index 13b4bd6a3..091c6d541 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -842,7 +842,7 @@ int _lf_schedule_at_tag(environment_t* env, trigger_t* trigger, tag_t tag, lf_to return 1; } -#if SCHEDULER != FS +#if SCHEDULER != STATIC /** * Schedule the specified trigger at env->current_tag.time plus the offset of the * specified trigger plus the delay. See schedule_token() in reactor.h for details. diff --git a/core/threaded/CMakeLists.txt b/core/threaded/CMakeLists.txt index 9468c3dfd..af8ea1fe5 100644 --- a/core/threaded/CMakeLists.txt +++ b/core/threaded/CMakeLists.txt @@ -2,7 +2,7 @@ set( THREADED_SOURCES reactor_threaded.c scheduler_adaptive.c - scheduler_FS.c + scheduler_static.c scheduler_GEDF_NP_CI.c scheduler_GEDF_NP.c scheduler_NP.c diff --git a/core/threaded/scheduler_FS.c b/core/threaded/scheduler_static.c similarity index 99% rename from core/threaded/scheduler_FS.c rename to core/threaded/scheduler_static.c index c9463764d..9f6a3e862 100644 --- a/core/threaded/scheduler_FS.c +++ b/core/threaded/scheduler_static.c @@ -29,13 +29,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************/ /** - * A fully static (FS) scheduler for the threaded runtime of the C target of - * Lingua Franca. + * A static scheduler for the threaded runtime of the C target of Lingua Franca. * * @author{Shaokai Lin } */ #include "lf_types.h" -#if SCHEDULER == FS || (!defined(SCHEDULER) && defined(LF_THREADED)) +#if SCHEDULER == STATIC || (!defined(SCHEDULER) && defined(LF_THREADED)) #ifndef NUMBER_OF_WORKERS #define NUMBER_OF_WORKERS 1 #endif // NUMBER_OF_WORKERS @@ -521,7 +520,7 @@ void lf_sched_init( // to a meaningful value. When the first time lf_sched_init() is // called, start_time has not been set. - // Initialize the local tags for the FS scheduler. + // Initialize the local tags for the STATIC scheduler. for (int i = 0; i < env->scheduler->num_reactor_self_instances; i++) { env->scheduler->reactor_self_instances[i]->tag.time = start_time; env->scheduler->reactor_self_instances[i]->tag.microstep = 0; diff --git a/include/api/set.h b/include/api/set.h index bcda87fce..2c95cf187 100644 --- a/include/api/set.h +++ b/include/api/set.h @@ -216,7 +216,7 @@ do { \ // As long as this is done from the context of a reaction, `self` is in scope and is a pointer to the self-struct // of the current reactor. -// The fully static (FS) runtime, uses time local to each reactor. If this is the case +// The fully static (STATIC) runtime, uses time local to each reactor. If this is the case // then we defined these macros to acces that timestamp rather than using the standard API // FIXME (erj): I am not really stoked about this added complexity #if defined REACTOR_LOCAL_TIME @@ -238,6 +238,6 @@ do { \ #define get_microstep() get_microstep(self->base.environment) #endif -// FIXME: How should this be implemented for the FS scheduler? +// FIXME: How should this be implemented for the STATIC scheduler? // #define lf_request_stop() _lf_request_stop(self->base.environment) diff --git a/include/core/lf_types.h b/include/core/lf_types.h index cd85ea37c..85b74263c 100644 --- a/include/core/lf_types.h +++ b/include/core/lf_types.h @@ -73,10 +73,10 @@ typedef unsigned short int ushort; #define LET 4 #define NP 5 #define PEDF_NP 6 -#define FS 7 +#define STATIC 7 // If we use the fully static scheduler, then we want local time at each reactor -#if SCHEDULER == FS +#if SCHEDULER == STATIC #ifndef REACTOR_LOCAL_TIME #define REACTOR_LOCAL_TIME #endif @@ -320,7 +320,7 @@ typedef struct self_base_t { #if defined MODAL_REACTORS reactor_mode_state_t _lf__mode_state; // The current mode (for modal models). #endif -// This is used by e.g. the fully static scheduler (FS) +// This is used by e.g. the fully static scheduler (STATIC) #if defined REACTOR_LOCAL_TIME // FIXME: The output_ports pointers isnt obviously related to local time tag_t tag; // The current tag of the reactor instance. lf_port_base_t **output_ports; // An array of pointers to output ports of this reactor. diff --git a/include/core/reactor_common.h b/include/core/reactor_common.h index 4b1034d36..19d32c1c9 100644 --- a/include/core/reactor_common.h +++ b/include/core/reactor_common.h @@ -10,8 +10,8 @@ #include "modes.h" #include "port.h" -// FIXME (erj): Super hack to disable chain optimzation when we are using the FS runtime. -#if SCHEDULER == FS +// FIXME (erj): Super hack to disable chain optimzation when we are using the STATIC runtime. +#if SCHEDULER == STATIC #else #define REACTION_CHAIN_OPTIMIZATION #endif diff --git a/include/core/threaded/scheduler_instance.h b/include/core/threaded/scheduler_instance.h index 8ddaa846f..bf4e682b3 100644 --- a/include/core/threaded/scheduler_instance.h +++ b/include/core/threaded/scheduler_instance.h @@ -45,7 +45,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "semaphore.h" #include -#if SCHEDULER == FS +#if SCHEDULER == STATIC #include "lf_types.h" #include "scheduler_instructions.h" #endif @@ -146,7 +146,7 @@ typedef struct lf_scheduler_t { // Is not touched by `init_sched_instance` and must be initialized by each scheduler that needs it custom_scheduler_data_t * custom_data; -#if SCHEDULER == FS +#if SCHEDULER == STATIC /** * @brief Points to an array of program counters for each worker. @@ -213,7 +213,7 @@ typedef struct lf_scheduler_t { typedef struct { size_t* num_reactions_per_level; size_t num_reactions_per_level_size; -#if SCHEDULER == FS +#if SCHEDULER == STATIC struct self_base_t** reactor_self_instances; size_t num_reactor_self_instances; bool* reactor_reached_stop_tag; From e497088d840f7a3b51b4c3a70da99e0a67e1ab72 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Thu, 20 Jul 2023 18:08:32 +0200 Subject: [PATCH 11/80] Enable tracing for VM instructions --- core/threaded/scheduler_static.c | 116 ++++++++++++++----------------- core/trace.c | 74 ++++++++++++++++++++ include/core/trace.h | 102 ++++++++++++++++++++++++++- 3 files changed, 226 insertions(+), 66 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 9f6a3e862..1ab83f40d 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -1,7 +1,4 @@ #if defined(LF_THREADED) -/* Fully-static scheduler for the threaded runtime of the C target of Lingua -Franca. */ - /************* Copyright (c) 2022, The University of Texas at Dallas. Copyright (c) 2022, The University of California at Berkeley. @@ -73,10 +70,10 @@ void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { // reaction queues). size_t workers_to_awaken = scheduler->number_of_idle_workers; - //LF_PRINT_DEBUG("Scheduler: Notifying %zu workers.", workers_to_awaken); + LF_PRINT_DEBUG("Scheduler: Notifying %zu workers.", workers_to_awaken); scheduler->number_of_idle_workers -= workers_to_awaken; - //LF_PRINT_DEBUG("Scheduler: New number of idle workers: %zu.", - //scheduler->number_of_idle_workers); + LF_PRINT_DEBUG("Scheduler: New number of idle workers: %zu.", + scheduler->number_of_idle_workers); if (workers_to_awaken > 1) { // Notify all the workers except the worker thread that has called this // function. @@ -110,8 +107,8 @@ void _lf_sched_wait_for_work( scheduler->number_of_workers) { // Last thread to go idle - //LF_PRINT_DEBUG("Scheduler: Worker %zu is the last idle thread.", - //worker_number); + LF_PRINT_DEBUG("Scheduler: Worker %zu is the last idle thread.", + worker_number); // The last worker advances all reactors to the next tag. for (int j = 0; j < scheduler->num_reactor_self_instances; j++) { @@ -145,6 +142,7 @@ void _lf_sched_wait_for_work( */ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number); bool stop = true; for (int i = 0; i < scheduler->num_reactor_self_instances; i++) { if (!scheduler->reactor_reached_stop_tag[i]) { @@ -152,19 +150,9 @@ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, long long break; } } - - /* - LF_PRINT_DEBUG("Start time is %ld. Current tag is (%ld, %d). Stop tag is (%ld, %d). Stop array: ", start_time, current_tag.time, current_tag.microstep, stop_tag.time, stop_tag.microstep); - for (int i = 0; i < scheduler->num_reactor_self_instances; i++) { - LF_PRINT_DEBUG("(%ld, %d)", - scheduler->reactor_self_instances[i]->tag.time, - scheduler->reactor_self_instances[i]->tag.microstep); - LF_PRINT_DEBUG("%d", scheduler->reactor_reached_stop_tag[i]); - } - */ - if (stop) *pc = rs1; // Jump to a specified location. else *pc += 1; // Increment pc. + tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number); } /** @@ -180,13 +168,16 @@ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + tracepoint_static_scheduler_EIT_starts(scheduler->env->trace, worker_number); reaction_t* reaction = scheduler->reaction_instances[rs1]; if (reaction->status == queued) { *returned_reaction = reaction; *exit_loop = true; } else - //LF_PRINT_DEBUG("*** Worker %zu skip execution", worker_number); + LF_PRINT_DEBUG("*** Worker %zu skip execution", worker_number); *pc += 1; // Increment pc. + tracepoint_static_scheduler_EIT_ends(scheduler->env->trace, worker_number); + } /** @@ -200,10 +191,12 @@ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, worker_number); reaction_t* reaction = scheduler->reaction_instances[rs1]; *returned_reaction = reaction; *exit_loop = true; *pc += 1; // Increment pc. + tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, worker_number); } /** @@ -218,15 +211,17 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + tracepoint_static_scheduler_DU_starts(scheduler->env->trace, worker_number); // FIXME: There seems to be an overflow problem. // When wakeup_time overflows but lf_time_physical() doesn't, // _lf_interruptable_sleep_until_locked() terminates immediately. instant_t wakeup_time = start_time + hyperperiod * (*iteration) + rs1; LF_PRINT_DEBUG("start_time: %lld, wakeup_time: %lld, rs1: %lld, iteration: %d, current_physical_time: %lld, hyperperiod: %lld\n", start_time, wakeup_time, rs1, (*iteration), lf_time_physical(), hyperperiod); - //LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); + LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); - //LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); + LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); *pc += 1; // Increment pc. + tracepoint_static_scheduler_DU_ends(scheduler->env->trace, worker_number); } /** @@ -240,10 +235,12 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - //LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); + tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number); + LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); while(scheduler->counters[rs1] < rs2); - //LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); + LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); *pc += 1; // Increment pc. + tracepoint_static_scheduler_WU_ends(scheduler->env->trace, worker_number); } /** @@ -257,7 +254,8 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - + tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number); + // This mutex is quite expensive. lf_mutex_lock(&(scheduler->env->mutex)); @@ -281,6 +279,8 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, long long lf_mutex_unlock(&(scheduler->env->mutex)); *pc += 1; // Increment pc. + + tracepoint_static_scheduler_ADV_ends(scheduler->env->trace, worker_number); } /** @@ -294,6 +294,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + tracepoint_static_scheduler_ADV2_starts(scheduler->env->trace, worker_number); self_base_t* reactor = scheduler->reactor_self_instances[rs1]; @@ -313,6 +314,8 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, long lon } *pc += 1; // Increment pc. + + tracepoint_static_scheduler_ADV2_ends(scheduler->env->trace, worker_number); } /** @@ -326,8 +329,10 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, long lon */ void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + tracepoint_static_scheduler_JMP_starts(scheduler->env->trace, worker_number); if (rs2 != -1) *iteration += 1; *pc = rs1; + tracepoint_static_scheduler_JMP_ends(scheduler->env->trace, worker_number); } /** @@ -342,14 +347,17 @@ void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - + tracepoint_static_scheduler_SAC_starts(scheduler->env->trace, worker_number); + // Compute the next tag for all reactors. instant_t next_timestamp = hyperperiod * (*iteration) + rs1; - tracepoint_worker_wait_starts(worker_number); + tracepoint_worker_wait_starts(scheduler->env->trace, worker_number); _lf_sched_wait_for_work(scheduler, worker_number, next_timestamp); - tracepoint_worker_wait_ends(worker_number); + tracepoint_worker_wait_ends(scheduler->env->trace, worker_number); *pc += 1; // Increment pc. + + tracepoint_static_scheduler_SAC_ends(scheduler->env->trace, worker_number); } /** @@ -363,10 +371,12 @@ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_INC(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + tracepoint_static_scheduler_INC_starts(scheduler->env->trace, worker_number); lf_mutex_lock(&(scheduler->env->mutex)); scheduler->counters[rs1] += rs2; lf_mutex_unlock(&(scheduler->env->mutex)); *pc += 1; // Increment pc. + tracepoint_static_scheduler_INC_ends(scheduler->env->trace, worker_number); } /** @@ -381,8 +391,10 @@ void execute_inst_INC(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_INC2(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + tracepoint_static_scheduler_INC2_starts(scheduler->env->trace, worker_number); scheduler->counters[rs1] += rs2; *pc += 1; // Increment pc. + tracepoint_static_scheduler_INC2_ends(scheduler->env->trace, worker_number); } /** @@ -391,7 +403,9 @@ void execute_inst_INC2(lf_scheduler_t* scheduler, size_t worker_number, long lon */ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + tracepoint_static_scheduler_STP_starts(scheduler->env->trace, worker_number); *exit_loop = true; + tracepoint_static_scheduler_STP_ends(scheduler->env->trace, worker_number); } /** @@ -413,74 +427,50 @@ void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t op, switch (op) { case ADV: op_str = "ADV"; - //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", - //worker_number, *pc, op_str, rs1, rs2); execute_inst_ADV(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); break; case ADV2: op_str = "ADV2"; - //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", - //worker_number, *pc, op_str, rs1, rs2); execute_inst_ADV2(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); break; case BIT: op_str = "BIT"; - //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", - //worker_number, *pc, op_str, rs1, rs2); execute_inst_BIT(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); break; case DU: op_str = "DU"; - //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", - //worker_number, *pc, op_str, rs1, rs2); execute_inst_DU(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); break; case EIT: op_str = "EIT"; - //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", - //worker_number, *pc, op_str, rs1, rs2); execute_inst_EIT(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); break; case EXE: op_str = "EXE"; - //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", - //worker_number, *pc, op_str, rs1, rs2); execute_inst_EXE(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); break; case INC: op_str = "INC"; - //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", - //worker_number, *pc, op_str, rs1, rs2); execute_inst_INC(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); break; case INC2: op_str = "INC2"; - //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", - //worker_number, *pc, op_str, rs1, rs2); execute_inst_INC2(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); break; case JMP: op_str = "JMP"; - //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", - //worker_number, *pc, op_str, rs1, rs2); execute_inst_JMP(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); break; case SAC: op_str = "SAC"; - //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", - //worker_number, *pc, op_str, rs1, rs2); execute_inst_SAC(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); break; case STP: op_str = "STP"; - //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", - //worker_number, *pc, op_str, rs1, rs2); execute_inst_STP(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); break; case WU: op_str = "WU"; - //LF_PRINT_DEBUG("*** Current instruction for worker %zu: [Line %zu] %s %lld %lld", - //worker_number, *pc, op_str, rs1, rs2); execute_inst_WU(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); break; default: @@ -505,7 +495,7 @@ void lf_sched_init( size_t number_of_workers, sched_params_t* params ) { - //LF_PRINT_DEBUG("Scheduler: Initializing with %zu workers", number_of_workers); + LF_PRINT_DEBUG("Scheduler: Initializing with %zu workers", number_of_workers); // Scheduler already initialized if (!init_sched_instance(env, &env->scheduler, number_of_workers, params)) { @@ -524,9 +514,6 @@ void lf_sched_init( for (int i = 0; i < env->scheduler->num_reactor_self_instances; i++) { env->scheduler->reactor_self_instances[i]->tag.time = start_time; env->scheduler->reactor_self_instances[i]->tag.microstep = 0; - //LF_PRINT_DEBUG("(%ld, %d)", - //env->scheduler->reactor_self_instances[i]->tag.time, - //env->scheduler->reactor_self_instances[i]->tag.microstep); } // Already initialized @@ -548,7 +535,7 @@ void lf_sched_init( * This must be called when the scheduler is no longer needed. */ void lf_sched_free(lf_scheduler_t* scheduler) { - //LF_PRINT_DEBUG("Freeing the pointers in the scheduler struct."); + LF_PRINT_DEBUG("Freeing the pointers in the scheduler struct."); free(scheduler->pc); free(scheduler->reactor_self_instances); free(scheduler->reaction_instances); @@ -567,7 +554,7 @@ void lf_sched_free(lf_scheduler_t* scheduler) { * worker thread should exit. */ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_number) { - //LF_PRINT_DEBUG("Worker %d inside lf_sched_get_ready_reaction", worker_number); + LF_PRINT_DEBUG("Worker %d inside lf_sched_get_ready_reaction", worker_number); const inst_t* current_schedule = scheduler->static_schedules[worker_number]; reaction_t* returned_reaction = NULL; @@ -587,11 +574,11 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu execute_inst(scheduler, worker_number, op, rs1, rs2, pc, &returned_reaction, &exit_loop, iteration); - //LF_PRINT_DEBUG("Worker %d: returned_reaction = %p, exit_loop = %d", - //worker_number, returned_reaction, exit_loop); + LF_PRINT_DEBUG("Worker %d: returned_reaction = %p, exit_loop = %d", + worker_number, returned_reaction, exit_loop); } - //LF_PRINT_DEBUG("Worker %d leaves lf_sched_get_ready_reaction", worker_number); + LF_PRINT_DEBUG("Worker %d leaves lf_sched_get_ready_reaction", worker_number); return returned_reaction; } @@ -605,7 +592,7 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu */ void lf_sched_done_with_reaction(size_t worker_number, reaction_t* done_reaction) { - //LF_PRINT_DEBUG("*** Worker %zu inside lf_sched_done_with_reaction, done with %s", worker_number, done_reaction->name); + LF_PRINT_DEBUG("*** Worker %zu inside lf_sched_done_with_reaction, done with %s", worker_number, done_reaction->name); // If the reaction status is queued, change it back to inactive. // We do not check for error here because the EXE instruction // can execute a reaction with an "inactive" status. @@ -616,7 +603,7 @@ void lf_sched_done_with_reaction(size_t worker_number, // using the EXE instructions. lf_bool_compare_and_swap(&done_reaction->status, queued, inactive); - //LF_PRINT_DEBUG("*** Worker %zu reports updated status for %s: %u", worker_number, done_reaction->name, done_reaction->status); + LF_PRINT_DEBUG("*** Worker %zu reports updated status for %s: %u", worker_number, done_reaction->name, done_reaction->status); } /** @@ -639,8 +626,7 @@ void lf_sched_done_with_reaction(size_t worker_number, * */ void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { - //LF_PRINT_DEBUG("*** Inside lf_sched_trigger_reaction"); - //LF_PRINT_DEBUG("*** Worker %d triggering reaction %s", worker_number, reaction->name); + LF_PRINT_DEBUG("*** Worker %d triggering reaction %s", worker_number, reaction->name); // Mark a reaction as queued, so that it will be executed when workers do work. if (!lf_bool_compare_and_swap(&reaction->status, inactive, queued)) { // FIXME: Uncommenting the code below yields weird exception. diff --git a/core/trace.c b/core/trace.c index 1e9703c09..4affa68b6 100644 --- a/core/trace.c +++ b/core/trace.c @@ -285,6 +285,7 @@ void tracepoint( if (!is_interval_start && physical_time == NULL) { time = lf_time_physical(); physical_time = &time; + printf("*** Time reported by clock: %lld\n", *physical_time); } environment_t *env = trace->env; @@ -457,6 +458,79 @@ void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, i tracepoint(trace, reaction_deadline_missed, reaction->self, NULL, worker, worker, reaction->number, NULL, NULL, 0, false); } +void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_ADV_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_ADV_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_ADV2_starts(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_ADV2_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_ADV2_ends(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_ADV2_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_BIT_starts(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_BIT_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_BIT_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_DU_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_DU_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_EIT_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_EIT_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_EXE_starts(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_EXE_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_EXE_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_INC_starts(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_INC_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_INC_ends(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_INC_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_INC2_starts(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_INC2_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_INC2_ends(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_INC2_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_JMP_starts(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_JMP_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_JMP_ends(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_JMP_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_SAC_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_SAC_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_STP_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_STP_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_WU_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} +void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker) { + tracepoint(trace, static_scheduler_WU_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +} + void stop_trace(trace_t* trace) { lf_critical_section_enter(trace->env); if (trace->_lf_trace_stop) { diff --git a/include/core/trace.h b/include/core/trace.h index 72e2d466a..38946d6c1 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -76,7 +76,32 @@ typedef enum worker_wait_ends, scheduler_advancing_time_starts, scheduler_advancing_time_ends, - federated, // Everything above this is tracing federated interactions. + // Static scheduler instructions + static_scheduler_ADV_starts, + static_scheduler_ADV2_starts, + static_scheduler_BIT_starts, + static_scheduler_DU_starts, + static_scheduler_EIT_starts, + static_scheduler_EXE_starts, + static_scheduler_INC_starts, + static_scheduler_INC2_starts, + static_scheduler_JMP_starts, + static_scheduler_SAC_starts, + static_scheduler_STP_starts, + static_scheduler_WU_starts, + static_scheduler_ADV_ends, + static_scheduler_ADV2_ends, + static_scheduler_BIT_ends, + static_scheduler_DU_ends, + static_scheduler_EIT_ends, + static_scheduler_EXE_ends, + static_scheduler_INC_ends, + static_scheduler_INC2_ends, + static_scheduler_JMP_ends, + static_scheduler_SAC_ends, + static_scheduler_STP_ends, + static_scheduler_WU_ends, + federated, // Everything below this is tracing federated interactions. // Sending messages send_ACK, send_TIMESTAMP, @@ -139,6 +164,31 @@ static const char *trace_event_names[] = { "Worker wait ends", "Scheduler advancing time starts", "Scheduler advancing time ends", + // Static scheduler instructions + "Start ADV: advance logical time", + "Start ADV2: advance logical time (lock-free)", + "Start BIT: branch if timeout", + "Start DU: delay until", + "Start EIT: execute if triggered", + "Start EXE: execute", + "Start INC: increment counter", + "Start INC2: increment counter (lock-free)", + "Start JMP: jump", + "Start SAC: synchronize, advance time, and clear counters", + "Start STP: stop", + "Start WU: wait until", + "End ADV: advance logical time", + "End ADV2: advance logical time (lock-free)", + "End BIT: branch if timeout", + "End DU: delay until", + "End EIT: execute if triggered", + "End EXE: execute", + "End INC: increment counter", + "End INC2: increment counter (lock-free)", + "End JMP: jump", + "End SAC: synchronize, advance time, and clear counters", + "End STP: stop", + "End WU: wait until", "Federated marker", // Sending messages "Sending ACK", @@ -430,6 +480,32 @@ void tracepoint_scheduler_advancing_time_ends(trace_t* trace); */ void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, int worker); +void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker); +void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker); +void tracepoint_static_scheduler_ADV2_starts(trace_t* trace, int worker); +void tracepoint_static_scheduler_ADV2_ends(trace_t* trace, int worker); +void tracepoint_static_scheduler_BIT_starts(trace_t* trace, int worker); +void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker); +void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker); +void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker); +void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker); +void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker); +void tracepoint_static_scheduler_EXE_starts(trace_t* trace, int worker); +void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker); +void tracepoint_static_scheduler_INC_starts(trace_t* trace, int worker); +void tracepoint_static_scheduler_INC_ends(trace_t* trace, int worker); +void tracepoint_static_scheduler_INC2_starts(trace_t* trace, int worker); +void tracepoint_static_scheduler_INC2_ends(trace_t* trace, int worker); +void tracepoint_static_scheduler_JMP_starts(trace_t* trace, int worker); +void tracepoint_static_scheduler_JMP_ends(trace_t* trace, int worker); +void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker); +void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker); +void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker); +void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker); +void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker); +void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker); + + /** * Flush any buffered trace records to the trace file and * close the files. @@ -522,6 +598,30 @@ void tracepoint_rti_from_federate(trace_t* trace, trace_event_t event_type, int #define tracepoint_scheduler_advancing_time_starts(...); #define tracepoint_scheduler_advancing_time_ends(...); #define tracepoint_reaction_deadline_missed(...); +#define tracepoint_static_scheduler_ADV_starts(...); +#define tracepoint_static_scheduler_ADV_ends(...); +#define tracepoint_static_scheduler_ADV2_starts(...); +#define tracepoint_static_scheduler_ADV2_ends(...); +#define tracepoint_static_scheduler_BIT_starts(...); +#define tracepoint_static_scheduler_BIT_ends(...); +#define tracepoint_static_scheduler_DU_starts(...); +#define tracepoint_static_scheduler_DU_ends(...); +#define tracepoint_static_scheduler_EIT_starts(...); +#define tracepoint_static_scheduler_EIT_ends(...); +#define tracepoint_static_scheduler_EXE_starts(...); +#define tracepoint_static_scheduler_EXE_ends(...); +#define tracepoint_static_scheduler_INC_starts(...); +#define tracepoint_static_scheduler_INC_ends(...); +#define tracepoint_static_scheduler_INC2_starts(...); +#define tracepoint_static_scheduler_INC2_ends(...); +#define tracepoint_static_scheduler_JMP_starts(...); +#define tracepoint_static_scheduler_JMP_ends(...); +#define tracepoint_static_scheduler_SAC_starts(...); +#define tracepoint_static_scheduler_SAC_ends(...); +#define tracepoint_static_scheduler_STP_starts(...); +#define tracepoint_static_scheduler_STP_ends(...); +#define tracepoint_static_scheduler_WU_starts(...); +#define tracepoint_static_scheduler_WU_ends(...); #define tracepoint_federate_to_rti(...); #define tracepoint_federate_from_rti(...); #define tracepoint_federate_to_federate(...) ; From 6aab8ed9bb7c28d2e0478eb4c519658b1ee2e7ea Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Thu, 20 Jul 2023 18:17:31 +0200 Subject: [PATCH 12/80] Remove tracing hacks --- core/trace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/core/trace.c b/core/trace.c index 4affa68b6..35e9eb541 100644 --- a/core/trace.c +++ b/core/trace.c @@ -285,7 +285,6 @@ void tracepoint( if (!is_interval_start && physical_time == NULL) { time = lf_time_physical(); physical_time = &time; - printf("*** Time reported by clock: %lld\n", *physical_time); } environment_t *env = trace->env; From d2f5c9a8641f18696564a9c96f691eea93ac3135 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Fri, 21 Jul 2023 13:40:16 +0200 Subject: [PATCH 13/80] Support better tracing experience by storing line numbers --- core/threaded/scheduler_static.c | 48 ++++++++-------- core/trace.c | 96 ++++++++++++++++---------------- include/core/trace.h | 72 ++++++++++++------------ 3 files changed, 108 insertions(+), 108 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 1ab83f40d..9a6d71fd9 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -142,7 +142,7 @@ void _lf_sched_wait_for_work( */ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); bool stop = true; for (int i = 0; i < scheduler->num_reactor_self_instances; i++) { if (!scheduler->reactor_reached_stop_tag[i]) { @@ -152,7 +152,7 @@ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, long long } if (stop) *pc = rs1; // Jump to a specified location. else *pc += 1; // Increment pc. - tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -168,7 +168,7 @@ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_EIT_starts(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_EIT_starts(scheduler->env->trace, worker_number, (int) *pc); reaction_t* reaction = scheduler->reaction_instances[rs1]; if (reaction->status == queued) { *returned_reaction = reaction; @@ -176,7 +176,7 @@ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, long long } else LF_PRINT_DEBUG("*** Worker %zu skip execution", worker_number); *pc += 1; // Increment pc. - tracepoint_static_scheduler_EIT_ends(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_EIT_ends(scheduler->env->trace, worker_number, (int) *pc); } @@ -191,12 +191,12 @@ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, worker_number, (int) *pc); reaction_t* reaction = scheduler->reaction_instances[rs1]; *returned_reaction = reaction; *exit_loop = true; *pc += 1; // Increment pc. - tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -211,7 +211,7 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_DU_starts(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_DU_starts(scheduler->env->trace, worker_number, (int) *pc); // FIXME: There seems to be an overflow problem. // When wakeup_time overflows but lf_time_physical() doesn't, // _lf_interruptable_sleep_until_locked() terminates immediately. @@ -221,7 +221,7 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, long long _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); *pc += 1; // Increment pc. - tracepoint_static_scheduler_DU_ends(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_DU_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -235,12 +235,12 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, (int) *pc); LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); while(scheduler->counters[rs1] < rs2); LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); *pc += 1; // Increment pc. - tracepoint_static_scheduler_WU_ends(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_WU_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -254,7 +254,7 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number, (int) *pc); // This mutex is quite expensive. lf_mutex_lock(&(scheduler->env->mutex)); @@ -280,7 +280,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, long long *pc += 1; // Increment pc. - tracepoint_static_scheduler_ADV_ends(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_ADV_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -294,7 +294,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_ADV2_starts(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_ADV2_starts(scheduler->env->trace, worker_number, (int) *pc); self_base_t* reactor = scheduler->reactor_self_instances[rs1]; @@ -315,7 +315,7 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, long lon *pc += 1; // Increment pc. - tracepoint_static_scheduler_ADV2_ends(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_ADV2_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -329,10 +329,10 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, long lon */ void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_JMP_starts(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_JMP_starts(scheduler->env->trace, worker_number, (int) *pc); if (rs2 != -1) *iteration += 1; *pc = rs1; - tracepoint_static_scheduler_JMP_ends(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_JMP_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -347,7 +347,7 @@ void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_SAC_starts(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_SAC_starts(scheduler->env->trace, worker_number, (int) *pc); // Compute the next tag for all reactors. instant_t next_timestamp = hyperperiod * (*iteration) + rs1; @@ -357,7 +357,7 @@ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, long long tracepoint_worker_wait_ends(scheduler->env->trace, worker_number); *pc += 1; // Increment pc. - tracepoint_static_scheduler_SAC_ends(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_SAC_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -371,12 +371,12 @@ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_INC(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_INC_starts(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_INC_starts(scheduler->env->trace, worker_number, (int) *pc); lf_mutex_lock(&(scheduler->env->mutex)); scheduler->counters[rs1] += rs2; lf_mutex_unlock(&(scheduler->env->mutex)); *pc += 1; // Increment pc. - tracepoint_static_scheduler_INC_ends(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_INC_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -391,10 +391,10 @@ void execute_inst_INC(lf_scheduler_t* scheduler, size_t worker_number, long long */ void execute_inst_INC2(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_INC2_starts(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_INC2_starts(scheduler->env->trace, worker_number, (int) *pc); scheduler->counters[rs1] += rs2; *pc += 1; // Increment pc. - tracepoint_static_scheduler_INC2_ends(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_INC2_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -403,9 +403,9 @@ void execute_inst_INC2(lf_scheduler_t* scheduler, size_t worker_number, long lon */ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_STP_starts(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_STP_starts(scheduler->env->trace, worker_number, (int) *pc); *exit_loop = true; - tracepoint_static_scheduler_STP_ends(scheduler->env->trace, worker_number); + tracepoint_static_scheduler_STP_ends(scheduler->env->trace, worker_number, (int) *pc); } /** diff --git a/core/trace.c b/core/trace.c index 35e9eb541..ca298ce92 100644 --- a/core/trace.c +++ b/core/trace.c @@ -457,77 +457,77 @@ void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, i tracepoint(trace, reaction_deadline_missed, reaction->self, NULL, worker, worker, reaction->number, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_ADV_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_ADV_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_ADV_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_ADV_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_ADV2_starts(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_ADV2_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_ADV2_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_ADV2_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_ADV2_ends(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_ADV2_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_ADV2_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_ADV2_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_BIT_starts(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_BIT_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_BIT_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_BIT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_BIT_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_BIT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_DU_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_DU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_DU_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_DU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_EIT_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_EIT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_EIT_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_EIT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_EXE_starts(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_EXE_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_EXE_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_EXE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_EXE_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_EXE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_INC_starts(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_INC_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_INC_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_INC_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_INC_ends(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_INC_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_INC_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_INC_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_INC2_starts(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_INC2_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_INC2_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_INC2_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_INC2_ends(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_INC2_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_INC2_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_INC2_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_JMP_starts(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_JMP_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_JMP_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_JMP_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_JMP_ends(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_JMP_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_JMP_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_JMP_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_SAC_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_SAC_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_SAC_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_SAC_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_STP_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_STP_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_STP_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_STP_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_WU_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_WU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker) { - tracepoint(trace, static_scheduler_WU_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); +void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_WU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } void stop_trace(trace_t* trace) { diff --git a/include/core/trace.h b/include/core/trace.h index 38946d6c1..58125731f 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -165,18 +165,18 @@ static const char *trace_event_names[] = { "Scheduler advancing time starts", "Scheduler advancing time ends", // Static scheduler instructions - "Start ADV: advance logical time", - "Start ADV2: advance logical time (lock-free)", - "Start BIT: branch if timeout", - "Start DU: delay until", - "Start EIT: execute if triggered", - "Start EXE: execute", - "Start INC: increment counter", - "Start INC2: increment counter (lock-free)", - "Start JMP: jump", - "Start SAC: synchronize, advance time, and clear counters", - "Start STP: stop", - "Start WU: wait until", + "ADV: advance logical time", + "ADV2: advance logical time (lock-free)", + "BIT: branch if timeout", + "DU: delay until", + "EIT: execute if triggered", + "EXE: execute", + "INC: increment counter", + "INC2: increment counter (lock-free)", + "JMP: jump", + "SAC: synchronize, advance time, and clear counters", + "STP: stop", + "WU: wait until", "End ADV: advance logical time", "End ADV2: advance logical time (lock-free)", "End BIT: branch if timeout", @@ -480,30 +480,30 @@ void tracepoint_scheduler_advancing_time_ends(trace_t* trace); */ void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, int worker); -void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker); -void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker); -void tracepoint_static_scheduler_ADV2_starts(trace_t* trace, int worker); -void tracepoint_static_scheduler_ADV2_ends(trace_t* trace, int worker); -void tracepoint_static_scheduler_BIT_starts(trace_t* trace, int worker); -void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker); -void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker); -void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker); -void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker); -void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker); -void tracepoint_static_scheduler_EXE_starts(trace_t* trace, int worker); -void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker); -void tracepoint_static_scheduler_INC_starts(trace_t* trace, int worker); -void tracepoint_static_scheduler_INC_ends(trace_t* trace, int worker); -void tracepoint_static_scheduler_INC2_starts(trace_t* trace, int worker); -void tracepoint_static_scheduler_INC2_ends(trace_t* trace, int worker); -void tracepoint_static_scheduler_JMP_starts(trace_t* trace, int worker); -void tracepoint_static_scheduler_JMP_ends(trace_t* trace, int worker); -void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker); -void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker); -void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker); -void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker); -void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker); -void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker); +void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_ADV2_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_ADV2_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_BIT_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_EXE_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_INC_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_INC_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_INC2_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_INC2_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_JMP_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_JMP_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker, int pc); /** From 176b74ae9233ed6c8724d0456b0085f6a75ec4eb Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Fri, 21 Jul 2023 18:20:23 +0200 Subject: [PATCH 14/80] Support ADDI and refactor --- core/threaded/scheduler_static.c | 276 +++++++++--------- core/trace.c | 109 ++++--- .../core/threaded/scheduler_instructions.h | 13 +- include/core/trace.h | 55 ++-- 4 files changed, 233 insertions(+), 220 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 9a6d71fd9..098e74f3e 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -53,7 +53,7 @@ extern instant_t start_time; // Global variables defined in schedule.c: extern const inst_t* static_schedules[]; -extern const long long int hyperperiod; +extern const uint64_t hyperperiod; extern volatile uint32_t hyperperiod_iterations[]; extern volatile uint32_t counters[]; extern const size_t num_counters; @@ -131,6 +131,102 @@ void _lf_sched_wait_for_work( } } +/** + * @brief ADDI: [Lock-free] Add to an integer variable (rs2) by an amount (rs3), + * and store the result in a destination variable (rs1). + * The compiler needs to guarantee a single writer. + * + * @param rs1 + * @param rs2 + * @param pc + * @param returned_reaction + * @param exit_loop + */ +void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, (int) *pc); + uint64_t *dst = (uint64_t *) rs1; + uint64_t *src = (uint64_t *) rs2; + *dst = *src + rs3; + *pc += 1; // Increment pc. + tracepoint_static_scheduler_ADDI_ends(scheduler->env->trace, worker_number, (int) *pc); +} + +/** + * @brief ADV: Advance time for a reactor up to a tag (relative to the current hyperperiod). + * + * @param rs1 + * @param rs2 + * @param pc + * @param returned_reaction + * @param exit_loop + */ +void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number, (int) *pc); + + // This mutex is quite expensive. + lf_mutex_lock(&(scheduler->env->mutex)); + + self_base_t* reactor = + scheduler->reactor_self_instances[rs1]; + reactor->tag.time = hyperperiod * (*iteration) + rs2; + reactor->tag.microstep = 0; + + // Reset all "is_present" fields of the output ports of the reactor + // Doing this here has the major implicatio that ADV has to execute AFTER + // all downstream reactions have finished. Since it is modifying state that is + // visible to thos reactions. + for (int i = 0; inum_output_ports; i++) { + reactor->output_ports[i]->is_present = false; + } + + if (_lf_is_tag_after_stop_tag(scheduler->env, reactor->tag)) { + scheduler->reactor_reached_stop_tag[rs1] = true; + } + + lf_mutex_unlock(&(scheduler->env->mutex)); + + *pc += 1; // Increment pc. + + tracepoint_static_scheduler_ADV_ends(scheduler->env->trace, worker_number, (int) *pc); +} + +/** + * @brief ADV: Advance time for a reactor up to a tag (relative to the current hyperperiod). + * + * @param rs1 + * @param rs2 + * @param pc + * @param returned_reaction + * @param exit_loop + */ +void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + tracepoint_static_scheduler_ADV2_starts(scheduler->env->trace, worker_number, (int) *pc); + + self_base_t* reactor = + scheduler->reactor_self_instances[rs1]; + reactor->tag.time = hyperperiod * (*iteration) + rs2; + reactor->tag.microstep = 0; + + // Reset all "is_present" fields of the output ports of the reactor + // Doing this here has the major implicatio that ADV has to execute AFTER + // all downstream reactions have finished. Since it is modifying state that is + // visible to thos reactions. + for (int i = 0; inum_output_ports; i++) { + reactor->output_ports[i]->is_present = false; + } + + if (_lf_is_tag_after_stop_tag(scheduler->env, reactor->tag)) { + scheduler->reactor_reached_stop_tag[rs1] = true; + } + + *pc += 1; // Increment pc. + + tracepoint_static_scheduler_ADV2_ends(scheduler->env->trace, worker_number, (int) *pc); +} + /** * @brief BIT: Branch If Timeout * Check if timeout is reached. If not, don't do anything. @@ -140,7 +236,7 @@ void _lf_sched_wait_for_work( * FIXME: Use a global variable num_active_reactors instead of iterating over * a for loop. */ -void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, +void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); bool stop = true; @@ -166,7 +262,7 @@ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, long long * @param returned_reaction * @param exit_loop */ -void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, +void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { tracepoint_static_scheduler_EIT_starts(scheduler->env->trace, worker_number, (int) *pc); reaction_t* reaction = scheduler->reaction_instances[rs1]; @@ -189,7 +285,7 @@ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, long long * @param returned_reaction * @param exit_loop */ -void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, +void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, worker_number, (int) *pc); reaction_t* reaction = scheduler->reaction_instances[rs1]; @@ -209,13 +305,14 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, long long * @param returned_reaction * @param exit_loop */ -void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, +void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { tracepoint_static_scheduler_DU_starts(scheduler->env->trace, worker_number, (int) *pc); // FIXME: There seems to be an overflow problem. // When wakeup_time overflows but lf_time_physical() doesn't, - // _lf_interruptable_sleep_until_locked() terminates immediately. - instant_t wakeup_time = start_time + hyperperiod * (*iteration) + rs1; + // _lf_interruptable_sleep_until_locked() terminates immediately. + uint64_t *src = (uint64_t *)rs1; + instant_t wakeup_time = start_time + *src + rs2; LF_PRINT_DEBUG("start_time: %lld, wakeup_time: %lld, rs1: %lld, iteration: %d, current_physical_time: %lld, hyperperiod: %lld\n", start_time, wakeup_time, rs1, (*iteration), lf_time_physical(), hyperperiod); LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); @@ -233,7 +330,7 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, long long * @param returned_reaction * @param exit_loop */ -void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, +void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, (int) *pc); LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); @@ -243,81 +340,6 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, long long tracepoint_static_scheduler_WU_ends(scheduler->env->trace, worker_number, (int) *pc); } -/** - * @brief ADV: Advance time for a reactor up to a tag (relative to the current hyperperiod). - * - * @param rs1 - * @param rs2 - * @param pc - * @param returned_reaction - * @param exit_loop - */ -void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number, (int) *pc); - - // This mutex is quite expensive. - lf_mutex_lock(&(scheduler->env->mutex)); - - self_base_t* reactor = - scheduler->reactor_self_instances[rs1]; - reactor->tag.time = hyperperiod * (*iteration) + rs2; - reactor->tag.microstep = 0; - - // Reset all "is_present" fields of the output ports of the reactor - // Doing this here has the major implicatio that ADV has to execute AFTER - // all downstream reactions have finished. Since it is modifying state that is - // visible to thos reactions. - for (int i = 0; inum_output_ports; i++) { - reactor->output_ports[i]->is_present = false; - } - - if (_lf_is_tag_after_stop_tag(scheduler->env, reactor->tag)) { - scheduler->reactor_reached_stop_tag[rs1] = true; - } - - lf_mutex_unlock(&(scheduler->env->mutex)); - - *pc += 1; // Increment pc. - - tracepoint_static_scheduler_ADV_ends(scheduler->env->trace, worker_number, (int) *pc); -} - -/** - * @brief ADV: Advance time for a reactor up to a tag (relative to the current hyperperiod). - * - * @param rs1 - * @param rs2 - * @param pc - * @param returned_reaction - * @param exit_loop - */ -void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_ADV2_starts(scheduler->env->trace, worker_number, (int) *pc); - - self_base_t* reactor = - scheduler->reactor_self_instances[rs1]; - reactor->tag.time = hyperperiod * (*iteration) + rs2; - reactor->tag.microstep = 0; - - // Reset all "is_present" fields of the output ports of the reactor - // Doing this here has the major implicatio that ADV has to execute AFTER - // all downstream reactions have finished. Since it is modifying state that is - // visible to thos reactions. - for (int i = 0; inum_output_ports; i++) { - reactor->output_ports[i]->is_present = false; - } - - if (_lf_is_tag_after_stop_tag(scheduler->env, reactor->tag)) { - scheduler->reactor_reached_stop_tag[rs1] = true; - } - - *pc += 1; // Increment pc. - - tracepoint_static_scheduler_ADV2_ends(scheduler->env->trace, worker_number, (int) *pc); -} - /** * @brief JMP: Jump to a particular line in the schedule. * @@ -327,7 +349,7 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, long lon * @param returned_reaction * @param exit_loop */ -void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, +void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { tracepoint_static_scheduler_JMP_starts(scheduler->env->trace, worker_number, (int) *pc); if (rs2 != -1) *iteration += 1; @@ -345,12 +367,13 @@ void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, long long * @param returned_reaction * @param exit_loop */ -void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, +void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { tracepoint_static_scheduler_SAC_starts(scheduler->env->trace, worker_number, (int) *pc); // Compute the next tag for all reactors. - instant_t next_timestamp = hyperperiod * (*iteration) + rs1; + uint64_t *src = (uint64_t *)rs1; + instant_t next_timestamp = *src + rs2; tracepoint_worker_wait_starts(scheduler->env->trace, worker_number); _lf_sched_wait_for_work(scheduler, worker_number, next_timestamp); @@ -360,48 +383,11 @@ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, long long tracepoint_static_scheduler_SAC_ends(scheduler->env->trace, worker_number, (int) *pc); } -/** - * @brief INC: INCrement a counter (rs1) by an amount (rs2). - * - * @param rs1 - * @param rs2 - * @param pc - * @param returned_reaction - * @param exit_loop - */ -void execute_inst_INC(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_INC_starts(scheduler->env->trace, worker_number, (int) *pc); - lf_mutex_lock(&(scheduler->env->mutex)); - scheduler->counters[rs1] += rs2; - lf_mutex_unlock(&(scheduler->env->mutex)); - *pc += 1; // Increment pc. - tracepoint_static_scheduler_INC_ends(scheduler->env->trace, worker_number, (int) *pc); -} - -/** - * @brief INC2: [Lock-free] INCrement a counter (rs1) by an amount (rs2). - * The compiler needs to guarantee a single writer. - * - * @param rs1 - * @param rs2 - * @param pc - * @param returned_reaction - * @param exit_loop - */ -void execute_inst_INC2(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { - tracepoint_static_scheduler_INC2_starts(scheduler->env->trace, worker_number, (int) *pc); - scheduler->counters[rs1] += rs2; - *pc += 1; // Increment pc. - tracepoint_static_scheduler_INC2_ends(scheduler->env->trace, worker_number, (int) *pc); -} - /** * @brief STP: SToP the execution. * */ -void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, long long int rs1, long long int rs2, size_t* pc, +void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { tracepoint_static_scheduler_STP_starts(scheduler->env->trace, worker_number, (int) *pc); *exit_loop = true; @@ -421,57 +407,53 @@ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, long long * @param exit_loop a pointer to a boolean indicating whether * the outer while loop should be exited */ -void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t op, long long int rs1, long long int rs2, +void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t op, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { char* op_str = NULL; switch (op) { + case ADDI: + op_str = "ADDI"; + execute_inst_ADDI(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); + break; case ADV: op_str = "ADV"; - execute_inst_ADV(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + execute_inst_ADV(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); break; case ADV2: op_str = "ADV2"; - execute_inst_ADV2(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + execute_inst_ADV2(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); break; case BIT: op_str = "BIT"; - execute_inst_BIT(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + execute_inst_BIT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); break; case DU: op_str = "DU"; - execute_inst_DU(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + execute_inst_DU(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); break; case EIT: op_str = "EIT"; - execute_inst_EIT(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + execute_inst_EIT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); break; case EXE: op_str = "EXE"; - execute_inst_EXE(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); - break; - case INC: - op_str = "INC"; - execute_inst_INC(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); - break; - case INC2: - op_str = "INC2"; - execute_inst_INC2(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + execute_inst_EXE(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); break; case JMP: op_str = "JMP"; - execute_inst_JMP(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + execute_inst_JMP(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); break; case SAC: op_str = "SAC"; - execute_inst_SAC(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + execute_inst_SAC(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); break; case STP: op_str = "STP"; - execute_inst_STP(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + execute_inst_STP(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); break; case WU: op_str = "WU"; - execute_inst_WU(scheduler, worker_number, rs1, rs2, pc, returned_reaction, exit_loop, iteration); + execute_inst_WU(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); break; default: lf_print_error_and_exit("Invalid instruction: %d", op); @@ -561,17 +543,19 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu bool exit_loop = false; size_t* pc = &scheduler->pc[worker_number]; opcode_t op; - long long int rs1; - long long int rs2; + uint64_t rs1; + uint64_t rs2; + uint64_t rs3; volatile uint32_t* iteration = &hyperperiod_iterations[worker_number]; while (!exit_loop) { op = current_schedule[*pc].op; rs1 = current_schedule[*pc].rs1; rs2 = current_schedule[*pc].rs2; + rs3 = current_schedule[*pc].rs3; // Execute the current instruction - execute_inst(scheduler, worker_number, op, rs1, rs2, pc, + execute_inst(scheduler, worker_number, op, rs1, rs2, rs3, pc, &returned_reaction, &exit_loop, iteration); LF_PRINT_DEBUG("Worker %d: returned_reaction = %p, exit_loop = %d", diff --git a/core/trace.c b/core/trace.c index ca298ce92..fac833f9a 100644 --- a/core/trace.c +++ b/core/trace.c @@ -457,75 +457,112 @@ void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, i tracepoint(trace, reaction_deadline_missed, reaction->self, NULL, worker, worker, reaction->number, NULL, NULL, 0, false); } +/** Trace the start of the ADDI instruction */ +void tracepoint_static_scheduler_ADDI_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_ADDI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +} + +/** Trace the start of the ADV instruction */ void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_ADV_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADV_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} + +/** Trace the start of the ADV2 instruction */ void tracepoint_static_scheduler_ADV2_starts(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_ADV2_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_ADV2_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADV2_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} + +/** Trace the start of the BIT instruction */ void tracepoint_static_scheduler_BIT_starts(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_BIT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_BIT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} + +/** Trace the start of the DU instruction */ void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_DU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_DU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} + +/** Trace the start of the EIT instruction */ void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_EIT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_EIT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} + +/** Trace the start of the EXE instruction */ void tracepoint_static_scheduler_EXE_starts(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_EXE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_EXE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + +/** Trace the start of the JMP instruction */ +void tracepoint_static_scheduler_JMP_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_JMP_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_INC_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_INC_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + +/** Trace the start of the SAC instruction */ +void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_SAC_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_INC_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_INC_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + +/** Trace the start of the STP instruction */ +void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_STP_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_INC2_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_INC2_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + +/** Trace the start of the WU instruction */ +void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_WU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_INC2_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_INC2_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + +/** Trace the end of the ADDI instruction */ +void tracepoint_static_scheduler_ADDI_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_ADDI_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_JMP_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_JMP_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + +/** Trace the end of the ADV instruction */ +void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_ADV_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +} + +/** Trace the end of the ADV2 instruction */ +void tracepoint_static_scheduler_ADV2_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_ADV2_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } + +/** Trace the end of the BIT instruction */ +void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_BIT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +} + +/** Trace the end of the DU instruction */ +void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_DU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +} + +/** Trace the end of the EIT instruction */ +void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_EIT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +} + +/** Trace the end of the EXE instruction */ +void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_EXE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +} + +/** Trace the end of the JMP instruction */ void tracepoint_static_scheduler_JMP_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_JMP_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_SAC_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} + +/** Trace the end of the SAC instruction */ void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_SAC_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_STP_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} + +/** Trace the end of the STP instruction */ void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_STP_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_WU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} + +/** Trace the end of the WU instruction */ void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_WU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } diff --git a/include/core/threaded/scheduler_instructions.h b/include/core/threaded/scheduler_instructions.h index e9deb431d..1f981d0f6 100644 --- a/include/core/threaded/scheduler_instructions.h +++ b/include/core/threaded/scheduler_instructions.h @@ -3,28 +3,26 @@ * @brief Format of the instruction set * * VM Instruction Set + * - ADDI rs1, rs2, rs3 : [Lock-free] Add to an integer variable (rs2) by an amount (rs3), and store the result in a destination variable (rs1). * - ADV rs1, rs2 : ADVance the logical time of a reactor (rs1) by a specified amount (rs2). Add a delay_until here. * - ADV2 rs1, rs2 : Lock-free version of ADV. The compiler needs to guarantee only a single thread can update a reactor's tag. * - BIT rs1, : (Branch-If-Timeout) Branch to a location (rs1) if all reactors reach timeout. * - DU rs1, rs2 : Delay Until a physical time offset (rs1) wrt the current hyperperiod is reached. * - EIT rs1 : Execute a reaction (rs1) If Triggered. FIXME: Combine with a branch. * - EXE rs1 : EXEcute a reaction (rs1) (used for known triggers such as startup, shutdown, and timers). - * - INC rs1, rs2 : INCrement a counter (rs1) by an amount (rs2). - * - INC2 rs1, rs2 : Lock-free version of INC. The compiler needs to guarantee single writer. * - JMP rs1 : JuMP to a location (rs1). * - SAC : (Sync-Advance-Clear) synchronize all workers until all execute SAC and let the last idle worker reset all counters to 0. * - STP : SToP the execution. * - WU rs1, rs2 : Wait Until a counting variable (rs1) to reach a desired value (rs2). */ typedef enum { + ADDI, ADV, ADV2, BIT, DU, EIT, EXE, - INC, - INC2, JMP, SAC, STP, @@ -32,7 +30,8 @@ typedef enum { } opcode_t; typedef struct inst_t { - opcode_t op; - long long int rs1; - long long int rs2; + opcode_t op; + uint64_t rs1; + uint64_t rs2; + uint64_t rs3; } inst_t; \ No newline at end of file diff --git a/include/core/trace.h b/include/core/trace.h index 58125731f..62de1b746 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -77,26 +77,24 @@ typedef enum scheduler_advancing_time_starts, scheduler_advancing_time_ends, // Static scheduler instructions + static_scheduler_ADDI_starts, static_scheduler_ADV_starts, static_scheduler_ADV2_starts, static_scheduler_BIT_starts, static_scheduler_DU_starts, static_scheduler_EIT_starts, static_scheduler_EXE_starts, - static_scheduler_INC_starts, - static_scheduler_INC2_starts, static_scheduler_JMP_starts, static_scheduler_SAC_starts, static_scheduler_STP_starts, static_scheduler_WU_starts, + static_scheduler_ADDI_ends, static_scheduler_ADV_ends, static_scheduler_ADV2_ends, static_scheduler_BIT_ends, static_scheduler_DU_ends, static_scheduler_EIT_ends, static_scheduler_EXE_ends, - static_scheduler_INC_ends, - static_scheduler_INC2_ends, static_scheduler_JMP_ends, static_scheduler_SAC_ends, static_scheduler_STP_ends, @@ -480,32 +478,29 @@ void tracepoint_scheduler_advancing_time_ends(trace_t* trace); */ void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, int worker); +void tracepoint_static_scheduler_ADDI_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADV2_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_ADV2_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_BIT_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EXE_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_INC_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_INC_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_INC2_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_INC2_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JMP_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_JMP_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_ADDI_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_ADV2_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_JMP_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker, int pc); - /** * Flush any buffered trace records to the trace file and * close the files. @@ -598,29 +593,27 @@ void tracepoint_rti_from_federate(trace_t* trace, trace_event_t event_type, int #define tracepoint_scheduler_advancing_time_starts(...); #define tracepoint_scheduler_advancing_time_ends(...); #define tracepoint_reaction_deadline_missed(...); +#define tracepoint_static_scheduler_ADDI_starts(...); #define tracepoint_static_scheduler_ADV_starts(...); -#define tracepoint_static_scheduler_ADV_ends(...); #define tracepoint_static_scheduler_ADV2_starts(...); -#define tracepoint_static_scheduler_ADV2_ends(...); #define tracepoint_static_scheduler_BIT_starts(...); -#define tracepoint_static_scheduler_BIT_ends(...); #define tracepoint_static_scheduler_DU_starts(...); -#define tracepoint_static_scheduler_DU_ends(...); #define tracepoint_static_scheduler_EIT_starts(...); -#define tracepoint_static_scheduler_EIT_ends(...); #define tracepoint_static_scheduler_EXE_starts(...); -#define tracepoint_static_scheduler_EXE_ends(...); -#define tracepoint_static_scheduler_INC_starts(...); -#define tracepoint_static_scheduler_INC_ends(...); -#define tracepoint_static_scheduler_INC2_starts(...); -#define tracepoint_static_scheduler_INC2_ends(...); #define tracepoint_static_scheduler_JMP_starts(...); -#define tracepoint_static_scheduler_JMP_ends(...); #define tracepoint_static_scheduler_SAC_starts(...); -#define tracepoint_static_scheduler_SAC_ends(...); #define tracepoint_static_scheduler_STP_starts(...); -#define tracepoint_static_scheduler_STP_ends(...); #define tracepoint_static_scheduler_WU_starts(...); +#define tracepoint_static_scheduler_ADDI_ends(...); +#define tracepoint_static_scheduler_ADV_ends(...); +#define tracepoint_static_scheduler_ADV2_ends(...); +#define tracepoint_static_scheduler_BIT_ends(...); +#define tracepoint_static_scheduler_DU_ends(...); +#define tracepoint_static_scheduler_EIT_ends(...); +#define tracepoint_static_scheduler_EXE_ends(...); +#define tracepoint_static_scheduler_JMP_ends(...); +#define tracepoint_static_scheduler_SAC_ends(...); +#define tracepoint_static_scheduler_STP_ends(...); #define tracepoint_static_scheduler_WU_ends(...); #define tracepoint_federate_to_rti(...); #define tracepoint_federate_from_rti(...); From f2cc4817278bf34cf638c0326eb774ce27c43f8e Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Fri, 21 Jul 2023 18:30:39 +0200 Subject: [PATCH 15/80] Update ADV and ADV2 --- core/threaded/scheduler_static.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 098e74f3e..2ac28eec7 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -168,9 +168,10 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, uint64_t // This mutex is quite expensive. lf_mutex_lock(&(scheduler->env->mutex)); + uint64_t *src = (uint64_t *)rs2; self_base_t* reactor = scheduler->reactor_self_instances[rs1]; - reactor->tag.time = hyperperiod * (*iteration) + rs2; + reactor->tag.time = *src + rs3; reactor->tag.microstep = 0; // Reset all "is_present" fields of the output ports of the reactor @@ -205,9 +206,10 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, uint64_t reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { tracepoint_static_scheduler_ADV2_starts(scheduler->env->trace, worker_number, (int) *pc); + uint64_t *src = (uint64_t *)rs2; self_base_t* reactor = scheduler->reactor_self_instances[rs1]; - reactor->tag.time = hyperperiod * (*iteration) + rs2; + reactor->tag.time = *src + rs3; reactor->tag.microstep = 0; // Reset all "is_present" fields of the output ports of the reactor From 321e17c8e103b6de1ffac6aa246063361f665b18 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Mon, 24 Jul 2023 14:24:49 +0200 Subject: [PATCH 16/80] Update comments --- core/threaded/scheduler_static.c | 85 +++---------------- .../core/threaded/scheduler_instructions.h | 6 +- 2 files changed, 14 insertions(+), 77 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 2ac28eec7..2b9c0de34 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -132,15 +132,7 @@ void _lf_sched_wait_for_work( } /** - * @brief ADDI: [Lock-free] Add to an integer variable (rs2) by an amount (rs3), - * and store the result in a destination variable (rs1). - * The compiler needs to guarantee a single writer. - * - * @param rs1 - * @param rs2 - * @param pc - * @param returned_reaction - * @param exit_loop + * @brief The implementation of the ADDI instruction */ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { @@ -153,13 +145,7 @@ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, uint64_t } /** - * @brief ADV: Advance time for a reactor up to a tag (relative to the current hyperperiod). - * - * @param rs1 - * @param rs2 - * @param pc - * @param returned_reaction - * @param exit_loop + * @brief The implementation of the ADV instruction */ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { @@ -194,13 +180,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, uint64_t } /** - * @brief ADV: Advance time for a reactor up to a tag (relative to the current hyperperiod). - * - * @param rs1 - * @param rs2 - * @param pc - * @param returned_reaction - * @param exit_loop + * @brief The implementation of the ADV2 instruction */ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { @@ -230,9 +210,7 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, uint64_t } /** - * @brief BIT: Branch If Timeout - * Check if timeout is reached. If not, don't do anything. - * If so, jump to a specified location (rs1). + * @brief The implementation of the BIT instruction * * FIXME: Should the timeout value be an operand? * FIXME: Use a global variable num_active_reactors instead of iterating over @@ -254,15 +232,7 @@ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t } /** - * @brief EIT: "Execute-If-Triggered" - * Check if the reaction status is "queued." - * If so, return the reaction pointer and advance pc. - * - * @param rs1 - * @param rs2 - * @param pc - * @param returned_reaction - * @param exit_loop + * @brief The implementation of the EIT instruction */ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { @@ -279,13 +249,7 @@ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t } /** - * @brief EXE: Execute a reaction - * - * @param rs1 - * @param rs2 - * @param pc - * @param returned_reaction - * @param exit_loop + * @brief The implementation of the EXE instruction */ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { @@ -298,14 +262,7 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, uint64_t } /** - * @brief DU: Delay Until a physical time offset (rs1) wrt the current hyperperiod is reached. - * - * @param worker_number - * @param rs1 - * @param rs2 - * @param pc - * @param returned_reaction - * @param exit_loop + * @brief The implementation of the DU instruction */ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { @@ -324,13 +281,7 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t r } /** - * @brief WU: Wait until a counting variable reaches a specified value. - * - * @param rs1 - * @param rs2 - * @param pc - * @param returned_reaction - * @param exit_loop + * @brief The implementation of the WU instruction */ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { @@ -343,13 +294,7 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t r } /** - * @brief JMP: Jump to a particular line in the schedule. - * - * @param rs1 - * @param rs2 - * @param pc - * @param returned_reaction - * @param exit_loop + * @brief The implementation of the JMP instruction */ void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { @@ -360,14 +305,7 @@ void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, uint64_t } /** - * @brief SAC: (Sync-Advance-Clear) synchronize all workers until all execute SAC - * and let the last idle worker reset all counters to 0. - * - * @param rs1 - * @param rs2 - * @param pc - * @param returned_reaction - * @param exit_loop + * @brief The implementation of the SAC instruction */ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { @@ -386,8 +324,7 @@ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, uint64_t } /** - * @brief STP: SToP the execution. - * + * @brief The implementation of the STP instruction */ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { diff --git a/include/core/threaded/scheduler_instructions.h b/include/core/threaded/scheduler_instructions.h index 1f981d0f6..f5a7b1112 100644 --- a/include/core/threaded/scheduler_instructions.h +++ b/include/core/threaded/scheduler_instructions.h @@ -4,14 +4,14 @@ * * VM Instruction Set * - ADDI rs1, rs2, rs3 : [Lock-free] Add to an integer variable (rs2) by an amount (rs3), and store the result in a destination variable (rs1). - * - ADV rs1, rs2 : ADVance the logical time of a reactor (rs1) by a specified amount (rs2). Add a delay_until here. + * - ADV rs1, rs2 : ADVance the logical time of a reactor (rs1) based on a variable offset (rs2) plus a fixed time duration (rs3). * - ADV2 rs1, rs2 : Lock-free version of ADV. The compiler needs to guarantee only a single thread can update a reactor's tag. * - BIT rs1, : (Branch-If-Timeout) Branch to a location (rs1) if all reactors reach timeout. - * - DU rs1, rs2 : Delay Until a physical time offset (rs1) wrt the current hyperperiod is reached. + * - DU rs1, rs2 : Delay Until the physical time reaches a variable offset (rs1) plus a fixed time duration (rs2). * - EIT rs1 : Execute a reaction (rs1) If Triggered. FIXME: Combine with a branch. * - EXE rs1 : EXEcute a reaction (rs1) (used for known triggers such as startup, shutdown, and timers). * - JMP rs1 : JuMP to a location (rs1). - * - SAC : (Sync-Advance-Clear) synchronize all workers until all execute SAC and let the last idle worker reset all counters to 0. + * - SAC : (Sync-Advance-Clear) synchronize all workers until all execute SAC, let the last idle worker reset all counters to 0, and advance all reactors' logical time to a variable offset (rs1) plus a fixed time duration (rs2). * - STP : SToP the execution. * - WU rs1, rs2 : Wait Until a counting variable (rs1) to reach a desired value (rs2). */ From 402d1da799abe5abda4116fd1728ce1a1ddd8e48 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Mon, 24 Jul 2023 14:49:14 +0200 Subject: [PATCH 17/80] Remove variables hyperperiod and iteration --- core/threaded/scheduler_static.c | 56 +++++++++++++++----------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 2b9c0de34..b17f6053c 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -53,8 +53,6 @@ extern instant_t start_time; // Global variables defined in schedule.c: extern const inst_t* static_schedules[]; -extern const uint64_t hyperperiod; -extern volatile uint32_t hyperperiod_iterations[]; extern volatile uint32_t counters[]; extern const size_t num_counters; @@ -89,7 +87,7 @@ void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { * scheduler to distribute work. Otherwise, it will wait on * 'scheduler->semaphore'. * This implementation of _lf_sched_wait_for_work also takes on the role of - * advancing time for all reactors at the end of the hyperperiod. + * advancing time for all reactors at the end of a hyperperiod. * * @param worker_number The worker number of the worker thread asking for work * to be assigned to it. @@ -135,7 +133,7 @@ void _lf_sched_wait_for_work( * @brief The implementation of the ADDI instruction */ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, (int) *pc); uint64_t *dst = (uint64_t *) rs1; uint64_t *src = (uint64_t *) rs2; @@ -148,7 +146,7 @@ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, uint64_t * @brief The implementation of the ADV instruction */ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number, (int) *pc); // This mutex is quite expensive. @@ -183,7 +181,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, uint64_t * @brief The implementation of the ADV2 instruction */ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_ADV2_starts(scheduler->env->trace, worker_number, (int) *pc); uint64_t *src = (uint64_t *)rs2; @@ -217,7 +215,7 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, uint64_t * a for loop. */ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); bool stop = true; for (int i = 0; i < scheduler->num_reactor_self_instances; i++) { @@ -235,7 +233,7 @@ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t * @brief The implementation of the EIT instruction */ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_EIT_starts(scheduler->env->trace, worker_number, (int) *pc); reaction_t* reaction = scheduler->reaction_instances[rs1]; if (reaction->status == queued) { @@ -252,7 +250,7 @@ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t * @brief The implementation of the EXE instruction */ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, worker_number, (int) *pc); reaction_t* reaction = scheduler->reaction_instances[rs1]; *returned_reaction = reaction; @@ -265,14 +263,14 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, uint64_t * @brief The implementation of the DU instruction */ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_DU_starts(scheduler->env->trace, worker_number, (int) *pc); // FIXME: There seems to be an overflow problem. // When wakeup_time overflows but lf_time_physical() doesn't, // _lf_interruptable_sleep_until_locked() terminates immediately. uint64_t *src = (uint64_t *)rs1; instant_t wakeup_time = start_time + *src + rs2; - LF_PRINT_DEBUG("start_time: %lld, wakeup_time: %lld, rs1: %lld, iteration: %d, current_physical_time: %lld, hyperperiod: %lld\n", start_time, wakeup_time, rs1, (*iteration), lf_time_physical(), hyperperiod); + LF_PRINT_DEBUG("start_time: %lld, wakeup_time: %lld, rs1: %lld, current_physical_time: %lld\n", start_time, wakeup_time, rs1, lf_time_physical()); LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); @@ -284,7 +282,7 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t r * @brief The implementation of the WU instruction */ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, (int) *pc); LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); while(scheduler->counters[rs1] < rs2); @@ -297,9 +295,8 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t r * @brief The implementation of the JMP instruction */ void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_JMP_starts(scheduler->env->trace, worker_number, (int) *pc); - if (rs2 != -1) *iteration += 1; *pc = rs1; tracepoint_static_scheduler_JMP_ends(scheduler->env->trace, worker_number, (int) *pc); } @@ -308,7 +305,7 @@ void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, uint64_t * @brief The implementation of the SAC instruction */ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_SAC_starts(scheduler->env->trace, worker_number, (int) *pc); // Compute the next tag for all reactors. @@ -327,7 +324,7 @@ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, uint64_t * @brief The implementation of the STP instruction */ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_STP_starts(scheduler->env->trace, worker_number, (int) *pc); *exit_loop = true; tracepoint_static_scheduler_STP_ends(scheduler->env->trace, worker_number, (int) *pc); @@ -347,52 +344,52 @@ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, uint64_t * the outer while loop should be exited */ void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t op, uint64_t rs1, uint64_t rs2, uint64_t rs3, - size_t* pc, reaction_t** returned_reaction, bool* exit_loop, volatile uint32_t* iteration) { + size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { char* op_str = NULL; switch (op) { case ADDI: op_str = "ADDI"; - execute_inst_ADDI(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); + execute_inst_ADDI(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case ADV: op_str = "ADV"; - execute_inst_ADV(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); + execute_inst_ADV(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case ADV2: op_str = "ADV2"; - execute_inst_ADV2(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); + execute_inst_ADV2(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case BIT: op_str = "BIT"; - execute_inst_BIT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); + execute_inst_BIT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case DU: op_str = "DU"; - execute_inst_DU(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); + execute_inst_DU(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case EIT: op_str = "EIT"; - execute_inst_EIT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); + execute_inst_EIT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case EXE: op_str = "EXE"; - execute_inst_EXE(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); + execute_inst_EXE(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case JMP: op_str = "JMP"; - execute_inst_JMP(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); + execute_inst_JMP(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case SAC: op_str = "SAC"; - execute_inst_SAC(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); + execute_inst_SAC(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case STP: op_str = "STP"; - execute_inst_STP(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); + execute_inst_STP(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case WU: op_str = "WU"; - execute_inst_WU(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop, iteration); + execute_inst_WU(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; default: lf_print_error_and_exit("Invalid instruction: %d", op); @@ -485,7 +482,6 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu uint64_t rs1; uint64_t rs2; uint64_t rs3; - volatile uint32_t* iteration = &hyperperiod_iterations[worker_number]; while (!exit_loop) { op = current_schedule[*pc].op; @@ -495,7 +491,7 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu // Execute the current instruction execute_inst(scheduler, worker_number, op, rs1, rs2, rs3, pc, - &returned_reaction, &exit_loop, iteration); + &returned_reaction, &exit_loop); LF_PRINT_DEBUG("Worker %d: returned_reaction = %p, exit_loop = %d", worker_number, returned_reaction, exit_loop); From e606e51905d56229c6f7686c63042fa821b51eff Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Mon, 24 Jul 2023 16:38:00 +0200 Subject: [PATCH 18/80] Fix BIT --- core/threaded/scheduler_static.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index b17f6053c..cb8c6d05b 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -44,6 +44,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "scheduler_sync_tag_advance.h" #include "scheduler.h" #include "semaphore.h" +#include "tag.h" #include "trace.h" #include "util.h" @@ -54,9 +55,23 @@ extern instant_t start_time; // Global variables defined in schedule.c: extern const inst_t* static_schedules[]; extern volatile uint32_t counters[]; +extern volatile instant_t offsets[]; extern const size_t num_counters; /////////////////// Scheduler Private API ///////////////////////// +/** + * @brief Check if a given tag reaches the specified stop tag. If so, mark it in + * a reactor_reached_stop_tag array in the scheduler struct. + */ +void _check_if_tag_reaches_stop_tag(lf_scheduler_t* scheduler, tag_t tag, int reactor_index) { + LF_PRINT_DEBUG("Scheduler: Reactor tag: %lld, stop_tag: %lld", tag.time, scheduler->env->stop_tag.time); + if (_lf_is_tag_after_stop_tag(scheduler->env, tag)) { + scheduler->reactor_reached_stop_tag[reactor_index] = true; + } else { + LF_PRINT_DEBUG("Scheduler: NOT updating the array."); + } +} + /** * @brief If there is work to be done, notify workers individually. * @@ -109,9 +124,11 @@ void _lf_sched_wait_for_work( worker_number); // The last worker advances all reactors to the next tag. + // Also check if the new tag reaches the stop tag. for (int j = 0; j < scheduler->num_reactor_self_instances; j++) { scheduler->reactor_self_instances[j]->tag.time = next_timestamp; scheduler->reactor_self_instances[j]->tag.microstep = 0; + _check_if_tag_reaches_stop_tag(scheduler, scheduler->reactor_self_instances[j]->tag, j); } // The last worker clears all the counters. @@ -137,6 +154,7 @@ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, uint64_t tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, (int) *pc); uint64_t *dst = (uint64_t *) rs1; uint64_t *src = (uint64_t *) rs2; + // FIXME: Will there be problems if instant_t adds uint64_t? *dst = *src + rs3; *pc += 1; // Increment pc. tracepoint_static_scheduler_ADDI_ends(scheduler->env->trace, worker_number, (int) *pc); @@ -166,9 +184,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, uint64_t reactor->output_ports[i]->is_present = false; } - if (_lf_is_tag_after_stop_tag(scheduler->env, reactor->tag)) { - scheduler->reactor_reached_stop_tag[rs1] = true; - } + _check_if_tag_reaches_stop_tag(scheduler, reactor->tag, rs1); lf_mutex_unlock(&(scheduler->env->mutex)); @@ -198,9 +214,7 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, uint64_t reactor->output_ports[i]->is_present = false; } - if (_lf_is_tag_after_stop_tag(scheduler->env, reactor->tag)) { - scheduler->reactor_reached_stop_tag[rs1] = true; - } + _check_if_tag_reaches_stop_tag(scheduler, reactor->tag, rs1); *pc += 1; // Increment pc. @@ -269,7 +283,7 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t r // When wakeup_time overflows but lf_time_physical() doesn't, // _lf_interruptable_sleep_until_locked() terminates immediately. uint64_t *src = (uint64_t *)rs1; - instant_t wakeup_time = start_time + *src + rs2; + instant_t wakeup_time = *src + rs2; LF_PRINT_DEBUG("start_time: %lld, wakeup_time: %lld, rs1: %lld, current_physical_time: %lld\n", start_time, wakeup_time, rs1, lf_time_physical()); LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); @@ -430,6 +444,7 @@ void lf_sched_init( // Initialize the local tags for the STATIC scheduler. for (int i = 0; i < env->scheduler->num_reactor_self_instances; i++) { + offsets[i] = start_time; // Initialize offsets here. env->scheduler->reactor_self_instances[i]->tag.time = start_time; env->scheduler->reactor_self_instances[i]->tag.microstep = 0; } From f669991cdd756d5d294a3fcfb5cae13b370159a3 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Tue, 25 Jul 2023 00:00:47 +0200 Subject: [PATCH 19/80] Fix tracing --- include/core/trace.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/core/trace.h b/include/core/trace.h index 62de1b746..dc269d955 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -163,26 +163,24 @@ static const char *trace_event_names[] = { "Scheduler advancing time starts", "Scheduler advancing time ends", // Static scheduler instructions + "ADDI: add immediate", "ADV: advance logical time", "ADV2: advance logical time (lock-free)", "BIT: branch if timeout", "DU: delay until", "EIT: execute if triggered", "EXE: execute", - "INC: increment counter", - "INC2: increment counter (lock-free)", "JMP: jump", "SAC: synchronize, advance time, and clear counters", "STP: stop", "WU: wait until", + "End ADDI: add immediate", "End ADV: advance logical time", "End ADV2: advance logical time (lock-free)", "End BIT: branch if timeout", "End DU: delay until", "End EIT: execute if triggered", "End EXE: execute", - "End INC: increment counter", - "End INC2: increment counter (lock-free)", "End JMP: jump", "End SAC: synchronize, advance time, and clear counters", "End STP: stop", From 26bb4af2b79a72c5c46551eab24d4d0e20306886 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Tue, 25 Jul 2023 16:25:58 +0200 Subject: [PATCH 20/80] Fix a bug when initializing time offsets --- core/threaded/scheduler_static.c | 8 ++++++-- include/api/set.h | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index cb8c6d05b..66507a319 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -55,7 +55,7 @@ extern instant_t start_time; // Global variables defined in schedule.c: extern const inst_t* static_schedules[]; extern volatile uint32_t counters[]; -extern volatile instant_t offsets[]; +extern volatile instant_t time_offsets[]; extern const size_t num_counters; /////////////////// Scheduler Private API ///////////////////////// @@ -444,11 +444,15 @@ void lf_sched_init( // Initialize the local tags for the STATIC scheduler. for (int i = 0; i < env->scheduler->num_reactor_self_instances; i++) { - offsets[i] = start_time; // Initialize offsets here. env->scheduler->reactor_self_instances[i]->tag.time = start_time; env->scheduler->reactor_self_instances[i]->tag.microstep = 0; } + // Initialize time_offsets for each worker. + for (int i = 0; i < number_of_workers; i++) { + time_offsets[i] = start_time; + } + // Already initialized return; } diff --git a/include/api/set.h b/include/api/set.h index 2c95cf187..bac62a06b 100644 --- a/include/api/set.h +++ b/include/api/set.h @@ -217,7 +217,7 @@ do { \ // of the current reactor. // The fully static (STATIC) runtime, uses time local to each reactor. If this is the case -// then we defined these macros to acces that timestamp rather than using the standard API +// then we defined these macros to access that timestamp rather than using the standard API // FIXME (erj): I am not really stoked about this added complexity #if defined REACTOR_LOCAL_TIME #define lf_tag() self->base.tag From 2387ae61aadf7a99664b67de1334e07e04ca2f7a Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sun, 6 Aug 2023 11:36:08 +0200 Subject: [PATCH 21/80] Fix race condition by removing the reactor_reached_stop_tag array since its updates are not atomic for some reason --- core/threaded/scheduler_static.c | 35 ++++++++++------------ include/core/threaded/scheduler_instance.h | 8 ----- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 66507a319..fff4c95a9 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @author{Shaokai Lin } */ +#include #include "lf_types.h" #if SCHEDULER == STATIC || (!defined(SCHEDULER) && defined(LF_THREADED)) #ifndef NUMBER_OF_WORKERS @@ -59,18 +60,6 @@ extern volatile instant_t time_offsets[]; extern const size_t num_counters; /////////////////// Scheduler Private API ///////////////////////// -/** - * @brief Check if a given tag reaches the specified stop tag. If so, mark it in - * a reactor_reached_stop_tag array in the scheduler struct. - */ -void _check_if_tag_reaches_stop_tag(lf_scheduler_t* scheduler, tag_t tag, int reactor_index) { - LF_PRINT_DEBUG("Scheduler: Reactor tag: %lld, stop_tag: %lld", tag.time, scheduler->env->stop_tag.time); - if (_lf_is_tag_after_stop_tag(scheduler->env, tag)) { - scheduler->reactor_reached_stop_tag[reactor_index] = true; - } else { - LF_PRINT_DEBUG("Scheduler: NOT updating the array."); - } -} /** * @brief If there is work to be done, notify workers individually. @@ -128,7 +117,6 @@ void _lf_sched_wait_for_work( for (int j = 0; j < scheduler->num_reactor_self_instances; j++) { scheduler->reactor_self_instances[j]->tag.time = next_timestamp; scheduler->reactor_self_instances[j]->tag.microstep = 0; - _check_if_tag_reaches_stop_tag(scheduler, scheduler->reactor_self_instances[j]->tag, j); } // The last worker clears all the counters. @@ -183,8 +171,6 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, uint64_t for (int i = 0; inum_output_ports; i++) { reactor->output_ports[i]->is_present = false; } - - _check_if_tag_reaches_stop_tag(scheduler, reactor->tag, rs1); lf_mutex_unlock(&(scheduler->env->mutex)); @@ -213,8 +199,6 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, uint64_t for (int i = 0; inum_output_ports; i++) { reactor->output_ports[i]->is_present = false; } - - _check_if_tag_reaches_stop_tag(scheduler, reactor->tag, rs1); *pc += 1; // Increment pc. @@ -226,14 +210,15 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, uint64_t * * FIXME: Should the timeout value be an operand? * FIXME: Use a global variable num_active_reactors instead of iterating over - * a for loop. + * a for loop. The current implementation is very inefficient. */ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); bool stop = true; for (int i = 0; i < scheduler->num_reactor_self_instances; i++) { - if (!scheduler->reactor_reached_stop_tag[i]) { + if (!_lf_is_tag_after_stop_tag(scheduler->env, scheduler->reactor_self_instances[i]->tag)) { + LF_PRINT_DEBUG("*** Worker %zu: reactor %d has not reached stop tag: (%lld, %u)", worker_number, i, scheduler->reactor_self_instances[i]->tag.time, scheduler->reactor_self_instances[i]->tag.microstep); stop = false; break; } @@ -363,46 +348,57 @@ void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t op, switch (op) { case ADDI: op_str = "ADDI"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_ADDI(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case ADV: op_str = "ADV"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_ADV(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case ADV2: op_str = "ADV2"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_ADV2(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case BIT: op_str = "BIT"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_BIT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case DU: op_str = "DU"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_DU(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case EIT: op_str = "EIT"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_EIT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case EXE: op_str = "EXE"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_EXE(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case JMP: op_str = "JMP"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_JMP(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case SAC: op_str = "SAC"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_SAC(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case STP: op_str = "STP"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_STP(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case WU: op_str = "WU"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_WU(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; default: @@ -462,7 +458,6 @@ void lf_sched_init( env->scheduler->reaction_instances = params->reaction_instances; env->scheduler->reactor_self_instances = params->reactor_self_instances; env->scheduler->num_reactor_self_instances = params->num_reactor_self_instances; - env->scheduler->reactor_reached_stop_tag = params->reactor_reached_stop_tag; env->scheduler->counters = counters; } diff --git a/include/core/threaded/scheduler_instance.h b/include/core/threaded/scheduler_instance.h index 9deda1755..b6c0be001 100644 --- a/include/core/threaded/scheduler_instance.h +++ b/include/core/threaded/scheduler_instance.h @@ -172,13 +172,6 @@ typedef struct lf_scheduler_t { */ size_t num_reactor_self_instances; - /** - * @brief Points to an array of bools indicating whether - * a reactor reaches stop. - * - */ - bool* reactor_reached_stop_tag; - /** * @brief Points to an array of pointers to reaction instances. * @@ -216,7 +209,6 @@ typedef struct { #if SCHEDULER == STATIC struct self_base_t** reactor_self_instances; size_t num_reactor_self_instances; - bool* reactor_reached_stop_tag; reaction_t** reaction_instances; #endif } sched_params_t; From 0ffbcc49c71aaf88956201a2f973b7939467ddf9 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Thu, 10 Aug 2023 16:50:10 +0200 Subject: [PATCH 22/80] Add branch instructions and no longer initialize offsets when initializing the scheduler. --- core/threaded/scheduler_static.c | 83 +++++++++++++++++-- .../core/threaded/scheduler_instructions.h | 30 ++++--- 2 files changed, 96 insertions(+), 17 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index fff4c95a9..e58640d25 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -205,6 +205,36 @@ void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, uint64_t tracepoint_static_scheduler_ADV2_ends(scheduler->env->trace, worker_number, (int) *pc); } +/** + * @brief The implementation of the BEQ instruction + */ +void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop) { + // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); + uint64_t *_rs1 = (uint64_t *) rs1; + uint64_t *_rs2 = (uint64_t *) rs2; + if (*_rs1 == *_rs2) *pc = rs3; + else *pc += 1; + // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); +} + +/** + * @brief The implementation of the BGE instruction + * + * FIXME: This is incorrect right now. BGE should always be checking between + * two registers. Timeout value should be stored in a separate register. + */ +void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop) { + // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); + uint64_t *_rs1 = (uint64_t *) rs1; + uint64_t *_rs2 = (uint64_t *) rs2; + printf("*** rs1: %lld, rs2: %lld, rs3: %lld\n", *_rs1, *_rs2, rs3); + if (*_rs1 >= *_rs2) *pc = rs3; + else *pc += 1; + // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); +} + /** * @brief The implementation of the BIT instruction * @@ -228,6 +258,32 @@ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } +/** + * @brief The implementation of the BLT instruction + */ +void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop) { + // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); + uint64_t *_rs1 = (uint64_t *) rs1; + uint64_t *_rs2 = (uint64_t *) rs2; + if (*_rs1 < *_rs2) *pc = rs3; + else *pc += 1; + // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); +} + +/** + * @brief The implementation of the BNE instruction + */ +void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop) { + // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); + uint64_t *_rs1 = (uint64_t *) rs1; + uint64_t *_rs2 = (uint64_t *) rs2; + if (*_rs1 != *_rs2) *pc = rs3; + else *pc += 1; + // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); +} + /** * @brief The implementation of the EIT instruction */ @@ -361,12 +417,32 @@ void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t op, LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_ADV2(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; + case BEQ: + op_str = "BEQ"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); + execute_inst_BEQ(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + break; + case BGE: + op_str = "BGE"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); + execute_inst_BGE(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + break; case BIT: op_str = "BIT"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_BIT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; - case DU: + case BLT: + op_str = "BLT"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); + execute_inst_BLT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + break; + case BNE: + op_str = "BNE"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); + execute_inst_BNE(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + break; + case DU: op_str = "DU"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_DU(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); @@ -444,11 +520,6 @@ void lf_sched_init( env->scheduler->reactor_self_instances[i]->tag.microstep = 0; } - // Initialize time_offsets for each worker. - for (int i = 0; i < number_of_workers; i++) { - time_offsets[i] = start_time; - } - // Already initialized return; } diff --git a/include/core/threaded/scheduler_instructions.h b/include/core/threaded/scheduler_instructions.h index f5a7b1112..820b6391c 100644 --- a/include/core/threaded/scheduler_instructions.h +++ b/include/core/threaded/scheduler_instructions.h @@ -3,23 +3,31 @@ * @brief Format of the instruction set * * VM Instruction Set - * - ADDI rs1, rs2, rs3 : [Lock-free] Add to an integer variable (rs2) by an amount (rs3), and store the result in a destination variable (rs1). - * - ADV rs1, rs2 : ADVance the logical time of a reactor (rs1) based on a variable offset (rs2) plus a fixed time duration (rs3). - * - ADV2 rs1, rs2 : Lock-free version of ADV. The compiler needs to guarantee only a single thread can update a reactor's tag. - * - BIT rs1, : (Branch-If-Timeout) Branch to a location (rs1) if all reactors reach timeout. - * - DU rs1, rs2 : Delay Until the physical time reaches a variable offset (rs1) plus a fixed time duration (rs2). - * - EIT rs1 : Execute a reaction (rs1) If Triggered. FIXME: Combine with a branch. - * - EXE rs1 : EXEcute a reaction (rs1) (used for known triggers such as startup, shutdown, and timers). - * - JMP rs1 : JuMP to a location (rs1). - * - SAC : (Sync-Advance-Clear) synchronize all workers until all execute SAC, let the last idle worker reset all counters to 0, and advance all reactors' logical time to a variable offset (rs1) plus a fixed time duration (rs2). - * - STP : SToP the execution. - * - WU rs1, rs2 : Wait Until a counting variable (rs1) to reach a desired value (rs2). + * ADDI rs1, rs2, rs3 : [Lock-free] Add to an integer variable (rs2) by an amount (rs3), and store the result in a destination variable (rs1). + * ADV rs1, rs2 : ADVance the logical time of a reactor (rs1) based on a variable offset (rs2) plus a fixed time duration (rs3). + * ADV2 rs1, rs2 : Lock-free version of ADV. The compiler needs to guarantee only a single thread can update a reactor's tag. + * BEQ rs1, rs2, rs3 : Take the branch (rs3) if rs1 is equal to rs2. + * BGE rs1, rs2, rs3 : Take the branch (rs3) if rs1 is greater than or equal to rs2. + * BIT rs1, : (Branch-If-Timeout) Branch to a location (rs1) if all reactors reach timeout. + * BLT rs1, rs2, rs3: Take the branch (rs3) if rs1 is less than rs2. + * BNE rs1, rs2, rs3 : Take the branch (rs3) if rs1 is not equal to rs2. + * DU rs1, rs2 : Delay Until the physical time reaches a variable offset (rs1) plus a fixed time duration (rs2). + * EIT rs1 : Execute a reaction (rs1) If Triggered. FIXME: Combine with a branch. + * EXE rs1 : EXEcute a reaction (rs1) (used for known triggers such as startup, shutdown, and timers). + * JMP rs1 : JuMP to a location (rs1). + * SAC : (Sync-Advance-Clear) synchronize all workers until all execute SAC, let the last idle worker reset all counters to 0, and advance all reactors' logical time to a variable offset (rs1) plus a fixed time duration (rs2). + * STP : SToP the execution. + * WU rs1, rs2 : Wait Until a counting variable (rs1) to reach a desired value (rs2). */ typedef enum { ADDI, ADV, ADV2, + BEQ, + BGE, BIT, + BLT, + BNE, DU, EIT, EXE, From fc5fb2b007c4044536194c388def295ff17d1162 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Mon, 14 Aug 2023 15:33:34 +0200 Subject: [PATCH 23/80] Remove debug message --- core/threaded/scheduler_static.c | 1 - 1 file changed, 1 deletion(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index e58640d25..61046c99c 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -229,7 +229,6 @@ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, uint64_t // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); uint64_t *_rs1 = (uint64_t *) rs1; uint64_t *_rs2 = (uint64_t *) rs2; - printf("*** rs1: %lld, rs2: %lld, rs3: %lld\n", *_rs1, *_rs2, rs3); if (*_rs1 >= *_rs2) *pc = rs3; else *pc += 1; // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); From 2d3c89c6ac3001d381bce648fb9caea14cdc1911 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Tue, 22 Aug 2023 14:43:28 +0200 Subject: [PATCH 24/80] Add ADD, ADVI, JAL, JALR, and WLT instructions to deprecate SAC. --- core/threaded/scheduler_static.c | 138 +++++++++++++----- core/trace.c | 24 +-- .../core/threaded/scheduler_instructions.h | 24 +-- include/core/trace.h | 32 ++-- 4 files changed, 135 insertions(+), 83 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 61046c99c..688febea8 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -55,9 +55,14 @@ extern instant_t start_time; // Global variables defined in schedule.c: extern const inst_t* static_schedules[]; -extern volatile uint32_t counters[]; -extern volatile instant_t time_offsets[]; +extern volatile uint64_t timeout; extern const size_t num_counters; +extern volatile uint64_t time_offset; +extern volatile uint64_t offset_inc; +extern const uint64_t zero; +extern volatile uint32_t counters[]; +extern volatile uint64_t return_addr[]; +extern volatile uint64_t binary_sema[]; /////////////////// Scheduler Private API ///////////////////////// @@ -134,6 +139,20 @@ void _lf_sched_wait_for_work( } } +/** + * @brief The implementation of the ADD instruction + */ +void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop) { + // tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, (int) *pc); + uint64_t *dst = (uint64_t *) rs1; + uint64_t *src = (uint64_t *) rs2; + uint64_t *src2 = (uint64_t *) rs3; + *dst = *src + *src2; + *pc += 1; // Increment pc. + // tracepoint_static_scheduler_ADDI_ends(scheduler->env->trace, worker_number, (int) *pc); +} + /** * @brief The implementation of the ADDI instruction */ @@ -155,24 +174,20 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, uint64_t reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number, (int) *pc); - // This mutex is quite expensive. - lf_mutex_lock(&(scheduler->env->mutex)); - - uint64_t *src = (uint64_t *)rs2; + uint64_t *base = (uint64_t *)rs2; + uint64_t *inc = (uint64_t *)rs3; self_base_t* reactor = scheduler->reactor_self_instances[rs1]; - reactor->tag.time = *src + rs3; + reactor->tag.time = *base + *inc; reactor->tag.microstep = 0; // Reset all "is_present" fields of the output ports of the reactor - // Doing this here has the major implicatio that ADV has to execute AFTER - // all downstream reactions have finished. Since it is modifying state that is - // visible to thos reactions. - for (int i = 0; inum_output_ports; i++) { + // Doing this here has the major implication that ADV has to execute AFTER + // all downstream reactions have finished, since it is modifying state that is + // visible to those reactions. + for (int i = 0; i < reactor->num_output_ports; i++) { reactor->output_ports[i]->is_present = false; } - - lf_mutex_unlock(&(scheduler->env->mutex)); *pc += 1; // Increment pc. @@ -180,29 +195,29 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, uint64_t } /** - * @brief The implementation of the ADV2 instruction + * @brief The implementation of the ADVI instruction */ -void execute_inst_ADV2(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_ADV2_starts(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_ADVI_starts(scheduler->env->trace, worker_number, (int) *pc); - uint64_t *src = (uint64_t *)rs2; + uint64_t *base = (uint64_t *)rs2; self_base_t* reactor = scheduler->reactor_self_instances[rs1]; - reactor->tag.time = *src + rs3; + reactor->tag.time = *base + rs3; reactor->tag.microstep = 0; // Reset all "is_present" fields of the output ports of the reactor - // Doing this here has the major implicatio that ADV has to execute AFTER - // all downstream reactions have finished. Since it is modifying state that is - // visible to thos reactions. - for (int i = 0; inum_output_ports; i++) { + // Doing this here has the major implication that ADV has to execute AFTER + // all downstream reactions have finished, since it is modifying state that is + // visible to those reactions. + for (int i = 0; i < reactor->num_output_ports; i++) { reactor->output_ports[i]->is_present = false; } *pc += 1; // Increment pc. - tracepoint_static_scheduler_ADV2_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_ADVI_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -229,6 +244,7 @@ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, uint64_t // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); uint64_t *_rs1 = (uint64_t *) rs1; uint64_t *_rs2 = (uint64_t *) rs2; + LF_PRINT_DEBUG("Worker %zu: BGE : operand 1 = %lld, operand 2 = %lld", worker_number, *_rs1, *_rs2); if (*_rs1 >= *_rs2) *pc = rs3; else *pc += 1; // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); @@ -324,7 +340,7 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t r // _lf_interruptable_sleep_until_locked() terminates immediately. uint64_t *src = (uint64_t *)rs1; instant_t wakeup_time = *src + rs2; - LF_PRINT_DEBUG("start_time: %lld, wakeup_time: %lld, rs1: %lld, current_physical_time: %lld\n", start_time, wakeup_time, rs1, lf_time_physical()); + LF_PRINT_DEBUG("start_time: %lld, wakeup_time: %lld, rs1: %lld, rs2: %lld, current_physical_time: %lld\n", start_time, wakeup_time, *src, rs2, lf_time_physical()); LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); @@ -332,6 +348,20 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t r tracepoint_static_scheduler_DU_ends(scheduler->env->trace, worker_number, (int) *pc); } +/** + * @brief The implementation of the WLT instruction + */ +void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop) { + // tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, (int) *pc); + LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); + volatile uint64_t *var = (volatile uint64_t *)rs1; + while(*var >= rs2); + LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); + *pc += 1; // Increment pc. + // tracepoint_static_scheduler_WU_ends(scheduler->env->trace, worker_number, (int) *pc); +} + /** * @brief The implementation of the WU instruction */ @@ -339,20 +369,41 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t r reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, (int) *pc); LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); - while(scheduler->counters[rs1] < rs2); + volatile uint64_t *var = (volatile uint64_t *)rs1; + while(*var < rs2); LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); *pc += 1; // Increment pc. tracepoint_static_scheduler_WU_ends(scheduler->env->trace, worker_number, (int) *pc); } /** - * @brief The implementation of the JMP instruction + * @brief The implementation of the JAL instruction */ -void execute_inst_JMP(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_JMP_starts(scheduler->env->trace, worker_number, (int) *pc); - *pc = rs1; - tracepoint_static_scheduler_JMP_ends(scheduler->env->trace, worker_number, (int) *pc); + // tracepoint_static_scheduler_JAL_starts(scheduler->env->trace, worker_number, (int) *pc); + // Use the destination register as the return address and, if the + // destination register is not the zero register, store pc+1 in it. + uint64_t *destReg = (uint64_t *)rs1; + if (destReg != &zero) *destReg = *pc + 1; + *pc = rs2; + // tracepoint_static_scheduler_JAL_ends(scheduler->env->trace, worker_number, (int) *pc); +} + +/** + * @brief The implementation of the JALR instruction + */ +void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop) { + // tracepoint_static_scheduler_JALR_starts(scheduler->env->trace, worker_number, (int) *pc); + // Use the destination register as the return address and, if the + // destination register is not the zero register, store pc+1 in it. + uint64_t *destReg = (uint64_t *)rs1; + if (destReg != &zero) *destReg = *pc + 1; + // Set pc to base addr + immediate. + uint64_t *baseAddr = (uint64_t *)rs2; + *pc = *baseAddr + rs3; + // tracepoint_static_scheduler_JALR_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -401,6 +452,11 @@ void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t op, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { char* op_str = NULL; switch (op) { + case ADD: + op_str = "ADD"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); + execute_inst_ADD(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + break; case ADDI: op_str = "ADDI"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); @@ -411,10 +467,10 @@ void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t op, LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_ADV(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; - case ADV2: - op_str = "ADV2"; + case ADVI: + op_str = "ADVI"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_ADV2(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + execute_inst_ADVI(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case BEQ: op_str = "BEQ"; @@ -456,10 +512,15 @@ void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t op, LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_EXE(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; - case JMP: - op_str = "JMP"; + case JAL: + op_str = "JAL"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_JMP(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + execute_inst_JAL(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + break; + case JALR: + op_str = "JALR"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); + execute_inst_JALR(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; case SAC: op_str = "SAC"; @@ -471,6 +532,11 @@ void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t op, LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); execute_inst_STP(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); break; + case WLT: + op_str = "WLT"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); + execute_inst_WLT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + break; case WU: op_str = "WU"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); diff --git a/core/trace.c b/core/trace.c index fac833f9a..992e81214 100644 --- a/core/trace.c +++ b/core/trace.c @@ -467,9 +467,9 @@ void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker, int pc) tracepoint(trace, static_scheduler_ADV_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -/** Trace the start of the ADV2 instruction */ -void tracepoint_static_scheduler_ADV2_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADV2_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +/** Trace the start of the ADVI instruction */ +void tracepoint_static_scheduler_ADVI_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_ADVI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } /** Trace the start of the BIT instruction */ @@ -492,9 +492,9 @@ void tracepoint_static_scheduler_EXE_starts(trace_t* trace, int worker, int pc) tracepoint(trace, static_scheduler_EXE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -/** Trace the start of the JMP instruction */ -void tracepoint_static_scheduler_JMP_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_JMP_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +/** Trace the start of the JAL instruction */ +void tracepoint_static_scheduler_JAL_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_JAL_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } /** Trace the start of the SAC instruction */ @@ -522,9 +522,9 @@ void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_ADV_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -/** Trace the end of the ADV2 instruction */ -void tracepoint_static_scheduler_ADV2_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADV2_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +/** Trace the end of the ADVI instruction */ +void tracepoint_static_scheduler_ADVI_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_ADVI_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } /** Trace the end of the BIT instruction */ @@ -547,9 +547,9 @@ void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_EXE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -/** Trace the end of the JMP instruction */ -void tracepoint_static_scheduler_JMP_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_JMP_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +/** Trace the end of the JAL instruction */ +void tracepoint_static_scheduler_JAL_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_JAL_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } /** Trace the end of the SAC instruction */ diff --git a/include/core/threaded/scheduler_instructions.h b/include/core/threaded/scheduler_instructions.h index 820b6391c..6bcc3902e 100644 --- a/include/core/threaded/scheduler_instructions.h +++ b/include/core/threaded/scheduler_instructions.h @@ -1,28 +1,12 @@ /** * @author Shaokai Lin * @brief Format of the instruction set - * - * VM Instruction Set - * ADDI rs1, rs2, rs3 : [Lock-free] Add to an integer variable (rs2) by an amount (rs3), and store the result in a destination variable (rs1). - * ADV rs1, rs2 : ADVance the logical time of a reactor (rs1) based on a variable offset (rs2) plus a fixed time duration (rs3). - * ADV2 rs1, rs2 : Lock-free version of ADV. The compiler needs to guarantee only a single thread can update a reactor's tag. - * BEQ rs1, rs2, rs3 : Take the branch (rs3) if rs1 is equal to rs2. - * BGE rs1, rs2, rs3 : Take the branch (rs3) if rs1 is greater than or equal to rs2. - * BIT rs1, : (Branch-If-Timeout) Branch to a location (rs1) if all reactors reach timeout. - * BLT rs1, rs2, rs3: Take the branch (rs3) if rs1 is less than rs2. - * BNE rs1, rs2, rs3 : Take the branch (rs3) if rs1 is not equal to rs2. - * DU rs1, rs2 : Delay Until the physical time reaches a variable offset (rs1) plus a fixed time duration (rs2). - * EIT rs1 : Execute a reaction (rs1) If Triggered. FIXME: Combine with a branch. - * EXE rs1 : EXEcute a reaction (rs1) (used for known triggers such as startup, shutdown, and timers). - * JMP rs1 : JuMP to a location (rs1). - * SAC : (Sync-Advance-Clear) synchronize all workers until all execute SAC, let the last idle worker reset all counters to 0, and advance all reactors' logical time to a variable offset (rs1) plus a fixed time duration (rs2). - * STP : SToP the execution. - * WU rs1, rs2 : Wait Until a counting variable (rs1) to reach a desired value (rs2). */ typedef enum { + ADD, ADDI, ADV, - ADV2, + ADVI, BEQ, BGE, BIT, @@ -31,9 +15,11 @@ typedef enum { DU, EIT, EXE, - JMP, + JAL, + JALR, SAC, STP, + WLT, WU, } opcode_t; diff --git a/include/core/trace.h b/include/core/trace.h index dc269d955..ca04c7047 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -79,23 +79,23 @@ typedef enum // Static scheduler instructions static_scheduler_ADDI_starts, static_scheduler_ADV_starts, - static_scheduler_ADV2_starts, + static_scheduler_ADVI_starts, static_scheduler_BIT_starts, static_scheduler_DU_starts, static_scheduler_EIT_starts, static_scheduler_EXE_starts, - static_scheduler_JMP_starts, + static_scheduler_JAL_starts, static_scheduler_SAC_starts, static_scheduler_STP_starts, static_scheduler_WU_starts, static_scheduler_ADDI_ends, static_scheduler_ADV_ends, - static_scheduler_ADV2_ends, + static_scheduler_ADVI_ends, static_scheduler_BIT_ends, static_scheduler_DU_ends, static_scheduler_EIT_ends, static_scheduler_EXE_ends, - static_scheduler_JMP_ends, + static_scheduler_JAL_ends, static_scheduler_SAC_ends, static_scheduler_STP_ends, static_scheduler_WU_ends, @@ -165,23 +165,23 @@ static const char *trace_event_names[] = { // Static scheduler instructions "ADDI: add immediate", "ADV: advance logical time", - "ADV2: advance logical time (lock-free)", + "ADVI: advance logical time (lock-free)", "BIT: branch if timeout", "DU: delay until", "EIT: execute if triggered", "EXE: execute", - "JMP: jump", + "JAL: jump", "SAC: synchronize, advance time, and clear counters", "STP: stop", "WU: wait until", "End ADDI: add immediate", "End ADV: advance logical time", - "End ADV2: advance logical time (lock-free)", + "End ADVI: advance logical time (lock-free)", "End BIT: branch if timeout", "End DU: delay until", "End EIT: execute if triggered", "End EXE: execute", - "End JMP: jump", + "End JAL: jump", "End SAC: synchronize, advance time, and clear counters", "End STP: stop", "End WU: wait until", @@ -478,23 +478,23 @@ void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, i void tracepoint_static_scheduler_ADDI_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_ADV2_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_ADVI_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_BIT_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EXE_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_JMP_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_JAL_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADDI_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_ADV2_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_ADVI_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_JMP_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_JAL_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker, int pc); @@ -593,23 +593,23 @@ void tracepoint_rti_from_federate(trace_t* trace, trace_event_t event_type, int #define tracepoint_reaction_deadline_missed(...); #define tracepoint_static_scheduler_ADDI_starts(...); #define tracepoint_static_scheduler_ADV_starts(...); -#define tracepoint_static_scheduler_ADV2_starts(...); +#define tracepoint_static_scheduler_ADVI_starts(...); #define tracepoint_static_scheduler_BIT_starts(...); #define tracepoint_static_scheduler_DU_starts(...); #define tracepoint_static_scheduler_EIT_starts(...); #define tracepoint_static_scheduler_EXE_starts(...); -#define tracepoint_static_scheduler_JMP_starts(...); +#define tracepoint_static_scheduler_JAL_starts(...); #define tracepoint_static_scheduler_SAC_starts(...); #define tracepoint_static_scheduler_STP_starts(...); #define tracepoint_static_scheduler_WU_starts(...); #define tracepoint_static_scheduler_ADDI_ends(...); #define tracepoint_static_scheduler_ADV_ends(...); -#define tracepoint_static_scheduler_ADV2_ends(...); +#define tracepoint_static_scheduler_ADVI_ends(...); #define tracepoint_static_scheduler_BIT_ends(...); #define tracepoint_static_scheduler_DU_ends(...); #define tracepoint_static_scheduler_EIT_ends(...); #define tracepoint_static_scheduler_EXE_ends(...); -#define tracepoint_static_scheduler_JMP_ends(...); +#define tracepoint_static_scheduler_JAL_ends(...); #define tracepoint_static_scheduler_SAC_ends(...); #define tracepoint_static_scheduler_STP_ends(...); #define tracepoint_static_scheduler_WU_ends(...); From 890c54e52d3df6ff4b4e8063a71247ea85a04c26 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 23 Sep 2023 16:35:01 +0200 Subject: [PATCH 25/80] Update PRET VM instructions to be more portable --- core/threaded/scheduler_static.c | 261 +++++++++--------- .../core/threaded/scheduler_instructions.h | 36 ++- 2 files changed, 163 insertions(+), 134 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 688febea8..ef47e10ef 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -55,14 +55,14 @@ extern instant_t start_time; // Global variables defined in schedule.c: extern const inst_t* static_schedules[]; -extern volatile uint64_t timeout; +extern reg_t timeout; extern const size_t num_counters; -extern volatile uint64_t time_offset; -extern volatile uint64_t offset_inc; +extern reg_t time_offset; +extern reg_t offset_inc; extern const uint64_t zero; extern volatile uint32_t counters[]; -extern volatile uint64_t return_addr[]; -extern volatile uint64_t binary_sema[]; +extern volatile reg_t return_addr[]; +extern volatile reg_t binary_sema[]; /////////////////// Scheduler Private API ///////////////////////// @@ -142,12 +142,12 @@ void _lf_sched_wait_for_work( /** * @brief The implementation of the ADD instruction */ -void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { // tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, (int) *pc); - uint64_t *dst = (uint64_t *) rs1; - uint64_t *src = (uint64_t *) rs2; - uint64_t *src2 = (uint64_t *) rs3; + reg_t *dst = op1.reg; + reg_t *src = op2.reg; + reg_t *src2 = op3.reg; *dst = *src + *src2; *pc += 1; // Increment pc. // tracepoint_static_scheduler_ADDI_ends(scheduler->env->trace, worker_number, (int) *pc); @@ -156,13 +156,13 @@ void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, uint64_t /** * @brief The implementation of the ADDI instruction */ -void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, (int) *pc); - uint64_t *dst = (uint64_t *) rs1; - uint64_t *src = (uint64_t *) rs2; - // FIXME: Will there be problems if instant_t adds uint64_t? - *dst = *src + rs3; + reg_t *dst = op1.reg; + reg_t *src = op2.reg; + // FIXME: Will there be problems if instant_t adds reg_t? + *dst = *src + op3.imm; *pc += 1; // Increment pc. tracepoint_static_scheduler_ADDI_ends(scheduler->env->trace, worker_number, (int) *pc); } @@ -170,14 +170,14 @@ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, uint64_t /** * @brief The implementation of the ADV instruction */ -void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number, (int) *pc); - uint64_t *base = (uint64_t *)rs2; - uint64_t *inc = (uint64_t *)rs3; + reg_t *base = op2.reg; + reg_t *inc = op3.reg; self_base_t* reactor = - scheduler->reactor_self_instances[rs1]; + scheduler->reactor_self_instances[op1.imm]; reactor->tag.time = *base + *inc; reactor->tag.microstep = 0; @@ -197,14 +197,14 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, uint64_t /** * @brief The implementation of the ADVI instruction */ -void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_ADVI_starts(scheduler->env->trace, worker_number, (int) *pc); - uint64_t *base = (uint64_t *)rs2; + reg_t *base = op2.reg; self_base_t* reactor = - scheduler->reactor_self_instances[rs1]; - reactor->tag.time = *base + rs3; + scheduler->reactor_self_instances[op1.imm]; + reactor->tag.time = *base + op3.imm; reactor->tag.microstep = 0; // Reset all "is_present" fields of the output ports of the reactor @@ -223,12 +223,12 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, uint64_t /** * @brief The implementation of the BEQ instruction */ -void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); - uint64_t *_rs1 = (uint64_t *) rs1; - uint64_t *_rs2 = (uint64_t *) rs2; - if (*_rs1 == *_rs2) *pc = rs3; + reg_t *_rs1 = op1.reg; + reg_t *_rs2 = op2.reg; + if (*_rs1 == *_rs2) *pc = op3.imm; else *pc += 1; // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } @@ -239,13 +239,13 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, uint64_t * FIXME: This is incorrect right now. BGE should always be checking between * two registers. Timeout value should be stored in a separate register. */ -void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); - uint64_t *_rs1 = (uint64_t *) rs1; - uint64_t *_rs2 = (uint64_t *) rs2; + reg_t *_rs1 = op1.reg; + reg_t *_rs2 = op2.reg; LF_PRINT_DEBUG("Worker %zu: BGE : operand 1 = %lld, operand 2 = %lld", worker_number, *_rs1, *_rs2); - if (*_rs1 >= *_rs2) *pc = rs3; + if (*_rs1 >= *_rs2) *pc = op3.imm; else *pc += 1; // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } @@ -257,7 +257,7 @@ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, uint64_t * FIXME: Use a global variable num_active_reactors instead of iterating over * a for loop. The current implementation is very inefficient. */ -void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); bool stop = true; @@ -268,7 +268,7 @@ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t break; } } - if (stop) *pc = rs1; // Jump to a specified location. + if (stop) *pc = op1.imm; // Jump to a specified location. else *pc += 1; // Increment pc. tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } @@ -276,12 +276,12 @@ void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t /** * @brief The implementation of the BLT instruction */ -void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); - uint64_t *_rs1 = (uint64_t *) rs1; - uint64_t *_rs2 = (uint64_t *) rs2; - if (*_rs1 < *_rs2) *pc = rs3; + reg_t *_rs1 = op1.reg; + reg_t *_rs2 = op2.reg; + if (*_rs1 < *_rs2) *pc = op3.imm; else *pc += 1; // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } @@ -289,23 +289,42 @@ void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t /** * @brief The implementation of the BNE instruction */ -void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); - uint64_t *_rs1 = (uint64_t *) rs1; - uint64_t *_rs2 = (uint64_t *) rs2; - if (*_rs1 != *_rs2) *pc = rs3; + reg_t *_rs1 = op1.reg; + reg_t *_rs2 = op2.reg; + if (*_rs1 != *_rs2) *pc = op3.imm; else *pc += 1; // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } +/** + * @brief The implementation of the DU instruction + */ +void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop) { + tracepoint_static_scheduler_DU_starts(scheduler->env->trace, worker_number, (int) *pc); + // FIXME: There seems to be an overflow problem. + // When wakeup_time overflows but lf_time_physical() doesn't, + // _lf_interruptable_sleep_until_locked() terminates immediately. + reg_t *src = op1.reg; + instant_t wakeup_time = *src + op2.imm; + LF_PRINT_DEBUG("start_time: %lld, wakeup_time: %lld, op1: %lld, op2: %lld, current_physical_time: %lld\n", start_time, wakeup_time, *src, op2.imm, lf_time_physical()); + LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); + _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); + LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); + *pc += 1; // Increment pc. + tracepoint_static_scheduler_DU_ends(scheduler->env->trace, worker_number, (int) *pc); +} + /** * @brief The implementation of the EIT instruction */ -void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_EIT_starts(scheduler->env->trace, worker_number, (int) *pc); - reaction_t* reaction = scheduler->reaction_instances[rs1]; + reaction_t* reaction = scheduler->reaction_instances[op1.imm]; if (reaction->status == queued) { *returned_reaction = reaction; *exit_loop = true; @@ -319,44 +338,26 @@ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t /** * @brief The implementation of the EXE instruction */ -void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, worker_number, (int) *pc); - reaction_t* reaction = scheduler->reaction_instances[rs1]; + reaction_t* reaction = scheduler->reaction_instances[op1.imm]; *returned_reaction = reaction; *exit_loop = true; *pc += 1; // Increment pc. tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, worker_number, (int) *pc); } -/** - * @brief The implementation of the DU instruction - */ -void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_DU_starts(scheduler->env->trace, worker_number, (int) *pc); - // FIXME: There seems to be an overflow problem. - // When wakeup_time overflows but lf_time_physical() doesn't, - // _lf_interruptable_sleep_until_locked() terminates immediately. - uint64_t *src = (uint64_t *)rs1; - instant_t wakeup_time = *src + rs2; - LF_PRINT_DEBUG("start_time: %lld, wakeup_time: %lld, rs1: %lld, rs2: %lld, current_physical_time: %lld\n", start_time, wakeup_time, *src, rs2, lf_time_physical()); - LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); - _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); - LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); - *pc += 1; // Increment pc. - tracepoint_static_scheduler_DU_ends(scheduler->env->trace, worker_number, (int) *pc); -} /** * @brief The implementation of the WLT instruction */ -void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { // tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, (int) *pc); LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); - volatile uint64_t *var = (volatile uint64_t *)rs1; - while(*var >= rs2); + reg_t *var = op1.reg; + while(*var >= op2.imm); LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); *pc += 1; // Increment pc. // tracepoint_static_scheduler_WU_ends(scheduler->env->trace, worker_number, (int) *pc); @@ -365,12 +366,12 @@ void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, uint64_t /** * @brief The implementation of the WU instruction */ -void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, (int) *pc); LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); - volatile uint64_t *var = (volatile uint64_t *)rs1; - while(*var < rs2); + reg_t *var = op1.reg; + while(*var < op2.imm); LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); *pc += 1; // Increment pc. tracepoint_static_scheduler_WU_ends(scheduler->env->trace, worker_number, (int) *pc); @@ -379,43 +380,43 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, uint64_t r /** * @brief The implementation of the JAL instruction */ -void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { // tracepoint_static_scheduler_JAL_starts(scheduler->env->trace, worker_number, (int) *pc); // Use the destination register as the return address and, if the // destination register is not the zero register, store pc+1 in it. - uint64_t *destReg = (uint64_t *)rs1; + reg_t *destReg = op1.reg; if (destReg != &zero) *destReg = *pc + 1; - *pc = rs2; + *pc = op2.imm; // tracepoint_static_scheduler_JAL_ends(scheduler->env->trace, worker_number, (int) *pc); } /** * @brief The implementation of the JALR instruction */ -void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { // tracepoint_static_scheduler_JALR_starts(scheduler->env->trace, worker_number, (int) *pc); // Use the destination register as the return address and, if the // destination register is not the zero register, store pc+1 in it. - uint64_t *destReg = (uint64_t *)rs1; + reg_t *destReg = op1.reg; if (destReg != &zero) *destReg = *pc + 1; // Set pc to base addr + immediate. - uint64_t *baseAddr = (uint64_t *)rs2; - *pc = *baseAddr + rs3; + reg_t *baseAddr = op2.reg; + *pc = *baseAddr + op3.imm; // tracepoint_static_scheduler_JALR_ends(scheduler->env->trace, worker_number, (int) *pc); } /** * @brief The implementation of the SAC instruction */ -void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_SAC_starts(scheduler->env->trace, worker_number, (int) *pc); // Compute the next tag for all reactors. - uint64_t *src = (uint64_t *)rs1; - instant_t next_timestamp = *src + rs2; + reg_t *src = op1.reg; + instant_t next_timestamp = *src + op2.imm; tracepoint_worker_wait_starts(scheduler->env->trace, worker_number); _lf_sched_wait_for_work(scheduler, worker_number, next_timestamp); @@ -428,7 +429,7 @@ void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, uint64_t /** * @brief The implementation of the STP instruction */ -void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, uint64_t rs1, uint64_t rs2, uint64_t rs3, size_t* pc, +void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_STP_starts(scheduler->env->trace, worker_number, (int) *pc); *exit_loop = true; @@ -438,9 +439,9 @@ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, uint64_t /** * @brief Execute an instruction * - * @param op the opcode - * @param rs1 the first operand - * @param rs2 the second operand + * @param opcode the opcode + * @param op1 the first operand + * @param op2 the second operand * @param pc a pointer to the program counter * @param returned_reaction a pointer to a reaction to be executed * @@ -448,102 +449,102 @@ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, uint64_t * @param exit_loop a pointer to a boolean indicating whether * the outer while loop should be exited */ -void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t op, uint64_t rs1, uint64_t rs2, uint64_t rs3, +void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t opcode, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { char* op_str = NULL; - switch (op) { + switch (opcode) { case ADD: op_str = "ADD"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_ADD(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_ADD(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case ADDI: op_str = "ADDI"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_ADDI(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_ADDI(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case ADV: op_str = "ADV"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_ADV(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_ADV(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case ADVI: op_str = "ADVI"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_ADVI(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_ADVI(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case BEQ: op_str = "BEQ"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_BEQ(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_BEQ(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case BGE: op_str = "BGE"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_BGE(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_BGE(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case BIT: op_str = "BIT"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_BIT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_BIT(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case BLT: op_str = "BLT"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_BLT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_BLT(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case BNE: op_str = "BNE"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_BNE(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_BNE(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case DU: op_str = "DU"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_DU(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_DU(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case EIT: op_str = "EIT"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_EIT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_EIT(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case EXE: op_str = "EXE"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_EXE(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_EXE(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case JAL: op_str = "JAL"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_JAL(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_JAL(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case JALR: op_str = "JALR"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_JALR(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_JALR(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case SAC: op_str = "SAC"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_SAC(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_SAC(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case STP: op_str = "STP"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_STP(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_STP(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case WLT: op_str = "WLT"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_WLT(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_WLT(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; case WU: op_str = "WU"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, rs1, rs2, rs3); - execute_inst_WU(scheduler, worker_number, rs1, rs2, rs3, pc, returned_reaction, exit_loop); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + execute_inst_WU(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; default: - lf_print_error_and_exit("Invalid instruction: %d", op); + lf_print_error_and_exit("Invalid instruction: %d", opcode); } } @@ -628,19 +629,19 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu reaction_t* returned_reaction = NULL; bool exit_loop = false; size_t* pc = &scheduler->pc[worker_number]; - opcode_t op; - uint64_t rs1; - uint64_t rs2; - uint64_t rs3; + opcode_t opcode; + operand_t op1; + operand_t op2; + operand_t op3; while (!exit_loop) { - op = current_schedule[*pc].op; - rs1 = current_schedule[*pc].rs1; - rs2 = current_schedule[*pc].rs2; - rs3 = current_schedule[*pc].rs3; + opcode = current_schedule[*pc].opcode; + op1 = current_schedule[*pc].op1; + op2 = current_schedule[*pc].op2; + op3 = current_schedule[*pc].op3; // Execute the current instruction - execute_inst(scheduler, worker_number, op, rs1, rs2, rs3, pc, + execute_inst(scheduler, worker_number, opcode, op1, op2, op3, pc, &returned_reaction, &exit_loop); LF_PRINT_DEBUG("Worker %d: returned_reaction = %p, exit_loop = %d", diff --git a/include/core/threaded/scheduler_instructions.h b/include/core/threaded/scheduler_instructions.h index 6bcc3902e..dd9a4f49a 100644 --- a/include/core/threaded/scheduler_instructions.h +++ b/include/core/threaded/scheduler_instructions.h @@ -23,9 +23,37 @@ typedef enum { WU, } opcode_t; + +/** + * @brief Convenient typedefs for the data types used by the C implementation of + * PRET VM. A register is 64bits and an immediate is 64bits. This avoids any + * issue with time and overflow. Arguably it is worth it even for smaller + * platforms. + * + */ +typedef volatile uint64_t reg_t; +typedef uint64_t imm_t; + +/** + * @brief An union representing a single operand for the PRET VM. A union + * means that we have one piece of memory, which is big enough to fit either + * one of the two members of the union. + * + */ +typedef union { + reg_t* reg; + imm_t imm; +} operand_t; + +/** + * @brief This struct represents a PRET VM instruction for C platforms. + * There is an opcode and three operands. The operands are unions so they + * can be either a pointer or an immediate + * + */ typedef struct inst_t { - opcode_t op; - uint64_t rs1; - uint64_t rs2; - uint64_t rs3; + opcode_t opcode; + operand_t op1; + operand_t op2; + operand_t op3; } inst_t; \ No newline at end of file From 031412eceefd0ab0fea68380a38f997d15f2c97f Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Wed, 4 Oct 2023 18:21:57 -0700 Subject: [PATCH 26/80] Remove unnecessary debug msg --- core/threaded/scheduler_static.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index ef47e10ef..1421272d0 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -643,9 +643,6 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu // Execute the current instruction execute_inst(scheduler, worker_number, opcode, op1, op2, op3, pc, &returned_reaction, &exit_loop); - - LF_PRINT_DEBUG("Worker %d: returned_reaction = %p, exit_loop = %d", - worker_number, returned_reaction, exit_loop); } LF_PRINT_DEBUG("Worker %d leaves lf_sched_get_ready_reaction", worker_number); From e9edc18913a763503c88daec0970624ed8295fd6 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Wed, 11 Oct 2023 18:32:25 -0700 Subject: [PATCH 27/80] Add a schedule init function to deal with the compile-time constant issue --- core/threaded/scheduler_static.c | 2 ++ include/core/threaded/scheduler_instance.h | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 1421272d0..77d85a297 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -596,6 +596,8 @@ void lf_sched_init( env->scheduler->reactor_self_instances = params->reactor_self_instances; env->scheduler->num_reactor_self_instances = params->num_reactor_self_instances; env->scheduler->counters = counters; + + initialize_static_schedule(); } /** diff --git a/include/core/threaded/scheduler_instance.h b/include/core/threaded/scheduler_instance.h index b6c0be001..f3cc4bbb6 100644 --- a/include/core/threaded/scheduler_instance.h +++ b/include/core/threaded/scheduler_instance.h @@ -232,4 +232,12 @@ bool init_sched_instance( size_t number_of_workers, sched_params_t* params); +#if SCHEDULER == STATIC +/** + * @brief Initialize the static schedule by filling in placeholders which are + * not considered "compile-time constants" by the compiler. + */ +void initialize_static_schedule(); +#endif + #endif // LF_SCHEDULER_PARAMS_H From d3d39e9c84268e57fac73a1f1db7e37ab400bd84 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sun, 15 Oct 2023 17:37:56 -0700 Subject: [PATCH 28/80] Extend environment for static scheduling --- include/core/environment.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/core/environment.h b/include/core/environment.h index ed93b72d2..4861e8d55 100644 --- a/include/core/environment.h +++ b/include/core/environment.h @@ -104,6 +104,14 @@ typedef struct environment_t { tag_t** _lf_intended_tag_fields; int _lf_intended_tag_fields_size; #endif // FEDERATED +#if SCHEDULER == STATIC + tag_t** reactor_tags; + int reactor_tags_size; + bool** reaction_trigger_present_array; + int reaction_trigger_present_array_size; + reaction_t** reaction_array; + int reaction_array_size; +#endif } environment_t; #ifdef MODAL_REACTORS From bb5ae6d42eb4ca4ddcde350525fbc35191deef3a Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Mon, 16 Oct 2023 15:19:20 -0700 Subject: [PATCH 29/80] Get a simple example to work --- core/threaded/scheduler_static.c | 6 +++--- include/core/environment.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 77d85a297..044d713e8 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -201,9 +201,8 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_ADVI_starts(scheduler->env->trace, worker_number, (int) *pc); + self_base_t *reactor = (self_base_t*) op1.reg; reg_t *base = op2.reg; - self_base_t* reactor = - scheduler->reactor_self_instances[op1.imm]; reactor->tag.time = *base + op3.imm; reactor->tag.microstep = 0; @@ -228,6 +227,7 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; + LF_PRINT_DEBUG("Worker %zu: BEQ : operand 1 = %lld, operand 2 = %lld", worker_number, *_rs1, *_rs2); if (*_rs1 == *_rs2) *pc = op3.imm; else *pc += 1; // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); @@ -341,7 +341,7 @@ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, operand_t void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, worker_number, (int) *pc); - reaction_t* reaction = scheduler->reaction_instances[op1.imm]; + reaction_t *reaction = (reaction_t*) op1.reg; *returned_reaction = reaction; *exit_loop = true; *pc += 1; // Increment pc. diff --git a/include/core/environment.h b/include/core/environment.h index 4861e8d55..3e888170c 100644 --- a/include/core/environment.h +++ b/include/core/environment.h @@ -105,8 +105,8 @@ typedef struct environment_t { int _lf_intended_tag_fields_size; #endif // FEDERATED #if SCHEDULER == STATIC - tag_t** reactor_tags; - int reactor_tags_size; + self_base_t** reactor_array; + int reactor_array_size; bool** reaction_trigger_present_array; int reaction_trigger_present_array_size; reaction_t** reaction_array; From 4d32a5cba7605b0267a2602eeb1d2d4a7b6228a1 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 26 Oct 2023 19:08:23 +0100 Subject: [PATCH 30/80] More tracepoints of the PretVM instructions --- core/threaded/scheduler_static.c | 8 ++++---- core/trace.c | 10 ++++++++++ include/core/trace.h | 12 ++++++++++-- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 1421272d0..6ba590f3c 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -382,13 +382,13 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - // tracepoint_static_scheduler_JAL_starts(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_JAL_starts(scheduler->env->trace, worker_number, (int) *pc); // Use the destination register as the return address and, if the // destination register is not the zero register, store pc+1 in it. reg_t *destReg = op1.reg; if (destReg != &zero) *destReg = *pc + 1; *pc = op2.imm; - // tracepoint_static_scheduler_JAL_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_JAL_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -396,7 +396,7 @@ void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - // tracepoint_static_scheduler_JALR_starts(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_JALR_starts(scheduler->env->trace, worker_number, (int) *pc); // Use the destination register as the return address and, if the // destination register is not the zero register, store pc+1 in it. reg_t *destReg = op1.reg; @@ -404,7 +404,7 @@ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_ // Set pc to base addr + immediate. reg_t *baseAddr = op2.reg; *pc = *baseAddr + op3.imm; - // tracepoint_static_scheduler_JALR_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_JALR_ends(scheduler->env->trace, worker_number, (int) *pc); } /** diff --git a/core/trace.c b/core/trace.c index 992e81214..782ed9a5a 100644 --- a/core/trace.c +++ b/core/trace.c @@ -497,6 +497,11 @@ void tracepoint_static_scheduler_JAL_starts(trace_t* trace, int worker, int pc) tracepoint(trace, static_scheduler_JAL_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } +/** Trace the start of the JALR instruction */ +void tracepoint_static_scheduler_JALR_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_JALR_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +} + /** Trace the start of the SAC instruction */ void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_SAC_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); @@ -552,6 +557,11 @@ void tracepoint_static_scheduler_JAL_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_JAL_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } +/** Trace the end of the JALR instruction */ +void tracepoint_static_scheduler_JALR_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_JALR_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +} + /** Trace the end of the SAC instruction */ void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_SAC_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); diff --git a/include/core/trace.h b/include/core/trace.h index ca04c7047..84bb29d22 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -85,6 +85,7 @@ typedef enum static_scheduler_EIT_starts, static_scheduler_EXE_starts, static_scheduler_JAL_starts, + static_scheduler_JALR_starts, static_scheduler_SAC_starts, static_scheduler_STP_starts, static_scheduler_WU_starts, @@ -96,6 +97,7 @@ typedef enum static_scheduler_EIT_ends, static_scheduler_EXE_ends, static_scheduler_JAL_ends, + static_scheduler_JALR_ends, static_scheduler_SAC_ends, static_scheduler_STP_ends, static_scheduler_WU_ends, @@ -171,7 +173,8 @@ static const char *trace_event_names[] = { "EIT: execute if triggered", "EXE: execute", "JAL: jump", - "SAC: synchronize, advance time, and clear counters", + "JALR: jump and return", + "SAC: synchronize advance time and clear counters", "STP: stop", "WU: wait until", "End ADDI: add immediate", @@ -182,7 +185,8 @@ static const char *trace_event_names[] = { "End EIT: execute if triggered", "End EXE: execute", "End JAL: jump", - "End SAC: synchronize, advance time, and clear counters", + "End JALR: jump and return", + "End SAC: synchronize advance time and clear counters", "End STP: stop", "End WU: wait until", "Federated marker", @@ -484,6 +488,7 @@ void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EXE_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JAL_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_JALR_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker, int pc); @@ -495,6 +500,7 @@ void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JAL_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_JALR_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker, int pc); @@ -599,6 +605,7 @@ void tracepoint_rti_from_federate(trace_t* trace, trace_event_t event_type, int #define tracepoint_static_scheduler_EIT_starts(...); #define tracepoint_static_scheduler_EXE_starts(...); #define tracepoint_static_scheduler_JAL_starts(...); +#define tracepoint_static_scheduler_JALR_starts(...); #define tracepoint_static_scheduler_SAC_starts(...); #define tracepoint_static_scheduler_STP_starts(...); #define tracepoint_static_scheduler_WU_starts(...); @@ -610,6 +617,7 @@ void tracepoint_rti_from_federate(trace_t* trace, trace_event_t event_type, int #define tracepoint_static_scheduler_EIT_ends(...); #define tracepoint_static_scheduler_EXE_ends(...); #define tracepoint_static_scheduler_JAL_ends(...); +#define tracepoint_static_scheduler_JALR_ends(...); #define tracepoint_static_scheduler_SAC_ends(...); #define tracepoint_static_scheduler_STP_ends(...); #define tracepoint_static_scheduler_WU_ends(...); From 90e8c8b2066120640bf786557c2475187a8a8871 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Sun, 12 Nov 2023 15:12:49 +0100 Subject: [PATCH 31/80] Uncomment static scheduler trace points --- core/threaded/scheduler_static.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 6ba590f3c..d9c1fd179 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -144,13 +144,13 @@ void _lf_sched_wait_for_work( */ void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - // tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, (int) *pc); reg_t *dst = op1.reg; reg_t *src = op2.reg; reg_t *src2 = op3.reg; *dst = *src + *src2; *pc += 1; // Increment pc. - // tracepoint_static_scheduler_ADDI_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_ADDI_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -241,13 +241,13 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; LF_PRINT_DEBUG("Worker %zu: BGE : operand 1 = %lld, operand 2 = %lld", worker_number, *_rs1, *_rs2); if (*_rs1 >= *_rs2) *pc = op3.imm; else *pc += 1; - // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } /** From d4a112756cca9a13488025242e396ac9dc294307 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Tue, 14 Nov 2023 17:12:49 -0800 Subject: [PATCH 32/80] Change STATIC to SCHED_STATIC --- core/reactor_common.c | 2 +- core/threaded/scheduler_static.c | 4 ++-- include/api/set.h | 4 ++-- include/core/reactor_common.h | 4 ++-- include/core/threaded/scheduler_instance.h | 6 +++--- test/CMakeLists.txt | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/reactor_common.c b/core/reactor_common.c index b6039aeb5..1860da269 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -841,7 +841,7 @@ int _lf_schedule_at_tag(environment_t* env, trigger_t* trigger, tag_t tag, lf_to return 1; } -#if SCHEDULER != STATIC +#if SCHEDULER != SCHED_STATIC /** * Schedule the specified trigger at env->current_tag.time plus the offset of the * specified trigger plus the delay. See schedule_token() in reactor.h for details. diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index d9c1fd179..3ee372e64 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -32,7 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "lf_types.h" -#if SCHEDULER == STATIC || (!defined(SCHEDULER) && defined(LF_THREADED)) +#if SCHEDULER == SCHED_STATIC || (!defined(SCHEDULER) && defined(LF_THREADED)) #ifndef NUMBER_OF_WORKERS #define NUMBER_OF_WORKERS 1 #endif // NUMBER_OF_WORKERS @@ -580,7 +580,7 @@ void lf_sched_init( // to a meaningful value. When the first time lf_sched_init() is // called, start_time has not been set. - // Initialize the local tags for the STATIC scheduler. + // Initialize the local tags for the SCHED_STATIC scheduler. for (int i = 0; i < env->scheduler->num_reactor_self_instances; i++) { env->scheduler->reactor_self_instances[i]->tag.time = start_time; env->scheduler->reactor_self_instances[i]->tag.microstep = 0; diff --git a/include/api/set.h b/include/api/set.h index bac62a06b..0339b3e60 100644 --- a/include/api/set.h +++ b/include/api/set.h @@ -216,7 +216,7 @@ do { \ // As long as this is done from the context of a reaction, `self` is in scope and is a pointer to the self-struct // of the current reactor. -// The fully static (STATIC) runtime, uses time local to each reactor. If this is the case +// The fully static (SCHED_STATIC) runtime, uses time local to each reactor. If this is the case // then we defined these macros to access that timestamp rather than using the standard API // FIXME (erj): I am not really stoked about this added complexity #if defined REACTOR_LOCAL_TIME @@ -238,6 +238,6 @@ do { \ #define get_microstep() get_microstep(self->base.environment) #endif -// FIXME: How should this be implemented for the STATIC scheduler? +// FIXME: How should this be implemented for the SCHED_STATIC scheduler? // #define lf_request_stop() _lf_request_stop(self->base.environment) diff --git a/include/core/reactor_common.h b/include/core/reactor_common.h index ddabfb396..25b242ef3 100644 --- a/include/core/reactor_common.h +++ b/include/core/reactor_common.h @@ -10,8 +10,8 @@ #include "modes.h" #include "port.h" -// FIXME (erj): Super hack to disable chain optimzation when we are using the STATIC runtime. -#if SCHEDULER == STATIC +// FIXME (erj): Super hack to disable chain optimzation when we are using the SCHED_STATIC runtime. +#if SCHEDULER == SCHED_STATIC #else #define REACTION_CHAIN_OPTIMIZATION #endif diff --git a/include/core/threaded/scheduler_instance.h b/include/core/threaded/scheduler_instance.h index b6c0be001..0f0b5186e 100644 --- a/include/core/threaded/scheduler_instance.h +++ b/include/core/threaded/scheduler_instance.h @@ -45,7 +45,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "semaphore.h" #include -#if SCHEDULER == STATIC +#if SCHEDULER == SCHED_STATIC #include "lf_types.h" #include "scheduler_instructions.h" #endif @@ -146,7 +146,7 @@ typedef struct lf_scheduler_t { // Is not touched by `init_sched_instance` and must be initialized by each scheduler that needs it custom_scheduler_data_t * custom_data; -#if SCHEDULER == STATIC +#if SCHEDULER == SCHED_STATIC /** * @brief Points to an array of program counters for each worker. @@ -206,7 +206,7 @@ typedef struct lf_scheduler_t { typedef struct { size_t* num_reactions_per_level; size_t num_reactions_per_level_size; -#if SCHEDULER == STATIC +#if SCHEDULER == SCHED_STATIC struct self_base_t** reactor_self_instances; size_t num_reactor_self_instances; reaction_t** reaction_instances; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8c652b01a..def1bbd2e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1 +1 @@ -add_library(test-lib STATIC src_gen_stub.c rand_utils.c) \ No newline at end of file +add_library(test-lib SCHED_STATIC src_gen_stub.c rand_utils.c) \ No newline at end of file From ce032528c7d26614b1ee91ff875709c1fe7df9df Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sun, 19 Nov 2023 23:41:33 -0800 Subject: [PATCH 33/80] Update include guard --- core/threaded/scheduler_static.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 3ee372e64..75f1e392e 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -1,4 +1,4 @@ -#if defined(LF_THREADED) +#if !defined(LF_SINGLE_THREADED) /************* Copyright (c) 2022, The University of Texas at Dallas. Copyright (c) 2022, The University of California at Berkeley. @@ -32,7 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "lf_types.h" -#if SCHEDULER == SCHED_STATIC || (!defined(SCHEDULER) && defined(LF_THREADED)) +#if defined SCHEDULER && SCHEDULER == SCHED_STATIC #ifndef NUMBER_OF_WORKERS #define NUMBER_OF_WORKERS 1 #endif // NUMBER_OF_WORKERS From 3e498c80118bba20683b2bafbacd668af9903b05 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Wed, 13 Dec 2023 21:05:21 -0800 Subject: [PATCH 34/80] Add WIP --- core/threaded/scheduler_static.c | 10 ++++------ include/core/environment.h | 8 ++++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index c70c2801c..287adfe4d 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -235,9 +235,6 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t /** * @brief The implementation of the BGE instruction - * - * FIXME: This is incorrect right now. BGE should always be checking between - * two registers. Timeout value should be stored in a separate register. */ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { @@ -341,9 +338,10 @@ void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, operand_t void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, worker_number, (int) *pc); - reaction_t *reaction = (reaction_t*) op1.reg; - *returned_reaction = reaction; - *exit_loop = true; + function_generic_t function = (function_generic_t)(uintptr_t)op1.reg; + void *args = (void*)op2.reg; + // Execute the function directly. + function(args); *pc += 1; // Increment pc. tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, worker_number, (int) *pc); } diff --git a/include/core/environment.h b/include/core/environment.h index 677795d96..fb3cd624c 100644 --- a/include/core/environment.h +++ b/include/core/environment.h @@ -107,12 +107,12 @@ typedef struct environment_t { int _lf_intended_tag_fields_size; #endif // FEDERATED #if SCHEDULER == SCHED_STATIC - self_base_t** reactor_array; - int reactor_array_size; - bool** reaction_trigger_present_array; - int reaction_trigger_present_array_size; + self_base_t** reactor_self_array; + int reactor_self_array_size; reaction_t** reaction_array; int reaction_array_size; + event_t** pqueue_heads; + int num_pqueue_heads; #endif #ifdef LF_ENCLAVES // TODO: Consider dropping #ifdef enclave_info_t *enclave_info; From ce9d42233957810fd2cd4b146bba897a39688fcf Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sat, 6 Jan 2024 23:11:21 +0800 Subject: [PATCH 35/80] Add header file for helper functions used in the static schedule --- core/threaded/scheduler_static.c | 1 + include/core/threaded/scheduler_static_functions.h | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 include/core/threaded/scheduler_static_functions.h diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 287adfe4d..d2b328730 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -42,6 +42,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform.h" #include "reactor_common.h" #include "scheduler_instance.h" +#include "scheduler_static_functions.h" #include "scheduler_sync_tag_advance.h" #include "scheduler.h" #include "semaphore.h" diff --git a/include/core/threaded/scheduler_static_functions.h b/include/core/threaded/scheduler_static_functions.h new file mode 100644 index 000000000..2761a62de --- /dev/null +++ b/include/core/threaded/scheduler_static_functions.h @@ -0,0 +1,12 @@ +/** + * @brief Function type with a void* argument. To make this type represent a + * generic function, one can write a wrapper function around the target function + * and use the first argument as a pointer to a struct of input arguments + * and return values. + */ +typedef void(*function_generic_t)(void*); + +/** + * @brief Wrapper function for peeking a priority queue. + */ +void push_pop_peek_pqueue(void* self); \ No newline at end of file From 0f30f05d52ac93a3fe81e265327132fd8c0d45e5 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sat, 20 Jan 2024 12:06:35 -0800 Subject: [PATCH 36/80] Add WIP. SimpleConnection kind of works. --- core/threaded/scheduler_static.c | 14 ++++++++++---- include/core/reactor.h | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index d2b328730..d7cb3e715 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -229,7 +229,13 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; LF_PRINT_DEBUG("Worker %zu: BEQ : operand 1 = %lld, operand 2 = %lld", worker_number, *_rs1, *_rs2); - if (*_rs1 == *_rs2) *pc = op3.imm; + // These NULL checks allow _rs1 and _rs2 to be uninitialized in the static + // schedule, which can save a few lines in the schedule. But it is debatable + // whether this is good practice. + // lf_print("_rs1 = %p, _rs2 = %p", _rs1, _rs2); + // if (_rs1 != NULL) printf("*_rs1 = %lld\n", *_rs1); + // if (_rs2 != NULL) printf("*_rs2 = %lld\n", *_rs2); + if (_rs1 != NULL && _rs2 != NULL && *_rs1 == *_rs2) *pc = op3.imm; else *pc += 1; // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } @@ -243,7 +249,7 @@ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; LF_PRINT_DEBUG("Worker %zu: BGE : operand 1 = %lld, operand 2 = %lld", worker_number, *_rs1, *_rs2); - if (*_rs1 >= *_rs2) *pc = op3.imm; + if (_rs1 != NULL && _rs2 != NULL && *_rs1 >= *_rs2) *pc = op3.imm; else *pc += 1; tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } @@ -279,7 +285,7 @@ void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; - if (*_rs1 < *_rs2) *pc = op3.imm; + if (_rs1 != NULL && _rs2 != NULL && *_rs1 < *_rs2) *pc = op3.imm; else *pc += 1; // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } @@ -292,7 +298,7 @@ void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; - if (*_rs1 != *_rs2) *pc = op3.imm; + if (_rs1 != NULL && _rs2 != NULL && *_rs1 != *_rs2) *pc = op3.imm; else *pc += 1; // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } diff --git a/include/core/reactor.h b/include/core/reactor.h index 0e56c0f3e..5f94a4265 100644 --- a/include/core/reactor.h +++ b/include/core/reactor.h @@ -105,6 +105,24 @@ void _lf_executable_preamble(environment_t* env); * reactor in form input_name.port_name. * @param value The value to insert into the self struct. */ +#if SCHEDULER == SCHED_STATIC +#define _LF_SET(out, val) \ +do { \ + /* We need to assign "val" to "out->value" since we need to give "val" an address */ \ + /* even if it is a literal */ \ + out->value = val; \ + _lf_set_present((lf_port_base_t*)out); \ + /* Create a token for the literal. How do we generalize this to any literal type? */ \ + int *payload = (int*)calloc(1, sizeof(int)); \ + *payload = val; \ + lf_token_t* token = _lf_initialize_token_with_value((token_template_t*)out, (void*)payload, 1); \ + /* VERY IMPORTANT: Increment reference count > 1 so that it does NOT get reused right away */ \ + /* FIXME: I still don't fully understand this. */ + token->ref_count = 1; \ + /* DEBUG: The token address should be distinct. */ \ + lf_print("Token address = %p", token); \ +} while(0) +#else #define _LF_SET(out, val) \ do { \ /* We need to assign "val" to "out->value" since we need to give "val" an address */ \ @@ -117,6 +135,7 @@ do { \ lf_token_t* token = _lf_initialize_token_with_value((token_template_t*)out, *((void**) &out->value), 1); \ } \ } while(0) +#endif /** * Version of set for output types given as 'type[]' where you From 2512f0c34a980a2c7d421e150c6bcafb51a7361a Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Thu, 25 Jan 2024 00:52:15 -0800 Subject: [PATCH 37/80] Make SimpleConnection test case work --- core/lf_token.c | 4 ++++ include/core/reactor.h | 23 +++++++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/core/lf_token.c b/core/lf_token.c index b309f0a2f..13b257f8a 100644 --- a/core/lf_token.c +++ b/core/lf_token.c @@ -221,6 +221,10 @@ lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length) { return result; } +// FIXME (Shaokai): The function name is probably a misnomer. +// It should better be _lf_get_new_token. +// I also don't get why the token isn't simply returned, and +// _lf_free_token_value or _lf_done_using has to be called. lf_token_t* _lf_get_token(token_template_t* tmplt) { if (tmplt->token != NULL) { if (tmplt->token->ref_count == 1) { diff --git a/include/core/reactor.h b/include/core/reactor.h index 5f94a4265..cb576e47b 100644 --- a/include/core/reactor.h +++ b/include/core/reactor.h @@ -49,6 +49,7 @@ #ifndef REACTOR_H #define REACTOR_H +#include // memcpy #include "lf_types.h" #include "modes.h" // Modal model support #include "port.h" @@ -111,16 +112,22 @@ do { \ /* We need to assign "val" to "out->value" since we need to give "val" an address */ \ /* even if it is a literal */ \ out->value = val; \ + /* DEBUG: lf_print("lf_set value = %d", (int)val); */ \ _lf_set_present((lf_port_base_t*)out); \ - /* Create a token for the literal. How do we generalize this to any literal type? */ \ - int *payload = (int*)calloc(1, sizeof(int)); \ - *payload = val; \ - lf_token_t* token = _lf_initialize_token_with_value((token_template_t*)out, (void*)payload, 1); \ + /* Create a token for the literal based on the token element_size. */ \ + size_t payload_size = ((token_type_t*)out)->element_size; \ + /* DEBUG: lf_print("payload_size = %zu", payload_size); */ \ + /* Put the literal in the payload using memcpy. */ \ + void *payload = malloc(payload_size); \ + memcpy(payload, &val, payload_size); \ + /* Create a new token and put it in the port. */ \ + lf_token_t* newtoken = _lf_new_token((token_type_t*)out, payload, 1); \ + _lf_replace_template_token((token_template_t*)out, newtoken); \ /* VERY IMPORTANT: Increment reference count > 1 so that it does NOT get reused right away */ \ - /* FIXME: I still don't fully understand this. */ - token->ref_count = 1; \ + /* FIXME: I still don't fully understand this. */ \ + newtoken->ref_count = 2; \ /* DEBUG: The token address should be distinct. */ \ - lf_print("Token address = %p", token); \ + /* DEBUG: lf_print("Token address = %p", newtoken); */ \ } while(0) #else #define _LF_SET(out, val) \ @@ -128,7 +135,7 @@ do { \ /* We need to assign "val" to "out->value" since we need to give "val" an address */ \ /* even if it is a literal */ \ out->value = val; \ - _lf_set_present((lf_port_base_t*)out); \ + _lf_set_present((lf_port_base_t*)out); \ if (((token_template_t*)out)->token != NULL) { \ /* The cast "*((void**) &out->value)" is a hack to make the code */ \ /* compile with non-token types where value is not a pointer. */ \ From 31428ab43324a5fb90dcdc28dbd2a79e22f06587 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sun, 11 Feb 2024 16:25:33 -0800 Subject: [PATCH 38/80] Prune unused code in the static scheduler --- core/threaded/scheduler_static.c | 181 +----------------- .../core/threaded/scheduler_instructions.h | 3 - 2 files changed, 6 insertions(+), 178 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index d7cb3e715..f25f21372 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -67,79 +67,6 @@ extern volatile reg_t binary_sema[]; /////////////////// Scheduler Private API ///////////////////////// -/** - * @brief If there is work to be done, notify workers individually. - * - * This assumes that the caller is not holding any thread mutexes. - */ -void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { - // Note: All threads are idle. Therefore, there is no need to lock the mutex - // while accessing the executing queue (which is pointing to one of the - // reaction queues). - size_t workers_to_awaken = - scheduler->number_of_idle_workers; - LF_PRINT_DEBUG("Scheduler: Notifying %zu workers.", workers_to_awaken); - scheduler->number_of_idle_workers -= workers_to_awaken; - LF_PRINT_DEBUG("Scheduler: New number of idle workers: %zu.", - scheduler->number_of_idle_workers); - if (workers_to_awaken > 1) { - // Notify all the workers except the worker thread that has called this - // function. - lf_semaphore_release(scheduler->semaphore, - (workers_to_awaken - 1)); - } -} - -/** - * @brief Wait until the scheduler assigns work. - * - * If the calling worker thread is the last to become idle, it will call on the - * scheduler to distribute work. Otherwise, it will wait on - * 'scheduler->semaphore'. - * This implementation of _lf_sched_wait_for_work also takes on the role of - * advancing time for all reactors at the end of a hyperperiod. - * - * @param worker_number The worker number of the worker thread asking for work - * to be assigned to it. - * @param next_timestamp The next timestamp all reactors advance to. - */ -void _lf_sched_wait_for_work( - lf_scheduler_t* scheduler, - size_t worker_number, - instant_t next_timestamp -) { - // Increment the number of idle workers by 1 and - // check if this is the last worker thread to become idle. - if (lf_atomic_add_fetch(&scheduler->number_of_idle_workers, - 1) == - scheduler->number_of_workers) { - - // Last thread to go idle - LF_PRINT_DEBUG("Scheduler: Worker %zu is the last idle thread.", - worker_number); - - // The last worker advances all reactors to the next tag. - // Also check if the new tag reaches the stop tag. - for (int j = 0; j < scheduler->num_reactor_self_instances; j++) { - scheduler->reactor_self_instances[j]->tag.time = next_timestamp; - scheduler->reactor_self_instances[j]->tag.microstep = 0; - } - - // The last worker clears all the counters. - for (int i = 0; i < num_counters; i++) { - counters[i] = 0; - } - - // The last worker calls on the scheduler to distribute work or advance tag. - _lf_sched_notify_workers(scheduler); - - } else { - // Not the last thread to become idle. - // Wait for work to be released. - lf_semaphore_acquire(scheduler->semaphore); - } -} - /** * @brief The implementation of the ADD instruction */ @@ -254,29 +181,6 @@ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } -/** - * @brief The implementation of the BIT instruction - * - * FIXME: Should the timeout value be an operand? - * FIXME: Use a global variable num_active_reactors instead of iterating over - * a for loop. The current implementation is very inefficient. - */ -void execute_inst_BIT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); - bool stop = true; - for (int i = 0; i < scheduler->num_reactor_self_instances; i++) { - if (!_lf_is_tag_after_stop_tag(scheduler->env, scheduler->reactor_self_instances[i]->tag)) { - LF_PRINT_DEBUG("*** Worker %zu: reactor %d has not reached stop tag: (%lld, %u)", worker_number, i, scheduler->reactor_self_instances[i]->tag.time, scheduler->reactor_self_instances[i]->tag.microstep); - stop = false; - break; - } - } - if (stop) *pc = op1.imm; // Jump to a specified location. - else *pc += 1; // Increment pc. - tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); -} - /** * @brief The implementation of the BLT instruction */ @@ -322,23 +226,6 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t tracepoint_static_scheduler_DU_ends(scheduler->env->trace, worker_number, (int) *pc); } -/** - * @brief The implementation of the EIT instruction - */ -void execute_inst_EIT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_EIT_starts(scheduler->env->trace, worker_number, (int) *pc); - reaction_t* reaction = scheduler->reaction_instances[op1.imm]; - if (reaction->status == queued) { - *returned_reaction = reaction; - *exit_loop = true; - } else - LF_PRINT_DEBUG("*** Worker %zu skip execution", worker_number); - *pc += 1; // Increment pc. - tracepoint_static_scheduler_EIT_ends(scheduler->env->trace, worker_number, (int) *pc); - -} - /** * @brief The implementation of the EXE instruction */ @@ -412,25 +299,6 @@ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_ tracepoint_static_scheduler_JALR_ends(scheduler->env->trace, worker_number, (int) *pc); } -/** - * @brief The implementation of the SAC instruction - */ -void execute_inst_SAC(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, - reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_SAC_starts(scheduler->env->trace, worker_number, (int) *pc); - - // Compute the next tag for all reactors. - reg_t *src = op1.reg; - instant_t next_timestamp = *src + op2.imm; - - tracepoint_worker_wait_starts(scheduler->env->trace, worker_number); - _lf_sched_wait_for_work(scheduler, worker_number, next_timestamp); - tracepoint_worker_wait_ends(scheduler->env->trace, worker_number); - *pc += 1; // Increment pc. - - tracepoint_static_scheduler_SAC_ends(scheduler->env->trace, worker_number, (int) *pc); -} - /** * @brief The implementation of the STP instruction */ @@ -488,11 +356,6 @@ void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t opco LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); execute_inst_BGE(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; - case BIT: - op_str = "BIT"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_BIT(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); - break; case BLT: op_str = "BLT"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); @@ -508,11 +371,6 @@ void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t opco LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); execute_inst_DU(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; - case EIT: - op_str = "EIT"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_EIT(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); - break; case EXE: op_str = "EXE"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); @@ -528,11 +386,6 @@ void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t opco LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); execute_inst_JALR(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); break; - case SAC: - op_str = "SAC"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_SAC(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); - break; case STP: op_str = "STP"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); @@ -633,10 +486,10 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu reaction_t* returned_reaction = NULL; bool exit_loop = false; size_t* pc = &scheduler->pc[worker_number]; - opcode_t opcode; - operand_t op1; - operand_t op2; - operand_t op3; + opcode_t opcode; + operand_t op1; + operand_t op2; + operand_t op3; while (!exit_loop) { opcode = current_schedule[*pc].opcode; @@ -662,20 +515,7 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu * @param done_reaction The reaction that is done. */ void lf_sched_done_with_reaction(size_t worker_number, - reaction_t* done_reaction) { - LF_PRINT_DEBUG("*** Worker %zu inside lf_sched_done_with_reaction, done with %s", worker_number, done_reaction->name); - // If the reaction status is queued, change it back to inactive. - // We do not check for error here because the EXE instruction - // can execute a reaction with an "inactive" status. - // The reason is that since runtime does not advance - // global time, the next timer events will not be - // scheduled and put onto the event queue. The next - // timer events are encoded directly into the schedule - // using the EXE instructions. - lf_bool_compare_and_swap(&done_reaction->status, queued, inactive); - - LF_PRINT_DEBUG("*** Worker %zu reports updated status for %s: %u", worker_number, done_reaction->name, done_reaction->status); -} + reaction_t* done_reaction) {} /** * @brief Inform the scheduler that worker thread 'worker_number' would like to @@ -696,15 +536,6 @@ void lf_sched_done_with_reaction(size_t worker_number, * worker number does not make sense (e.g., the caller is not a worker thread). * */ -void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { - LF_PRINT_DEBUG("*** Worker %d triggering reaction %s", worker_number, reaction->name); - // Mark a reaction as queued, so that it will be executed when workers do work. - if (!lf_bool_compare_and_swap(&reaction->status, inactive, queued)) { - // FIXME: Uncommenting the code below yields weird exception. - // lf_print_error_and_exit("Worker %d reports unexpected reaction status for reaction %s: %d. Expected %d.", - // worker_number, reaction->name, - // reaction->status, inactive); - } -} +void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) {} #endif #endif diff --git a/include/core/threaded/scheduler_instructions.h b/include/core/threaded/scheduler_instructions.h index dd9a4f49a..5bb5123be 100644 --- a/include/core/threaded/scheduler_instructions.h +++ b/include/core/threaded/scheduler_instructions.h @@ -9,15 +9,12 @@ typedef enum { ADVI, BEQ, BGE, - BIT, BLT, BNE, DU, - EIT, EXE, JAL, JALR, - SAC, STP, WLT, WU, From 2fe28a6f6afb77fd9045f5436123f8dffc94e126 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sat, 24 Feb 2024 17:56:22 -0800 Subject: [PATCH 39/80] Fix seg fault in BEQ --- core/threaded/scheduler_static.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index f25f21372..be886ab09 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -155,13 +155,12 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; - LF_PRINT_DEBUG("Worker %zu: BEQ : operand 1 = %lld, operand 2 = %lld", worker_number, *_rs1, *_rs2); // These NULL checks allow _rs1 and _rs2 to be uninitialized in the static // schedule, which can save a few lines in the schedule. But it is debatable // whether this is good practice. // lf_print("_rs1 = %p, _rs2 = %p", _rs1, _rs2); - // if (_rs1 != NULL) printf("*_rs1 = %lld\n", *_rs1); - // if (_rs2 != NULL) printf("*_rs2 = %lld\n", *_rs2); + if (_rs1 != NULL) LF_PRINT_DEBUG("*_rs1 = %lld\n", *_rs1); + if (_rs2 != NULL) LF_PRINT_DEBUG("*_rs2 = %lld\n", *_rs2); if (_rs1 != NULL && _rs2 != NULL && *_rs1 == *_rs2) *pc = op3.imm; else *pc += 1; // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); From ebbdb7c77b197c34197e16e194cafc98692d593d Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 26 Feb 2024 19:54:24 +0100 Subject: [PATCH 40/80] Get logical tag of EXE_starts and EXE_ends --- core/threaded/scheduler_static.c | 4 ++-- core/trace.c | 24 ++++++++++++++++++------ include/core/trace.h | 5 +++-- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index be886ab09..b2eef7409 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -230,13 +230,13 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, (int) *pc); function_generic_t function = (function_generic_t)(uintptr_t)op1.reg; void *args = (void*)op2.reg; // Execute the function directly. function(args); *pc += 1; // Increment pc. - tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, (int) *pc); } diff --git a/core/trace.c b/core/trace.c index 45b62763f..8b0707636 100644 --- a/core/trace.c +++ b/core/trace.c @@ -331,8 +331,8 @@ void tracepoint( * @param worker The thread number of the worker thread or 0 for single-threaded execution. */ void tracepoint_reaction_starts(trace_t* trace, reaction_t* reaction, int worker) { - tracepoint(trace, reaction_starts, reaction->self, NULL, worker, worker, reaction->number, NULL, NULL, 0, true); -} + tracepoint(trace, reaction_starts, reaction->self, NULL, worker, worker, reaction->number, NULL, NULL, 0, true); + } /** * Trace the end of a reaction execution. @@ -490,8 +490,14 @@ void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker, int pc) } /** Trace the start of the EXE instruction */ -void tracepoint_static_scheduler_EXE_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_EXE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +void tracepoint_static_scheduler_EXE_starts(trace_t* trace, self_base_t *reactor, int worker, int pc) { + tag_t *tag = NULL; + + if (reactor) { + tag = &reactor->tag; + } + + tracepoint(trace, static_scheduler_EXE_starts, reactor, tag, worker, worker, pc, NULL, NULL, 0, false); } /** Trace the start of the JAL instruction */ @@ -550,8 +556,14 @@ void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker, int pc) { } /** Trace the end of the EXE instruction */ -void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_EXE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); +void tracepoint_static_scheduler_EXE_ends(trace_t* trace, self_base_t *reactor, int worker, int pc) { + tag_t *tag = NULL; + + if (reactor) { + tag = &reactor->tag; + } + + tracepoint(trace, static_scheduler_EXE_ends, reactor, tag, worker, worker, pc, NULL, NULL, 0, false); } /** Trace the end of the JAL instruction */ diff --git a/include/core/trace.h b/include/core/trace.h index a9a152d0e..48fbd05ce 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -490,7 +490,6 @@ void tracepoint_static_scheduler_ADVI_starts(trace_t* trace, int worker, int pc) void tracepoint_static_scheduler_BIT_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_EXE_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JAL_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JALR_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker, int pc); @@ -502,13 +501,15 @@ void tracepoint_static_scheduler_ADVI_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_EXE_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JAL_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JALR_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_EXE_starts(trace_t* trace, self_base_t *reactor, int worker, int pc); +void tracepoint_static_scheduler_EXE_ends(trace_t* trace, self_base_t *reactor, int worker, int pc); + /** * Flush any buffered trace records to the trace file and * close the files. From ccf50e5ac08b4d145b2bfc0578e39ddd9bf7b739 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Thu, 29 Feb 2024 00:19:50 -0800 Subject: [PATCH 41/80] Add a version of EXE tracing function specific for reactions, clean up tracing functions --- core/threaded/scheduler_static.c | 22 ++++----- core/trace.c | 76 +++++++++++--------------------- include/core/trace.h | 28 ++---------- 3 files changed, 42 insertions(+), 84 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index b2eef7409..90268b19c 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -152,7 +152,6 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ */ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; // These NULL checks allow _rs1 and _rs2 to be uninitialized in the static @@ -163,7 +162,6 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t if (_rs2 != NULL) LF_PRINT_DEBUG("*_rs2 = %lld\n", *_rs2); if (_rs1 != NULL && _rs2 != NULL && *_rs1 == *_rs2) *pc = op3.imm; else *pc += 1; - // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -171,13 +169,11 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; LF_PRINT_DEBUG("Worker %zu: BGE : operand 1 = %lld, operand 2 = %lld", worker_number, *_rs1, *_rs2); if (_rs1 != NULL && _rs2 != NULL && *_rs1 >= *_rs2) *pc = op3.imm; else *pc += 1; - tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -185,12 +181,10 @@ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; if (_rs1 != NULL && _rs2 != NULL && *_rs1 < *_rs2) *pc = op3.imm; else *pc += 1; - // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -198,12 +192,10 @@ void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - // tracepoint_static_scheduler_BIT_starts(scheduler->env->trace, worker_number, (int) *pc); reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; if (_rs1 != NULL && _rs2 != NULL && *_rs1 != *_rs2) *pc = op3.imm; else *pc += 1; - // tracepoint_static_scheduler_BIT_ends(scheduler->env->trace, worker_number, (int) *pc); } /** @@ -230,13 +222,23 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, (int) *pc); + if (op3.imm == ULLONG_MAX) { + tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, (int) *pc); + } + else { + tracepoint_static_scheduler_EXE_reaction_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, (int) *pc, (int) op3.imm); + } function_generic_t function = (function_generic_t)(uintptr_t)op1.reg; void *args = (void*)op2.reg; // Execute the function directly. function(args); *pc += 1; // Increment pc. - tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, (int) *pc); + if (op3.imm == ULLONG_MAX) { + tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, (int) *pc); + } + else { + tracepoint_static_scheduler_EXE_reaction_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, (int) *pc, (int) op3.imm); + } } diff --git a/core/trace.c b/core/trace.c index 8b0707636..fa4e6e8e0 100644 --- a/core/trace.c +++ b/core/trace.c @@ -331,8 +331,8 @@ void tracepoint( * @param worker The thread number of the worker thread or 0 for single-threaded execution. */ void tracepoint_reaction_starts(trace_t* trace, reaction_t* reaction, int worker) { - tracepoint(trace, reaction_starts, reaction->self, NULL, worker, worker, reaction->number, NULL, NULL, 0, true); - } + tracepoint(trace, reaction_starts, reaction->self, NULL, worker, worker, reaction->number, NULL, NULL, 0, true); +} /** * Trace the end of a reaction execution. @@ -461,68 +461,56 @@ void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, i /** Trace the start of the ADDI instruction */ void tracepoint_static_scheduler_ADDI_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADDI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + tracepoint(trace, static_scheduler_ADDI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); } /** Trace the start of the ADV instruction */ void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADV_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + tracepoint(trace, static_scheduler_ADV_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); } /** Trace the start of the ADVI instruction */ void tracepoint_static_scheduler_ADVI_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADVI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - -/** Trace the start of the BIT instruction */ -void tracepoint_static_scheduler_BIT_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_BIT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + tracepoint(trace, static_scheduler_ADVI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); } /** Trace the start of the DU instruction */ void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_DU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - -/** Trace the start of the EIT instruction */ -void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_EIT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + tracepoint(trace, static_scheduler_DU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); } /** Trace the start of the EXE instruction */ void tracepoint_static_scheduler_EXE_starts(trace_t* trace, self_base_t *reactor, int worker, int pc) { tag_t *tag = NULL; + if (reactor) tag = &reactor->tag; + tracepoint(trace, static_scheduler_EXE_starts, reactor, tag, worker, worker, pc, NULL, NULL, 0, true); +} - if (reactor) { - tag = &reactor->tag; - } - - tracepoint(trace, static_scheduler_EXE_starts, reactor, tag, worker, worker, pc, NULL, NULL, 0, false); +/** Trace the start of the EXE instruction (for reactions) */ +void tracepoint_static_scheduler_EXE_reaction_starts(trace_t* trace, self_base_t *reactor, int worker, int pc, int reaction_number) { + tag_t *tag = NULL; + if (reactor) tag = &reactor->tag; + tracepoint(trace, reaction_starts, reactor, tag, worker, worker, reaction_number, NULL, NULL, 0, true); } /** Trace the start of the JAL instruction */ void tracepoint_static_scheduler_JAL_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_JAL_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + tracepoint(trace, static_scheduler_JAL_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); } /** Trace the start of the JALR instruction */ void tracepoint_static_scheduler_JALR_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_JALR_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - -/** Trace the start of the SAC instruction */ -void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_SAC_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + tracepoint(trace, static_scheduler_JALR_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); } /** Trace the start of the STP instruction */ void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_STP_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + tracepoint(trace, static_scheduler_STP_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); } /** Trace the start of the WU instruction */ void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_WU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); + tracepoint(trace, static_scheduler_WU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); } /** Trace the end of the ADDI instruction */ @@ -540,32 +528,25 @@ void tracepoint_static_scheduler_ADVI_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_ADVI_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -/** Trace the end of the BIT instruction */ -void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_BIT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - /** Trace the end of the DU instruction */ void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_DU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -/** Trace the end of the EIT instruction */ -void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_EIT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - /** Trace the end of the EXE instruction */ void tracepoint_static_scheduler_EXE_ends(trace_t* trace, self_base_t *reactor, int worker, int pc) { tag_t *tag = NULL; - - if (reactor) { - tag = &reactor->tag; - } - + if (reactor) tag = &reactor->tag; tracepoint(trace, static_scheduler_EXE_ends, reactor, tag, worker, worker, pc, NULL, NULL, 0, false); } +/** Trace the end of the EXE instruction (for reactions) */ +void tracepoint_static_scheduler_EXE_reaction_ends(trace_t* trace, self_base_t *reactor, int worker, int pc, int reaction_number) { + tag_t *tag = NULL; + if (reactor) tag = &reactor->tag; + tracepoint(trace, reaction_ends, reactor, tag, worker, worker, reaction_number, NULL, NULL, 0, false); +} + /** Trace the end of the JAL instruction */ void tracepoint_static_scheduler_JAL_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_JAL_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); @@ -576,11 +557,6 @@ void tracepoint_static_scheduler_JALR_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_JALR_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } -/** Trace the end of the SAC instruction */ -void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_SAC_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - /** Trace the end of the STP instruction */ void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_STP_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); diff --git a/include/core/trace.h b/include/core/trace.h index 48fbd05ce..2ffdfcc82 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -80,25 +80,19 @@ typedef enum static_scheduler_ADDI_starts, static_scheduler_ADV_starts, static_scheduler_ADVI_starts, - static_scheduler_BIT_starts, static_scheduler_DU_starts, - static_scheduler_EIT_starts, static_scheduler_EXE_starts, static_scheduler_JAL_starts, static_scheduler_JALR_starts, - static_scheduler_SAC_starts, static_scheduler_STP_starts, static_scheduler_WU_starts, static_scheduler_ADDI_ends, static_scheduler_ADV_ends, static_scheduler_ADVI_ends, - static_scheduler_BIT_ends, static_scheduler_DU_ends, - static_scheduler_EIT_ends, static_scheduler_EXE_ends, static_scheduler_JAL_ends, static_scheduler_JALR_ends, - static_scheduler_SAC_ends, static_scheduler_STP_ends, static_scheduler_WU_ends, federated, // Everything below this is for tracing federated interactions. @@ -170,25 +164,19 @@ static const char *trace_event_names[] = { "ADDI: add immediate", "ADV: advance logical time", "ADVI: advance logical time (lock-free)", - "BIT: branch if timeout", "DU: delay until", - "EIT: execute if triggered", "EXE: execute", "JAL: jump", "JALR: jump and return", - "SAC: synchronize advance time and clear counters", "STP: stop", "WU: wait until", "End ADDI: add immediate", "End ADV: advance logical time", "End ADVI: advance logical time (lock-free)", - "End BIT: branch if timeout", "End DU: delay until", - "End EIT: execute if triggered", "End EXE: execute", "End JAL: jump", "End JALR: jump and return", - "End SAC: synchronize advance time and clear counters", "End STP: stop", "End WU: wait until", "Federated marker", @@ -487,28 +475,24 @@ void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, i void tracepoint_static_scheduler_ADDI_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADVI_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_BIT_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_EIT_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JAL_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JALR_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_SAC_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADDI_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADVI_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_BIT_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_EIT_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JAL_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JALR_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_SAC_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EXE_starts(trace_t* trace, self_base_t *reactor, int worker, int pc); void tracepoint_static_scheduler_EXE_ends(trace_t* trace, self_base_t *reactor, int worker, int pc); +void tracepoint_static_scheduler_EXE_reaction_starts(trace_t* trace, self_base_t *reactor, int worker, int pc, int reaction_number); +void tracepoint_static_scheduler_EXE_reaction_ends(trace_t* trace, self_base_t *reactor, int worker, int pc, int reaction_number); /** * Flush any buffered trace records to the trace file and @@ -619,25 +603,21 @@ typedef struct trace_t trace_t; #define tracepoint_static_scheduler_ADDI_starts(...); #define tracepoint_static_scheduler_ADV_starts(...); #define tracepoint_static_scheduler_ADVI_starts(...); -#define tracepoint_static_scheduler_BIT_starts(...); #define tracepoint_static_scheduler_DU_starts(...); -#define tracepoint_static_scheduler_EIT_starts(...); #define tracepoint_static_scheduler_EXE_starts(...); +#define tracepoint_static_scheduler_EXE_reaction_starts(...); #define tracepoint_static_scheduler_JAL_starts(...); #define tracepoint_static_scheduler_JALR_starts(...); -#define tracepoint_static_scheduler_SAC_starts(...); #define tracepoint_static_scheduler_STP_starts(...); #define tracepoint_static_scheduler_WU_starts(...); #define tracepoint_static_scheduler_ADDI_ends(...); #define tracepoint_static_scheduler_ADV_ends(...); #define tracepoint_static_scheduler_ADVI_ends(...); -#define tracepoint_static_scheduler_BIT_ends(...); #define tracepoint_static_scheduler_DU_ends(...); -#define tracepoint_static_scheduler_EIT_ends(...); #define tracepoint_static_scheduler_EXE_ends(...); +#define tracepoint_static_scheduler_EXE_reaction_ends(...); #define tracepoint_static_scheduler_JAL_ends(...); #define tracepoint_static_scheduler_JALR_ends(...); -#define tracepoint_static_scheduler_SAC_ends(...); #define tracepoint_static_scheduler_STP_ends(...); #define tracepoint_static_scheduler_WU_ends(...); #define tracepoint_federate_to_rti(...); From a47356b650199ddab2ccbdd295028a75b472bbc9 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Tue, 5 Mar 2024 17:18:24 -0800 Subject: [PATCH 42/80] Update tracing and add debug flag to instructions --- core/threaded/scheduler_static.c | 74 ++++++++++--------- core/trace.c | 4 + .../core/threaded/scheduler_instructions.h | 1 + 3 files changed, 44 insertions(+), 35 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 90268b19c..3f5f70fad 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -70,7 +70,7 @@ extern volatile reg_t binary_sema[]; /** * @brief The implementation of the ADD instruction */ -void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, (int) *pc); reg_t *dst = op1.reg; @@ -84,7 +84,7 @@ void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t /** * @brief The implementation of the ADDI instruction */ -void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, (int) *pc); reg_t *dst = op1.reg; @@ -98,7 +98,7 @@ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, operand_ /** * @brief The implementation of the ADV instruction */ -void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number, (int) *pc); @@ -125,7 +125,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t /** * @brief The implementation of the ADVI instruction */ -void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_ADVI_starts(scheduler->env->trace, worker_number, (int) *pc); @@ -150,16 +150,18 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ /** * @brief The implementation of the BEQ instruction */ -void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; // These NULL checks allow _rs1 and _rs2 to be uninitialized in the static // schedule, which can save a few lines in the schedule. But it is debatable // whether this is good practice. - // lf_print("_rs1 = %p, _rs2 = %p", _rs1, _rs2); - if (_rs1 != NULL) LF_PRINT_DEBUG("*_rs1 = %lld\n", *_rs1); - if (_rs2 != NULL) LF_PRINT_DEBUG("*_rs2 = %lld\n", *_rs2); + if (debug) { + lf_print("DEBUG: _rs1 = %p, _rs2 = %p", _rs1, _rs2); + if (_rs1 != NULL) lf_print("DEBUG: *_rs1 = %lld", *_rs1); + if (_rs2 != NULL) lf_print("DEBUG: *_rs2 = %lld", *_rs2); + } if (_rs1 != NULL && _rs2 != NULL && *_rs1 == *_rs2) *pc = op3.imm; else *pc += 1; } @@ -167,7 +169,7 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t /** * @brief The implementation of the BGE instruction */ -void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; @@ -179,7 +181,7 @@ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t /** * @brief The implementation of the BLT instruction */ -void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; @@ -190,7 +192,7 @@ void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t /** * @brief The implementation of the BNE instruction */ -void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; @@ -201,7 +203,7 @@ void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t /** * @brief The implementation of the DU instruction */ -void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_DU_starts(scheduler->env->trace, worker_number, (int) *pc); // FIXME: There seems to be an overflow problem. @@ -220,7 +222,7 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t /** * @brief The implementation of the EXE instruction */ -void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { if (op3.imm == ULLONG_MAX) { tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, (int) *pc); @@ -245,7 +247,7 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t /** * @brief The implementation of the WLT instruction */ -void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { // tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, (int) *pc); LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); @@ -259,7 +261,7 @@ void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t /** * @brief The implementation of the WU instruction */ -void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, (int) *pc); LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); @@ -273,7 +275,7 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t /** * @brief The implementation of the JAL instruction */ -void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_JAL_starts(scheduler->env->trace, worker_number, (int) *pc); // Use the destination register as the return address and, if the @@ -287,7 +289,7 @@ void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t /** * @brief The implementation of the JALR instruction */ -void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_JALR_starts(scheduler->env->trace, worker_number, (int) *pc); // Use the destination register as the return address and, if the @@ -303,7 +305,7 @@ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_ /** * @brief The implementation of the STP instruction */ -void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, size_t* pc, +void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { tracepoint_static_scheduler_STP_starts(scheduler->env->trace, worker_number, (int) *pc); *exit_loop = true; @@ -323,84 +325,84 @@ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, operand_t * @param exit_loop a pointer to a boolean indicating whether * the outer while loop should be exited */ -void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t opcode, operand_t op1, operand_t op2, operand_t op3, +void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t opcode, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { char* op_str = NULL; switch (opcode) { case ADD: op_str = "ADD"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_ADD(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_ADD(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case ADDI: op_str = "ADDI"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_ADDI(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_ADDI(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case ADV: op_str = "ADV"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_ADV(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_ADV(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case ADVI: op_str = "ADVI"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_ADVI(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_ADVI(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case BEQ: op_str = "BEQ"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_BEQ(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_BEQ(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case BGE: op_str = "BGE"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_BGE(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_BGE(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case BLT: op_str = "BLT"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_BLT(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_BLT(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case BNE: op_str = "BNE"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_BNE(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_BNE(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case DU: op_str = "DU"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_DU(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_DU(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case EXE: op_str = "EXE"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_EXE(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_EXE(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case JAL: op_str = "JAL"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_JAL(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_JAL(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case JALR: op_str = "JALR"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_JALR(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_JALR(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case STP: op_str = "STP"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_STP(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_STP(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case WLT: op_str = "WLT"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_WLT(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_WLT(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; case WU: op_str = "WU"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_WU(scheduler, worker_number, op1, op2, op3, pc, returned_reaction, exit_loop); + execute_inst_WU(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); break; default: lf_print_error_and_exit("Invalid instruction: %d", opcode); @@ -491,15 +493,17 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu operand_t op1; operand_t op2; operand_t op3; + bool debug; while (!exit_loop) { opcode = current_schedule[*pc].opcode; op1 = current_schedule[*pc].op1; op2 = current_schedule[*pc].op2; op3 = current_schedule[*pc].op3; + debug = current_schedule[*pc].debug; // Execute the current instruction - execute_inst(scheduler, worker_number, opcode, op1, op2, op3, pc, + execute_inst(scheduler, worker_number, opcode, op1, op2, op3, debug, pc, &returned_reaction, &exit_loop); } diff --git a/core/trace.c b/core/trace.c index fa4e6e8e0..5a4bc051d 100644 --- a/core/trace.c +++ b/core/trace.c @@ -459,6 +459,8 @@ void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, i tracepoint(trace, reaction_deadline_missed, reaction->self, NULL, worker, worker, reaction->number, NULL, NULL, 0, false); } +#if SCHEDULER == SCHED_STATIC + /** Trace the start of the ADDI instruction */ void tracepoint_static_scheduler_ADDI_starts(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_ADDI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); @@ -567,6 +569,8 @@ void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_WU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } +#endif + void stop_trace(trace_t* trace) { LF_CRITICAL_SECTION_ENTER(trace->env); stop_trace_locked(trace); diff --git a/include/core/threaded/scheduler_instructions.h b/include/core/threaded/scheduler_instructions.h index 5bb5123be..12904cc66 100644 --- a/include/core/threaded/scheduler_instructions.h +++ b/include/core/threaded/scheduler_instructions.h @@ -53,4 +53,5 @@ typedef struct inst_t { operand_t op1; operand_t op2; operand_t op3; + bool debug; } inst_t; \ No newline at end of file From 261cb8b6abfb7fa68c0e26851dbcc533d155e8a1 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Wed, 6 Mar 2024 11:52:42 -0800 Subject: [PATCH 43/80] Improve static tracing --- core/threaded/scheduler_static.c | 86 +++++++++++++++++++------------- core/trace.c | 60 ++++++++++++++++++++++ include/core/trace.h | 84 ++++++++++++++++++++++++------- 3 files changed, 177 insertions(+), 53 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 3f5f70fad..749990f8b 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -72,13 +72,14 @@ extern volatile reg_t binary_sema[]; */ void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, (int) *pc); + int pc_orig = (int) *pc; + tracepoint_static_scheduler_ADD_starts(scheduler->env->trace, worker_number, pc_orig); reg_t *dst = op1.reg; reg_t *src = op2.reg; reg_t *src2 = op3.reg; *dst = *src + *src2; *pc += 1; // Increment pc. - tracepoint_static_scheduler_ADDI_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_ADD_ends(scheduler->env->trace, worker_number, pc_orig); } /** @@ -86,13 +87,14 @@ void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, (int) *pc); + int pc_orig = (int) *pc; + tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, pc_orig); reg_t *dst = op1.reg; reg_t *src = op2.reg; // FIXME: Will there be problems if instant_t adds reg_t? *dst = *src + op3.imm; *pc += 1; // Increment pc. - tracepoint_static_scheduler_ADDI_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_ADDI_ends(scheduler->env->trace, worker_number, pc_orig); } /** @@ -100,7 +102,8 @@ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, operand_ */ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number, (int) *pc); + int pc_orig = (int) *pc; + tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number, pc_orig); reg_t *base = op2.reg; reg_t *inc = op3.reg; @@ -118,8 +121,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t } *pc += 1; // Increment pc. - - tracepoint_static_scheduler_ADV_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_ADV_ends(scheduler->env->trace, worker_number, pc_orig); } /** @@ -127,7 +129,8 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_ADVI_starts(scheduler->env->trace, worker_number, (int) *pc); + int pc_orig = (int) *pc; + tracepoint_static_scheduler_ADVI_starts(scheduler->env->trace, worker_number, pc_orig); self_base_t *reactor = (self_base_t*) op1.reg; reg_t *base = op2.reg; @@ -141,10 +144,8 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ for (int i = 0; i < reactor->num_output_ports; i++) { reactor->output_ports[i]->is_present = false; } - *pc += 1; // Increment pc. - - tracepoint_static_scheduler_ADVI_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_ADVI_ends(scheduler->env->trace, worker_number, pc_orig); } /** @@ -152,6 +153,8 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ */ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + int pc_orig = (int) *pc; + tracepoint_static_scheduler_BEQ_starts(scheduler->env->trace, worker_number, pc_orig); reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; // These NULL checks allow _rs1 and _rs2 to be uninitialized in the static @@ -164,6 +167,7 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t } if (_rs1 != NULL && _rs2 != NULL && *_rs1 == *_rs2) *pc = op3.imm; else *pc += 1; + tracepoint_static_scheduler_BEQ_ends(scheduler->env->trace, worker_number, pc_orig); } /** @@ -171,11 +175,14 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + int pc_orig = (int) *pc; + tracepoint_static_scheduler_BGE_starts(scheduler->env->trace, worker_number, pc_orig); reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; LF_PRINT_DEBUG("Worker %zu: BGE : operand 1 = %lld, operand 2 = %lld", worker_number, *_rs1, *_rs2); if (_rs1 != NULL && _rs2 != NULL && *_rs1 >= *_rs2) *pc = op3.imm; else *pc += 1; + tracepoint_static_scheduler_BGE_ends(scheduler->env->trace, worker_number, pc_orig); } /** @@ -183,10 +190,13 @@ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + int pc_orig = (int) *pc; + tracepoint_static_scheduler_BLT_starts(scheduler->env->trace, worker_number, pc_orig); reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; if (_rs1 != NULL && _rs2 != NULL && *_rs1 < *_rs2) *pc = op3.imm; else *pc += 1; + tracepoint_static_scheduler_BLT_ends(scheduler->env->trace, worker_number, pc_orig); } /** @@ -194,10 +204,13 @@ void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + int pc_orig = (int) *pc; + tracepoint_static_scheduler_BNE_starts(scheduler->env->trace, worker_number, pc_orig); reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; if (_rs1 != NULL && _rs2 != NULL && *_rs1 != *_rs2) *pc = op3.imm; else *pc += 1; + tracepoint_static_scheduler_BNE_ends(scheduler->env->trace, worker_number, pc_orig); } /** @@ -205,7 +218,8 @@ void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_DU_starts(scheduler->env->trace, worker_number, (int) *pc); + int pc_orig = (int) *pc; + tracepoint_static_scheduler_DU_starts(scheduler->env->trace, worker_number, pc_orig); // FIXME: There seems to be an overflow problem. // When wakeup_time overflows but lf_time_physical() doesn't, // _lf_interruptable_sleep_until_locked() terminates immediately. @@ -216,7 +230,7 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); *pc += 1; // Increment pc. - tracepoint_static_scheduler_DU_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_DU_ends(scheduler->env->trace, worker_number, pc_orig); } /** @@ -224,23 +238,20 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - if (op3.imm == ULLONG_MAX) { - tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, (int) *pc); - } - else { - tracepoint_static_scheduler_EXE_reaction_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, (int) *pc, (int) op3.imm); - } + int pc_orig = (int) *pc; + if (op3.imm == ULLONG_MAX) + tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig); + else + tracepoint_static_scheduler_EXE_reaction_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm); function_generic_t function = (function_generic_t)(uintptr_t)op1.reg; void *args = (void*)op2.reg; // Execute the function directly. function(args); *pc += 1; // Increment pc. - if (op3.imm == ULLONG_MAX) { - tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, (int) *pc); - } - else { - tracepoint_static_scheduler_EXE_reaction_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, (int) *pc, (int) op3.imm); - } + if (op3.imm == ULLONG_MAX) + tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig); + else + tracepoint_static_scheduler_EXE_reaction_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm); } @@ -249,13 +260,14 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - // tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, (int) *pc); + int pc_orig = (int) *pc; + tracepoint_static_scheduler_WLT_starts(scheduler->env->trace, worker_number, pc_orig); LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); reg_t *var = op1.reg; while(*var >= op2.imm); LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); *pc += 1; // Increment pc. - // tracepoint_static_scheduler_WU_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_WLT_ends(scheduler->env->trace, worker_number, pc_orig); } /** @@ -263,13 +275,14 @@ void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, (int) *pc); + int pc_orig = (int) *pc; + tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, pc_orig); LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); reg_t *var = op1.reg; while(*var < op2.imm); LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); *pc += 1; // Increment pc. - tracepoint_static_scheduler_WU_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_WU_ends(scheduler->env->trace, worker_number, pc_orig); } /** @@ -277,13 +290,14 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_JAL_starts(scheduler->env->trace, worker_number, (int) *pc); + int pc_orig = (int) *pc; + tracepoint_static_scheduler_JAL_starts(scheduler->env->trace, worker_number, pc_orig); // Use the destination register as the return address and, if the // destination register is not the zero register, store pc+1 in it. reg_t *destReg = op1.reg; if (destReg != &zero) *destReg = *pc + 1; *pc = op2.imm; - tracepoint_static_scheduler_JAL_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_JAL_ends(scheduler->env->trace, worker_number, pc_orig); } /** @@ -291,7 +305,8 @@ void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_JALR_starts(scheduler->env->trace, worker_number, (int) *pc); + int pc_orig = (int) *pc; + tracepoint_static_scheduler_JALR_starts(scheduler->env->trace, worker_number, pc_orig); // Use the destination register as the return address and, if the // destination register is not the zero register, store pc+1 in it. reg_t *destReg = op1.reg; @@ -299,7 +314,7 @@ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_ // Set pc to base addr + immediate. reg_t *baseAddr = op2.reg; *pc = *baseAddr + op3.imm; - tracepoint_static_scheduler_JALR_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_JALR_ends(scheduler->env->trace, worker_number, pc_orig); } /** @@ -307,9 +322,10 @@ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_ */ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - tracepoint_static_scheduler_STP_starts(scheduler->env->trace, worker_number, (int) *pc); + int pc_orig = (int) *pc; + tracepoint_static_scheduler_STP_starts(scheduler->env->trace, worker_number, pc_orig); *exit_loop = true; - tracepoint_static_scheduler_STP_ends(scheduler->env->trace, worker_number, (int) *pc); + tracepoint_static_scheduler_STP_ends(scheduler->env->trace, worker_number, pc_orig); } /** diff --git a/core/trace.c b/core/trace.c index 5a4bc051d..64f55df61 100644 --- a/core/trace.c +++ b/core/trace.c @@ -461,6 +461,11 @@ void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, i #if SCHEDULER == SCHED_STATIC +/** Trace the start of the ADD instruction */ +void tracepoint_static_scheduler_ADD_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_ADD_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); +} + /** Trace the start of the ADDI instruction */ void tracepoint_static_scheduler_ADDI_starts(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_ADDI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); @@ -476,6 +481,26 @@ void tracepoint_static_scheduler_ADVI_starts(trace_t* trace, int worker, int pc) tracepoint(trace, static_scheduler_ADVI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); } +/** Trace the start of the BEQ instruction */ +void tracepoint_static_scheduler_BEQ_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_BEQ_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); +} + +/** Trace the start of the BGE instruction */ +void tracepoint_static_scheduler_BGE_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_BGE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); +} + +/** Trace the start of the BLT instruction */ +void tracepoint_static_scheduler_BLT_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_BLT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); +} + +/** Trace the start of the BNE instruction */ +void tracepoint_static_scheduler_BNE_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_BNE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); +} + /** Trace the start of the DU instruction */ void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_DU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); @@ -510,11 +535,21 @@ void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker, int pc) tracepoint(trace, static_scheduler_STP_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); } +/** Trace the start of the WLT instruction */ +void tracepoint_static_scheduler_WLT_starts(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_WLT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); +} + /** Trace the start of the WU instruction */ void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_WU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); } +/** Trace the end of the ADD instruction */ +void tracepoint_static_scheduler_ADD_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_ADD_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); +} + /** Trace the end of the ADDI instruction */ void tracepoint_static_scheduler_ADDI_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_ADDI_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); @@ -530,6 +565,26 @@ void tracepoint_static_scheduler_ADVI_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_ADVI_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } +/** Trace the end of the BEQ instruction */ +void tracepoint_static_scheduler_BEQ_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_BEQ_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); +} + +/** Trace the end of the BGE instruction */ +void tracepoint_static_scheduler_BGE_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_BGE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); +} + +/** Trace the end of the BLT instruction */ +void tracepoint_static_scheduler_BLT_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_BLT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); +} + +/** Trace the end of the BNE instruction */ +void tracepoint_static_scheduler_BNE_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_BNE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); +} + /** Trace the end of the DU instruction */ void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_DU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); @@ -564,6 +619,11 @@ void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_STP_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); } +/** Trace the end of the WLT instruction */ +void tracepoint_static_scheduler_WLT_ends(trace_t* trace, int worker, int pc) { + tracepoint(trace, static_scheduler_WLT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); +} + /** Trace the end of the WU instruction */ void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker, int pc) { tracepoint(trace, static_scheduler_WU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); diff --git a/include/core/trace.h b/include/core/trace.h index 2ffdfcc82..24a557503 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -77,23 +77,35 @@ typedef enum scheduler_advancing_time_starts, scheduler_advancing_time_ends, // Static scheduler instructions + static_scheduler_ADD_starts, static_scheduler_ADDI_starts, static_scheduler_ADV_starts, static_scheduler_ADVI_starts, + static_scheduler_BEQ_starts, + static_scheduler_BGE_starts, + static_scheduler_BLT_starts, + static_scheduler_BNE_starts, static_scheduler_DU_starts, static_scheduler_EXE_starts, static_scheduler_JAL_starts, static_scheduler_JALR_starts, static_scheduler_STP_starts, + static_scheduler_WLT_starts, static_scheduler_WU_starts, + static_scheduler_ADD_ends, static_scheduler_ADDI_ends, static_scheduler_ADV_ends, static_scheduler_ADVI_ends, + static_scheduler_BEQ_ends, + static_scheduler_BGE_ends, + static_scheduler_BLT_ends, + static_scheduler_BNE_ends, static_scheduler_DU_ends, static_scheduler_EXE_ends, static_scheduler_JAL_ends, static_scheduler_JALR_ends, static_scheduler_STP_ends, + static_scheduler_WLT_ends, static_scheduler_WU_ends, federated, // Everything below this is for tracing federated interactions. // Sending messages @@ -161,24 +173,36 @@ static const char *trace_event_names[] = { "Scheduler advancing time starts", "Scheduler advancing time ends", // Static scheduler instructions - "ADDI: add immediate", - "ADV: advance logical time", - "ADVI: advance logical time (lock-free)", - "DU: delay until", - "EXE: execute", - "JAL: jump", - "JALR: jump and return", - "STP: stop", - "WU: wait until", - "End ADDI: add immediate", - "End ADV: advance logical time", - "End ADVI: advance logical time (lock-free)", - "End DU: delay until", - "End EXE: execute", - "End JAL: jump", - "End JALR: jump and return", - "End STP: stop", - "End WU: wait until", + "ADD", + "ADDI", + "ADV", + "ADVI", + "BEQ", + "BGE", + "BLT", + "BNE", + "DU", + "EXE", + "JAL", + "JALR", + "STP", + "WLT", + "WU", + "End ADD", + "End ADDI", + "End ADV", + "End ADVI", + "End BEQ", + "End BGE", + "End BLT", + "End BNE", + "End DU", + "End EXE", + "End JAL", + "End JALR", + "End STP", + "End WLT", + "End WU", "Federated marker", // Sending messages "Sending ACK", @@ -472,21 +496,33 @@ void tracepoint_scheduler_advancing_time_ends(trace_t* trace); */ void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, int worker); +void tracepoint_static_scheduler_ADD_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADDI_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADVI_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_BEQ_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_BGE_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_BLT_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_BNE_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JAL_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JALR_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_WLT_starts(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_ADD_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADDI_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_ADVI_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_BEQ_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_BGE_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_BLT_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_BNE_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JAL_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_JALR_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc); +void tracepoint_static_scheduler_WLT_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker, int pc); void tracepoint_static_scheduler_EXE_starts(trace_t* trace, self_base_t *reactor, int worker, int pc); @@ -600,25 +636,37 @@ typedef struct trace_t trace_t; #define tracepoint_scheduler_advancing_time_starts(...); #define tracepoint_scheduler_advancing_time_ends(...); #define tracepoint_reaction_deadline_missed(...); +#define tracepoint_static_scheduler_ADD_starts(...); #define tracepoint_static_scheduler_ADDI_starts(...); #define tracepoint_static_scheduler_ADV_starts(...); #define tracepoint_static_scheduler_ADVI_starts(...); +#define tracepoint_static_scheduler_BEQ_starts(...); +#define tracepoint_static_scheduler_BGE_starts(...); +#define tracepoint_static_scheduler_BLT_starts(...); +#define tracepoint_static_scheduler_BNE_starts(...); #define tracepoint_static_scheduler_DU_starts(...); #define tracepoint_static_scheduler_EXE_starts(...); #define tracepoint_static_scheduler_EXE_reaction_starts(...); #define tracepoint_static_scheduler_JAL_starts(...); #define tracepoint_static_scheduler_JALR_starts(...); #define tracepoint_static_scheduler_STP_starts(...); +#define tracepoint_static_scheduler_WLT_starts(...); #define tracepoint_static_scheduler_WU_starts(...); +#define tracepoint_static_scheduler_ADD_ends(...); #define tracepoint_static_scheduler_ADDI_ends(...); #define tracepoint_static_scheduler_ADV_ends(...); #define tracepoint_static_scheduler_ADVI_ends(...); +#define tracepoint_static_scheduler_BEQ_ends(...); +#define tracepoint_static_scheduler_BGE_ends(...); +#define tracepoint_static_scheduler_BLT_ends(...); +#define tracepoint_static_scheduler_BNE_ends(...); #define tracepoint_static_scheduler_DU_ends(...); #define tracepoint_static_scheduler_EXE_ends(...); #define tracepoint_static_scheduler_EXE_reaction_ends(...); #define tracepoint_static_scheduler_JAL_ends(...); #define tracepoint_static_scheduler_JALR_ends(...); #define tracepoint_static_scheduler_STP_ends(...); +#define tracepoint_static_scheduler_WLT_ends(...); #define tracepoint_static_scheduler_WU_ends(...); #define tracepoint_federate_to_rti(...); #define tracepoint_federate_from_rti(...); From 55bb599c8e01341179f1e1d36183931c883cd86d Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Wed, 6 Mar 2024 22:43:48 -0800 Subject: [PATCH 44/80] Use spin wait and fix tracing --- core/threaded/scheduler_static.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 749990f8b..c1b0f1154 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -227,7 +227,8 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t instant_t wakeup_time = *src + op2.imm; LF_PRINT_DEBUG("start_time: %lld, wakeup_time: %lld, op1: %lld, op2: %lld, current_physical_time: %lld\n", start_time, wakeup_time, *src, op2.imm, lf_time_physical()); LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); - _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); + // _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); + while (lf_time_physical() < wakeup_time); LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); *pc += 1; // Increment pc. tracepoint_static_scheduler_DU_ends(scheduler->env->trace, worker_number, pc_orig); @@ -239,19 +240,15 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { int pc_orig = (int) *pc; - if (op3.imm == ULLONG_MAX) - tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig); - else - tracepoint_static_scheduler_EXE_reaction_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm); + if (op3.imm == ULLONG_MAX) {tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig);} + else {tracepoint_static_scheduler_EXE_reaction_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm);} function_generic_t function = (function_generic_t)(uintptr_t)op1.reg; void *args = (void*)op2.reg; // Execute the function directly. function(args); *pc += 1; // Increment pc. - if (op3.imm == ULLONG_MAX) - tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig); - else - tracepoint_static_scheduler_EXE_reaction_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm); + if (op3.imm == ULLONG_MAX) {tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig);} + else {tracepoint_static_scheduler_EXE_reaction_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm);} } From 57fffe10dc8a774d8697415ec63626c88f90aefc Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sat, 9 Mar 2024 13:45:35 -0800 Subject: [PATCH 45/80] Add WIP for chrome tracing --- util/tracing/trace_to_chrome.c | 212 ++++++++++++++++++++++++++++++++- 1 file changed, 209 insertions(+), 3 deletions(-) diff --git a/util/tracing/trace_to_chrome.c b/util/tracing/trace_to_chrome.c index ec4cb1b1e..873b4d367 100644 --- a/util/tracing/trace_to_chrome.c +++ b/util/tracing/trace_to_chrome.c @@ -51,6 +51,15 @@ FILE* trace_file = NULL; /** File for writing the output data. */ FILE* output_file = NULL; +/** + * By default, the Chrome tracing displays events in us granularity. So + * timestamps by default are divided by scaling=1000 to show correct units in + * the GUI. However, for sub-us events, it is preferable to set scaling=1 so + * that the execution time of events are not abstracted to 0. + */ +int scaling_factor = 1000; +// double scaling_factor = 1; // For seeing sub-us events. + /** * Print a usage message. */ @@ -68,6 +77,76 @@ int max_reaction_number = 0; /** Indicator to plot vs. physical time only. */ bool physical_time_only = false; +/** A helper function for retriving virtual instruction name from event type */ +char* get_instruction_name(trace_event_t event_type) { + switch(event_type) { + case static_scheduler_ADD_starts: + case static_scheduler_ADD_ends: + return "ADD"; + break; + case static_scheduler_ADDI_starts: + case static_scheduler_ADDI_ends: + return "ADDI"; + break; + case static_scheduler_ADV_starts: + case static_scheduler_ADV_ends: + return "ADV"; + break; + case static_scheduler_ADVI_starts: + case static_scheduler_ADVI_ends: + return "ADVI"; + break; + case static_scheduler_BEQ_starts: + case static_scheduler_BEQ_ends: + return "BEQ"; + break; + case static_scheduler_BGE_starts: + case static_scheduler_BGE_ends: + return "BGE"; + break; + case static_scheduler_BLT_starts: + case static_scheduler_BLT_ends: + return "BLT"; + break; + case static_scheduler_BNE_starts: + case static_scheduler_BNE_ends: + return "BNE"; + break; + case static_scheduler_DU_starts: + case static_scheduler_DU_ends: + return "DU"; + break; + case static_scheduler_EXE_starts: + case static_scheduler_EXE_ends: + return "EXE"; + break; + case static_scheduler_JAL_starts: + case static_scheduler_JAL_ends: + return "JAL"; + break; + case static_scheduler_JALR_starts: + case static_scheduler_JALR_ends: + return "JALR"; + break; + case static_scheduler_STP_starts: + case static_scheduler_STP_ends: + return "STP"; + break; + case static_scheduler_WLT_starts: + case static_scheduler_WLT_ends: + return "WLT"; + break; + case static_scheduler_WU_starts: + case static_scheduler_WU_ends: + return "WU"; + break; + default: + fprintf(stderr, "WARNING: Unrecognized virtual instruction detected: %s\n", + trace_event_names[event_type]); + return "UNKNOWN"; + } +} + /** * Read a trace in the trace_file and write it to the output_file in json. * @return The number of records read or 0 upon seeing an EOF. @@ -95,6 +174,13 @@ size_t read_and_write_trace() { } else if (trace[i].event_type == scheduler_advancing_time_starts || trace[i].event_type == scheduler_advancing_time_starts) { reactor_name = "ADVANCE TIME"; + } else if (trace[i].event_type >= static_scheduler_ADD_starts + || trace[i].event_type <= static_scheduler_WU_ends) { + int pc = trace[i].dst_id; + char *inst_name = get_instruction_name(trace[i].event_type); + char str[20]; + sprintf(str, "%d: %s", pc, inst_name); + reactor_name = str; } else { reactor_name = "NO REACTOR"; } @@ -111,9 +197,9 @@ size_t read_and_write_trace() { // physical time in microseconds. But for schedule_called events, // it will instead be the logical time at which the action or timer // is to be scheduled. - interval_t elapsed_physical_time = (trace[i].physical_time - start_time)/1000; + interval_t elapsed_physical_time = (trace[i].physical_time - start_time)/scaling_factor; interval_t timestamp = elapsed_physical_time; - interval_t elapsed_logical_time = (trace[i].logical_time - start_time)/1000; + interval_t elapsed_logical_time = (trace[i].logical_time - start_time)/scaling_factor; if (elapsed_physical_time < 0) { fprintf(stderr, "WARNING: Negative elapsed physical time %lld. Skipping trace entry.\n", elapsed_physical_time); @@ -154,7 +240,7 @@ size_t read_and_write_trace() { phase = "i"; pid = reactor_index + 1; // One pid per reactor. if (!physical_time_only) { - timestamp = elapsed_logical_time + trace[i].extra_delay/1000; + timestamp = elapsed_logical_time + trace[i].extra_delay/scaling_factor; } thread_id = trigger_index; name = trigger_name; @@ -193,6 +279,126 @@ size_t read_and_write_trace() { pid = PID_FOR_WORKER_ADVANCING_TIME; phase = "E"; break; + case static_scheduler_ADD_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_ADDI_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_ADV_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_ADVI_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_BEQ_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_BGE_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_BLT_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_BNE_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_DU_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_EXE_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_JAL_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_JALR_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_STP_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_WLT_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_WU_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_ADD_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_ADDI_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_ADV_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_ADVI_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_BEQ_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_BGE_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_BLT_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_BNE_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_DU_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_EXE_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_JAL_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_JALR_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_STP_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_WLT_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_WU_ends: + pid = 0; + phase = "E"; + break; default: fprintf(stderr, "WARNING: Unrecognized event type %d: %s\n", trace[i].event_type, trace_event_names[trace[i].event_type]); From 3dbb4a13f5c9811508f7ffe3c93ee9a2bcbf0bc9 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sun, 10 Mar 2024 11:49:42 -0700 Subject: [PATCH 46/80] Add WIP --- core/utils/CMakeLists.txt | 2 +- core/utils/circular_buffer.c | 70 ++++++++++++++++++++++++++++ include/api/reaction_macros.h | 50 ++++++++++---------- include/core/environment.h | 2 +- include/core/reactor.h | 1 + include/core/utils/circular_buffer.h | 24 ++++++++++ 6 files changed, 122 insertions(+), 27 deletions(-) create mode 100644 core/utils/circular_buffer.c create mode 100644 include/core/utils/circular_buffer.h diff --git a/core/utils/CMakeLists.txt b/core/utils/CMakeLists.txt index 7ab0db8d4..4d0576e94 100644 --- a/core/utils/CMakeLists.txt +++ b/core/utils/CMakeLists.txt @@ -1,4 +1,4 @@ -set(UTIL_SOURCES vector.c pqueue_base.c pqueue_tag.c pqueue.c util.c lf_semaphore.c) +set(UTIL_SOURCES vector.c pqueue_base.c pqueue_tag.c pqueue.c util.c lf_semaphore.c circular_buffer.c) list(TRANSFORM UTIL_SOURCES PREPEND utils/) diff --git a/core/utils/circular_buffer.c b/core/utils/circular_buffer.c new file mode 100644 index 000000000..2fd620d5f --- /dev/null +++ b/core/utils/circular_buffer.c @@ -0,0 +1,70 @@ +/** + * @file circular_buffer.c + * @brief A circular buffer implementation from stack overflow + * (https://stackoverflow.com/questions/827691/how-do-you-implement-a-circular-buffer-in-c) + * + * @copyright Copyright (c) 2024 + * + */ + +#include "util.h" +#include "circular_buffer.h" + +void cb_init(circular_buffer *cb, size_t capacity, size_t sz) +{ + cb->buffer = malloc(capacity * sz); + if(cb->buffer == NULL) { + // handle error + lf_print("ERROR: Fail to allocate memory to circular buffer."); + return; + } + cb->buffer_end = (char *)cb->buffer + capacity * sz; + cb->capacity = capacity; + cb->count = 0; + cb->sz = sz; + cb->head = cb->buffer; + cb->tail = cb->buffer; +} + +void cb_free(circular_buffer *cb) +{ + free(cb->buffer); + // clear out other fields too, just to be safe +} + +void cb_push_back(circular_buffer *cb, const void *item) +{ + if(cb->count == cb->capacity){ + lf_print("ERROR: Buffer is full. Some in-flight events will be overwritten!"); + } + memcpy(cb->head, item, cb->sz); + cb->head = (char*)cb->head + cb->sz; + if(cb->head == cb->buffer_end) + cb->head = cb->buffer; + cb->count++; +} + +void cb_pop_front(circular_buffer *cb, void *item) +{ + if(cb->count == 0){ + // handle error + lf_print("ERROR: Popping from an empty buffer!"); + return; + } + memcpy(item, cb->tail, cb->sz); + cb->tail = (char*)cb->tail + cb->sz; + if(cb->tail == cb->buffer_end) + cb->tail = cb->buffer; + cb->count--; +} + +int cb_peek(circular_buffer *cb, void *item) +{ + if(cb->count == 0){ + // handle error + lf_print("Warning: Peeking from an empty buffer!"); + return 1; + } + memcpy(item, cb->tail, cb->sz); + return 0; +} \ No newline at end of file diff --git a/include/api/reaction_macros.h b/include/api/reaction_macros.h index 19eb9f2cb..ac19c9e98 100644 --- a/include/api/reaction_macros.h +++ b/include/api/reaction_macros.h @@ -69,30 +69,30 @@ * reactor in form input_name.port_name. * @param value The value to insert into the self struct. */ -#if SCHEDULER == SCHED_STATIC -#define lf_set(out, val) \ -do { \ - /* We need to assign "val" to "out->value" since we need to give "val" an address */ \ - /* even if it is a literal */ \ - out->value = val; \ - /* DEBUG: lf_print("lf_set value = %d", (int)val); */ \ - lf_set_present((lf_port_base_t*)out); \ - /* Create a token for the literal based on the token element_size. */ \ - size_t payload_size = ((token_type_t*)out)->element_size; \ - /* DEBUG: lf_print("payload_size = %zu", payload_size); */ \ - /* Put the literal in the payload using memcpy. */ \ - void *payload = malloc(payload_size); \ - memcpy(payload, &val, payload_size); \ - /* Create a new token and put it in the port. */ \ - lf_token_t* newtoken = _lf_new_token((token_type_t*)out, payload, 1); \ - _lf_replace_template_token((token_template_t*)out, newtoken); \ - /* VERY IMPORTANT: Increment reference count > 1 so that it does NOT get reused right away */ \ - /* FIXME: I still don't fully understand this. */ \ - newtoken->ref_count = 2; \ - /* DEBUG: The token address should be distinct. */ \ - /* DEBUG: lf_print("Token address = %p", newtoken); */ \ -} while(0) -#else +// #if SCHEDULER == SCHED_STATIC +// #define lf_set(out, val) \ +// do { \ +// /* We need to assign "val" to "out->value" since we need to give "val" an address */ \ +// /* even if it is a literal */ \ +// out->value = val; \ +// /* DEBUG: lf_print("lf_set value = %d", (int)val); */ \ +// lf_set_present((lf_port_base_t*)out); \ +// /* Create a token for the literal based on the token element_size. */ \ +// size_t payload_size = ((token_type_t*)out)->element_size; \ +// /* DEBUG: lf_print("payload_size = %zu", payload_size); */ \ +// /* Put the literal in the payload using memcpy. */ \ +// void *payload = malloc(payload_size); \ +// memcpy(payload, &val, payload_size); \ +// /* Create a new token and put it in the port. */ \ +// lf_token_t* newtoken = _lf_new_token((token_type_t*)out, payload, 1); \ +// _lf_replace_template_token((token_template_t*)out, newtoken); \ +// /* VERY IMPORTANT: Increment reference count > 1 so that it does NOT get reused right away */ \ +// /* FIXME: I still don't fully understand this. */ \ +// newtoken->ref_count = 2; \ +// /* DEBUG: The token address should be distinct. */ \ +// /* DEBUG: lf_print("Token address = %p", newtoken); */ \ +// } while(0) +// #else #define lf_set(out, val) \ do { \ out->value = val; \ @@ -103,7 +103,7 @@ do { \ lf_token_t* token = _lf_initialize_token_with_value((token_template_t*)out, *((void**) &out->value), 1); \ } \ } while(0) -#endif +// #endif /** * @brief Set the specified output (or input of a contained reactor) diff --git a/include/core/environment.h b/include/core/environment.h index cfdb59ddb..5b9523371 100644 --- a/include/core/environment.h +++ b/include/core/environment.h @@ -115,7 +115,7 @@ typedef struct environment_t { int reactor_self_array_size; reaction_t** reaction_array; int reaction_array_size; - event_t** pqueue_heads; + event_t* pqueue_heads; int num_pqueue_heads; #endif #ifdef LF_ENCLAVES // TODO: Consider dropping #ifdef diff --git a/include/core/reactor.h b/include/core/reactor.h index 64363c73a..c86915db2 100644 --- a/include/core/reactor.h +++ b/include/core/reactor.h @@ -26,6 +26,7 @@ #include "clock.h" // Time-related functions. #include "trace.h" #include "util.h" +#include "circular_buffer.h" // HACK: So that circular buffer is visible in all user-facing reactor header files. /** * @brief Macro to suppress warnings about unused variables. diff --git a/include/core/utils/circular_buffer.h b/include/core/utils/circular_buffer.h new file mode 100644 index 000000000..729979927 --- /dev/null +++ b/include/core/utils/circular_buffer.h @@ -0,0 +1,24 @@ +#ifndef CIRCULAR_BUFFER_H +#define CIRCULAR_BUFFER_H + +#include +#include + +typedef struct circular_buffer +{ + void *buffer; // data buffer + void *buffer_end; // end of data buffer + size_t capacity; // maximum number of items in the buffer + size_t count; // number of items in the buffer + size_t sz; // size of each item in the buffer + void *head; // pointer to head + void *tail; // pointer to tail +} circular_buffer; + +void cb_init(circular_buffer *cb, size_t capacity, size_t sz); +void cb_free(circular_buffer *cb); +void cb_push_back(circular_buffer *cb, const void *item); +void cb_pop_front(circular_buffer *cb, void *item); +int cb_peek(circular_buffer *cb, void *item); + +#endif \ No newline at end of file From 2d27f14b09c0a1697a83b39a77e22238525d8829 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Tue, 12 Mar 2024 21:43:26 -0700 Subject: [PATCH 47/80] Only trace EXE now --- core/threaded/scheduler_static.c | 60 ++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index c1b0f1154..20f0d8e2f 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -50,6 +50,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "trace.h" #include "util.h" +#define TRACE_ALL_INSTRUCTIONS false + /////////////////// External Variables ///////////////////////// // Global variable defined in tag.c: extern instant_t start_time; @@ -73,13 +75,17 @@ extern volatile reg_t binary_sema[]; void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { int pc_orig = (int) *pc; +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_ADD_starts(scheduler->env->trace, worker_number, pc_orig); +#endif reg_t *dst = op1.reg; reg_t *src = op2.reg; reg_t *src2 = op3.reg; *dst = *src + *src2; *pc += 1; // Increment pc. +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_ADD_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** @@ -87,14 +93,18 @@ void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { +#if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, pc_orig); +#endif reg_t *dst = op1.reg; reg_t *src = op2.reg; // FIXME: Will there be problems if instant_t adds reg_t? *dst = *src + op3.imm; *pc += 1; // Increment pc. +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_ADDI_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** @@ -102,9 +112,10 @@ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, operand_ */ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { +#if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number, pc_orig); - +#endif reg_t *base = op2.reg; reg_t *inc = op3.reg; self_base_t* reactor = @@ -121,7 +132,9 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t } *pc += 1; // Increment pc. +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_ADV_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** @@ -129,9 +142,10 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { +#if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_ADVI_starts(scheduler->env->trace, worker_number, pc_orig); - +#endif self_base_t *reactor = (self_base_t*) op1.reg; reg_t *base = op2.reg; reactor->tag.time = *base + op3.imm; @@ -145,7 +159,9 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ reactor->output_ports[i]->is_present = false; } *pc += 1; // Increment pc. +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_ADVI_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** @@ -153,8 +169,10 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ */ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { +#if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_BEQ_starts(scheduler->env->trace, worker_number, pc_orig); +#endif reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; // These NULL checks allow _rs1 and _rs2 to be uninitialized in the static @@ -167,7 +185,9 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t } if (_rs1 != NULL && _rs2 != NULL && *_rs1 == *_rs2) *pc = op3.imm; else *pc += 1; +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_BEQ_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** @@ -175,14 +195,18 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { +#if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_BGE_starts(scheduler->env->trace, worker_number, pc_orig); +#endif reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; LF_PRINT_DEBUG("Worker %zu: BGE : operand 1 = %lld, operand 2 = %lld", worker_number, *_rs1, *_rs2); if (_rs1 != NULL && _rs2 != NULL && *_rs1 >= *_rs2) *pc = op3.imm; else *pc += 1; +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_BGE_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** @@ -190,13 +214,17 @@ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { +#if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_BLT_starts(scheduler->env->trace, worker_number, pc_orig); +#endif reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; if (_rs1 != NULL && _rs2 != NULL && *_rs1 < *_rs2) *pc = op3.imm; else *pc += 1; +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_BLT_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** @@ -204,13 +232,17 @@ void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { +#if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_BNE_starts(scheduler->env->trace, worker_number, pc_orig); +#endif reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; if (_rs1 != NULL && _rs2 != NULL && *_rs1 != *_rs2) *pc = op3.imm; else *pc += 1; +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_BNE_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** @@ -218,8 +250,10 @@ void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { +#if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_DU_starts(scheduler->env->trace, worker_number, pc_orig); +#endif // FIXME: There seems to be an overflow problem. // When wakeup_time overflows but lf_time_physical() doesn't, // _lf_interruptable_sleep_until_locked() terminates immediately. @@ -231,7 +265,9 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t while (lf_time_physical() < wakeup_time); LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); *pc += 1; // Increment pc. +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_DU_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** @@ -257,14 +293,18 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { +#if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_WLT_starts(scheduler->env->trace, worker_number, pc_orig); +#endif LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); reg_t *var = op1.reg; while(*var >= op2.imm); LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); *pc += 1; // Increment pc. +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_WLT_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** @@ -272,14 +312,18 @@ void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { +#if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, pc_orig); +#endif LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); reg_t *var = op1.reg; while(*var < op2.imm); LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); *pc += 1; // Increment pc. +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_WU_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** @@ -287,14 +331,18 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { +#if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_JAL_starts(scheduler->env->trace, worker_number, pc_orig); +#endif // Use the destination register as the return address and, if the // destination register is not the zero register, store pc+1 in it. reg_t *destReg = op1.reg; if (destReg != &zero) *destReg = *pc + 1; *pc = op2.imm; +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_JAL_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** @@ -302,8 +350,10 @@ void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { +#if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_JALR_starts(scheduler->env->trace, worker_number, pc_orig); +#endif // Use the destination register as the return address and, if the // destination register is not the zero register, store pc+1 in it. reg_t *destReg = op1.reg; @@ -311,7 +361,9 @@ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_ // Set pc to base addr + immediate. reg_t *baseAddr = op2.reg; *pc = *baseAddr + op3.imm; +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_JALR_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** @@ -319,10 +371,14 @@ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_ */ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { +#if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_STP_starts(scheduler->env->trace, worker_number, pc_orig); +#endif *exit_loop = true; +#if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_STP_ends(scheduler->env->trace, worker_number, pc_orig); +#endif } /** From 3635412db9bc29ff2403eb6e45ac90fa443ac9f6 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Wed, 13 Mar 2024 22:02:07 -0700 Subject: [PATCH 48/80] Fix unrecognized instruction error --- util/tracing/trace_to_chrome.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/tracing/trace_to_chrome.c b/util/tracing/trace_to_chrome.c index 873b4d367..898c5d7a6 100644 --- a/util/tracing/trace_to_chrome.c +++ b/util/tracing/trace_to_chrome.c @@ -175,7 +175,7 @@ size_t read_and_write_trace() { || trace[i].event_type == scheduler_advancing_time_starts) { reactor_name = "ADVANCE TIME"; } else if (trace[i].event_type >= static_scheduler_ADD_starts - || trace[i].event_type <= static_scheduler_WU_ends) { + && trace[i].event_type <= static_scheduler_WU_ends) { int pc = trace[i].dst_id; char *inst_name = get_instruction_name(trace[i].event_type); char str[20]; From 40b45dd8608912ec9bbc1673cfb14e2ef2e6a3a8 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Wed, 13 Mar 2024 22:24:17 -0700 Subject: [PATCH 49/80] Implement a more flexible DU that decides between spinning and sleep based on the wake-up time --- core/threaded/scheduler_static.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 20f0d8e2f..65f229521 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -261,8 +261,16 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t instant_t wakeup_time = *src + op2.imm; LF_PRINT_DEBUG("start_time: %lld, wakeup_time: %lld, op1: %lld, op2: %lld, current_physical_time: %lld\n", start_time, wakeup_time, *src, op2.imm, lf_time_physical()); LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); - // _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); - while (lf_time_physical() < wakeup_time); + instant_t wait_interval = wakeup_time - lf_time_physical(); + if (wait_interval > 0) { + if (wait_interval < MSEC(1)) { + // Spin wait if the wait interval is less than 1 ms. + while (lf_time_physical() < wakeup_time); + } else if (wait_interval >= MSEC(1)) { + // Otherwise sleep. + _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); + } + } LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); *pc += 1; // Increment pc. #if TRACE_ALL_INSTRUCTIONS From 4c57e17d98ec5a5cd92b01f0400545fc1de7d28f Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Mon, 18 Mar 2024 17:31:00 -0700 Subject: [PATCH 50/80] Increase spin wait threshold to 100 msec --- core/threaded/scheduler_static.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 65f229521..73e4fe5b3 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -51,6 +51,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "util.h" #define TRACE_ALL_INSTRUCTIONS false +#define SPIN_WAIT_THRESHOLD MSEC(100) /////////////////// External Variables ///////////////////////// // Global variable defined in tag.c: @@ -263,10 +264,10 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); instant_t wait_interval = wakeup_time - lf_time_physical(); if (wait_interval > 0) { - if (wait_interval < MSEC(1)) { + if (wait_interval < SPIN_WAIT_THRESHOLD) { // Spin wait if the wait interval is less than 1 ms. while (lf_time_physical() < wakeup_time); - } else if (wait_interval >= MSEC(1)) { + } else { // Otherwise sleep. _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); } From e27fcd94970872d39c23550b40f8a0dc710f5e5d Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Mon, 18 Mar 2024 17:51:50 -0700 Subject: [PATCH 51/80] Use spin wait for NP for fairness --- core/clock.c | 4 +++- core/reactor.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/core/clock.c b/core/clock.c index 0620c6ccd..78ed14232 100644 --- a/core/clock.c +++ b/core/clock.c @@ -55,6 +55,8 @@ int lf_clock_cond_timedwait(lf_cond_t *cond, instant_t wakeup_time) { // Remove any clock sync offset and call the Platform API. clock_sync_remove_offset(&wakeup_time); #endif - return _lf_cond_timedwait(cond, wakeup_time); + // return _lf_cond_timedwait(cond, wakeup_time); + while (lf_time_physical() < wakeup_time); + return true; } #endif diff --git a/core/reactor.c b/core/reactor.c index 9e2092dcd..11b0380d2 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -66,7 +66,9 @@ void lf_set_present(lf_port_base_t* port) { int wait_until(environment_t* env, instant_t wakeup_time) { if (!fast) { LF_PRINT_LOG("Waiting for elapsed logical time " PRINTF_TIME ".", wakeup_time - start_time); - return lf_clock_interruptable_sleep_until_locked(env, wakeup_time); + // return lf_clock_interruptable_sleep_until_locked(env, wakeup_time); + while (lf_time_physical() < wakeup_time); + return 0; } return 0; } From e89f09ab1298a2c4084635cc6962ca815eed089d Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Fri, 22 Mar 2024 01:00:41 -0700 Subject: [PATCH 52/80] Use circular buffers --- core/utils/circular_buffer.c | 14 ++++++++++++ include/api/reaction_macros.h | 34 ++++++++-------------------- include/core/utils/circular_buffer.h | 1 + 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/core/utils/circular_buffer.c b/core/utils/circular_buffer.c index 2fd620d5f..890349c23 100644 --- a/core/utils/circular_buffer.c +++ b/core/utils/circular_buffer.c @@ -9,6 +9,7 @@ #include "util.h" #include "circular_buffer.h" +#include "lf_types.h" void cb_init(circular_buffer *cb, size_t capacity, size_t sz) { @@ -67,4 +68,17 @@ int cb_peek(circular_buffer *cb, void *item) } memcpy(item, cb->tail, cb->sz); return 0; +} + +void cb_dump_events(circular_buffer *cb) +{ + lf_print("*** Dumping Events ***"); + void *p = cb->tail; + while (p != cb->head) { + event_t* e = (event_t*)p; + lf_print("Event @ %lld w/ token %p", e->time, e->token); + p += cb->sz; + if (p == cb->buffer_end) p = cb->buffer; + } + lf_print("**********************"); } \ No newline at end of file diff --git a/include/api/reaction_macros.h b/include/api/reaction_macros.h index ac19c9e98..39fbbf285 100644 --- a/include/api/reaction_macros.h +++ b/include/api/reaction_macros.h @@ -69,30 +69,14 @@ * reactor in form input_name.port_name. * @param value The value to insert into the self struct. */ -// #if SCHEDULER == SCHED_STATIC -// #define lf_set(out, val) \ -// do { \ -// /* We need to assign "val" to "out->value" since we need to give "val" an address */ \ -// /* even if it is a literal */ \ -// out->value = val; \ -// /* DEBUG: lf_print("lf_set value = %d", (int)val); */ \ -// lf_set_present((lf_port_base_t*)out); \ -// /* Create a token for the literal based on the token element_size. */ \ -// size_t payload_size = ((token_type_t*)out)->element_size; \ -// /* DEBUG: lf_print("payload_size = %zu", payload_size); */ \ -// /* Put the literal in the payload using memcpy. */ \ -// void *payload = malloc(payload_size); \ -// memcpy(payload, &val, payload_size); \ -// /* Create a new token and put it in the port. */ \ -// lf_token_t* newtoken = _lf_new_token((token_type_t*)out, payload, 1); \ -// _lf_replace_template_token((token_template_t*)out, newtoken); \ -// /* VERY IMPORTANT: Increment reference count > 1 so that it does NOT get reused right away */ \ -// /* FIXME: I still don't fully understand this. */ \ -// newtoken->ref_count = 2; \ -// /* DEBUG: The token address should be distinct. */ \ -// /* DEBUG: lf_print("Token address = %p", newtoken); */ \ -// } while(0) -// #else +#if SCHEDULER == SCHED_STATIC +#define lf_set(out, val) \ +do { \ + out->value = val; \ + lf_set_present(out); \ + out->token = val; /* The long-term solution is to generate an event type for each connection buffer of primitive type. */ \ +} while(0) +#else #define lf_set(out, val) \ do { \ out->value = val; \ @@ -103,7 +87,7 @@ do { \ lf_token_t* token = _lf_initialize_token_with_value((token_template_t*)out, *((void**) &out->value), 1); \ } \ } while(0) -// #endif +#endif /** * @brief Set the specified output (or input of a contained reactor) diff --git a/include/core/utils/circular_buffer.h b/include/core/utils/circular_buffer.h index 729979927..dfd2d8a9c 100644 --- a/include/core/utils/circular_buffer.h +++ b/include/core/utils/circular_buffer.h @@ -20,5 +20,6 @@ void cb_free(circular_buffer *cb); void cb_push_back(circular_buffer *cb, const void *item); void cb_pop_front(circular_buffer *cb, void *item); int cb_peek(circular_buffer *cb, void *item); +void cb_dump_events(circular_buffer *cb); #endif \ No newline at end of file From ca533a95915bbba88e871ab46228a8931f9ff3c1 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Fri, 22 Mar 2024 10:24:37 -0700 Subject: [PATCH 53/80] Increase trace buffer and optimize circular buffer --- core/utils/circular_buffer.c | 19 ++++++++++++++----- include/core/environment.h | 2 +- include/core/trace.h | 3 ++- include/core/utils/circular_buffer.h | 3 ++- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/core/utils/circular_buffer.c b/core/utils/circular_buffer.c index 890349c23..508dd4a47 100644 --- a/core/utils/circular_buffer.c +++ b/core/utils/circular_buffer.c @@ -59,15 +59,24 @@ void cb_pop_front(circular_buffer *cb, void *item) cb->count--; } -int cb_peek(circular_buffer *cb, void *item) +void cb_remove_front(circular_buffer *cb) { if(cb->count == 0){ // handle error - lf_print("Warning: Peeking from an empty buffer!"); - return 1; + lf_print("ERROR: Removing from an empty buffer!"); + return; } - memcpy(item, cb->tail, cb->sz); - return 0; + cb->tail = (char*)cb->tail + cb->sz; + if(cb->tail == cb->buffer_end) + cb->tail = cb->buffer; + cb->count--; +} + +void* cb_peek(circular_buffer *cb) +{ + if(cb->count == 0) + return NULL; + return cb->tail; } void cb_dump_events(circular_buffer *cb) diff --git a/include/core/environment.h b/include/core/environment.h index 5b9523371..cfdb59ddb 100644 --- a/include/core/environment.h +++ b/include/core/environment.h @@ -115,7 +115,7 @@ typedef struct environment_t { int reactor_self_array_size; reaction_t** reaction_array; int reaction_array_size; - event_t* pqueue_heads; + event_t** pqueue_heads; int num_pqueue_heads; #endif #ifdef LF_ENCLAVES // TODO: Consider dropping #ifdef diff --git a/include/core/trace.h b/include/core/trace.h index 24a557503..1e84dbc35 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -252,7 +252,8 @@ static const char *trace_event_names[] = { }; // FIXME: Target property should specify the capacity of the trace buffer. -#define TRACE_BUFFER_CAPACITY 2048 +// #define TRACE_BUFFER_CAPACITY 2048 +#define TRACE_BUFFER_CAPACITY 32768 /** Size of the table of trace objects. */ #define TRACE_OBJECT_TABLE_SIZE 1024 diff --git a/include/core/utils/circular_buffer.h b/include/core/utils/circular_buffer.h index dfd2d8a9c..b8f25928f 100644 --- a/include/core/utils/circular_buffer.h +++ b/include/core/utils/circular_buffer.h @@ -19,7 +19,8 @@ void cb_init(circular_buffer *cb, size_t capacity, size_t sz); void cb_free(circular_buffer *cb); void cb_push_back(circular_buffer *cb, const void *item); void cb_pop_front(circular_buffer *cb, void *item); -int cb_peek(circular_buffer *cb, void *item); +void cb_remove_front(circular_buffer *cb); +void* cb_peek(circular_buffer *cb); void cb_dump_events(circular_buffer *cb); #endif \ No newline at end of file From ec0f645f07feb9045b5ef76ce49b961e46f7282f Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Fri, 22 Mar 2024 10:28:20 -0700 Subject: [PATCH 54/80] Increase trace buffer capacity to 64k --- include/core/trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/core/trace.h b/include/core/trace.h index 1e84dbc35..040d827c2 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -253,7 +253,7 @@ static const char *trace_event_names[] = { // FIXME: Target property should specify the capacity of the trace buffer. // #define TRACE_BUFFER_CAPACITY 2048 -#define TRACE_BUFFER_CAPACITY 32768 +#define TRACE_BUFFER_CAPACITY 65536 /** Size of the table of trace objects. */ #define TRACE_OBJECT_TABLE_SIZE 1024 From d4af904e3c84361807a4caf2f32974d4df14fd6a Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Fri, 22 Mar 2024 10:32:34 -0700 Subject: [PATCH 55/80] Drop the buffer capacity back to 32k --- include/core/trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/core/trace.h b/include/core/trace.h index 040d827c2..1e84dbc35 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -253,7 +253,7 @@ static const char *trace_event_names[] = { // FIXME: Target property should specify the capacity of the trace buffer. // #define TRACE_BUFFER_CAPACITY 2048 -#define TRACE_BUFFER_CAPACITY 65536 +#define TRACE_BUFFER_CAPACITY 32768 /** Size of the table of trace objects. */ #define TRACE_OBJECT_TABLE_SIZE 1024 From 732b13af8a52e2d3dbcb733cb0c557c47e303c68 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Fri, 22 Mar 2024 10:52:50 -0700 Subject: [PATCH 56/80] Drop to 16KB to try to get chrome to work --- include/core/trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/core/trace.h b/include/core/trace.h index 1e84dbc35..87c11ae01 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -253,7 +253,7 @@ static const char *trace_event_names[] = { // FIXME: Target property should specify the capacity of the trace buffer. // #define TRACE_BUFFER_CAPACITY 2048 -#define TRACE_BUFFER_CAPACITY 32768 +#define TRACE_BUFFER_CAPACITY 16384 /** Size of the table of trace objects. */ #define TRACE_OBJECT_TABLE_SIZE 1024 From 4ad2cdf3fbd3297736fee2ff52bb63197df3c4d7 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Fri, 22 Mar 2024 11:05:37 -0700 Subject: [PATCH 57/80] Back to 32k --- include/core/trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/core/trace.h b/include/core/trace.h index 87c11ae01..1e84dbc35 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -253,7 +253,7 @@ static const char *trace_event_names[] = { // FIXME: Target property should specify the capacity of the trace buffer. // #define TRACE_BUFFER_CAPACITY 2048 -#define TRACE_BUFFER_CAPACITY 16384 +#define TRACE_BUFFER_CAPACITY 32768 /** Size of the table of trace objects. */ #define TRACE_OBJECT_TABLE_SIZE 1024 From 05fcd4c05442d47894aee661304d54ccdf77d9bd Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Fri, 22 Mar 2024 18:05:16 -0700 Subject: [PATCH 58/80] Use function pointers to execute virtual instructions. Stop tracing auxiliary EXE (helps a lot). --- core/threaded/scheduler_static.c | 116 ++---------------- include/core/threaded/scheduler_instance.h | 3 + .../core/threaded/scheduler_instructions.h | 22 +++- .../threaded/scheduler_static_functions.h | 38 +++++- 4 files changed, 74 insertions(+), 105 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 73e4fe5b3..7727035d5 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -285,15 +285,19 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { int pc_orig = (int) *pc; - if (op3.imm == ULLONG_MAX) {tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig);} - else {tracepoint_static_scheduler_EXE_reaction_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm);} + if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm);} +#if TRACE_ALL_INSTRUCTIONS + else {tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig);} +#endif function_generic_t function = (function_generic_t)(uintptr_t)op1.reg; void *args = (void*)op2.reg; // Execute the function directly. function(args); *pc += 1; // Increment pc. - if (op3.imm == ULLONG_MAX) {tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig);} - else {tracepoint_static_scheduler_EXE_reaction_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm);} + if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm);} +#if TRACE_ALL_INSTRUCTIONS + else {tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig);} +#endif } @@ -390,103 +394,6 @@ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, operand_t #endif } -/** - * @brief Execute an instruction - * - * @param opcode the opcode - * @param op1 the first operand - * @param op2 the second operand - * @param pc a pointer to the program counter - * @param returned_reaction a pointer to a reaction to be executed - * - * FIXME: This feels like a bad design in the abstraction. - * @param exit_loop a pointer to a boolean indicating whether - * the outer while loop should be exited - */ -void execute_inst(lf_scheduler_t* scheduler, size_t worker_number, opcode_t opcode, operand_t op1, operand_t op2, operand_t op3, bool debug, - size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { - char* op_str = NULL; - switch (opcode) { - case ADD: - op_str = "ADD"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_ADD(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case ADDI: - op_str = "ADDI"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_ADDI(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case ADV: - op_str = "ADV"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_ADV(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case ADVI: - op_str = "ADVI"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_ADVI(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case BEQ: - op_str = "BEQ"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_BEQ(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case BGE: - op_str = "BGE"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_BGE(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case BLT: - op_str = "BLT"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_BLT(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case BNE: - op_str = "BNE"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_BNE(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case DU: - op_str = "DU"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_DU(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case EXE: - op_str = "EXE"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_EXE(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case JAL: - op_str = "JAL"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_JAL(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case JALR: - op_str = "JALR"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_JALR(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case STP: - op_str = "STP"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_STP(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case WLT: - op_str = "WLT"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_WLT(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - case WU: - op_str = "WU"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - execute_inst_WU(scheduler, worker_number, op1, op2, op3, debug, pc, returned_reaction, exit_loop); - break; - default: - lf_print_error_and_exit("Invalid instruction: %d", opcode); - } -} - ///////////////////// Scheduler Init and Destroy API ///////////////////////// /** * @brief Initialize the scheduler. @@ -567,6 +474,8 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu reaction_t* returned_reaction = NULL; bool exit_loop = false; size_t* pc = &scheduler->pc[worker_number]; + + function_virtual_instruction_t func; opcode_t opcode; operand_t op1; operand_t op2; @@ -574,14 +483,15 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu bool debug; while (!exit_loop) { - opcode = current_schedule[*pc].opcode; + func = current_schedule[*pc].func; + // opcode = current_schedule[*pc].opcode; // FIXME: Opcode is unused. op1 = current_schedule[*pc].op1; op2 = current_schedule[*pc].op2; op3 = current_schedule[*pc].op3; debug = current_schedule[*pc].debug; // Execute the current instruction - execute_inst(scheduler, worker_number, opcode, op1, op2, op3, debug, pc, + func(scheduler, worker_number, op1, op2, op3, debug, pc, &returned_reaction, &exit_loop); } diff --git a/include/core/threaded/scheduler_instance.h b/include/core/threaded/scheduler_instance.h index 924b1ca7d..5e2e5c3b9 100644 --- a/include/core/threaded/scheduler_instance.h +++ b/include/core/threaded/scheduler_instance.h @@ -46,6 +46,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #if SCHEDULER == SCHED_STATIC +// Forward declaration so that lf_scheduler_t is visible in +// scheduler_instructions.h +typedef struct lf_scheduler_t lf_scheduler_t; #include "lf_types.h" #include "scheduler_instructions.h" #endif diff --git a/include/core/threaded/scheduler_instructions.h b/include/core/threaded/scheduler_instructions.h index 12904cc66..ae702a4e3 100644 --- a/include/core/threaded/scheduler_instructions.h +++ b/include/core/threaded/scheduler_instructions.h @@ -2,6 +2,9 @@ * @author Shaokai Lin * @brief Format of the instruction set */ +#ifndef SCHEDULER_INSTRUCTIONS_H +#define SCHEDULER_INSTRUCTIONS_H + typedef enum { ADD, ADDI, @@ -42,6 +45,20 @@ typedef union { imm_t imm; } operand_t; +/** + * @brief Virtual instruction function pointer + */ +typedef void (*function_virtual_instruction_t)( + lf_scheduler_t* scheduler, + size_t worker_number, + operand_t op1, + operand_t op2, + operand_t op3, + bool debug, + size_t* pc, + reaction_t** returned_reaction, + bool* exit_loop); + /** * @brief This struct represents a PRET VM instruction for C platforms. * There is an opcode and three operands. The operands are unions so they @@ -49,9 +66,12 @@ typedef union { * */ typedef struct inst_t { + function_virtual_instruction_t func; opcode_t opcode; operand_t op1; operand_t op2; operand_t op3; bool debug; -} inst_t; \ No newline at end of file +} inst_t; + +#endif \ No newline at end of file diff --git a/include/core/threaded/scheduler_static_functions.h b/include/core/threaded/scheduler_static_functions.h index 2761a62de..11874dac3 100644 --- a/include/core/threaded/scheduler_static_functions.h +++ b/include/core/threaded/scheduler_static_functions.h @@ -1,3 +1,6 @@ +#ifndef SCHEDULER_STATIC_FUNCTION_H +#define SCHEDULER_STATIC_FUNCTION_H + /** * @brief Function type with a void* argument. To make this type represent a * generic function, one can write a wrapper function around the target function @@ -9,4 +12,37 @@ typedef void(*function_generic_t)(void*); /** * @brief Wrapper function for peeking a priority queue. */ -void push_pop_peek_pqueue(void* self); \ No newline at end of file +void push_pop_peek_pqueue(void* self); + +void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); +void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, + reaction_t** returned_reaction, bool* exit_loop); + +#endif \ No newline at end of file From 09693280416d5e70c1f448210b086878e54df8b3 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Fri, 22 Mar 2024 18:17:56 -0700 Subject: [PATCH 59/80] Remove tracepoints except reaction starts and stops --- core/trace.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/core/trace.c b/core/trace.c index 64f55df61..93a0f4781 100644 --- a/core/trace.c +++ b/core/trace.c @@ -349,6 +349,7 @@ void tracepoint_reaction_ends(trace_t* trace, reaction_t* reaction, int worker) * @param extra_delay The extra delay passed to schedule(). */ void tracepoint_schedule(trace_t* trace, trigger_t* trigger, interval_t extra_delay) { + /* // schedule() can only trigger reactions within the same reactor as the action // or timer. If there is such a reaction, find its reactor's self struct and // put that into the tracepoint. We only have to look at the first reaction. @@ -363,6 +364,7 @@ void tracepoint_schedule(trace_t* trace, trigger_t* trigger, interval_t extra_de // True argument specifies to record physical time as late as possible, when // the event is already on the event queue. tracepoint(trace, schedule_called, reactor, NULL, -1, 0, 0, NULL, trigger, extra_delay, true); + */ } /** @@ -423,7 +425,7 @@ void tracepoint_user_value(void* self, char* description, long long value) { * @param worker The thread number of the worker thread or 0 for single-threaded execution. */ void tracepoint_worker_wait_starts(trace_t* trace, int worker) { - tracepoint(trace, worker_wait_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, true); + // tracepoint(trace, worker_wait_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, true); } /** @@ -431,7 +433,7 @@ void tracepoint_worker_wait_starts(trace_t* trace, int worker) { * @param worker The thread number of the worker thread or 0 for single-threaded execution. */ void tracepoint_worker_wait_ends(trace_t* trace, int worker) { - tracepoint(trace, worker_wait_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); + // tracepoint(trace, worker_wait_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); } /** @@ -439,7 +441,7 @@ void tracepoint_worker_wait_ends(trace_t* trace, int worker) { * appear on the event queue. */ void tracepoint_scheduler_advancing_time_starts(trace_t* trace) { - tracepoint(trace, scheduler_advancing_time_starts, NULL, NULL, -1, -1, -1, NULL, NULL, 0, true); + // tracepoint(trace, scheduler_advancing_time_starts, NULL, NULL, -1, -1, -1, NULL, NULL, 0, true); } /** @@ -447,7 +449,7 @@ void tracepoint_scheduler_advancing_time_starts(trace_t* trace) { * appear on the event queue. */ void tracepoint_scheduler_advancing_time_ends(trace_t* trace) { - tracepoint(trace, scheduler_advancing_time_ends, NULL, NULL, -1, -1, -1, NULL, NULL, 0, false); + // tracepoint(trace, scheduler_advancing_time_ends, NULL, NULL, -1, -1, -1, NULL, NULL, 0, false); } /** @@ -456,7 +458,7 @@ void tracepoint_scheduler_advancing_time_ends(trace_t* trace) { * @param worker The thread number of the worker thread or 0 for single-threaded execution. */ void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, int worker) { - tracepoint(trace, reaction_deadline_missed, reaction->self, NULL, worker, worker, reaction->number, NULL, NULL, 0, false); + // tracepoint(trace, reaction_deadline_missed, reaction->self, NULL, worker, worker, reaction->number, NULL, NULL, 0, false); } #if SCHEDULER == SCHED_STATIC From 884386ebbd382fcf4b3c9c6ff760630c8949cc9f Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sat, 23 Mar 2024 17:08:12 -0700 Subject: [PATCH 60/80] ADVI stops clearing is_present fields --- core/threaded/scheduler_static.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 7727035d5..c6961e802 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -151,14 +151,6 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ reg_t *base = op2.reg; reactor->tag.time = *base + op3.imm; reactor->tag.microstep = 0; - - // Reset all "is_present" fields of the output ports of the reactor - // Doing this here has the major implication that ADV has to execute AFTER - // all downstream reactions have finished, since it is modifying state that is - // visible to those reactions. - for (int i = 0; i < reactor->num_output_ports; i++) { - reactor->output_ports[i]->is_present = false; - } *pc += 1; // Increment pc. #if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_ADVI_ends(scheduler->env->trace, worker_number, pc_orig); From bd0b5a2f00695194d6d69014ce144fd4579c0a48 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sat, 23 Mar 2024 17:12:15 -0700 Subject: [PATCH 61/80] Use pure spin wait in DU for evaluation --- core/threaded/scheduler_static.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index c6961e802..bf2e720c7 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -256,13 +256,14 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); instant_t wait_interval = wakeup_time - lf_time_physical(); if (wait_interval > 0) { - if (wait_interval < SPIN_WAIT_THRESHOLD) { - // Spin wait if the wait interval is less than 1 ms. - while (lf_time_physical() < wakeup_time); - } else { - // Otherwise sleep. - _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); - } + // if (wait_interval < SPIN_WAIT_THRESHOLD) { + // // Spin wait if the wait interval is less than 1 ms. + // while (lf_time_physical() < wakeup_time); + // } else { + // // Otherwise sleep. + // _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); + // } + while (lf_time_physical() < wakeup_time); } LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); *pc += 1; // Increment pc. From c7b7285c9a367a246da91c7ef2c9e818d8ff0d79 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Thu, 28 Mar 2024 20:08:59 -0700 Subject: [PATCH 62/80] Add useful debugging messages --- core/threaded/scheduler_static.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index bf2e720c7..99fc8c061 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -151,6 +151,7 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ reg_t *base = op2.reg; reactor->tag.time = *base + op3.imm; reactor->tag.microstep = 0; + LF_PRINT_DEBUG("*** [Line %zu] Worker %zu advance reactor time (%p) from %lld to %lld by %lld", *pc, worker_number, &(reactor->tag.time), *base, reactor->tag.time, op3.imm); *pc += 1; // Increment pc. #if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_ADVI_ends(scheduler->env->trace, worker_number, pc_orig); @@ -251,10 +252,11 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t // When wakeup_time overflows but lf_time_physical() doesn't, // _lf_interruptable_sleep_until_locked() terminates immediately. reg_t *src = op1.reg; + instant_t current_time = lf_time_physical(); instant_t wakeup_time = *src + op2.imm; - LF_PRINT_DEBUG("start_time: %lld, wakeup_time: %lld, op1: %lld, op2: %lld, current_physical_time: %lld\n", start_time, wakeup_time, *src, op2.imm, lf_time_physical()); - LF_PRINT_DEBUG("*** Worker %zu delaying", worker_number); - instant_t wait_interval = wakeup_time - lf_time_physical(); + instant_t wait_interval = wakeup_time - current_time; + // LF_PRINT_DEBUG("*** start_time: %lld, wakeup_time: %lld, op1: %lld, op2: %lld, current_physical_time: %lld\n", start_time, wakeup_time, *src, op2.imm, lf_time_physical()); + LF_PRINT_DEBUG("*** [Line %zu] Worker %zu delaying, current_physical_time: %lld, wakeup_time: %lld, wait_interval: %lld", *pc, worker_number, current_time, wakeup_time, wait_interval); if (wait_interval > 0) { // if (wait_interval < SPIN_WAIT_THRESHOLD) { // // Spin wait if the wait interval is less than 1 ms. @@ -265,7 +267,7 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t // } while (lf_time_physical() < wakeup_time); } - LF_PRINT_DEBUG("*** Worker %zu done delaying", worker_number); + LF_PRINT_DEBUG("*** [Line %zu] Worker %zu done delaying", *pc, worker_number); *pc += 1; // Increment pc. #if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_DU_ends(scheduler->env->trace, worker_number, pc_orig); @@ -285,7 +287,9 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t function_generic_t function = (function_generic_t)(uintptr_t)op1.reg; void *args = (void*)op2.reg; // Execute the function directly. + LF_PRINT_DEBUG("*** [Line %zu] Worker %zu executing reaction", *pc, worker_number); function(args); + LF_PRINT_DEBUG("*** [Line %zu] Worker %zu done executing reaction", *pc, worker_number); *pc += 1; // Increment pc. if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm);} #if TRACE_ALL_INSTRUCTIONS From 0e1e61bf741cdb029e6a2e710b8d94d12f71b990 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Fri, 29 Mar 2024 12:50:30 -0700 Subject: [PATCH 63/80] Bump trace buffer to 128KB --- include/core/trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/core/trace.h b/include/core/trace.h index 1e84dbc35..20d125677 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -253,7 +253,7 @@ static const char *trace_event_names[] = { // FIXME: Target property should specify the capacity of the trace buffer. // #define TRACE_BUFFER_CAPACITY 2048 -#define TRACE_BUFFER_CAPACITY 32768 +#define TRACE_BUFFER_CAPACITY 131072 /** Size of the table of trace objects. */ #define TRACE_OBJECT_TABLE_SIZE 1024 From 3a37b151b975f34c657ccd7c471fe4eef18a3b53 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sun, 7 Apr 2024 12:05:11 -0700 Subject: [PATCH 64/80] Stop setting the token field in lf_set --- include/api/reaction_macros.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/api/reaction_macros.h b/include/api/reaction_macros.h index 39fbbf285..35d0385a0 100644 --- a/include/api/reaction_macros.h +++ b/include/api/reaction_macros.h @@ -74,7 +74,6 @@ do { \ out->value = val; \ lf_set_present(out); \ - out->token = val; /* The long-term solution is to generate an event type for each connection buffer of primitive type. */ \ } while(0) #else #define lf_set(out, val) \ From 2e0f2ff79e2a4c9dd427da832f8ca298702ea5a1 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sun, 21 Apr 2024 23:06:30 -0700 Subject: [PATCH 65/80] Add debug messages back --- core/threaded/scheduler_static.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 99fc8c061..26ef9d6ed 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -75,6 +75,8 @@ extern volatile reg_t binary_sema[]; */ void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "ADD"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); int pc_orig = (int) *pc; #if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_ADD_starts(scheduler->env->trace, worker_number, pc_orig); @@ -94,6 +96,8 @@ void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "ADDI"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, pc_orig); @@ -113,6 +117,8 @@ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, operand_ */ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "ADV"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number, pc_orig); @@ -143,6 +149,8 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "ADVI"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_ADVI_starts(scheduler->env->trace, worker_number, pc_orig); @@ -151,7 +159,6 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ reg_t *base = op2.reg; reactor->tag.time = *base + op3.imm; reactor->tag.microstep = 0; - LF_PRINT_DEBUG("*** [Line %zu] Worker %zu advance reactor time (%p) from %lld to %lld by %lld", *pc, worker_number, &(reactor->tag.time), *base, reactor->tag.time, op3.imm); *pc += 1; // Increment pc. #if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_ADVI_ends(scheduler->env->trace, worker_number, pc_orig); @@ -163,6 +170,8 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ */ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "BEQ"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_BEQ_starts(scheduler->env->trace, worker_number, pc_orig); @@ -189,6 +198,8 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "BGE"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_BGE_starts(scheduler->env->trace, worker_number, pc_orig); @@ -208,6 +219,8 @@ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "BLT"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_BLT_starts(scheduler->env->trace, worker_number, pc_orig); @@ -226,6 +239,8 @@ void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "BNE"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_BNE_starts(scheduler->env->trace, worker_number, pc_orig); @@ -244,6 +259,8 @@ void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "DU"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_DU_starts(scheduler->env->trace, worker_number, pc_orig); @@ -279,6 +296,8 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "EXE"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); int pc_orig = (int) *pc; if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm);} #if TRACE_ALL_INSTRUCTIONS @@ -303,6 +322,8 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "WLT"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_WLT_starts(scheduler->env->trace, worker_number, pc_orig); @@ -322,6 +343,8 @@ void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "WU"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, pc_orig); @@ -341,6 +364,8 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "JAL"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_JAL_starts(scheduler->env->trace, worker_number, pc_orig); @@ -360,6 +385,8 @@ void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t */ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "JALR"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_JALR_starts(scheduler->env->trace, worker_number, pc_orig); @@ -381,6 +408,8 @@ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_ */ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { + char* op_str = "STP"; + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_STP_starts(scheduler->env->trace, worker_number, pc_orig); From b2306637982aaee3bc9174aa04ab30a618e0f09b Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sat, 1 Jun 2024 16:06:22 -0400 Subject: [PATCH 66/80] Revert "Stop setting the token field in lf_set" This reverts commit 3a37b151b975f34c657ccd7c471fe4eef18a3b53. --- include/api/reaction_macros.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/api/reaction_macros.h b/include/api/reaction_macros.h index 35d0385a0..39fbbf285 100644 --- a/include/api/reaction_macros.h +++ b/include/api/reaction_macros.h @@ -74,6 +74,7 @@ do { \ out->value = val; \ lf_set_present(out); \ + out->token = val; /* The long-term solution is to generate an event type for each connection buffer of primitive type. */ \ } while(0) #else #define lf_set(out, val) \ From 44313a29be8874e94cc1a626529c37dfc71c55c5 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Wed, 3 Jul 2024 11:45:07 +0800 Subject: [PATCH 67/80] Fix the incompatible conversion warning/error --- include/api/reaction_macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/api/reaction_macros.h b/include/api/reaction_macros.h index 39fbbf285..d5aa189d7 100644 --- a/include/api/reaction_macros.h +++ b/include/api/reaction_macros.h @@ -74,7 +74,7 @@ do { \ out->value = val; \ lf_set_present(out); \ - out->token = val; /* The long-term solution is to generate an event type for each connection buffer of primitive type. */ \ + out->token = (lf_token_t *)(uintptr_t)val; /* The long-term solution is to generate an event type for each connection buffer of primitive type. */ \ } while(0) #else #define lf_set(out, val) \ From 11dc8de34282306b00b7ca8003386b672f988aec Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Wed, 14 Aug 2024 18:00:32 +0800 Subject: [PATCH 68/80] Fix JAL and update ADVI debug output --- core/threaded/scheduler_static.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 26ef9d6ed..e6c99e25e 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -150,7 +150,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_t op1, operand_t op2, operand_t op3, bool debug, size_t* pc, reaction_t** returned_reaction, bool* exit_loop) { char* op_str = "ADVI"; - LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); + LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s (reactor %p) %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.reg, *(op2.reg), op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; tracepoint_static_scheduler_ADVI_starts(scheduler->env->trace, worker_number, pc_orig); @@ -374,7 +374,7 @@ void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t // destination register is not the zero register, store pc+1 in it. reg_t *destReg = op1.reg; if (destReg != &zero) *destReg = *pc + 1; - *pc = op2.imm; + *pc = op2.imm + op3.imm; // New pc = label + offset #if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_JAL_ends(scheduler->env->trace, worker_number, pc_orig); #endif From 7ab1111b631d517ceed572520fdd62c2511ef161 Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sat, 31 Aug 2024 14:47:23 -0700 Subject: [PATCH 69/80] Fix port setting for ADVI --- core/threaded/scheduler_static.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index e6c99e25e..6714d1f46 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -159,6 +159,15 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ reg_t *base = op2.reg; reactor->tag.time = *base + op3.imm; reactor->tag.microstep = 0; + + // Reset all "is_present" fields of the output ports of the reactor + // Doing this here has the major implication that ADVI has to execute AFTER + // all downstream reactions have finished, since it is modifying state that is + // visible to those reactions. + for (int i = 0; i < reactor->num_output_ports; i++) { + reactor->output_ports[i]->is_present = false; + } + *pc += 1; // Increment pc. #if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_ADVI_ends(scheduler->env->trace, worker_number, pc_orig); From 61880903bfbd711292dd943d66a6f63d671cee8a Mon Sep 17 00:00:00 2001 From: Shaokai Jerry Lin Date: Sat, 31 Aug 2024 18:56:25 -0700 Subject: [PATCH 70/80] Combine spin wait and thread sleep, and adjust spin wait threshold --- core/threaded/scheduler_static.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 6714d1f46..450cf823a 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -51,7 +51,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "util.h" #define TRACE_ALL_INSTRUCTIONS false -#define SPIN_WAIT_THRESHOLD MSEC(100) +#define SPIN_WAIT_THRESHOLD SEC(1) /////////////////// External Variables ///////////////////////// // Global variable defined in tag.c: @@ -280,18 +280,21 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t reg_t *src = op1.reg; instant_t current_time = lf_time_physical(); instant_t wakeup_time = *src + op2.imm; + LF_PRINT_DEBUG("DU wakeup time: %lld, base: %lld, offset: %lld", wakeup_time, *src, op2.imm); instant_t wait_interval = wakeup_time - current_time; // LF_PRINT_DEBUG("*** start_time: %lld, wakeup_time: %lld, op1: %lld, op2: %lld, current_physical_time: %lld\n", start_time, wakeup_time, *src, op2.imm, lf_time_physical()); LF_PRINT_DEBUG("*** [Line %zu] Worker %zu delaying, current_physical_time: %lld, wakeup_time: %lld, wait_interval: %lld", *pc, worker_number, current_time, wakeup_time, wait_interval); if (wait_interval > 0) { - // if (wait_interval < SPIN_WAIT_THRESHOLD) { - // // Spin wait if the wait interval is less than 1 ms. - // while (lf_time_physical() < wakeup_time); - // } else { - // // Otherwise sleep. - // _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); - // } - while (lf_time_physical() < wakeup_time); + // Approach 1: Only spin when the wait interval is less than SPIN_WAIT_THRESHOLD. + if (wait_interval < SPIN_WAIT_THRESHOLD) { + // Spin wait if the wait interval is less than 1 ms. + while (lf_time_physical() < wakeup_time); + } else { + // Otherwise sleep. + _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); + } + // Approach 2: Spin wait. + // while (lf_time_physical() < wakeup_time); } LF_PRINT_DEBUG("*** [Line %zu] Worker %zu done delaying", *pc, worker_number); *pc += 1; // Increment pc. From 08e2506f599787f3ed36e0ecda11917d5b3e9d6c Mon Sep 17 00:00:00 2001 From: Shaokai Jerry Lin Date: Mon, 7 Oct 2024 17:18:01 -0700 Subject: [PATCH 71/80] Get tracing to work and various fixes --- core/threaded/scheduler_static.c | 72 ++- core/trace.c | 822 ------------------------------- core/utils/circular_buffer.c | 2 +- include/core/trace.h | 687 -------------------------- include/core/tracepoint.h | 123 +++++ trace/api/types/trace_types.h | 181 ++++--- util/tracing/trace_to_chrome.c | 435 +++++----------- 7 files changed, 410 insertions(+), 1912 deletions(-) delete mode 100644 core/trace.c delete mode 100644 include/core/trace.h diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 450cf823a..205237b62 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -47,7 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "scheduler.h" #include "semaphore.h" #include "tag.h" -#include "trace.h" +#include "tracepoint.h" #include "util.h" #define TRACE_ALL_INSTRUCTIONS false @@ -77,9 +77,9 @@ void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t reaction_t** returned_reaction, bool* exit_loop) { char* op_str = "ADD"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - int pc_orig = (int) *pc; #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_ADD_starts(scheduler->env->trace, worker_number, pc_orig); + int pc_orig = (int) *pc; + tracepoint_static_scheduler_ADD_starts(worker_number, pc_orig); #endif reg_t *dst = op1.reg; reg_t *src = op2.reg; @@ -87,7 +87,7 @@ void execute_inst_ADD(lf_scheduler_t* scheduler, size_t worker_number, operand_t *dst = *src + *src2; *pc += 1; // Increment pc. #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_ADD_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_ADD_ends(worker_number, pc_orig); #endif } @@ -100,7 +100,7 @@ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, operand_ LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - tracepoint_static_scheduler_ADDI_starts(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_ADDI_starts(worker_number, pc_orig); #endif reg_t *dst = op1.reg; reg_t *src = op2.reg; @@ -108,7 +108,7 @@ void execute_inst_ADDI(lf_scheduler_t* scheduler, size_t worker_number, operand_ *dst = *src + op3.imm; *pc += 1; // Increment pc. #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_ADDI_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_ADDI_ends(worker_number, pc_orig); #endif } @@ -121,7 +121,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - tracepoint_static_scheduler_ADV_starts(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_ADV_starts(worker_number, pc_orig); #endif reg_t *base = op2.reg; reg_t *inc = op3.reg; @@ -140,7 +140,7 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t *pc += 1; // Increment pc. #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_ADV_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_ADV_ends(worker_number, pc_orig); #endif } @@ -153,7 +153,7 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s (reactor %p) %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.reg, *(op2.reg), op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - tracepoint_static_scheduler_ADVI_starts(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_ADVI_starts(worker_number, pc_orig); #endif self_base_t *reactor = (self_base_t*) op1.reg; reg_t *base = op2.reg; @@ -170,7 +170,7 @@ void execute_inst_ADVI(lf_scheduler_t* scheduler, size_t worker_number, operand_ *pc += 1; // Increment pc. #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_ADVI_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_ADVI_ends(worker_number, pc_orig); #endif } @@ -183,7 +183,7 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - tracepoint_static_scheduler_BEQ_starts(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_BEQ_starts(worker_number, pc_orig); #endif reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; @@ -198,7 +198,7 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t if (_rs1 != NULL && _rs2 != NULL && *_rs1 == *_rs2) *pc = op3.imm; else *pc += 1; #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_BEQ_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_BEQ_ends(worker_number, pc_orig); #endif } @@ -211,7 +211,7 @@ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - tracepoint_static_scheduler_BGE_starts(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_BGE_starts(worker_number, pc_orig); #endif reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; @@ -219,7 +219,7 @@ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t if (_rs1 != NULL && _rs2 != NULL && *_rs1 >= *_rs2) *pc = op3.imm; else *pc += 1; #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_BGE_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_BGE_ends(worker_number, pc_orig); #endif } @@ -232,14 +232,14 @@ void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - tracepoint_static_scheduler_BLT_starts(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_BLT_starts(worker_number, pc_orig); #endif reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; if (_rs1 != NULL && _rs2 != NULL && *_rs1 < *_rs2) *pc = op3.imm; else *pc += 1; #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_BLT_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_BLT_ends(worker_number, pc_orig); #endif } @@ -252,14 +252,14 @@ void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - tracepoint_static_scheduler_BNE_starts(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_BNE_starts(worker_number, pc_orig); #endif reg_t *_rs1 = op1.reg; reg_t *_rs2 = op2.reg; if (_rs1 != NULL && _rs2 != NULL && *_rs1 != *_rs2) *pc = op3.imm; else *pc += 1; #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_BNE_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_BNE_ends(worker_number, pc_orig); #endif } @@ -272,7 +272,7 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - tracepoint_static_scheduler_DU_starts(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_DU_starts(worker_number, pc_orig); #endif // FIXME: There seems to be an overflow problem. // When wakeup_time overflows but lf_time_physical() doesn't, @@ -299,7 +299,7 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** [Line %zu] Worker %zu done delaying", *pc, worker_number); *pc += 1; // Increment pc. #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_DU_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_DU_ends(worker_number, pc_orig); #endif } @@ -310,10 +310,10 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t reaction_t** returned_reaction, bool* exit_loop) { char* op_str = "EXE"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - int pc_orig = (int) *pc; - if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm);} + if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_starts((self_base_t *) op2.reg, worker_number, (int) op3.imm);} #if TRACE_ALL_INSTRUCTIONS - else {tracepoint_static_scheduler_EXE_starts(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig);} + int pc_orig = (int) *pc; + else {tracepoint_static_scheduler_EXE_starts((self_base_t *) op2.reg, worker_number, pc_orig);} #endif function_generic_t function = (function_generic_t)(uintptr_t)op1.reg; void *args = (void*)op2.reg; @@ -322,9 +322,9 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t function(args); LF_PRINT_DEBUG("*** [Line %zu] Worker %zu done executing reaction", *pc, worker_number); *pc += 1; // Increment pc. - if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig, (int) op3.imm);} + if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_ends((self_base_t *) op2.reg, worker_number, (int) op3.imm);} #if TRACE_ALL_INSTRUCTIONS - else {tracepoint_static_scheduler_EXE_ends(scheduler->env->trace, (self_base_t *) op2.reg, worker_number, pc_orig);} + else {tracepoint_static_scheduler_EXE_ends((self_base_t *) op2.reg, worker_number, pc_orig);} #endif } @@ -338,7 +338,7 @@ void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - tracepoint_static_scheduler_WLT_starts(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_WLT_starts(worker_number, pc_orig); #endif LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); reg_t *var = op1.reg; @@ -346,7 +346,7 @@ void execute_inst_WLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); *pc += 1; // Increment pc. #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_WLT_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_WLT_ends(worker_number, pc_orig); #endif } @@ -359,7 +359,7 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - tracepoint_static_scheduler_WU_starts(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_WU_starts(worker_number, pc_orig); #endif LF_PRINT_DEBUG("*** Worker %zu waiting", worker_number); reg_t *var = op1.reg; @@ -367,7 +367,7 @@ void execute_inst_WU(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu done waiting", worker_number); *pc += 1; // Increment pc. #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_WU_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_WU_ends(worker_number, pc_orig); #endif } @@ -380,7 +380,7 @@ void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - tracepoint_static_scheduler_JAL_starts(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_JAL_starts(worker_number, pc_orig); #endif // Use the destination register as the return address and, if the // destination register is not the zero register, store pc+1 in it. @@ -388,7 +388,7 @@ void execute_inst_JAL(lf_scheduler_t* scheduler, size_t worker_number, operand_t if (destReg != &zero) *destReg = *pc + 1; *pc = op2.imm + op3.imm; // New pc = label + offset #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_JAL_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_JAL_ends(worker_number, pc_orig); #endif } @@ -401,7 +401,7 @@ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_ LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - tracepoint_static_scheduler_JALR_starts(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_JALR_starts(worker_number, pc_orig); #endif // Use the destination register as the return address and, if the // destination register is not the zero register, store pc+1 in it. @@ -411,7 +411,7 @@ void execute_inst_JALR(lf_scheduler_t* scheduler, size_t worker_number, operand_ reg_t *baseAddr = op2.reg; *pc = *baseAddr + op3.imm; #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_JALR_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_JALR_ends(worker_number, pc_orig); #endif } @@ -424,11 +424,11 @@ void execute_inst_STP(lf_scheduler_t* scheduler, size_t worker_number, operand_t LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - tracepoint_static_scheduler_STP_starts(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_STP_starts(worker_number, pc_orig); #endif *exit_loop = true; #if TRACE_ALL_INSTRUCTIONS - tracepoint_static_scheduler_STP_ends(scheduler->env->trace, worker_number, pc_orig); + tracepoint_static_scheduler_STP_ends(worker_number, pc_orig); #endif } @@ -514,7 +514,6 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu size_t* pc = &scheduler->pc[worker_number]; function_virtual_instruction_t func; - opcode_t opcode; operand_t op1; operand_t op2; operand_t op3; @@ -522,7 +521,6 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu while (!exit_loop) { func = current_schedule[*pc].func; - // opcode = current_schedule[*pc].opcode; // FIXME: Opcode is unused. op1 = current_schedule[*pc].op1; op2 = current_schedule[*pc].op2; op3 = current_schedule[*pc].op3; diff --git a/core/trace.c b/core/trace.c deleted file mode 100644 index 93a0f4781..000000000 --- a/core/trace.c +++ /dev/null @@ -1,822 +0,0 @@ -/** - * @file - * @author Edward A. Lee - * - * @section LICENSE -Copyright (c) 2020, The University of California at Berkeley and TU Dresden - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - * @section DESCRIPTION - * Include this file instead of trace.h to get tracing. - * See trace.h file for instructions. - */ - -#include "trace.h" - -#ifdef LF_TRACE - -#include -#include -#include - -#include "platform.h" - -#ifdef RTI_TRACE -#include "net_common.h" // Defines message types -#endif // RTI_TRACE - -#include "reactor_common.h" -#include "util.h" - -/** Macro to use when access to trace file fails. */ -#define _LF_TRACE_FAILURE(trace) \ - do { \ - fprintf(stderr, "WARNING: Access to trace file failed.\n"); \ - fclose(trace->_lf_trace_file); \ - trace->_lf_trace_file = NULL; \ - return -1; \ - } while(0) - - -trace_t* trace_new(environment_t* env, const char * filename) { - trace_t * trace = (trace_t *) calloc(1, sizeof(trace_t)); - LF_ASSERT_NON_NULL(trace); - - trace->_lf_trace_stop=1; - trace->env = env; - - // Determine length of the filename - size_t len = strlen(filename) + 1; - - // Allocate memory for the filename on the trace struct - trace->filename = (char*) malloc(len * sizeof(char)); - LF_ASSERT_NON_NULL(trace->filename); - - // Copy it to the struct - strncpy(trace->filename, filename, len); - - return trace; -} - -void trace_free(trace_t *trace) { - free(trace->filename); - free(trace); -} - - -int _lf_register_trace_event(trace_t* trace, void* pointer1, void* pointer2, _lf_trace_object_t type, char* description) { - LF_CRITICAL_SECTION_ENTER(trace->env); - if (trace->_lf_trace_object_descriptions_size >= TRACE_OBJECT_TABLE_SIZE) { - LF_CRITICAL_SECTION_EXIT(trace->env); - fprintf(stderr, "WARNING: Exceeded trace object table size. Trace file will be incomplete.\n"); - return 0; - } - trace->_lf_trace_object_descriptions[trace->_lf_trace_object_descriptions_size].pointer = pointer1; - trace->_lf_trace_object_descriptions[trace->_lf_trace_object_descriptions_size].trigger = pointer2; - trace->_lf_trace_object_descriptions[trace->_lf_trace_object_descriptions_size].type = type; - trace->_lf_trace_object_descriptions[trace->_lf_trace_object_descriptions_size].description = description; - trace->_lf_trace_object_descriptions_size++; - LF_CRITICAL_SECTION_EXIT(trace->env); - return 1; -} - -int register_user_trace_event(void *self, char* description) { - LF_ASSERT(self, "Need a pointer to a self struct to register a user trace event"); - trace_t * trace = ((self_base_t *) self)->environment->trace; - return _lf_register_trace_event(trace, description, NULL, trace_user, description); -} - - -/** - * Write the trace header information. - * See trace.h. - * @return The number of items written to the object table or -1 for failure. - */ -int write_trace_header(trace_t* trace) { - if (trace->_lf_trace_file != NULL) { - // The first item in the header is the start time. - // This is both the starting physical time and the starting logical time. - instant_t start_time = lf_time_start(); - // printf("DEBUG: Start time written to trace file is %lld.\n", start_time); - size_t items_written = fwrite( - &start_time, - sizeof(instant_t), - 1, - trace->_lf_trace_file - ); - if (items_written != 1) _LF_TRACE_FAILURE(trace); - - // The next item in the header is the size of the - // _lf_trace_object_descriptions table. - // printf("DEBUG: Table size written to trace file is %d.\n", _lf_trace_object_descriptions_size); - items_written = fwrite( - &trace->_lf_trace_object_descriptions_size, - sizeof(int), - 1, - trace->_lf_trace_file - ); - if (items_written != 1) _LF_TRACE_FAILURE(trace); - - // Next we write the table. - for (int i = 0; i < trace->_lf_trace_object_descriptions_size; i++) { - // printf("DEBUG: Object pointer: %p.\n", _lf_trace_object_descriptions[i].pointer); - // Write the pointer to the self struct. - items_written = fwrite( - &trace->_lf_trace_object_descriptions[i].pointer, - sizeof(void*), - 1, - trace->_lf_trace_file - ); - if (items_written != 1) _LF_TRACE_FAILURE(trace); - - // Write the pointer to the trigger_t struct. - items_written = fwrite( - &trace->_lf_trace_object_descriptions[i].trigger, - sizeof(trigger_t*), - 1, - trace->_lf_trace_file - ); - if (items_written != 1) _LF_TRACE_FAILURE(trace); - - // Write the object type. - items_written = fwrite( - &trace->_lf_trace_object_descriptions[i].type, // Write the pointer value. - sizeof(_lf_trace_object_t), - 1, - trace->_lf_trace_file - ); - if (items_written != 1) _LF_TRACE_FAILURE(trace); - - // Write the description. - int description_size = strlen(trace->_lf_trace_object_descriptions[i].description); - // printf("DEBUG: Object description: %s.\n", trace->_lf_trace_object_descriptions[i].description); - items_written = fwrite( - trace->_lf_trace_object_descriptions[i].description, - sizeof(char), - description_size + 1, // Include null terminator. - trace->_lf_trace_file - ); - if (items_written != description_size + 1) _LF_TRACE_FAILURE(trace); - } - } - return trace->_lf_trace_object_descriptions_size; -} - -/** - * @brief Flush the specified buffer to a file. - * This assumes the caller has entered a critical section. - * @param worker Index specifying the trace to flush. - */ -void flush_trace_locked(trace_t* trace, int worker) { - if (trace->_lf_trace_stop == 0 - && trace->_lf_trace_file != NULL - && trace->_lf_trace_buffer_size[worker] > 0 - ) { - // If the trace header has not been written, write it now. - // This is deferred to here so that user trace objects can be - // registered in startup reactions. - if (!trace->_lf_trace_header_written) { - if (write_trace_header(trace) < 0) { - lf_print_error("Failed to write trace header. Trace file will be incomplete."); - return; - } - trace->_lf_trace_header_written = true; - } - - // Write first the length of the array. - size_t items_written = fwrite( - &trace->_lf_trace_buffer_size[worker], - sizeof(int), - 1, - trace->_lf_trace_file - ); - if (items_written != 1) { - fprintf(stderr, "WARNING: Access to trace file failed.\n"); - fclose(trace->_lf_trace_file); - trace->_lf_trace_file = NULL; - } else { - // Write the contents. - items_written = fwrite( - trace->_lf_trace_buffer[worker], - sizeof(trace_record_t), - trace->_lf_trace_buffer_size[worker], - trace->_lf_trace_file - ); - if (items_written != trace->_lf_trace_buffer_size[worker]) { - fprintf(stderr, "WARNING: Access to trace file failed.\n"); - fclose(trace->_lf_trace_file); - trace->_lf_trace_file = NULL; - } - } - trace->_lf_trace_buffer_size[worker] = 0; - } -} - -/** - * @brief Flush the specified buffer to a file. - * @param worker Index specifying the trace to flush. - */ -void flush_trace(trace_t* trace, int worker) { - // To avoid having more than one worker writing to the file at the same time, - // enter a critical section. - LF_CRITICAL_SECTION_ENTER(GLOBAL_ENVIRONMENT); - flush_trace_locked(trace, worker); - LF_CRITICAL_SECTION_EXIT(GLOBAL_ENVIRONMENT); -} - -void start_trace(trace_t* trace) { - // FIXME: location of trace file should be customizable. - trace->_lf_trace_file = fopen(trace->filename, "w"); - if (trace->_lf_trace_file == NULL) { - fprintf(stderr, "WARNING: Failed to open log file with error code %d." - "No log will be written.\n", errno); - } - // Do not write the trace header information to the file yet - // so that startup reactions can register user-defined trace objects. - // write_trace_header(); - trace->_lf_trace_header_written = false; - - // Allocate an array of arrays of trace records, one per worker thread plus one - // for the 0 thread (the main thread, or in an single-threaded program, the only - // thread). - trace->_lf_number_of_trace_buffers = _lf_number_of_workers + 1; - trace->_lf_trace_buffer = (trace_record_t**)malloc(sizeof(trace_record_t*) * trace->_lf_number_of_trace_buffers); - for (int i = 0; i < trace->_lf_number_of_trace_buffers; i++) { - trace->_lf_trace_buffer[i] = (trace_record_t*)malloc(sizeof(trace_record_t) * TRACE_BUFFER_CAPACITY); - } - // Array of counters that track the size of each trace record (per thread). - trace->_lf_trace_buffer_size = (int*)calloc(sizeof(int), trace->_lf_number_of_trace_buffers); - - trace->_lf_trace_stop = 0; - LF_PRINT_DEBUG("Started tracing."); -} - -void tracepoint( - trace_t* trace, - trace_event_t event_type, - void* reactor, - tag_t* tag, - int worker, - int src_id, - int dst_id, - instant_t* physical_time, - trigger_t* trigger, - interval_t extra_delay, - bool is_interval_start -) { - instant_t time; - if (!is_interval_start && physical_time == NULL) { - time = lf_time_physical(); - physical_time = &time; - } - - environment_t *env = trace->env; - // Worker argument determines which buffer to write to. - int index = (worker >= 0) ? worker : 0; - - // Flush the buffer if it is full. - if (trace->_lf_trace_buffer_size[index] >= TRACE_BUFFER_CAPACITY) { - // No more room in the buffer. Write the buffer to the file. - flush_trace(trace, index); - } - // The above flush_trace resets the write pointer. - int i = trace->_lf_trace_buffer_size[index]; - // Write to memory buffer. - // Get the correct time of the event - - trace->_lf_trace_buffer[index][i].event_type = event_type; - trace->_lf_trace_buffer[index][i].pointer = reactor; - trace->_lf_trace_buffer[index][i].src_id = src_id; - trace->_lf_trace_buffer[index][i].dst_id = dst_id; - if (tag != NULL) { - trace->_lf_trace_buffer[index][i].logical_time = tag->time; - trace->_lf_trace_buffer[index][i].microstep = tag->microstep; - } else if (env != NULL) { - trace->_lf_trace_buffer[index][i].logical_time = ((environment_t *)env)->current_tag.time; - trace->_lf_trace_buffer[index][i].microstep = ((environment_t*)env)->current_tag.microstep; - } - - trace->_lf_trace_buffer[index][i].trigger = trigger; - trace->_lf_trace_buffer[index][i].extra_delay = extra_delay; - if (is_interval_start && physical_time == NULL) { - time = lf_time_physical(); - physical_time = &time; - } - trace->_lf_trace_buffer[index][i].physical_time = *physical_time; - trace->_lf_trace_buffer_size[index]++; -} - -/** - * Trace the start of a reaction execution. - * @param reaction Pointer to the reaction_t struct for the reaction. - * @param worker The thread number of the worker thread or 0 for single-threaded execution. - */ -void tracepoint_reaction_starts(trace_t* trace, reaction_t* reaction, int worker) { - tracepoint(trace, reaction_starts, reaction->self, NULL, worker, worker, reaction->number, NULL, NULL, 0, true); -} - -/** - * Trace the end of a reaction execution. - * @param reaction Pointer to the reaction_t struct for the reaction. - * @param worker The thread number of the worker thread or 0 for single-threaded execution. - */ -void tracepoint_reaction_ends(trace_t* trace, reaction_t* reaction, int worker) { - tracepoint(trace, reaction_ends, reaction->self, NULL, worker, worker, reaction->number, NULL, NULL, 0, false); -} - -/** - * Trace a call to schedule. - * @param trigger Pointer to the trigger_t struct for the trigger. - * @param extra_delay The extra delay passed to schedule(). - */ -void tracepoint_schedule(trace_t* trace, trigger_t* trigger, interval_t extra_delay) { - /* - // schedule() can only trigger reactions within the same reactor as the action - // or timer. If there is such a reaction, find its reactor's self struct and - // put that into the tracepoint. We only have to look at the first reaction. - // If there is no reaction, insert NULL for the reactor. - void* reactor = NULL; - if (trigger->number_of_reactions > 0 - && trigger->reactions[0] != NULL) { - reactor = trigger->reactions[0]->self; - } - // NOTE: The -1 argument indicates no worker. - // This is OK because it is called only while holding the mutex lock. - // True argument specifies to record physical time as late as possible, when - // the event is already on the event queue. - tracepoint(trace, schedule_called, reactor, NULL, -1, 0, 0, NULL, trigger, extra_delay, true); - */ -} - -/** - * Trace a user-defined event. Before calling this, you must call - * register_user_trace_event() with a pointer to the same string - * or else the event will not be recognized. - * @param self Pointer to the self struct of the reactor from which we want - * to trace this event. This pointer is used to get the correct environment and - * thus the correct logical tag of the event. - * @param description Pointer to the description string. - */ -void tracepoint_user_event(void* self, char* description) { - // -1s indicate unknown reaction number and worker thread. - // NOTE: We currently have no way to get the number of the worker that - // is executing the reaction that calls this, so we can't pass a worker - // number to the tracepoint function. We pass -1, indicating no worker. - // But to be safe, then, we have acquire a mutex before calling this - // because multiple reactions might be calling the same tracepoint function. - // There will be a performance hit for this. - LF_ASSERT(self, "A pointer to the self struct is needed to trace an event"); - environment_t *env = ((self_base_t *)self)->environment; - trace_t *trace = env->trace; - LF_CRITICAL_SECTION_ENTER(env); - tracepoint(trace, user_event, description, NULL, -1, -1, -1, NULL, NULL, 0, false); - LF_CRITICAL_SECTION_EXIT(env); -} - -/** - * Trace a user-defined event with a value. - * Before calling this, you must call - * register_user_trace_event() with a pointer to the same string - * or else the event will not be recognized. - * @param self Pointer to the self struct of the reactor from which we want - * to trace this event. This pointer is used to get the correct environment and - * thus the correct logical tag of the event. - * @param description Pointer to the description string. - * @param value The value of the event. This is a long long for - * convenience so that time values can be passed unchanged. - * But int values work as well. - */ -void tracepoint_user_value(void* self, char* description, long long value) { - // -1s indicate unknown reaction number and worker thread. - // NOTE: We currently have no way to get the number of the worker that - // is executing the reaction that calls this, so we can't pass a worker - // number to the tracepoint function. We pass -1, indicating no worker. - // But to be safe, then, we have acquire a mutex before calling this - // because multiple reactions might be calling the same tracepoint function. - // There will be a performance hit for this. - environment_t *env = ((self_base_t *)self)->environment; - trace_t *trace = env->trace; - LF_CRITICAL_SECTION_ENTER(env); - tracepoint(trace, user_value, description, NULL, -1, -1, -1, NULL, NULL, value, false); - LF_CRITICAL_SECTION_EXIT(env); -} - -/** - * Trace the start of a worker waiting for something to change on the event or reaction queue. - * @param worker The thread number of the worker thread or 0 for single-threaded execution. - */ -void tracepoint_worker_wait_starts(trace_t* trace, int worker) { - // tracepoint(trace, worker_wait_starts, NULL, NULL, worker, worker, -1, NULL, NULL, 0, true); -} - -/** - * Trace the end of a worker waiting for something to change on the event or reaction queue. - * @param worker The thread number of the worker thread or 0 for single-threaded execution. - */ -void tracepoint_worker_wait_ends(trace_t* trace, int worker) { - // tracepoint(trace, worker_wait_ends, NULL, NULL, worker, worker, -1, NULL, NULL, 0, false); -} - -/** - * Trace the start of the scheduler waiting for logical time to advance or an event to - * appear on the event queue. - */ -void tracepoint_scheduler_advancing_time_starts(trace_t* trace) { - // tracepoint(trace, scheduler_advancing_time_starts, NULL, NULL, -1, -1, -1, NULL, NULL, 0, true); -} - -/** - * Trace the end of the scheduler waiting for logical time to advance or an event to - * appear on the event queue. - */ -void tracepoint_scheduler_advancing_time_ends(trace_t* trace) { - // tracepoint(trace, scheduler_advancing_time_ends, NULL, NULL, -1, -1, -1, NULL, NULL, 0, false); -} - -/** - * Trace the occurrence of a deadline miss. - * @param reaction Pointer to the reaction_t struct for the reaction. - * @param worker The thread number of the worker thread or 0 for single-threaded execution. - */ -void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, int worker) { - // tracepoint(trace, reaction_deadline_missed, reaction->self, NULL, worker, worker, reaction->number, NULL, NULL, 0, false); -} - -#if SCHEDULER == SCHED_STATIC - -/** Trace the start of the ADD instruction */ -void tracepoint_static_scheduler_ADD_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADD_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the ADDI instruction */ -void tracepoint_static_scheduler_ADDI_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADDI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the ADV instruction */ -void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADV_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the ADVI instruction */ -void tracepoint_static_scheduler_ADVI_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADVI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the BEQ instruction */ -void tracepoint_static_scheduler_BEQ_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_BEQ_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the BGE instruction */ -void tracepoint_static_scheduler_BGE_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_BGE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the BLT instruction */ -void tracepoint_static_scheduler_BLT_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_BLT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the BNE instruction */ -void tracepoint_static_scheduler_BNE_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_BNE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the DU instruction */ -void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_DU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the EXE instruction */ -void tracepoint_static_scheduler_EXE_starts(trace_t* trace, self_base_t *reactor, int worker, int pc) { - tag_t *tag = NULL; - if (reactor) tag = &reactor->tag; - tracepoint(trace, static_scheduler_EXE_starts, reactor, tag, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the EXE instruction (for reactions) */ -void tracepoint_static_scheduler_EXE_reaction_starts(trace_t* trace, self_base_t *reactor, int worker, int pc, int reaction_number) { - tag_t *tag = NULL; - if (reactor) tag = &reactor->tag; - tracepoint(trace, reaction_starts, reactor, tag, worker, worker, reaction_number, NULL, NULL, 0, true); -} - -/** Trace the start of the JAL instruction */ -void tracepoint_static_scheduler_JAL_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_JAL_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the JALR instruction */ -void tracepoint_static_scheduler_JALR_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_JALR_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the STP instruction */ -void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_STP_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the WLT instruction */ -void tracepoint_static_scheduler_WLT_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_WLT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the start of the WU instruction */ -void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_WU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the end of the ADD instruction */ -void tracepoint_static_scheduler_ADD_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADD_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the end of the ADDI instruction */ -void tracepoint_static_scheduler_ADDI_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADDI_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - -/** Trace the end of the ADV instruction */ -void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADV_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - -/** Trace the end of the ADVI instruction */ -void tracepoint_static_scheduler_ADVI_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_ADVI_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - -/** Trace the end of the BEQ instruction */ -void tracepoint_static_scheduler_BEQ_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_BEQ_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the end of the BGE instruction */ -void tracepoint_static_scheduler_BGE_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_BGE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the end of the BLT instruction */ -void tracepoint_static_scheduler_BLT_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_BLT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the end of the BNE instruction */ -void tracepoint_static_scheduler_BNE_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_BNE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the end of the DU instruction */ -void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_DU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - -/** Trace the end of the EXE instruction */ -void tracepoint_static_scheduler_EXE_ends(trace_t* trace, self_base_t *reactor, int worker, int pc) { - tag_t *tag = NULL; - if (reactor) tag = &reactor->tag; - tracepoint(trace, static_scheduler_EXE_ends, reactor, tag, worker, worker, pc, NULL, NULL, 0, false); -} - -/** Trace the end of the EXE instruction (for reactions) */ -void tracepoint_static_scheduler_EXE_reaction_ends(trace_t* trace, self_base_t *reactor, int worker, int pc, int reaction_number) { - tag_t *tag = NULL; - if (reactor) tag = &reactor->tag; - tracepoint(trace, reaction_ends, reactor, tag, worker, worker, reaction_number, NULL, NULL, 0, false); -} - -/** Trace the end of the JAL instruction */ -void tracepoint_static_scheduler_JAL_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_JAL_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - -/** Trace the end of the JALR instruction */ -void tracepoint_static_scheduler_JALR_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_JALR_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - -/** Trace the end of the STP instruction */ -void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_STP_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - -/** Trace the end of the WLT instruction */ -void tracepoint_static_scheduler_WLT_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_WLT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, true); -} - -/** Trace the end of the WU instruction */ -void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker, int pc) { - tracepoint(trace, static_scheduler_WU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0, false); -} - -#endif - -void stop_trace(trace_t* trace) { - LF_CRITICAL_SECTION_ENTER(trace->env); - stop_trace_locked(trace); - LF_CRITICAL_SECTION_EXIT(trace->env); -} - -void stop_trace_locked(trace_t* trace) { - if (trace->_lf_trace_stop) { - // Trace was already stopped. Nothing to do. - return; - } - // In multithreaded execution, thread 0 invokes wrapup reactions, so we - // put that trace last. However, it could also include some startup events. - // In any case, the trace file does not guarantee any ordering. - for (int i = 1; i < trace->_lf_number_of_trace_buffers; i++) { - // Flush the buffer if it has data. - // printf("DEBUG: Trace buffer %d has %d records.\n", i, trace->_lf_trace_buffer_size[i]); - if (trace->_lf_trace_buffer_size && trace->_lf_trace_buffer_size[i] > 0) { - flush_trace_locked(trace, i); - } - } - if (trace->_lf_trace_buffer_size && trace->_lf_trace_buffer_size[0] > 0) { - flush_trace_locked(trace, 0); - } - trace->_lf_trace_stop = 1; - if (trace->_lf_trace_file != NULL) { - fclose(trace->_lf_trace_file); - trace->_lf_trace_file = NULL; - } - LF_PRINT_DEBUG("Stopped tracing."); -} - -//////////////////////////////////////////////////////////// -//// For federated execution - -#if defined FEDERATED || defined LF_ENCLAVES - -/** - * Trace federate sending a message to the RTI. - * @param event_type The type of event. Possible values are: - * - * @param fed_id The federate identifier. - * @param tag Pointer to the tag that has been sent, or NULL. - */ -void tracepoint_federate_to_rti(trace_t *trace, trace_event_t event_type, int fed_id, tag_t* tag) { - tracepoint( - trace, - event_type, - NULL, // void* pointer, - tag, // tag* tag, - -1, // int worker, // no worker ID needed because this is called within a mutex - fed_id, // int src_id, - -1, // int dst_id, - NULL, // instant_t* physical_time (will be generated) - NULL, // trigger_t* trigger, - 0, // interval_t extra_delay - true // is_interval_start - ); -} - -/** - * Trace federate receiving a message from the RTI. - * @param event_type The type of event. Possible values are: - * - * @param fed_id The federate identifier. - * @param tag Pointer to the tag that has been received, or NULL. - */ -void tracepoint_federate_from_rti(trace_t* trace, trace_event_t event_type, int fed_id, tag_t* tag) { - // trace_event_t event_type = (type == MSG_TYPE_TAG_ADVANCE_GRANT)? federate_TAG : federate_PTAG; - tracepoint( - trace, - event_type, - NULL, // void* pointer, - tag, // tag* tag, - -1, // int worker, // no worker ID needed because this is called within a mutex - fed_id, // int src_id, - -1, // int dst_id, - NULL, // instant_t* physical_time (will be generated) - NULL, // trigger_t* trigger, - 0, // interval_t extra_delay - false // is_interval_start - ); -} - -/** - * Trace federate sending a message to another federate. - * @param event_type The type of event. Possible values are: - * - * @param fed_id The federate identifier. - * @param partner_id The partner federate identifier. - * @param tag Pointer to the tag that has been sent, or NULL. - */ -void tracepoint_federate_to_federate(trace_t* trace, trace_event_t event_type, int fed_id, int partner_id, tag_t *tag) { - tracepoint( - trace, - event_type, - NULL, // void* pointer, - tag, // tag* tag, - -1, // int worker, // no worker ID needed because this is called within a mutex - fed_id, // int src_id, - partner_id, // int dst_id, - NULL, // instant_t* physical_time (will be generated) - NULL, // trigger_t* trigger, - 0, // interval_t extra_delay - true // is_interval_start - ); -} - -/** - * Trace federate receiving a message from another federate. - * @param event_type The type of event. Possible values are: - * - * @param fed_id The federate identifier. - * @param partner_id The partner federate identifier. - * @param tag Pointer to the tag that has been received, or NULL. - */ -void tracepoint_federate_from_federate(trace_t* trace, trace_event_t event_type, int fed_id, int partner_id, tag_t *tag) { - tracepoint( - trace, - event_type, - NULL, // void* pointer, - tag, // tag* tag, - -1, // int worker, // no worker ID needed because this is called within a mutex - fed_id, // int src_id, - partner_id, // int dst_id, - NULL, // instant_t* physical_time (will be generated) - NULL, // trigger_t* trigger, - 0, // interval_t extra_delay - false // is_interval_start - ); -} -#endif // FEDERATED - -//////////////////////////////////////////////////////////// -//// For RTI execution - -#ifdef RTI_TRACE - -/** - * Trace RTI sending a message to a federate. - * @param event_type The type of event. Possible values are: - * - * @param fed_id The fedaerate ID. - * @param tag Pointer to the tag that has been sent, or NULL. - */ -void tracepoint_rti_to_federate(trace_t* trace, trace_event_t event_type, int fed_id, tag_t* tag) { - tracepoint( - trace, - event_type, - NULL, // void* pointer, - tag, // tag_t* tag, - fed_id, // int worker (one thread per federate) - -1, // int src_id - fed_id, // int dst_id - NULL, // instant_t* physical_time (will be generated) - NULL, // trigger_t* trigger, - 0, // interval_t extra_delay - true // is_interval_start - ); -} - -/** - * Trace RTI receiving a message from a federate. - * @param event_type The type of event. Possible values are: - * - * @param fed_id The fedaerate ID. - * @param tag Pointer to the tag that has been sent, or NULL. - */ -void tracepoint_rti_from_federate(trace_t* trace, trace_event_t event_type, int fed_id, tag_t* tag) { - tracepoint( - trace, - event_type, - NULL, // void* pointer, - tag, // tag_t* tag, - fed_id, // int worker (one thread per federate) - -1, // int src_id (RTI is the source of the tracepoint) - fed_id, // int dst_id - NULL, // instant_t* physical_time (will be generated) - NULL, // trigger_t* trigger, - 0, // interval_t extra_delay - false // is_interval_start - ); -} - -#endif // RTI_TRACE - -#endif // LF_TRACE diff --git a/core/utils/circular_buffer.c b/core/utils/circular_buffer.c index 508dd4a47..67c47abc7 100644 --- a/core/utils/circular_buffer.c +++ b/core/utils/circular_buffer.c @@ -85,7 +85,7 @@ void cb_dump_events(circular_buffer *cb) void *p = cb->tail; while (p != cb->head) { event_t* e = (event_t*)p; - lf_print("Event @ %lld w/ token %p", e->time, e->token); + lf_print("Event @ %lld w/ token %p", e->base.tag.time, e->token); p += cb->sz; if (p == cb->buffer_end) p = cb->buffer; } diff --git a/include/core/trace.h b/include/core/trace.h deleted file mode 100644 index 20d125677..000000000 --- a/include/core/trace.h +++ /dev/null @@ -1,687 +0,0 @@ -/** - * @file - * @author Edward A. Lee - * - * @section LICENSE -Copyright (c) 2020, The University of California at Berkeley and TU Dresden - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - * @section DESCRIPTION - * Definitions of tracepoint events for use with the C code generator and any other - * code generator that uses the C infrastructure (such as the Python code generator). - * - * See: https://www.lf-lang.org/docs/handbook/tracing?target=c - * - * The trace file is named trace.lft and is a binary file with the following format: - * - * Header: - * * instant_t: The start time. This is both the starting physical time and the starting logical time. - * * int: Size N of the table mapping pointers to descriptions. - * This is followed by N records each of which has: - * * A pointer value (the key). - * * A null-terminated string (the description). - * - * Traces: - * A sequence of traces, each of which begins with an int giving the length of the trace - * followed by binary representations of the trace_record struct written using fwrite(). - */ - -#ifdef RTI_TRACE -#define LF_TRACE -#endif - -#ifndef TRACE_H -#define TRACE_H - -#include "lf_types.h" -#include - -#ifdef FEDERATED -#include "net_common.h" -#endif // FEDERATED - -/** - * Trace event types. If you update this, be sure to update the - * string representation below. Also, create a tracepoint function - * for each event type. - */ -typedef enum -{ - reaction_starts, - reaction_ends, - reaction_deadline_missed, - schedule_called, - user_event, - user_value, - worker_wait_starts, - worker_wait_ends, - scheduler_advancing_time_starts, - scheduler_advancing_time_ends, - // Static scheduler instructions - static_scheduler_ADD_starts, - static_scheduler_ADDI_starts, - static_scheduler_ADV_starts, - static_scheduler_ADVI_starts, - static_scheduler_BEQ_starts, - static_scheduler_BGE_starts, - static_scheduler_BLT_starts, - static_scheduler_BNE_starts, - static_scheduler_DU_starts, - static_scheduler_EXE_starts, - static_scheduler_JAL_starts, - static_scheduler_JALR_starts, - static_scheduler_STP_starts, - static_scheduler_WLT_starts, - static_scheduler_WU_starts, - static_scheduler_ADD_ends, - static_scheduler_ADDI_ends, - static_scheduler_ADV_ends, - static_scheduler_ADVI_ends, - static_scheduler_BEQ_ends, - static_scheduler_BGE_ends, - static_scheduler_BLT_ends, - static_scheduler_BNE_ends, - static_scheduler_DU_ends, - static_scheduler_EXE_ends, - static_scheduler_JAL_ends, - static_scheduler_JALR_ends, - static_scheduler_STP_ends, - static_scheduler_WLT_ends, - static_scheduler_WU_ends, - federated, // Everything below this is for tracing federated interactions. - // Sending messages - send_ACK, - send_FAILED, - send_TIMESTAMP, - send_NET, - send_LTC, - send_STOP_REQ, - send_STOP_REQ_REP, - send_STOP_GRN, - send_FED_ID, - send_PTAG, - send_TAG, - send_REJECT, - send_RESIGN, - send_PORT_ABS, - send_CLOSE_RQ, - send_TAGGED_MSG, - send_P2P_TAGGED_MSG, - send_MSG, - send_P2P_MSG, - send_ADR_AD, - send_ADR_QR, - // Receiving messages - receive_ACK, - receive_FAILED, - receive_TIMESTAMP, - receive_NET, - receive_LTC, - receive_STOP_REQ, - receive_STOP_REQ_REP, - receive_STOP_GRN, - receive_FED_ID, - receive_PTAG, - receive_TAG, - receive_REJECT, - receive_RESIGN, - receive_PORT_ABS, - receive_CLOSE_RQ, - receive_TAGGED_MSG, - receive_P2P_TAGGED_MSG, - receive_MSG, - receive_P2P_MSG, - receive_ADR_AD, - receive_ADR_QR, - receive_UNIDENTIFIED, - NUM_EVENT_TYPES -} trace_event_t; - -#ifdef LF_TRACE - -/** - * String description of event types. - */ -static const char *trace_event_names[] = { - "Reaction starts", - "Reaction ends", - "Reaction deadline missed", - "Schedule called", - "User-defined event", - "User-defined valued event", - "Worker wait starts", - "Worker wait ends", - "Scheduler advancing time starts", - "Scheduler advancing time ends", - // Static scheduler instructions - "ADD", - "ADDI", - "ADV", - "ADVI", - "BEQ", - "BGE", - "BLT", - "BNE", - "DU", - "EXE", - "JAL", - "JALR", - "STP", - "WLT", - "WU", - "End ADD", - "End ADDI", - "End ADV", - "End ADVI", - "End BEQ", - "End BGE", - "End BLT", - "End BNE", - "End DU", - "End EXE", - "End JAL", - "End JALR", - "End STP", - "End WLT", - "End WU", - "Federated marker", - // Sending messages - "Sending ACK", - "Sending FAILED", - "Sending TIMESTAMP", - "Sending NET", - "Sending LTC", - "Sending STOP_REQ", - "Sending STOP_REQ_REP", - "Sending STOP_GRN", - "Sending FED_ID", - "Sending PTAG", - "Sending TAG", - "Sending REJECT", - "Sending RESIGN", - "Sending PORT_ABS", - "Sending CLOSE_RQ", - "Sending TAGGED_MSG", - "Sending P2P_TAGGED_MSG", - "Sending MSG", - "Sending P2P_MSG", - "Sending ADR_AD", - "Sending ADR_QR", - // Receiving messages - "Receiving ACK", - "Receiving FAILED", - "Receiving TIMESTAMP", - "Receiving NET", - "Receiving LTC", - "Receiving STOP_REQ", - "Receiving STOP_REQ_REP", - "Receiving STOP_GRN", - "Receiving FED_ID", - "Receiving PTAG", - "Receiving TAG", - "Receiving REJECT", - "Receiving RESIGN", - "Receiving PORT_ABS", - "Receiving CLOSE_RQ", - "Receiving TAGGED_MSG", - "Receiving P2P_TAGGED_MSG", - "Receiving MSG", - "Receiving P2P_MSG", - "Receiving ADR_AD", - "Receiving ADR_QR", - "Receiving UNIDENTIFIED", -}; - -// FIXME: Target property should specify the capacity of the trace buffer. -// #define TRACE_BUFFER_CAPACITY 2048 -#define TRACE_BUFFER_CAPACITY 131072 - -/** Size of the table of trace objects. */ -#define TRACE_OBJECT_TABLE_SIZE 1024 - -/** - * @brief A trace record that is written in binary to the trace file. - */ -typedef struct trace_record_t { - trace_event_t event_type; - void* pointer; // pointer identifying the record, e.g. to self struct for a reactor. - int src_id; // The ID number of the source (e.g. worker or federate) or -1 for no ID number. - int dst_id; // The ID number of the destination (e.g. reaction or federate) or -1 for no ID number. - instant_t logical_time; - microstep_t microstep; - instant_t physical_time; - trigger_t* trigger; - interval_t extra_delay; -} trace_record_t; - -/** - * Identifier for what is in the object table. - */ -typedef enum { - trace_reactor, // Self struct. - trace_trigger, // Timer or action (argument to schedule()). - trace_user // User-defined trace object. -} _lf_trace_object_t; - -/** - * Struct for table of pointers to a description of the object. - */ -typedef struct object_description_t object_description_t; -struct object_description_t { - void* pointer; // Pointer to the reactor self struct or other identifying pointer. - void* trigger; // Pointer to the trigger (action or timer) or other secondary ID, if any. - _lf_trace_object_t type; // The type of trace object. - char* description; // A NULL terminated string. -}; -/** - * - * @brief This struct holds all the state associated with tracing in a single environment. - * Each environment which has tracing enabled will have such a struct on its environment struct. - * - */ -typedef struct trace_t { - /** - * Array of buffers into which traces are written. - * When a buffer becomes full, the contents is flushed to the file, - * which will create a significant pause in the calling thread. - */ - trace_record_t** _lf_trace_buffer; - int* _lf_trace_buffer_size; - - /** The number of trace buffers allocated when tracing starts. */ - int _lf_number_of_trace_buffers; - - /** Marker that tracing is stopping or has stopped. */ - int _lf_trace_stop; - - /** The file into which traces are written. */ - FILE* _lf_trace_file; - - /** The file name where the traces are written*/ - char *filename; - - /** Table of pointers to a description of the object. */ - object_description_t _lf_trace_object_descriptions[TRACE_OBJECT_TABLE_SIZE]; - int _lf_trace_object_descriptions_size; - - /** Indicator that the trace header information has been written to the file. */ - bool _lf_trace_header_written; - - /** Pointer back to the environment which we are tracing within*/ - environment_t* env; -} trace_t; - - -/** - * @brief Dynamically allocate a new tracing object. - * - * @param env The environment in which we are tracing. If passed NULL we use the GLOBAL_ENVIRONMENT - * @param filename Name of the file in which to store the trace - * @return trace_t* A newly allocated trace object with environment pointer and filename initialized - */ -trace_t* trace_new(environment_t *env, const char *filename); - -/** - * @brief Free the memory allocated for the trace object - * - * @param trace - */ -void trace_free(trace_t *trace); - - -/** - * Register a trace object. - * @param env Pointer to the environment in which the event is traced - * @param pointer1 Pointer that identifies the object, typically to a reactor self struct. - * @param pointer2 Further identifying pointer, typically to a trigger (action or timer) or NULL if irrelevant. - * @param type The type of trace object. - * @param description The human-readable description of the object. - * @return 1 if successful, 0 if the trace object table is full. - */ -int _lf_register_trace_event(trace_t* trace, void* pointer1, void* pointer2, _lf_trace_object_t type, char* description); - -/** - * Register a user trace event. This should be called once, providing a pointer to a string - * that describes a phenomenon being traced. Use the same pointer as the first argument to - * tracepoint_user_event() and tracepoint_user_value(). - * @param description Pointer to a human-readable description of the event. - * @return 1 if successful, 0 if the trace object table is full. - */ -int register_user_trace_event(void* self, char* description); - -/** - * Open a trace file and start tracing. - * @param filename The filename for the trace file. - */ -void start_trace(trace_t* trace); - -/** - * Trace an event identified by a type and a pointer to the self struct of the reactor instance. - * This is a generic tracepoint function. It is better to use one of the specific functions. - * The worker argument determines which buffer to write to. - * Hence, as long as this argument is distinct for each caller, the callers can be in - * different threads without the need for a mutex lock. - * @param event_type The type of event (see trace_event_t in trace.h) - * @param reactor The pointer to the self struct of the reactor instance in the trace table. - * @param tag Pointer to a tag or NULL to use current tag. - * @param worker The ID of the worker thread (which determines which buffer to write to). - * @param src_id The ID number of the source (e.g. worker or federate) or -1 for no ID number. - * @param dst_id The ID number of the destination (e.g. reaction or federate) or -1 for no ID number. - * @param physical_time If the caller has already accessed physical time, provide it here. - * Otherwise, provide NULL. This argument avoids a second call to lf_time_physical() - * and ensures that the physical time in the trace is the same as that used by the caller. - * @param trigger Pointer to the trigger_t struct for calls to schedule or NULL otherwise. - * @param extra_delay The extra delay passed to schedule(). If not relevant for this event - * type, pass 0. - * @param is_interval_start True to indicate that this tracepoint is at the beginning of - * time interval, such as reaction invocation, so that physical time is captured as late - * as possible. False to indicate that it is at the end of an interval, such as the end - * of a reaction invocation, so that physical time is captured as early as possible. - */ -void tracepoint( - trace_t* trace, - trace_event_t event_type, - void* reactor, - tag_t* tag, - int worker, - int src_id, - int dst_id, - instant_t* physical_time, - trigger_t* trigger, - interval_t extra_delay, - bool is_interval_start -); - -/** - * Trace the start of a reaction execution. - * @param env The environment in which we are executing - * @param reaction Pointer to the reaction_t struct for the reaction. - * @param worker The thread number of the worker thread or 0 for single-threaded execution. - */ -void tracepoint_reaction_starts(trace_t* trace, reaction_t* reaction, int worker); - -/** - * Trace the end of a reaction execution. - * @param env The environment in which we are executing - * @param reaction Pointer to the reaction_t struct for the reaction. - * @param worker The thread number of the worker thread or 0 for single-threaded execution. - */ -void tracepoint_reaction_ends(trace_t* trace, reaction_t* reaction, int worker); - -/** - * Trace a call to schedule. - * @param env The environment in which we are executing - * @param trigger Pointer to the trigger_t struct for the trigger. - * @param extra_delay The extra delay passed to schedule(). - */ -void tracepoint_schedule(trace_t* trace, trigger_t* trigger, interval_t extra_delay); - -/** - * Trace a user-defined event. Before calling this, you must call - * register_user_trace_event() with a pointer to the same string - * or else the event will not be recognized. - * @param self Pointer to the self struct of the reactor from which we want - * to trace this event. This pointer is used to get the correct environment and - * thus the correct logical tag of the event. - * @param description Pointer to the description string. - */ -void tracepoint_user_event(void* self, char* description); - -/** - * Trace a user-defined event with a value. - * Before calling this, you must call - * register_user_trace_event() with a pointer to the same string - * or else the event will not be recognized. - * @param self Pointer to the self struct of the reactor from which we want - * to trace this event. This pointer is used to get the correct environment and - * thus the correct logical tag of the event. - * @param description Pointer to the description string. - * @param value The value of the event. This is a long long for - * convenience so that time values can be passed unchanged. - * But int values work as well. - */ -void tracepoint_user_value(void* self, char* description, long long value); - -/** - * Trace the start of a worker waiting for something to change on the reaction queue. - * @param env The environment in which we are executing - * @param worker The thread number of the worker thread or 0 for single-threaded execution. - */ -void tracepoint_worker_wait_starts(trace_t* trace, int worker); - -/** - * Trace the end of a worker waiting for something to change on reaction queue. - * @param env The environment in which we are executing - * @param worker The thread number of the worker thread or 0 for single-threaded execution. - */ -void tracepoint_worker_wait_ends(trace_t* trace, int worker); - -/** - * Trace the start of the scheduler waiting for logical time to advance or an event to - * appear on the event queue. - * @param env The environment in which we are executing - */ -void tracepoint_scheduler_advancing_time_starts(trace_t* trace); - -/** - * Trace the end of the scheduler waiting for logical time to advance or an event to - * appear on the event queue. - * @param env The environment in which we are executing - */ -void tracepoint_scheduler_advancing_time_ends(trace_t* trace); - -/** - * Trace the occurence of a deadline miss. - * @param env The environment in which we are executing - * @param reaction Pointer to the reaction_t struct for the reaction. - * @param worker The thread number of the worker thread or 0 for single-threaded execution. - */ -void tracepoint_reaction_deadline_missed(trace_t* trace, reaction_t *reaction, int worker); - -void tracepoint_static_scheduler_ADD_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_ADDI_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_ADV_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_ADVI_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_BEQ_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_BGE_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_BLT_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_BNE_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_DU_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_JAL_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_JALR_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_STP_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_WLT_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_WU_starts(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_ADD_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_ADDI_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_ADV_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_ADVI_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_BEQ_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_BGE_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_BLT_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_BNE_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_DU_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_JAL_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_JALR_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_STP_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_WLT_ends(trace_t* trace, int worker, int pc); -void tracepoint_static_scheduler_WU_ends(trace_t* trace, int worker, int pc); - -void tracepoint_static_scheduler_EXE_starts(trace_t* trace, self_base_t *reactor, int worker, int pc); -void tracepoint_static_scheduler_EXE_ends(trace_t* trace, self_base_t *reactor, int worker, int pc); -void tracepoint_static_scheduler_EXE_reaction_starts(trace_t* trace, self_base_t *reactor, int worker, int pc, int reaction_number); -void tracepoint_static_scheduler_EXE_reaction_ends(trace_t* trace, self_base_t *reactor, int worker, int pc, int reaction_number); - -/** - * Flush any buffered trace records to the trace file and - * close the files. - */ -void stop_trace(trace_t* trace); - -/** - * Version of stop_trace() that does not lock the trace mutex. - */ -void stop_trace_locked(trace_t* trace); - -//////////////////////////////////////////////////////////// -//// For federated execution - -#if defined(FEDERATED) || defined(LF_ENCLAVES) - -/** - * Trace federate sending a message to the RTI. - * @param event_type The type of event. Possible values are: - * - * @param fed_id The federate identifier. - * @param tag Pointer to the tag that has been sent, or NULL. - */ -void tracepoint_federate_to_rti(trace_t* trace, trace_event_t event_type, int fed_id, tag_t* tag); - -/** - * Trace federate receiving a message from the RTI. - * @param event_type The type of event. Possible values are: - * - * @param fed_id The federate identifier. - * @param tag Pointer to the tag that has been received, or NULL. - */ -void tracepoint_federate_from_rti(trace_t* trace, trace_event_t event_type, int fed_id, tag_t* tag); - -/** - * Trace federate sending a message to another federate. - * @param event_type The type of event. Possible values are: - * - * @param fed_id The federate identifier. - * @param partner_id The partner federate identifier. - * @param tag Pointer to the tag that has been sent, or NULL. - */ -void tracepoint_federate_to_federate(trace_t* trace, trace_event_t event_type, int fed_id, int partner_id, tag_t *tag); - -/** - * Trace federate receiving a message from another federate. - * @param event_type The type of event. Possible values are: - * - * @param fed_id The federate identifier. - * @param partner_id The partner federate identifier. - * @param tag Pointer to the tag that has been received, or NULL. - */ -void tracepoint_federate_from_federate(trace_t* trace, trace_event_t event_type, int fed_id, int partner_id, tag_t *tag); - -#else -#define tracepoint_federate_to_rti(...); -#define tracepoint_federate_from_rti(...); -#define tracepoint_federate_to_federate(...); -#define tracepoint_federate_from_federate(...); -#endif // FEDERATED - -//////////////////////////////////////////////////////////// -//// For RTI execution - -#ifdef RTI_TRACE - -/** - * Trace RTI sending a message to a federate. - * @param event_type The type of event. Possible values are: - * - * @param fed_id The fedaerate ID. - * @param tag Pointer to the tag that has been sent, or NULL. - */ -void tracepoint_rti_to_federate(trace_t* trace, trace_event_t event_type, int fed_id, tag_t* tag); - -/** - * Trace RTI receiving a message from a federate. - * @param event_type The type of event. Possible values are: - * - * @param fed_id The fedaerate ID. - * @param tag Pointer to the tag that has been sent, or NULL. - */ -void tracepoint_rti_from_federate(trace_t* trace, trace_event_t event_type, int fed_id, tag_t* tag); - -#else -#define tracepoint_rti_to_federate(...); -#define tracepoint_rti_from_federate(...) ; -#endif // RTI_TRACE - -#else -typedef struct trace_t trace_t; - -// empty definition in case we compile without tracing -#define _lf_register_trace_event(...) -#define register_user_trace_event(...) -#define tracepoint(...) -#define tracepoint_reaction_starts(...) -#define tracepoint_reaction_ends(...) -#define tracepoint_schedule(...) -#define tracepoint_user_event(...) -#define tracepoint_user_value(...) -#define tracepoint_worker_wait_starts(...) -#define tracepoint_worker_wait_ends(...) -#define tracepoint_scheduler_advancing_time_starts(...); -#define tracepoint_scheduler_advancing_time_ends(...); -#define tracepoint_reaction_deadline_missed(...); -#define tracepoint_static_scheduler_ADD_starts(...); -#define tracepoint_static_scheduler_ADDI_starts(...); -#define tracepoint_static_scheduler_ADV_starts(...); -#define tracepoint_static_scheduler_ADVI_starts(...); -#define tracepoint_static_scheduler_BEQ_starts(...); -#define tracepoint_static_scheduler_BGE_starts(...); -#define tracepoint_static_scheduler_BLT_starts(...); -#define tracepoint_static_scheduler_BNE_starts(...); -#define tracepoint_static_scheduler_DU_starts(...); -#define tracepoint_static_scheduler_EXE_starts(...); -#define tracepoint_static_scheduler_EXE_reaction_starts(...); -#define tracepoint_static_scheduler_JAL_starts(...); -#define tracepoint_static_scheduler_JALR_starts(...); -#define tracepoint_static_scheduler_STP_starts(...); -#define tracepoint_static_scheduler_WLT_starts(...); -#define tracepoint_static_scheduler_WU_starts(...); -#define tracepoint_static_scheduler_ADD_ends(...); -#define tracepoint_static_scheduler_ADDI_ends(...); -#define tracepoint_static_scheduler_ADV_ends(...); -#define tracepoint_static_scheduler_ADVI_ends(...); -#define tracepoint_static_scheduler_BEQ_ends(...); -#define tracepoint_static_scheduler_BGE_ends(...); -#define tracepoint_static_scheduler_BLT_ends(...); -#define tracepoint_static_scheduler_BNE_ends(...); -#define tracepoint_static_scheduler_DU_ends(...); -#define tracepoint_static_scheduler_EXE_ends(...); -#define tracepoint_static_scheduler_EXE_reaction_ends(...); -#define tracepoint_static_scheduler_JAL_ends(...); -#define tracepoint_static_scheduler_JALR_ends(...); -#define tracepoint_static_scheduler_STP_ends(...); -#define tracepoint_static_scheduler_WLT_ends(...); -#define tracepoint_static_scheduler_WU_ends(...); -#define tracepoint_federate_to_rti(...); -#define tracepoint_federate_from_rti(...); -#define tracepoint_federate_to_federate(...) ; -#define tracepoint_federate_from_federate(...) ; -#define tracepoint_rti_to_federate(...); -#define tracepoint_rti_from_federate(...) ; - -#define start_trace(...) -#define stop_trace(...) -#define stop_trace_locked(...) -#define trace_new(...) NULL -#define trace_free(...) - - -#endif // LF_TRACE -#endif // TRACE_H diff --git a/include/core/tracepoint.h b/include/core/tracepoint.h index 4a8a5bc79..4be0d3d99 100644 --- a/include/core/tracepoint.h +++ b/include/core/tracepoint.h @@ -198,6 +198,117 @@ void tracepoint_user_value(void* self, char* description, long long value); */ void lf_tracing_check_version(); +//////////////////////////////////////////////////////////// +//// For quasi-static scheduling + +#if SCHEDULER == SCHED_STATIC + +#define tracepoint_static_scheduler_ADD_starts(worker, pc) \ + call_tracepoint(static_scheduler_ADD_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_ADD_ends(worker, pc) \ + call_tracepoint(static_scheduler_ADD_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_ADDI_starts(worker, pc) \ + call_tracepoint(static_scheduler_ADDI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_ADDI_ends(worker, pc) \ + call_tracepoint(static_scheduler_ADDI_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_ADV_starts(worker, pc) \ + call_tracepoint(static_scheduler_ADV_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_ADV_ends(worker, pc) \ + call_tracepoint(static_scheduler_ADV_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_ADVI_starts(worker, pc) \ + call_tracepoint(static_scheduler_ADVI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_ADVI_ends(worker, pc) \ + call_tracepoint(static_scheduler_ADVI_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_BEQ_starts(worker, pc) \ + call_tracepoint(static_scheduler_BEQ_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_BEQ_ends(worker, pc) \ + call_tracepoint(static_scheduler_BEQ_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_BGE_starts(worker, pc) \ + call_tracepoint(static_scheduler_BGE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_BGE_ends(worker, pc) \ + call_tracepoint(static_scheduler_BGE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_BLT_starts(worker, pc) \ + call_tracepoint(static_scheduler_BLT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_BLT_ends(worker, pc) \ + call_tracepoint(static_scheduler_BLT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_BNE_starts(worker, pc) \ + call_tracepoint(static_scheduler_BNE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_BNE_ends(worker, pc) \ + call_tracepoint(static_scheduler_BNE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_DU_starts(worker, pc) \ + call_tracepoint(static_scheduler_DU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_DU_ends(worker, pc) \ + call_tracepoint(static_scheduler_DU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_EXE_starts(worker, pc) \ + call_tracepoint(static_scheduler_EXE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_EXE_ends(worker, pc) \ + call_tracepoint(static_scheduler_EXE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_JAL_starts(worker, pc) \ + call_tracepoint(static_scheduler_JAL_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_JAL_ends(worker, pc) \ + call_tracepoint(static_scheduler_JAL_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_JALR_starts(worker, pc) \ + call_tracepoint(static_scheduler_JALR_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_JALR_ends(worker, pc) \ + call_tracepoint(static_scheduler_JALR_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_STP_starts(worker, pc) \ + call_tracepoint(static_scheduler_STP_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_STP_ends(worker, pc) \ + call_tracepoint(static_scheduler_STP_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_WLT_starts(worker, pc) \ + call_tracepoint(static_scheduler_WLT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_WLT_ends(worker, pc) \ + call_tracepoint(static_scheduler_WLT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_WU_starts(worker, pc) \ + call_tracepoint(static_scheduler_WU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +#define tracepoint_static_scheduler_WU_ends(worker, pc) \ + call_tracepoint(static_scheduler_WU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + +/** + * A special case when EXE is called on a reaction. In this case, + * "reaction_starts" is used similar to tracepoint_reaction_starts(). + */ +#define tracepoint_static_scheduler_EXE_reaction_starts(reactor, worker, reaction_number) \ + tag_t *tag = NULL; \ + if (reactor) tag = &reactor->tag; \ + call_tracepoint(reaction_starts, reactor, tag, worker, worker, reaction_number, NULL, NULL, 0) + +#define tracepoint_static_scheduler_EXE_reaction_ends(reactor, worker, reaction_number) \ + tag_t *tag = NULL; \ + if (reactor) tag = &reactor->tag; \ + call_tracepoint(reaction_ends, reactor, tag, worker, worker, reaction_number, NULL, NULL, 0) + +#endif // SCHED_STATIC + //////////////////////////////////////////////////////////// //// For federated execution @@ -401,6 +512,18 @@ static inline void lf_tracing_set_start_time(int64_t start_time) { (void)start_t (void)reaction; \ (void)worker; \ } +#define tracepoint_static_scheduler_EXE_reaction_starts(reactor, worker, reaction_number) \ + while (0) { \ + (void)reactor; \ + (void)worker; \ + (void)reaction_number; \ + } +#define tracepoint_static_scheduler_EXE_reaction_ends(reactor, worker, reaction_number) \ + while (0) { \ + (void)reactor; \ + (void)worker; \ + (void)reaction_number; \ + } #endif // LF_TRACE #endif // TRACEPOINT_H diff --git a/trace/api/types/trace_types.h b/trace/api/types/trace_types.h index 6d8758fa4..7001ac9fa 100644 --- a/trace/api/types/trace_types.h +++ b/trace/api/types/trace_types.h @@ -15,70 +15,102 @@ * string representation below. Also, create a tracepoint function * for each event type. */ -typedef enum { - reaction_starts, - reaction_ends, - reaction_deadline_missed, - schedule_called, - user_event, - user_value, - worker_wait_starts, - worker_wait_ends, - scheduler_advancing_time_starts, - scheduler_advancing_time_ends, - federated, // Everything below this is for tracing federated interactions. - // Sending messages - send_ACK, - send_FAILED, - send_TIMESTAMP, - send_NET, - send_LTC, - send_STOP_REQ, - send_STOP_REQ_REP, - send_STOP_GRN, - send_FED_ID, - send_PTAG, - send_TAG, - send_REJECT, - send_RESIGN, - send_PORT_ABS, - send_CLOSE_RQ, - send_TAGGED_MSG, - send_P2P_TAGGED_MSG, - send_MSG, - send_P2P_MSG, - send_ADR_AD, - send_ADR_QR, - // Receiving messages - receive_ACK, - receive_FAILED, - receive_TIMESTAMP, - receive_NET, - receive_LTC, - receive_STOP_REQ, - receive_STOP_REQ_REP, - receive_STOP_GRN, - receive_FED_ID, - receive_PTAG, - receive_TAG, - receive_REJECT, - receive_RESIGN, - receive_PORT_ABS, - receive_CLOSE_RQ, - receive_TAGGED_MSG, - receive_P2P_TAGGED_MSG, - receive_MSG, - receive_P2P_MSG, - receive_ADR_AD, - receive_ADR_QR, - receive_UNIDENTIFIED, - NUM_EVENT_TYPES +typedef enum +{ + reaction_starts, + reaction_ends, + reaction_deadline_missed, + schedule_called, + user_event, + user_value, + worker_wait_starts, + worker_wait_ends, + scheduler_advancing_time_starts, + scheduler_advancing_time_ends, + // Static scheduler instructions + static_scheduler_ADD_starts, + static_scheduler_ADDI_starts, + static_scheduler_ADV_starts, + static_scheduler_ADVI_starts, + static_scheduler_BEQ_starts, + static_scheduler_BGE_starts, + static_scheduler_BLT_starts, + static_scheduler_BNE_starts, + static_scheduler_DU_starts, + static_scheduler_EXE_starts, + static_scheduler_JAL_starts, + static_scheduler_JALR_starts, + static_scheduler_STP_starts, + static_scheduler_WLT_starts, + static_scheduler_WU_starts, + static_scheduler_ADD_ends, + static_scheduler_ADDI_ends, + static_scheduler_ADV_ends, + static_scheduler_ADVI_ends, + static_scheduler_BEQ_ends, + static_scheduler_BGE_ends, + static_scheduler_BLT_ends, + static_scheduler_BNE_ends, + static_scheduler_DU_ends, + static_scheduler_EXE_ends, + static_scheduler_JAL_ends, + static_scheduler_JALR_ends, + static_scheduler_STP_ends, + static_scheduler_WLT_ends, + static_scheduler_WU_ends, + federated, // Everything below this is for tracing federated interactions. + // Sending messages + send_ACK, + send_FAILED, + send_TIMESTAMP, + send_NET, + send_LTC, + send_STOP_REQ, + send_STOP_REQ_REP, + send_STOP_GRN, + send_FED_ID, + send_PTAG, + send_TAG, + send_REJECT, + send_RESIGN, + send_PORT_ABS, + send_CLOSE_RQ, + send_TAGGED_MSG, + send_P2P_TAGGED_MSG, + send_MSG, + send_P2P_MSG, + send_ADR_AD, + send_ADR_QR, + // Receiving messages + receive_ACK, + receive_FAILED, + receive_TIMESTAMP, + receive_NET, + receive_LTC, + receive_STOP_REQ, + receive_STOP_REQ_REP, + receive_STOP_GRN, + receive_FED_ID, + receive_PTAG, + receive_TAG, + receive_REJECT, + receive_RESIGN, + receive_PORT_ABS, + receive_CLOSE_RQ, + receive_TAGGED_MSG, + receive_P2P_TAGGED_MSG, + receive_MSG, + receive_P2P_MSG, + receive_ADR_AD, + receive_ADR_QR, + receive_UNIDENTIFIED, + NUM_EVENT_TYPES } trace_event_t; /** * String description of event types. */ -static const char* trace_event_names[] = { +static const char *trace_event_names[] = { "Reaction starts", "Reaction ends", "Reaction deadline missed", @@ -89,6 +121,37 @@ static const char* trace_event_names[] = { "Worker wait ends", "Scheduler advancing time starts", "Scheduler advancing time ends", + // Static scheduler instructions + "ADD", + "ADDI", + "ADV", + "ADVI", + "BEQ", + "BGE", + "BLT", + "BNE", + "DU", + "EXE", + "JAL", + "JALR", + "STP", + "WLT", + "WU", + "End ADD", + "End ADDI", + "End ADV", + "End ADVI", + "End BEQ", + "End BGE", + "End BLT", + "End BNE", + "End DU", + "End EXE", + "End JAL", + "End JALR", + "End STP", + "End WLT", + "End WU", "Federated marker", // Sending messages "Sending ACK", diff --git a/util/tracing/trace_to_chrome.c b/util/tracing/trace_to_chrome.c index 02c54435a..363725fcf 100644 --- a/util/tracing/trace_to_chrome.c +++ b/util/tracing/trace_to_chrome.c @@ -53,6 +53,7 @@ FILE* trace_file = NULL; FILE* output_file = NULL; /** + * SPECIFIC TO QUASI-STATIC SCHEDULING: * By default, the Chrome tracing displays events in us granularity. So * timestamps by default are divided by scaling=1000 to show correct units in * the GUI. However, for sub-us events, it is preferable to set scaling=1 so @@ -78,7 +79,10 @@ int max_reaction_number = 0; /** Indicator to plot vs. physical time only. */ bool physical_time_only = false; -/** A helper function for retriving virtual instruction name from event type */ +/** + * SPECIFIC TO QUASI-STATIC SCHEDULING: + * A helper function for retriving virtual instruction name from event type + */ char* get_instruction_name(trace_event_t event_type) { switch(event_type) { case static_scheduler_ADD_starts: @@ -164,310 +168,9 @@ size_t read_and_write_trace() { if (trace[i].event_type > federated) continue; - if (trace[i].dst_id >= 0) { - reaction_name = (char*)malloc(4); - snprintf(reaction_name, 4, "%d", trace[i].dst_id); - } - // printf("DEBUG: Reactor's self struct pointer: %p\n", trace[i].pointer); - int reactor_index; - char* reactor_name = get_object_description(trace[i].pointer, &reactor_index); - if (reactor_name == NULL) { - if (trace[i].event_type == worker_wait_starts || trace[i].event_type == worker_wait_ends) { - reactor_name = "WAIT"; - } else if (trace[i].event_type == scheduler_advancing_time_starts - || trace[i].event_type == scheduler_advancing_time_starts) { - reactor_name = "ADVANCE TIME"; - } else if (trace[i].event_type >= static_scheduler_ADD_starts - && trace[i].event_type <= static_scheduler_WU_ends) { - int pc = trace[i].dst_id; - char *inst_name = get_instruction_name(trace[i].event_type); - char str[20]; - sprintf(str, "%d: %s", pc, inst_name); - reactor_name = str; - } else { - reactor_name = "NO REACTOR"; - } - } - // Default name is the reactor name. - char* name = reactor_name; - - int trigger_index; - char* trigger_name = get_trigger_name(trace[i].trigger, &trigger_index); - if (trigger_name == NULL) { - trigger_name = "NONE"; - } - // By default, the timestamp used in the trace is the elapsed - // physical time in microseconds. But for schedule_called events, - // it will instead be the logical time at which the action or timer - // is to be scheduled. - interval_t elapsed_physical_time = (trace[i].physical_time - start_time)/scaling_factor; - interval_t timestamp = elapsed_physical_time; - interval_t elapsed_logical_time = (trace[i].logical_time - start_time)/scaling_factor; - - if (elapsed_physical_time < 0) { - fprintf(stderr, "WARNING: Negative elapsed physical time %lld. Skipping trace entry.\n", elapsed_physical_time); - continue; - } - if (elapsed_logical_time < 0) { - fprintf(stderr, "WARNING: Negative elapsed logical time %lld. Skipping trace entry.\n", elapsed_logical_time); - continue; - } - - // Default thread id is the worker number. - int thread_id = trace[i].src_id; - - char* args; - asprintf(&args, "{" - "\"reaction\": %s," // reaction number. - "\"logical time\": %lld," // logical time. - "\"physical time\": %lld," // physical time. - "\"microstep\": %d" // microstep. - "}", - reaction_name, - elapsed_logical_time, - elapsed_physical_time, - trace[i].microstep - ); - char* phase; - int pid; - switch(trace[i].event_type) { - case reaction_starts: - phase = "B"; - pid = 0; // Process 0 will be named "Execution" - break; - case reaction_ends: - phase = "E"; - pid = 0; // Process 0 will be named "Execution" - break; - case schedule_called: - phase = "i"; - pid = reactor_index + 1; // One pid per reactor. - if (!physical_time_only) { - timestamp = elapsed_logical_time + trace[i].extra_delay/scaling_factor; - } - thread_id = trigger_index; - name = trigger_name; - break; - case user_event: - pid = PID_FOR_USER_EVENT; - phase= "i"; - if (!physical_time_only) { - timestamp = elapsed_logical_time; - } - thread_id = reactor_index; - break; - case user_value: - pid = PID_FOR_USER_EVENT; - phase= "C"; - if (!physical_time_only) { - timestamp = elapsed_logical_time; - } - thread_id = reactor_index; - free(args); - asprintf(&args, "{\"value\": %lld}", trace[i].extra_delay); - break; - case worker_wait_starts: - pid = PID_FOR_WORKER_WAIT; - phase = "B"; - break; - case worker_wait_ends: - pid = PID_FOR_WORKER_WAIT; - phase = "E"; - break; - case scheduler_advancing_time_starts: - pid = PID_FOR_WORKER_ADVANCING_TIME; - phase = "B"; - break; - case scheduler_advancing_time_ends: - pid = PID_FOR_WORKER_ADVANCING_TIME; - phase = "E"; - break; - case static_scheduler_ADD_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_ADDI_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_ADV_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_ADVI_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_BEQ_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_BGE_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_BLT_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_BNE_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_DU_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_EXE_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_JAL_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_JALR_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_STP_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_WLT_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_WU_starts: - pid = 0; - phase = "B"; - break; - case static_scheduler_ADD_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_ADDI_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_ADV_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_ADVI_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_BEQ_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_BGE_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_BLT_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_BNE_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_DU_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_EXE_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_JAL_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_JALR_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_STP_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_WLT_ends: - pid = 0; - phase = "E"; - break; - case static_scheduler_WU_ends: - pid = 0; - phase = "E"; - break; - default: - fprintf(stderr, "WARNING: Unrecognized event type %d: %s\n", - trace[i].event_type, trace_event_names[trace[i].event_type]); - pid = PID_FOR_UNKNOWN_EVENT; - phase = "i"; - } - fprintf(output_file, "{" - "\"name\": \"%s\", " // name is the reactor or trigger name. - "\"cat\": \"%s\", " // category is the type of event. - "\"ph\": \"%s\", " // phase is "B" (begin), "E" (end), or "X" (complete). - "\"tid\": %d, " // thread ID. - "\"pid\": %d, " // process ID is required. - "\"ts\": %lld, " // timestamp in microseconds - "\"args\": %s" // additional arguments from above. - "},\n", - name, - trace_event_names[trace[i].event_type], - phase, - thread_id, - pid, - timestamp, - args - ); - free(args); - - if (trace[i].src_id > max_thread_id) { - max_thread_id = trace[i].src_id; - } - // If the event is reaction_starts and physical_time_only is not set, - // then also generate an instantaneous - // event to be shown in the reactor's section, along with timers and actions. - if (trace[i].event_type == reaction_starts && !physical_time_only) { - phase = "i"; - pid = reactor_index + 1; - reaction_name = (char*)malloc(4); - char name[13]; - snprintf(name, 13, "reaction %d", trace[i].dst_id); - - // NOTE: If the reactor has more than 1024 timers and actions, then - // there will be a collision of thread IDs here. - thread_id = 1024 + trace[i].dst_id; - if (trace[i].dst_id > max_reaction_number) { - max_reaction_number = trace[i].dst_id; - } - - fprintf(output_file, "{" - "\"name\": \"%s\", " // name is the reactor or trigger name. - "\"cat\": \"%s\", " // category is the type of event. - "\"ph\": \"%s\", " // phase is "B" (begin), "E" (end), or "X" (complete). - "\"tid\": %d, " // thread ID. - "\"pid\": %d, " // process ID is required. - "\"ts\": %lld, " // timestamp in microseconds - "\"args\": {" - "\"microstep\": %d, " // microstep. - "\"physical time\": %lld" // physical time. - "}},\n", - name, - "Reaction", - phase, - thread_id, - pid, - elapsed_logical_time, - trace[i].microstep, - elapsed_physical_time - ); - } + if (trace[i].dst_id >= 0) { + reaction_name = (char*)malloc(4); + snprintf(reaction_name, 4, "%d", trace[i].dst_id); } // printf("DEBUG: Reactor's self struct pointer: %p\n", trace[i].pointer); int reactor_index; @@ -575,6 +278,126 @@ size_t read_and_write_trace() { pid = PID_FOR_WORKER_ADVANCING_TIME; phase = "E"; break; + case static_scheduler_ADD_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_ADDI_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_ADV_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_ADVI_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_BEQ_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_BGE_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_BLT_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_BNE_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_DU_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_EXE_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_JAL_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_JALR_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_STP_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_WLT_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_WU_starts: + pid = 0; + phase = "B"; + break; + case static_scheduler_ADD_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_ADDI_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_ADV_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_ADVI_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_BEQ_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_BGE_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_BLT_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_BNE_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_DU_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_EXE_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_JAL_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_JALR_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_STP_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_WLT_ends: + pid = 0; + phase = "E"; + break; + case static_scheduler_WU_ends: + pid = 0; + phase = "E"; + break; default: fprintf(stderr, "WARNING: Unrecognized event type %d: %s\n", trace[i].event_type, trace_event_names[trace[i].event_type]); @@ -823,4 +646,4 @@ int main(int argc, char* argv[]) { write_metadata_events(output_file); fprintf(output_file, "]}\n"); } -} +} \ No newline at end of file From 5874882644820bbc05e35bbf582070175be72eff Mon Sep 17 00:00:00 2001 From: Shaokai Jerry Lin Date: Tue, 8 Oct 2024 16:39:03 -0700 Subject: [PATCH 72/80] Fix tracing --- core/threaded/scheduler_static.c | 14 +++++-- include/core/tracepoint.h | 68 ++++++++++++++++---------------- util/tracing/trace_to_chrome.c | 7 +++- 3 files changed, 49 insertions(+), 40 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 205237b62..96e683739 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -50,7 +50,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tracepoint.h" #include "util.h" +#ifndef TRACE_ALL_INSTRUCTIONS #define TRACE_ALL_INSTRUCTIONS false +#endif #define SPIN_WAIT_THRESHOLD SEC(1) /////////////////// External Variables ///////////////////////// @@ -310,10 +312,12 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t reaction_t** returned_reaction, bool* exit_loop) { char* op_str = "EXE"; LF_PRINT_DEBUG("*** Worker %zu executing instruction: [Line %zu] %s %" PRIu64 " %" PRIu64 " %" PRIu64, worker_number, *pc, op_str, op1.imm, op2.imm, op3.imm); - if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_starts((self_base_t *) op2.reg, worker_number, (int) op3.imm);} #if TRACE_ALL_INSTRUCTIONS int pc_orig = (int) *pc; - else {tracepoint_static_scheduler_EXE_starts((self_base_t *) op2.reg, worker_number, pc_orig);} + if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_starts((void*)op2.reg, worker_number, op3.imm);} + else {tracepoint_static_scheduler_EXE_starts(worker_number, pc_orig);} +#else + if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_starts((void*)op2.reg, worker_number, op3.imm);} #endif function_generic_t function = (function_generic_t)(uintptr_t)op1.reg; void *args = (void*)op2.reg; @@ -322,9 +326,11 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t function(args); LF_PRINT_DEBUG("*** [Line %zu] Worker %zu done executing reaction", *pc, worker_number); *pc += 1; // Increment pc. - if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_ends((self_base_t *) op2.reg, worker_number, (int) op3.imm);} #if TRACE_ALL_INSTRUCTIONS - else {tracepoint_static_scheduler_EXE_ends((self_base_t *) op2.reg, worker_number, pc_orig);} + if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_ends((void*)op2.reg, worker_number, op3.imm);} + else {tracepoint_static_scheduler_EXE_ends(worker_number, pc_orig);} +#else + if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_ends((void*)op2.reg, worker_number, op3.imm);} #endif } diff --git a/include/core/tracepoint.h b/include/core/tracepoint.h index 4be0d3d99..8a96d559a 100644 --- a/include/core/tracepoint.h +++ b/include/core/tracepoint.h @@ -203,108 +203,108 @@ void lf_tracing_check_version(); #if SCHEDULER == SCHED_STATIC +#define NULL_TAG ((tag_t){.time=LLONG_MAX, .microstep=0}) + #define tracepoint_static_scheduler_ADD_starts(worker, pc) \ - call_tracepoint(static_scheduler_ADD_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_ADD_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_ADD_ends(worker, pc) \ - call_tracepoint(static_scheduler_ADD_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_ADD_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_ADDI_starts(worker, pc) \ - call_tracepoint(static_scheduler_ADDI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_ADDI_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_ADDI_ends(worker, pc) \ - call_tracepoint(static_scheduler_ADDI_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_ADDI_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_ADV_starts(worker, pc) \ - call_tracepoint(static_scheduler_ADV_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_ADV_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_ADV_ends(worker, pc) \ - call_tracepoint(static_scheduler_ADV_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_ADV_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_ADVI_starts(worker, pc) \ - call_tracepoint(static_scheduler_ADVI_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_ADVI_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_ADVI_ends(worker, pc) \ - call_tracepoint(static_scheduler_ADVI_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_ADVI_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_BEQ_starts(worker, pc) \ - call_tracepoint(static_scheduler_BEQ_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_BEQ_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_BEQ_ends(worker, pc) \ - call_tracepoint(static_scheduler_BEQ_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_BEQ_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_BGE_starts(worker, pc) \ - call_tracepoint(static_scheduler_BGE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_BGE_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_BGE_ends(worker, pc) \ - call_tracepoint(static_scheduler_BGE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_BGE_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_BLT_starts(worker, pc) \ - call_tracepoint(static_scheduler_BLT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_BLT_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_BLT_ends(worker, pc) \ - call_tracepoint(static_scheduler_BLT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_BLT_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_BNE_starts(worker, pc) \ - call_tracepoint(static_scheduler_BNE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_BNE_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_BNE_ends(worker, pc) \ - call_tracepoint(static_scheduler_BNE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_BNE_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_DU_starts(worker, pc) \ - call_tracepoint(static_scheduler_DU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_DU_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_DU_ends(worker, pc) \ - call_tracepoint(static_scheduler_DU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_DU_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_EXE_starts(worker, pc) \ - call_tracepoint(static_scheduler_EXE_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_EXE_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_EXE_ends(worker, pc) \ - call_tracepoint(static_scheduler_EXE_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_EXE_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_JAL_starts(worker, pc) \ - call_tracepoint(static_scheduler_JAL_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_JAL_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_JAL_ends(worker, pc) \ - call_tracepoint(static_scheduler_JAL_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_JAL_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_JALR_starts(worker, pc) \ - call_tracepoint(static_scheduler_JALR_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_JALR_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_JALR_ends(worker, pc) \ - call_tracepoint(static_scheduler_JALR_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_JALR_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_STP_starts(worker, pc) \ - call_tracepoint(static_scheduler_STP_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_STP_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_STP_ends(worker, pc) \ - call_tracepoint(static_scheduler_STP_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_STP_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_WLT_starts(worker, pc) \ - call_tracepoint(static_scheduler_WLT_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_WLT_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_WLT_ends(worker, pc) \ - call_tracepoint(static_scheduler_WLT_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_WLT_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_WU_starts(worker, pc) \ - call_tracepoint(static_scheduler_WU_starts, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_WU_starts, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) #define tracepoint_static_scheduler_WU_ends(worker, pc) \ - call_tracepoint(static_scheduler_WU_ends, NULL, NULL, worker, worker, pc, NULL, NULL, 0) + call_tracepoint(static_scheduler_WU_ends, NULL, NULL_TAG, worker, worker, pc, NULL, NULL, 0) /** * A special case when EXE is called on a reaction. In this case, * "reaction_starts" is used similar to tracepoint_reaction_starts(). */ #define tracepoint_static_scheduler_EXE_reaction_starts(reactor, worker, reaction_number) \ - tag_t *tag = NULL; \ - if (reactor) tag = &reactor->tag; \ + tag_t tag = ((self_base_t *)reactor)->tag; \ call_tracepoint(reaction_starts, reactor, tag, worker, worker, reaction_number, NULL, NULL, 0) #define tracepoint_static_scheduler_EXE_reaction_ends(reactor, worker, reaction_number) \ - tag_t *tag = NULL; \ - if (reactor) tag = &reactor->tag; \ + tag_t tag = ((self_base_t *)reactor)->tag; \ call_tracepoint(reaction_ends, reactor, tag, worker, worker, reaction_number, NULL, NULL, 0) #endif // SCHED_STATIC diff --git a/util/tracing/trace_to_chrome.c b/util/tracing/trace_to_chrome.c index 363725fcf..171364fbf 100644 --- a/util/tracing/trace_to_chrome.c +++ b/util/tracing/trace_to_chrome.c @@ -60,7 +60,7 @@ FILE* output_file = NULL; * that the execution time of events are not abstracted to 0. */ int scaling_factor = 1000; -// double scaling_factor = 1; // For seeing sub-us events. +// int scaling_factor = 1; // For seeing sub-us events. /** * Print a usage message. @@ -179,8 +179,11 @@ size_t read_and_write_trace() { if (trace[i].event_type == worker_wait_starts || trace[i].event_type == worker_wait_ends) { reactor_name = "WAIT"; } else if (trace[i].event_type == scheduler_advancing_time_starts || - trace[i].event_type == scheduler_advancing_time_starts) { + trace[i].event_type == scheduler_advancing_time_ends) { reactor_name = "ADVANCE TIME"; + } else if (strcmp(get_instruction_name(trace[i].event_type), "UNKNOWN") != 0) { + // Check if the event is related to PretVM. + reactor_name = get_instruction_name(trace[i].event_type); } else { reactor_name = "NO REACTOR"; } From 700835b37f8d8dec57cb06d18bb4c7228e3d76d0 Mon Sep 17 00:00:00 2001 From: Shaokai Jerry Lin Date: Tue, 8 Oct 2024 20:39:11 -0700 Subject: [PATCH 73/80] Remove an unused header --- core/threaded/scheduler_static.c | 1 - 1 file changed, 1 deletion(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 96e683739..f09f4e3a7 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -45,7 +45,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "scheduler_static_functions.h" #include "scheduler_sync_tag_advance.h" #include "scheduler.h" -#include "semaphore.h" #include "tag.h" #include "tracepoint.h" #include "util.h" From 998f555aa29c3249870bcc47c1f0bb0e686a3dc8 Mon Sep 17 00:00:00 2001 From: Shaokai Jerry Lin Date: Wed, 16 Oct 2024 22:39:45 -0700 Subject: [PATCH 74/80] Fix operand naming and add a debug message to BLT --- core/threaded/scheduler_static.c | 35 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index f09f4e3a7..1cc751609 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -186,17 +186,17 @@ void execute_inst_BEQ(lf_scheduler_t* scheduler, size_t worker_number, operand_t int pc_orig = (int) *pc; tracepoint_static_scheduler_BEQ_starts(worker_number, pc_orig); #endif - reg_t *_rs1 = op1.reg; - reg_t *_rs2 = op2.reg; - // These NULL checks allow _rs1 and _rs2 to be uninitialized in the static + reg_t *_op1 = op1.reg; + reg_t *_op2 = op2.reg; + // These NULL checks allow _op1 and _op2 to be uninitialized in the static // schedule, which can save a few lines in the schedule. But it is debatable // whether this is good practice. if (debug) { - lf_print("DEBUG: _rs1 = %p, _rs2 = %p", _rs1, _rs2); - if (_rs1 != NULL) lf_print("DEBUG: *_rs1 = %lld", *_rs1); - if (_rs2 != NULL) lf_print("DEBUG: *_rs2 = %lld", *_rs2); + lf_print("DEBUG: _op1 = %p, _op2 = %p", _op1, _op2); + if (_op1 != NULL) lf_print("DEBUG: *_op1 = %lld", *_op1); + if (_op2 != NULL) lf_print("DEBUG: *_op2 = %lld", *_op2); } - if (_rs1 != NULL && _rs2 != NULL && *_rs1 == *_rs2) *pc = op3.imm; + if (_op1 != NULL && _op2 != NULL && *_op1 == *_op2) *pc = op3.imm; else *pc += 1; #if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_BEQ_ends(worker_number, pc_orig); @@ -214,10 +214,10 @@ void execute_inst_BGE(lf_scheduler_t* scheduler, size_t worker_number, operand_t int pc_orig = (int) *pc; tracepoint_static_scheduler_BGE_starts(worker_number, pc_orig); #endif - reg_t *_rs1 = op1.reg; - reg_t *_rs2 = op2.reg; - LF_PRINT_DEBUG("Worker %zu: BGE : operand 1 = %lld, operand 2 = %lld", worker_number, *_rs1, *_rs2); - if (_rs1 != NULL && _rs2 != NULL && *_rs1 >= *_rs2) *pc = op3.imm; + reg_t *_op1 = op1.reg; + reg_t *_op2 = op2.reg; + LF_PRINT_DEBUG("Worker %zu: BGE : operand 1 = %lld, operand 2 = %lld", worker_number, *_op1, *_op2); + if (_op1 != NULL && _op2 != NULL && *_op1 >= *_op2) *pc = op3.imm; else *pc += 1; #if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_BGE_ends(worker_number, pc_orig); @@ -235,10 +235,11 @@ void execute_inst_BLT(lf_scheduler_t* scheduler, size_t worker_number, operand_t int pc_orig = (int) *pc; tracepoint_static_scheduler_BLT_starts(worker_number, pc_orig); #endif - reg_t *_rs1 = op1.reg; - reg_t *_rs2 = op2.reg; - if (_rs1 != NULL && _rs2 != NULL && *_rs1 < *_rs2) *pc = op3.imm; + reg_t *_op1 = op1.reg; + reg_t *_op2 = op2.reg; + if (_op1 != NULL && _op2 != NULL && *_op1 < *_op2) *pc = op3.imm; else *pc += 1; + if (debug) lf_print("op1: %lld, op2: %lld, op1 < op2: %d", *_op1, *_op2, *_op1 < *_op2); #if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_BLT_ends(worker_number, pc_orig); #endif @@ -255,9 +256,9 @@ void execute_inst_BNE(lf_scheduler_t* scheduler, size_t worker_number, operand_t int pc_orig = (int) *pc; tracepoint_static_scheduler_BNE_starts(worker_number, pc_orig); #endif - reg_t *_rs1 = op1.reg; - reg_t *_rs2 = op2.reg; - if (_rs1 != NULL && _rs2 != NULL && *_rs1 != *_rs2) *pc = op3.imm; + reg_t *_op1 = op1.reg; + reg_t *_op2 = op2.reg; + if (_op1 != NULL && _op2 != NULL && *_op1 != *_op2) *pc = op3.imm; else *pc += 1; #if TRACE_ALL_INSTRUCTIONS tracepoint_static_scheduler_BNE_ends(worker_number, pc_orig); From 51e63f6536b8ca6a6922a4300832c088eaa290d1 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 24 Oct 2024 11:18:48 -0700 Subject: [PATCH 75/80] Turn off -Werror for now --- core/lf_utils.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lf_utils.cmake b/core/lf_utils.cmake index 5b6b35921..bb4e81eb7 100644 --- a/core/lf_utils.cmake +++ b/core/lf_utils.cmake @@ -1,6 +1,6 @@ function(lf_enable_compiler_warnings target) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - target_compile_options(${target} PRIVATE -Wall -Wextra -Wpedantic -Werror) + target_compile_options(${target} PRIVATE -Wall -Wextra -Wpedantic) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") target_compile_options(${target} PRIVATE /W4) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") From 1082131e61bc4eeb5e85ae1c7156bad873b29118 Mon Sep 17 00:00:00 2001 From: Shaokai Jerry Lin Date: Thu, 24 Oct 2024 16:47:21 -0700 Subject: [PATCH 76/80] Unify the semantics of ADV and ADVI --- core/threaded/scheduler_static.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 1cc751609..be50ea1b9 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -124,10 +124,9 @@ void execute_inst_ADV(lf_scheduler_t* scheduler, size_t worker_number, operand_t int pc_orig = (int) *pc; tracepoint_static_scheduler_ADV_starts(worker_number, pc_orig); #endif + self_base_t *reactor = (self_base_t*) op1.reg; reg_t *base = op2.reg; reg_t *inc = op3.reg; - self_base_t* reactor = - scheduler->reactor_self_instances[op1.imm]; reactor->tag.time = *base + *inc; reactor->tag.microstep = 0; From 75df70f8e51d01d0a83b8a688f89054ccb654717 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 7 Nov 2024 15:53:38 -0800 Subject: [PATCH 77/80] Use lf_sleep instead of busywait --- core/threaded/scheduler_static.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index be50ea1b9..6795c4f4f 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -282,20 +282,17 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t instant_t current_time = lf_time_physical(); instant_t wakeup_time = *src + op2.imm; LF_PRINT_DEBUG("DU wakeup time: %lld, base: %lld, offset: %lld", wakeup_time, *src, op2.imm); + // Check if we need to sleep. + instant_t current_time; + _lf_clock_gettime(¤t_time); instant_t wait_interval = wakeup_time - current_time; - // LF_PRINT_DEBUG("*** start_time: %lld, wakeup_time: %lld, op1: %lld, op2: %lld, current_physical_time: %lld\n", start_time, wakeup_time, *src, op2.imm, lf_time_physical()); - LF_PRINT_DEBUG("*** [Line %zu] Worker %zu delaying, current_physical_time: %lld, wakeup_time: %lld, wait_interval: %lld", *pc, worker_number, current_time, wakeup_time, wait_interval); + LF_PRINT_DEBUG( + "*** [Line %zu] Worker %zu delaying, current_physical_time: %lld, wakeup_time: %lld, wait_interval: %lld", *pc, + worker_number, current_time, wakeup_time, wait_interval); if (wait_interval > 0) { - // Approach 1: Only spin when the wait interval is less than SPIN_WAIT_THRESHOLD. - if (wait_interval < SPIN_WAIT_THRESHOLD) { - // Spin wait if the wait interval is less than 1 ms. - while (lf_time_physical() < wakeup_time); - } else { - // Otherwise sleep. - _lf_interruptable_sleep_until_locked(scheduler->env, wakeup_time); - } - // Approach 2: Spin wait. - // while (lf_time_physical() < wakeup_time); + // Recalculate the wakeup time for max accuracy. + _lf_clock_gettime(¤t_time); + lf_sleep(wakeup_time - current_time); } LF_PRINT_DEBUG("*** [Line %zu] Worker %zu done delaying", *pc, worker_number); *pc += 1; // Increment pc. From e8f0d5483fa9a92faffc2bc462dd51e81d1760cb Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 7 Nov 2024 16:05:21 -0800 Subject: [PATCH 78/80] Typo --- core/threaded/scheduler_static.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index 6795c4f4f..e8979cd37 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -275,11 +275,7 @@ void execute_inst_DU(lf_scheduler_t* scheduler, size_t worker_number, operand_t int pc_orig = (int) *pc; tracepoint_static_scheduler_DU_starts(worker_number, pc_orig); #endif - // FIXME: There seems to be an overflow problem. - // When wakeup_time overflows but lf_time_physical() doesn't, - // _lf_interruptable_sleep_until_locked() terminates immediately. reg_t *src = op1.reg; - instant_t current_time = lf_time_physical(); instant_t wakeup_time = *src + op2.imm; LF_PRINT_DEBUG("DU wakeup time: %lld, base: %lld, offset: %lld", wakeup_time, *src, op2.imm); // Check if we need to sleep. From c63e8041f32eb9474bf106eac707ce5698b41f73 Mon Sep 17 00:00:00 2001 From: Shaokai Jerry Lin Date: Sun, 10 Nov 2024 16:15:44 -0800 Subject: [PATCH 79/80] Fix a race condition related to out-of-order execution --- core/threaded/scheduler_static.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index e8979cd37..c8a336d84 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -324,6 +324,13 @@ void execute_inst_EXE(lf_scheduler_t* scheduler, size_t worker_number, operand_t #else if (op3.imm != ULLONG_MAX) {tracepoint_static_scheduler_EXE_reaction_ends((void*)op2.reg, worker_number, op3.imm);} #endif + // This full memory barrier is required to ensure that the worker + // counter after this EXE instruction only gets incremented when the + // reaction body or auxiliary function runs to completion, i.e., it + // prevents the compiler or the CPU hardware from making bad + // out-of-order execution decisions. + // See RaceCondition.lf for more details. + __sync_synchronize(); } From 75b9a5070699c7833ebd7c2e0772ea8eb7ea33ed Mon Sep 17 00:00:00 2001 From: Shaokai Jerry Lin Date: Mon, 18 Nov 2024 15:36:25 -0800 Subject: [PATCH 80/80] Remove author tags for anonymity --- core/lf_token.c | 6 +---- core/threaded/scheduler_static.c | 27 ------------------- .../core/threaded/scheduler_instructions.h | 1 - 3 files changed, 1 insertion(+), 33 deletions(-) diff --git a/core/lf_token.c b/core/lf_token.c index 1c7910b96..c71127c01 100644 --- a/core/lf_token.c +++ b/core/lf_token.c @@ -235,11 +235,7 @@ lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length) { result->ref_count = 0; return result; } - -// FIXME (Shaokai): The function name is probably a misnomer. -// It should better be _lf_get_new_token. -// I also don't get why the token isn't simply returned, and -// _lf_free_token_value or _lf_done_using has to be called. + lf_token_t* _lf_get_token(token_template_t* tmplt) { LF_CRITICAL_SECTION_ENTER(GLOBAL_ENVIRONMENT); if (tmplt->token != NULL && tmplt->token->ref_count == 1) { diff --git a/core/threaded/scheduler_static.c b/core/threaded/scheduler_static.c index c8a336d84..5331ca659 100644 --- a/core/threaded/scheduler_static.c +++ b/core/threaded/scheduler_static.c @@ -1,34 +1,7 @@ #if !defined(LF_SINGLE_THREADED) -/************* -Copyright (c) 2022, The University of Texas at Dallas. Copyright (c) 2022, The -University of California at Berkeley. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***************/ /** * A static scheduler for the threaded runtime of the C target of Lingua Franca. - * - * @author{Shaokai Lin } */ #include #include "lf_types.h" diff --git a/include/core/threaded/scheduler_instructions.h b/include/core/threaded/scheduler_instructions.h index ae702a4e3..91b8886e9 100644 --- a/include/core/threaded/scheduler_instructions.h +++ b/include/core/threaded/scheduler_instructions.h @@ -1,5 +1,4 @@ /** - * @author Shaokai Lin * @brief Format of the instruction set */ #ifndef SCHEDULER_INSTRUCTIONS_H