Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Static scheduler #241

Draft
wants to merge 111 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
7de874e
Bring in the FS scheduler from the manual example.
lsk567 Jun 26, 2023
48d5bbf
Merge branch 'main' into static-schedule
lsk567 Jun 26, 2023
0a76f87
Implement DU using a hyperperiod-based semantics.
lsk567 Jun 28, 2023
66b22cc
Merge branch 'main' into static-schedule
lsk567 Jun 28, 2023
2015f09
Support reactor-local time
erlingrj Jun 30, 2023
05622fd
Hide chain optimization for the FS scheduler
erlingrj Jun 30, 2023
4616369
Add the infrastructure for resetting is_present of ports on a per-rea…
erlingrj Jul 3, 2023
f3e3ba0
Merge branch 'main' into static-schedule
lsk567 Jul 6, 2023
5d79291
Merge branch 'static-schedule' into fs-erling
lsk567 Jul 10, 2023
bf504df
Merge pull request #247 from lf-lang/fs-erling
lsk567 Jul 10, 2023
bfe021d
Comment out lf_request_stop() macro
lsk567 Jul 10, 2023
3e4bd00
Change ADV to advance to absolute time wrt hyperperiod; change sync-a…
lsk567 Jul 10, 2023
995a014
Merge branch 'main' into static-schedule
lsk567 Jul 17, 2023
edcae4f
Support lf_schedule
lsk567 Jul 18, 2023
a6e08b3
Support lf_schedule with payloads, given limitations
lsk567 Jul 18, 2023
42cad35
Rename FS to STATIC
lsk567 Jul 18, 2023
e497088
Enable tracing for VM instructions
lsk567 Jul 20, 2023
6aab8ed
Remove tracing hacks
lsk567 Jul 20, 2023
d2f5c9a
Support better tracing experience by storing line numbers
lsk567 Jul 21, 2023
176b74a
Support ADDI and refactor
lsk567 Jul 21, 2023
f2cc481
Update ADV and ADV2
lsk567 Jul 21, 2023
321e17c
Update comments
lsk567 Jul 24, 2023
aafa8c7
Merge pull request #254 from lf-lang/var-refs-in-schedules
lsk567 Jul 24, 2023
402d1da
Remove variables hyperperiod and iteration
lsk567 Jul 24, 2023
fbdb4ac
Merge branch 'main' into static-schedule
lsk567 Jul 24, 2023
e606e51
Fix BIT
lsk567 Jul 24, 2023
f669991
Fix tracing
lsk567 Jul 24, 2023
26bb4af
Fix a bug when initializing time offsets
lsk567 Jul 25, 2023
26439fc
Merge branch 'main' into static-schedule
lsk567 Jul 28, 2023
e7eac8a
Merge branch 'main' into static-schedule
lsk567 Aug 6, 2023
2387ae6
Fix race condition by removing the reactor_reached_stop_tag array sin…
lsk567 Aug 6, 2023
0ffbcc4
Add branch instructions and no longer initialize offsets when initial…
lsk567 Aug 10, 2023
fc5fb2b
Remove debug message
lsk567 Aug 14, 2023
185a0ae
Merge branch 'main' into static-schedule
lsk567 Aug 15, 2023
2d3c89c
Add ADD, ADVI, JAL, JALR, and WLT instructions to deprecate SAC.
lsk567 Aug 22, 2023
ccedcab
Merge branch 'main' into static-schedule
lsk567 Aug 22, 2023
890c54e
Update PRET VM instructions to be more portable
erlingrj Sep 23, 2023
7bea24f
Merge branch 'main' into static-schedule
lsk567 Sep 25, 2023
740d5cc
Merge remote-tracking branch 'origin/static-schedule' into static-upd…
erlingrj Sep 25, 2023
ac59cfa
Merge pull request #277 from lf-lang/static-update-instr
erlingrj Sep 25, 2023
838ad16
Merge branch 'main' into static-schedule
lsk567 Oct 5, 2023
031412e
Remove unnecessary debug msg
lsk567 Oct 5, 2023
e9edc18
Add a schedule init function to deal with the compile-time constant i…
lsk567 Oct 12, 2023
d3d39e9
Extend environment for static scheduling
lsk567 Oct 16, 2023
bb5ae6d
Get a simple example to work
lsk567 Oct 16, 2023
4d32a5c
More tracepoints of the PretVM instructions
ChadliaJerad Oct 26, 2023
90e8c8b
Uncomment static scheduler trace points
ChadliaJerad Nov 12, 2023
e49225a
Merge branch 'main' into static-schedule
lsk567 Nov 15, 2023
d4a1127
Change STATIC to SCHED_STATIC
lsk567 Nov 15, 2023
ce03252
Update include guard
lsk567 Nov 20, 2023
8971b1f
Merge branch 'static-schedule' into static-schedule-explicit-triggers
lsk567 Dec 7, 2023
3e498c8
Add WIP
lsk567 Dec 14, 2023
ce9d422
Add header file for helper functions used in the static schedule
lsk567 Jan 6, 2024
0f30f05
Add WIP. SimpleConnection kind of works.
lsk567 Jan 20, 2024
2512f0c
Make SimpleConnection test case work
lsk567 Jan 25, 2024
4118922
Merge branch 'main' into static-schedule
lsk567 Feb 11, 2024
31428ab
Prune unused code in the static scheduler
lsk567 Feb 12, 2024
2fe28a6
Fix seg fault in BEQ
lsk567 Feb 25, 2024
7fd9ba0
Merge branch 'main' into static-schedule
lsk567 Feb 25, 2024
ebbdb7c
Get logical tag of EXE_starts and EXE_ends
erlingrj Feb 26, 2024
ccf50e5
Add a version of EXE tracing function specific for reactions, clean u…
lsk567 Feb 29, 2024
cac23fb
Merge pull request #367 from lf-lang/static-tracing
lsk567 Feb 29, 2024
a47356b
Update tracing and add debug flag to instructions
lsk567 Mar 6, 2024
261cb8b
Improve static tracing
lsk567 Mar 6, 2024
55bb599
Use spin wait and fix tracing
lsk567 Mar 7, 2024
57fffe1
Add WIP for chrome tracing
lsk567 Mar 9, 2024
3dbb4a1
Add WIP
lsk567 Mar 10, 2024
2d27f14
Only trace EXE now
lsk567 Mar 13, 2024
3635412
Fix unrecognized instruction error
lsk567 Mar 14, 2024
40b45dd
Implement a more flexible DU that decides between spinning and sleep …
lsk567 Mar 14, 2024
4c57e17
Increase spin wait threshold to 100 msec
lsk567 Mar 19, 2024
e27fcd9
Use spin wait for NP for fairness
lsk567 Mar 19, 2024
f783227
Merge branch 'static-schedule' into static-schedule-circular-buffer
lsk567 Mar 22, 2024
e89f09a
Use circular buffers
lsk567 Mar 22, 2024
ca533a9
Increase trace buffer and optimize circular buffer
lsk567 Mar 22, 2024
ec0f645
Increase trace buffer capacity to 64k
lsk567 Mar 22, 2024
d4af904
Drop the buffer capacity back to 32k
lsk567 Mar 22, 2024
732b13a
Drop to 16KB to try to get chrome to work
lsk567 Mar 22, 2024
4ad2cdf
Back to 32k
lsk567 Mar 22, 2024
05fcd4c
Use function pointers to execute virtual instructions. Stop tracing a…
lsk567 Mar 23, 2024
0969328
Remove tracepoints except reaction starts and stops
lsk567 Mar 23, 2024
884386e
ADVI stops clearing is_present fields
lsk567 Mar 24, 2024
bd0b5a2
Use pure spin wait in DU for evaluation
lsk567 Mar 24, 2024
c7b7285
Add useful debugging messages
lsk567 Mar 29, 2024
0e1e61b
Bump trace buffer to 128KB
lsk567 Mar 29, 2024
3a37b15
Stop setting the token field in lf_set
lsk567 Apr 7, 2024
2e0f2ff
Add debug messages back
lsk567 Apr 22, 2024
b230663
Revert "Stop setting the token field in lf_set"
lsk567 Jun 1, 2024
cd5a633
Merge branch 'static-schedule' into static-schedule-opt
lsk567 Jun 2, 2024
44313a2
Fix the incompatible conversion warning/error
lsk567 Jul 3, 2024
5f1c224
Merge branch 'static-schedule' into static-schedule-opt
lsk567 Aug 4, 2024
11dc8de
Fix JAL and update ADVI debug output
lsk567 Aug 14, 2024
7ab1111
Fix port setting for ADVI
lsk567 Aug 31, 2024
6188090
Combine spin wait and thread sleep, and adjust spin wait threshold
Sep 1, 2024
4c8f3fd
Merge branch 'main' into static-schedule
lsk567 Sep 24, 2024
d76e82e
Merge branch 'main' into static-schedule-merge
lsk567 Oct 7, 2024
08e2506
Get tracing to work and various fixes
lsk567 Oct 8, 2024
5874882
Fix tracing
lsk567 Oct 8, 2024
700835b
Remove an unused header
lsk567 Oct 9, 2024
998f555
Fix operand naming and add a debug message to BLT
lsk567 Oct 17, 2024
e8975a9
Merge branch 'main' into static-schedule
lsk567 Oct 21, 2024
51e63f6
Turn off -Werror for now
erlingrj Oct 24, 2024
1082131
Unify the semantics of ADV and ADVI
lsk567 Oct 24, 2024
1837c6c
Merge branch 'static-schedule' of https://github.com/lf-lang/reactor-…
erlingrj Oct 25, 2024
75df70f
Use lf_sleep instead of busywait
erlingrj Nov 7, 2024
9b4b818
Merge branch 'static-schedule' into static-use-lf-sleep
erlingrj Nov 7, 2024
e8f0d54
Typo
erlingrj Nov 8, 2024
6538c34
Merge pull request #495 from lf-lang/static-use-lf-sleep
lsk567 Nov 8, 2024
c63e804
Fix a race condition related to out-of-order execution
lsk567 Nov 11, 2024
75b9a50
Remove author tags for anonymity
lsk567 Nov 18, 2024
1a97ab5
Merge branch 'main' into static-schedule
lsk567 Dec 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/lf_token.c
Original file line number Diff line number Diff line change
@@ -235,7 +235,7 @@ lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length) {
result->ref_count = 0;
return result;
}

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) {
2 changes: 1 addition & 1 deletion core/lf_utils.cmake
Original file line number Diff line number Diff line change
@@ -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")
1 change: 1 addition & 0 deletions core/threaded/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ set(
THREADED_SOURCES
reactor_threaded.c
scheduler_adaptive.c
scheduler_static.c
scheduler_GEDF_NP.c
scheduler_NP.c
scheduler_sync_tag_advance.c
548 changes: 548 additions & 0 deletions core/threaded/scheduler_static.c

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion core/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
set(UTIL_SOURCES vector.c pqueue_base.c pqueue_tag.c pqueue.c util.c)
set(UTIL_SOURCES vector.c pqueue_base.c pqueue_tag.c pqueue.c util.c circular_buffer.c)

if(NOT DEFINED LF_SINGLE_THREADED)
list(APPEND UTIL_SOURCES lf_semaphore.c)
93 changes: 93 additions & 0 deletions core/utils/circular_buffer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* @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"
#include "lf_types.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;
}
Comment on lines +14 to +28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improve error handling in cb_init.

If memory allocation fails, the function should free any partially allocated resources and return an error code.

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 = NULL;
+        cb->capacity = 0;
+        cb->count = 0;
+        cb->sz = 0;
+        cb->head = NULL;
+        cb->tail = NULL;
+        return -1;
    }
    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;
+    return 0;
}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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_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.");
cb->buffer_end = NULL;
cb->capacity = 0;
cb->count = 0;
cb->sz = 0;
cb->head = NULL;
cb->tail = NULL;
return -1;
}
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;
return 0;
}


void cb_free(circular_buffer *cb)
{
free(cb->buffer);
// clear out other fields too, just to be safe
}
Comment on lines +30 to +34
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reset circular buffer attributes in cb_free.

To prevent potential use-after-free errors, reset other attributes of the circular buffer after freeing the memory.

void cb_free(circular_buffer *cb)
{
    free(cb->buffer);
    // clear out other fields too, just to be safe
+    cb->buffer = NULL;
+    cb->buffer_end = NULL;
+    cb->capacity = 0;
+    cb->count = 0;
+    cb->sz = 0;
+    cb->head = NULL;
+    cb->tail = NULL;
}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void cb_free(circular_buffer *cb)
{
free(cb->buffer);
// clear out other fields too, just to be safe
}
void cb_free(circular_buffer *cb)
{
free(cb->buffer);
// clear out other fields too, just to be safe
cb->buffer = NULL;
cb->buffer_end = NULL;
cb->capacity = 0;
cb->count = 0;
cb->sz = 0;
cb->head = NULL;
cb->tail = NULL;
}


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--;
}

void cb_remove_front(circular_buffer *cb)
{
if(cb->count == 0){
// handle error
lf_print("ERROR: Removing from an empty buffer!");
return;
}
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)
{
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->base.tag.time, e->token);
p += cb->sz;
if (p == cb->buffer_end) p = cb->buffer;
}
lf_print("**********************");
}
33 changes: 33 additions & 0 deletions include/api/reaction_macros.h
Original file line number Diff line number Diff line change
@@ -69,6 +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 { \
out->value = val; \
lf_set_present(out); \
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) \
do { \
out->value = val; \
@@ -80,6 +88,7 @@
out->token = token; \
} \
} while (0)
#endif

/**
* @brief Set the specified output (or input of a contained reactor)
@@ -183,6 +192,29 @@
// 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 (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

/**
* Return the current tag of the environment invoking this reaction.
*/
#define lf_tag() self->base.tag

/**
* Return the current logical time in nanoseconds of the environment invoking this reaction.
*/
#define lf_time_logical() self->base.tag.time

/**
* Return the current logical time of the environment invoking this reaction relative to the
* start time in nanoseconds.
*/
#define lf_time_logical_elapsed() (self->base.tag.time - lf_time_start())

#else

/**
* Return the current tag of the environment invoking this reaction.
*/
@@ -199,4 +231,5 @@
*/
#define lf_time_logical_elapsed() lf_time_logical_elapsed(self->base.environment)

#endif // REACTOR_LOCAL_TIME
#endif // REACTION_MACROS_H
16 changes: 12 additions & 4 deletions include/core/environment.h
Original file line number Diff line number Diff line change
@@ -85,10 +85,18 @@ typedef struct environment_t {
lf_cond_t global_tag_barrier_requestors_reached_zero;
#endif // LF_SINGLE_THREADED
#if defined(FEDERATED)
tag_t** _lf_intended_tag_fields;
int _lf_intended_tag_fields_size;
bool need_to_send_LTC;
#endif // FEDERATED
tag_t** _lf_intended_tag_fields;
int _lf_intended_tag_fields_size;
bool need_to_send_LTC;
#endif // FEDERATED
#if SCHEDULER == SCHED_STATIC
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;
#endif
15 changes: 15 additions & 0 deletions include/core/lf_types.h
Original file line number Diff line number Diff line change
@@ -47,6 +47,14 @@ typedef unsigned short int ushort;
#define SCHED_ADAPTIVE 1
#define SCHED_GEDF_NP 2
#define SCHED_NP 3
#define SCHED_STATIC 4

// If we use the fully static scheduler, then we want local time at each reactor
#if SCHEDULER == SCHED_STATIC
#ifndef REACTOR_LOCAL_TIME
#define REACTOR_LOCAL_TIME
#endif
#endif

/*
* A struct representing a barrier in threaded
@@ -284,6 +292,13 @@ 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 (SCHED_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.
// Used to reset the is_present fields
int num_output_ports;
#endif
} self_base_t;

/**
2 changes: 2 additions & 0 deletions include/core/reactor.h
Original file line number Diff line number Diff line change
@@ -18,13 +18,15 @@
#ifndef REACTOR_H
#define REACTOR_H

#include <string.h> // memcpy
#include "lf_types.h"
#include "modes.h" // Modal model support
#include "port.h"
#include "tag.h" // Time-related functions.
#include "clock.h" // Time-related functions.
#include "tracepoint.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.
6 changes: 6 additions & 0 deletions include/core/reactor_common.h
Original file line number Diff line number Diff line change
@@ -31,6 +31,12 @@

////////////////////// Constants & Macros //////////////////////

// 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

/**
* @brief Constant giving the minimum amount of time to sleep to wait
* for physical time to reach a logical time.
74 changes: 67 additions & 7 deletions include/core/threaded/scheduler_instance.h
Original file line number Diff line number Diff line change
@@ -19,6 +19,14 @@
#include <stdbool.h>
#include <stddef.h> // for size_t

#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

#define DEFAULT_MAX_REACTION_LEVEL 100

// Forward declarations
@@ -31,13 +39,18 @@ typedef struct custom_scheduler_data_t custom_scheduler_data_t;
* @note Members of this struct are added based on existing schedulers' needs.
* These should be expanded to accommodate new schedulers.
*/
typedef struct lf_scheduler_t {
struct environment_t* env;
/**
* @brief Maximum number of levels for reactions in the program.
*
*/
size_t max_reaction_level;
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.
*
*/
size_t max_reaction_level;

/**
* @brief Indicate whether the program should stop
@@ -68,6 +81,45 @@ typedef struct lf_scheduler_t {
*/
volatile size_t number_of_idle_workers;

#if SCHEDULER == SCHED_STATIC

/**
* @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 pointers to reaction instances.
*
*/
reaction_t** reaction_instances;

/**
* @brief Points to an array of integer counters.
*
*/
volatile uint32_t* counters;

#endif
// Pointer to an optional custom data structure that each scheduler can define.
// 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
@@ -110,4 +162,12 @@ typedef struct {
bool init_sched_instance(struct environment_t* env, lf_scheduler_t** instance, size_t number_of_workers,
sched_params_t* params);

#if SCHEDULER == SCHED_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
76 changes: 76 additions & 0 deletions include/core/threaded/scheduler_instructions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* @brief Format of the instruction set
*/
#ifndef SCHEDULER_INSTRUCTIONS_H
#define SCHEDULER_INSTRUCTIONS_H

typedef enum {
ADD,
ADDI,
ADV,
ADVI,
BEQ,
BGE,
BLT,
BNE,
DU,
EXE,
JAL,
JALR,
STP,
WLT,
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;
Comment on lines +33 to +34
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper type safety and usage.

Ensure that the typedefs for reg_t and imm_t are used correctly and safely.

+typedef volatile uint64_t reg_t;
+typedef uint64_t imm_t;
+// Ensure proper type safety
+static_assert(sizeof(reg_t) == sizeof(imm_t), "reg_t and imm_t must be the same size");
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
typedef volatile uint64_t reg_t;
typedef uint64_t imm_t;
typedef volatile uint64_t reg_t;
typedef uint64_t imm_t;
// Ensure proper type safety
static_assert(sizeof(reg_t) == sizeof(imm_t), "reg_t and imm_t must be the same size");


/**
* @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 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
* can be either a pointer or an immediate
*
*/
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;

#endif
48 changes: 48 additions & 0 deletions include/core/threaded/scheduler_static_functions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#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
* 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);

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
123 changes: 123 additions & 0 deletions include/core/tracepoint.h
Original file line number Diff line number Diff line change
@@ -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 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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_ADD_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_ADDI_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_ADV_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_ADVI_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_BEQ_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_BGE_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_BLT_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_BNE_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_DU_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_EXE_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_JAL_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_JALR_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_STP_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_WLT_ends(worker, pc) \
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_TAG, worker, worker, pc, NULL, NULL, 0)

#define tracepoint_static_scheduler_WU_ends(worker, pc) \
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 = ((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 = ((self_base_t *)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
26 changes: 26 additions & 0 deletions include/core/utils/circular_buffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef CIRCULAR_BUFFER_H
#define CIRCULAR_BUFFER_H

#include <stdlib.h>
#include <string.h>

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
Comment on lines +9 to +15
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper memory alignment and handling.

Ensure that the buffer memory is properly aligned and handled to avoid potential issues.

+    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
+    // Ensure proper memory alignment
+    alignas(alignof(max_align_t)) char data[];
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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
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
// Ensure proper memory alignment
alignas(alignof(max_align_t)) char data[];

} 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);
void cb_remove_front(circular_buffer *cb);
void* cb_peek(circular_buffer *cb);
void cb_dump_events(circular_buffer *cb);

#endif
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_library(test-lib SCHED_STATIC src_gen_stub.c rand_utils.c)
181 changes: 122 additions & 59 deletions trace/api/types/trace_types.h
Original file line number Diff line number Diff line change
@@ -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",
210 changes: 208 additions & 2 deletions util/tracing/trace_to_chrome.c
Original file line number Diff line number Diff line change
@@ -52,6 +52,16 @@ FILE* trace_file = NULL;
/** File for writing the output data. */
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
* that the execution time of events are not abstracted to 0.
*/
int scaling_factor = 1000;
// int scaling_factor = 1; // For seeing sub-us events.

/**
* Print a usage message.
*/
@@ -69,6 +79,79 @@ int max_reaction_number = 0;
/** Indicator to plot vs. physical time only. */
bool physical_time_only = false;

/**
* 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:
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.
@@ -96,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";
}
@@ -195,6 +281,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]);
@@ -443,4 +649,4 @@ int main(int argc, char* argv[]) {
write_metadata_events(output_file);
fprintf(output_file, "]}\n");
}
}
}