Skip to content

Commit

Permalink
Track the task executed by a thread with the thread-local storage.
Browse files Browse the repository at this point in the history
When the thread's local handle is NULL, this indicates the thread is
not active in any task but is instead in the implicit global task.

- Store a suspended task at a taskwait with new scoped annotations.

- On task-enter, set the active task to the new task.

- On task-leave, clear the active task.

- On task-synchronise, set/clear the active task as appropriate.
  When a task encounters a task scheduling point, assume it is
  suspended and store the handle in a scope surrounding the task
  scheduling point. Immediately clear the thread's active task i.e.
  effectively switch back to the implicit task before (possibly)
  then switching to another task.

- Assert that only the main thread touches the root/phase tasks, but
  doesn't actually track them (to remain consistent with the idea
  that NULL means a thread is in the implicit global task).

- Do not track whether a thread immediately resumes the same task
  after a task scheduling point, since I don't need this at this
  time.
  • Loading branch information
adamtuft committed Apr 29, 2024
1 parent 6fc0566 commit 72ed890
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 99 deletions.
119 changes: 59 additions & 60 deletions include/api/otter-task-graph/otter-task-graph-user.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@
credit: https://stackoverflow.com/a/48045656
*/
#define OTTER_IMPL_THIRD_ARG(a, b, c, ...) c
#define OTTER_IMPL_VA_OPT_AVAIL_I(...) \
OTTER_IMPL_THIRD_ARG(__VA_OPT__(, ), 1, 0, )
#define OTTER_IMPL_VA_OPT_AVAIL_I(...) OTTER_IMPL_THIRD_ARG(__VA_OPT__(, ), 1, 0, )
#define OTTER_IMPL_VA_OPT_AVAIL OTTER_IMPL_VA_OPT_AVAIL_I(?)

/* my addition to make variadic macros agnostic of __VA_OPT__ support */
Expand Down Expand Up @@ -112,10 +111,9 @@
* @param ...: Variadic arguments for use with \p label.
*
*/
#define OTTER_INIT_TASK(task, parent, add_to_pool, label, ...) \
task = otterTaskInitialise(parent, -1, add_to_pool, true, \
OTTER_SOURCE_LOCATION(), \
label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))
#define OTTER_INIT_TASK(task, parent, add_to_pool, label, ...) \
task = otterTaskInitialise(parent, -1, add_to_pool, true, OTTER_SOURCE_LOCATION(), \
label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))

/**
* @brief Declare and initialise a new task handle in the current scope.
Expand All @@ -141,10 +139,9 @@
* @param ...: Variadic arguments for use with \p label.
*
*/
#define OTTER_DEFINE_TASK(task, parent, add_to_pool, label, ...) \
OTTER_DECLARE_HANDLE(task); \
OTTER_INIT_TASK(task, parent, add_to_pool, \
label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))
#define OTTER_DEFINE_TASK(task, parent, add_to_pool, label, ...) \
OTTER_DECLARE_HANDLE(task); \
OTTER_INIT_TASK(task, parent, add_to_pool, label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))

/**
* @brief Add a task handle to the task pool with the given label.
Expand All @@ -157,8 +154,7 @@
* @param ...: Variadic arguments for use with \p label.
*
*/
#define OTTER_POOL_ADD(task, label, ...) \
otterTaskPushLabel(task, label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))
#define OTTER_POOL_ADD(task, label, ...) otterTaskPushLabel(task, label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))

/**
* @brief Remove a task from the task pool with the given label. \p task is
Expand All @@ -172,8 +168,7 @@
* @param ...: Variadic arguments for use with \p label.
*
*/
#define OTTER_POOL_POP(task, label, ...) \
task = otterTaskPopLabel(label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))
#define OTTER_POOL_POP(task, label, ...) task = otterTaskPopLabel(label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))

/**
* @brief Borrow a task from the task pool with the given label. \p task is
Expand All @@ -192,8 +187,7 @@
* @param ...: Variadic arguments for use with \p label.
*
*/
#define OTTER_POOL_BORROW(task, label, ...) \
task = otterTaskBorrowLabel(label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))
#define OTTER_POOL_BORROW(task, label, ...) task = otterTaskBorrowLabel(label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))

/**
* @brief Declare a handle in the current scope, assigning a task removed from
Expand All @@ -208,9 +202,9 @@
* @param ...: Variadic arguments for use with \p label.
*
*/
#define OTTER_POOL_DECL_POP(task, label, ...) \
OTTER_DECLARE_HANDLE(task); \
OTTER_POOL_POP(task, label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))
#define OTTER_POOL_DECL_POP(task, label, ...) \
OTTER_DECLARE_HANDLE(task); \
OTTER_POOL_POP(task, label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))

/**
* @brief Declare a handle in the current scope, assigning a task borrowed from
Expand All @@ -230,9 +224,9 @@
* @param ...: Variadic arguments for use with \p label.
*
*/
#define OTTER_POOL_DECL_BORROW(task, label, ...) \
OTTER_DECLARE_HANDLE(task); \
OTTER_POOL_BORROW(task, label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))
#define OTTER_POOL_DECL_BORROW(task, label, ...) \
OTTER_DECLARE_HANDLE(task); \
OTTER_POOL_BORROW(task, label OTTER_IMPL_PASS_ARGS(__VA_ARGS__))

/**
* @brief Record the start of the code represented by the given task handle.
Expand Down Expand Up @@ -271,8 +265,7 @@
*
* @see #OTTER_TASK_END
*/
#define OTTER_TASK_START(task) \
task = otterTaskStart(task, OTTER_SOURCE_LOCATION())
#define OTTER_TASK_START(task) task = otterTaskStart(task, OTTER_SOURCE_LOCATION())

/**
* @brief Counterpart to `OTTER_TASK_START()`, indicating the end of the code
Expand All @@ -299,9 +292,8 @@
* (`descendants`).
*
*/
#define OTTER_TASK_WAIT_FOR(task, mode) \
otterSynchroniseTasks(task, otter_sync_##mode, otter_endpoint_discrete, \
OTTER_SOURCE_LOCATION())
#define OTTER_TASK_WAIT_FOR(task, mode) \
otterSynchroniseTasks(task, otter_sync_##mode, otter_endpoint_discrete, OTTER_SOURCE_LOCATION())

/**
* @brief Record the start of a region where the task waits for children or
Expand All @@ -325,9 +317,8 @@
* scheduling point at the barrier.
*
*/
#define OTTER_TASK_WAIT_START(task, mode) \
otterSynchroniseTasks(task, otter_sync_##mode, otter_endpoint_enter, \
OTTER_SOURCE_LOCATION())
#define OTTER_TASK_WAIT_START(task, mode) \
otterSynchroniseTasks(task, otter_sync_##mode, otter_endpoint_enter, OTTER_SOURCE_LOCATION())

/**
* @brief Record the end of a region where the task waits for children or
Expand All @@ -336,35 +327,44 @@
* @note Counterpart to #OTTER_TASK_WAIT_START
*
*/
#define OTTER_TASK_WAIT_END(task, mode) \
otterSynchroniseTasks(task, otter_sync_##mode, otter_endpoint_leave, \
OTTER_SOURCE_LOCATION())
#define OTTER_TASK_WAIT_END(task, mode) \
otterSynchroniseTasks(task, otter_sync_##mode, otter_endpoint_leave, OTTER_SOURCE_LOCATION())

/**
* @brief Start a new algorithmic phase.
*
* By default, all trace events fall into the same global phase. However, some
* codes run through particular phases and will want to study these phases
* independently. With the present routine you mark the begin of such a phase.
* Each phase has to be given a unique name.
*
*
* ## Usage
*
* - Must be matched by a corresponding `OTTER_PHASE_END()` or
* `OTTER_PHASE_SWITCH()`.
*
*
* ## Semantics
*
* Creates a meta-region to nest all other regions encountered within it.
*
*
* @param name A unique string identifying this phase.
*
* @see `OTTER_PHASE_END()`
* @see `OTTER_PHASE_SWITCH()`
*
#define OTTER_TASK_WAIT_START_SCOPED(mode) \
{ \
otter_task_sync_t _otter_suspend_mode = otter_sync_##mode; \
otter_task_context *_otter_suspended_task = otterSynchroniseTasks( \
otterGetActiveTask(), _otter_suspend_mode, otter_endpoint_enter, OTTER_SOURCE_LOCATION());

#define OTTER_TASK_WAIT_END_SCOPED() \
otterSynchroniseTasks(_otter_suspended_task, _otter_suspend_mode, otter_endpoint_leave, OTTER_SOURCE_LOCATION()); \
}

/** \
* @brief Start a new algorithmic phase. \
* \
* By default, all trace events fall into the same global phase. However, some \
* codes run through particular phases and will want to study these phases \
* independently. With the present routine you mark the begin of such a phase. \
* Each phase has to be given a unique name. \
* \
* \
* ## Usage \
* \
* - Must be matched by a corresponding `OTTER_PHASE_END()` or \
* `OTTER_PHASE_SWITCH()`. \
* \
* \
* ## Semantics \
* \
* Creates a meta-region to nest all other regions encountered within it. \
* \
* \
* @param name A unique string identifying this phase. \
* \
* @see `OTTER_PHASE_END()` \
* @see `OTTER_PHASE_SWITCH()` \
* \
*/
#define OTTER_PHASE_BEGIN(name) otterPhaseBegin((name), OTTER_SOURCE_LOCATION())

Expand Down Expand Up @@ -397,7 +397,6 @@
* @see `OTTER_PHASE_END()`
*
*/
#define OTTER_PHASE_SWITCH(name) \
otterPhaseSwitch((name), OTTER_SOURCE_LOCATION())
#define OTTER_PHASE_SWITCH(name) otterPhaseSwitch((name), OTTER_SOURCE_LOCATION())

#endif
68 changes: 35 additions & 33 deletions include/api/otter-task-graph/otter-task-graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include <stdbool.h>

#if !defined(OTTER_USE_PRIVATE_HEADER)
#warning \
#warning \
"It is not recommended to include this file directly. Please use otter/otter-task-graph-user.h, or pass -DOTTER_USE_PRIVATE_HEADER to ignore this warning"
#endif

Expand All @@ -32,32 +32,22 @@ typedef struct otter_task_context otter_task_context;
* @see otterSynchroniseTasks
*
*/
typedef enum otter_task_sync_t {
otter_sync_children,
otter_sync_descendants
} otter_task_sync_t;
typedef enum otter_task_sync_t { otter_sync_children, otter_sync_descendants } otter_task_sync_t;

/**
* @brief Indicates the endpoint of an event i.e. whether it represents entry to
* or exit from some region of code, or a discrete event.
*
*/
typedef enum {
otter_endpoint_enter = 0,
otter_endpoint_leave = 1,
otter_endpoint_discrete = 2
} otter_endpoint_t;
typedef enum { otter_endpoint_enter = 0, otter_endpoint_leave = 1, otter_endpoint_discrete = 2 } otter_endpoint_t;

/**
* @brief Used to indicate whether a task should be added to a given task pool.
*
* @see otterTaskInitialise
*
*/
typedef enum otter_add_to_pool_t {
otter_no_add_to_pool = 0,
otter_add_to_pool = 1
} otter_add_to_pool_t;
typedef enum otter_add_to_pool_t { otter_no_add_to_pool = 0, otter_add_to_pool = 1 } otter_add_to_pool_t;

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -150,12 +140,9 @@ void otterTraceStop(void);
* @param format: the format of the label, using subsequent arguments.
*
*/
otter_task_context *otterTaskInitialise(otter_task_context *parent_task,
int flavour,
otter_add_to_pool_t add_to_pool,
bool record_task_create_event,
const char *file, const char *func,
int line, const char *format, ...);
otter_task_context *otterTaskInitialise(otter_task_context *parent_task, int flavour, otter_add_to_pool_t add_to_pool,
bool record_task_create_event, const char *file, const char *func, int line,
const char *format, ...);

/******
* Annotating Task Create, Start & End
Expand All @@ -179,8 +166,8 @@ otter_task_context *otterTaskInitialise(otter_task_context *parent_task,
*
* @see `otterTaskInitialise()`
*/
void otterTaskCreate(otter_task_context *task, otter_task_context *parent_task,
const char *file, const char *func, int line);
void otterTaskCreate(otter_task_context *task, otter_task_context *parent_task, const char *file, const char *func,
int line);

/**
* @brief Record the start of a region which represents previously initialised
Expand Down Expand Up @@ -211,8 +198,7 @@ void otterTaskCreate(otter_task_context *task, otter_task_context *parent_task,
*
* @returns A pointer to a otter_task_context which represents the started task
*/
otter_task_context *otterTaskStart(otter_task_context *task, const char *file,
const char *func, int line);
otter_task_context *otterTaskStart(otter_task_context *task, const char *file, const char *func, int line);

/**
* @brief Counterpart to `otterTaskStart()`, indicating the end of the code
Expand All @@ -225,8 +211,7 @@ otter_task_context *otterTaskStart(otter_task_context *task, const char *file,
*
* @see `otterTaskStart()`
*/
void otterTaskEnd(otter_task_context *task, const char *file, const char *func,
int line);
void otterTaskEnd(otter_task_context *task, const char *file, const char *func, int line);

/******
* Registering & Retrieving Tasks
Expand Down Expand Up @@ -301,10 +286,11 @@ otter_task_context *otterTaskBorrowLabel(const char *format, ...);
* point.
* @param line: The line where the task encountered the synchronisation point.
*
* @returns The handle of the suspended or resumed task, according to `endpoint`.
*
*/
void otterSynchroniseTasks(otter_task_context *task, otter_task_sync_t mode,
otter_endpoint_t endpoint, const char *file,
const char *func, int line);
otter_task_context *otterSynchroniseTasks(otter_task_context *task, otter_task_sync_t mode, otter_endpoint_t endpoint,
const char *file, const char *func, int line);

/******
* Managing Phases
Expand Down Expand Up @@ -339,8 +325,7 @@ void otterSynchroniseTasks(otter_task_context *task, otter_task_sync_t mode,
* @see `otterPhaseSwitch()`
*
*/
void otterPhaseBegin(const char *name, const char *file, const char *func,
int line);
void otterPhaseBegin(const char *name, const char *file, const char *func, int line);

/**
* @brief End the present algorithmic phase.
Expand Down Expand Up @@ -378,8 +363,25 @@ void otterPhaseEnd(const char *file, const char *func, int line);
* @see `otterPhaseEnd()`
*
*/
void otterPhaseSwitch(const char *name, const char *file, const char *func,
int line);
void otterPhaseSwitch(const char *name, const char *file, const char *func, int line);

/******
* Managing The Active Task
******/

/**
* @brief Get the active task for the encountering thread.
*
* @return otter_task_context*
*/
otter_task_context *otterGetActiveTask(void);

/**
* @brief Set the active task for the encountering thread.
*
* @return otter_task_context*
*/
void otterSetActiveTask(otter_task_context *task);

#ifdef __cplusplus
}
Expand Down
Loading

0 comments on commit 72ed890

Please sign in to comment.