-
-
Notifications
You must be signed in to change notification settings - Fork 170
API to annotate block points #195
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -8,6 +8,18 @@ | |||||
| #if !defined(COZ_H) | ||||||
| #define COZ_H | ||||||
|
|
||||||
| /// Embedders can define COZ_ENABLED explicitly to 1 or 0 to globally to | ||||||
| /// enable/disable coz tracepoints at build time without needing to modify code. | ||||||
| /// If set to 0 before including this header for the first time, all macros | ||||||
| /// become noops. This is useful to commit coz tracepoints into a codebase but | ||||||
| /// not require linking against the coz runtime and not having any code bloat | ||||||
| /// nor runtime overhead from using the macros. | ||||||
| #ifndef COZ_ENABLED | ||||||
| #define COZ_ENABLED 1 | ||||||
| #endif | ||||||
|
|
||||||
| #if COZ_ENABLED | ||||||
|
|
||||||
| #ifndef __USE_GNU | ||||||
| # define __USE_GNU | ||||||
| #endif | ||||||
|
|
@@ -37,31 +49,57 @@ typedef struct { | |||||
| size_t backoff; // Used to batch updates to the shared counter. Currently unused. | ||||||
| } coz_counter_t; | ||||||
|
|
||||||
| // The type of the _coz_get_counter function | ||||||
| typedef coz_counter_t* (*coz_get_counter_t)(int, const char*); | ||||||
|
|
||||||
| // Locate and invoke _coz_get_counter | ||||||
| static coz_counter_t* _call_coz_get_counter(int type, const char* name) { | ||||||
| static unsigned char _initialized = 0; | ||||||
| static coz_get_counter_t fn; // The pointer to _coz_get_counter | ||||||
|
|
||||||
| if(!_initialized) { | ||||||
| if(dlsym) { | ||||||
| // Locate the _coz_get_counter method | ||||||
| void* p = dlsym(RTLD_DEFAULT, "_coz_get_counter"); | ||||||
|
|
||||||
| // Use memcpy to avoid pedantic GCC complaint about storing function pointer in void* | ||||||
| memcpy(&fn, &p, sizeof(p)); | ||||||
| } | ||||||
|
|
||||||
| _initialized = 1; | ||||||
| // Use memcpy to avoid pedantic GCC complaint about storing function pointer in void* | ||||||
| static unsigned char initialized = dlsym == NULL; | ||||||
| static coz_counter_t* (*fn)(int, const char*); | ||||||
|
|
||||||
| if (!initialized) { | ||||||
| void* p = dlsym(RTLD_DEFAULT, "_coz_get_counter"); | ||||||
| memcpy(&fn, &p, sizeof(p)); | ||||||
| initialized = true; | ||||||
| } | ||||||
|
|
||||||
| // Call the function, or return null if profiler is not found | ||||||
| if(fn) return fn(type, name); | ||||||
|
|
||||||
| if (fn) return fn(type, name); | ||||||
| else return 0; | ||||||
| } | ||||||
|
|
||||||
| static void _call_coz_pre_block() { | ||||||
| static unsigned char initialized = dlsym == 0; | ||||||
|
||||||
| static void (*fn)(); | ||||||
|
|
||||||
| if (!initialized) { | ||||||
| void* p = dlsym(RTLD_DEFAULT, "_coz_pre_block"); | ||||||
| memcpy(&fn, &p, sizeof(p)); | ||||||
| initialized = true; | ||||||
| } | ||||||
| if (fn) return fn(); | ||||||
|
||||||
| } | ||||||
|
|
||||||
| static void _call_coz_post_block(bool skip_delays) { | ||||||
| static unsigned char initialized = dlsym == 0; | ||||||
|
||||||
| static void (*fn)(bool); | ||||||
|
|
||||||
| if (!initialized) { | ||||||
| void* p = dlsym(RTLD_DEFAULT, "_coz_post_block"); | ||||||
| memcpy(&fn, &p, sizeof(p)); | ||||||
| initialized = true; | ||||||
| } | ||||||
| if (fn) return fn(skip_delays); | ||||||
|
||||||
| } | ||||||
|
|
||||||
| static void _call_coz_wake_other() { | ||||||
| static unsigned char initialized = dlsym == 0; | ||||||
|
||||||
| static void (*fn)(); | ||||||
|
|
||||||
| if (!initialized) { | ||||||
| void* p = dlsym(RTLD_DEFAULT, "_coz_wake_other"); | ||||||
| memcpy(&fn, &p, sizeof(p)); | ||||||
| initialized = true; | ||||||
| } | ||||||
| if (fn) return fn(); | ||||||
|
||||||
| } | ||||||
|
|
||||||
| // Macro to initialize and increment a counter | ||||||
| #define COZ_INCREMENT_COUNTER(type, name) \ | ||||||
| if(1) { \ | ||||||
|
|
@@ -77,17 +115,98 @@ static coz_counter_t* _call_coz_get_counter(int type, const char* name) { | |||||
| } \ | ||||||
| } | ||||||
|
|
||||||
| #define STR2(x) #x | ||||||
| #define STR2(x) #x | ||||||
| #define STR(x) STR2(x) | ||||||
|
|
||||||
| /// Indicate progress for the counter with the given name. | ||||||
| /// | ||||||
| /// Example: | ||||||
| /// ``` | ||||||
| /// while (more_events()) { | ||||||
| /// COZ_PROGRESS_NAMED("event_processed"); | ||||||
| /// process_event(); | ||||||
| /// } | ||||||
| /// ``` | ||||||
| #define COZ_PROGRESS_NAMED(name) COZ_INCREMENT_COUNTER(COZ_COUNTER_TYPE_THROUGHPUT, name) | ||||||
|
|
||||||
| /// Indicate progress for the counter named implicitly after the file and line | ||||||
| /// number it is placed on. | ||||||
| /// | ||||||
| /// Example: | ||||||
| /// ``` | ||||||
| /// while (more_events()) { | ||||||
| /// COZ_PROGRESS; | ||||||
| /// process_event(); | ||||||
| /// } | ||||||
| /// ``` | ||||||
| #define COZ_PROGRESS COZ_INCREMENT_COUNTER(COZ_COUNTER_TYPE_THROUGHPUT, __FILE__ ":" STR(__LINE__)) | ||||||
| #define COZ_BEGIN(name) COZ_INCREMENT_COUNTER(COZ_COUNTER_TYPE_BEGIN, name) | ||||||
| #define COZ_END(name) COZ_INCREMENT_COUNTER(COZ_COUNTER_TYPE_END, name) | ||||||
|
|
||||||
| /// Call before (possibly) blocking (e.g. if you're about to maybe block on a | ||||||
| /// futex). | ||||||
| /// | ||||||
| /// Example: | ||||||
| /// ``` | ||||||
| /// lock() { | ||||||
| /// int expected = 0; | ||||||
| /// if (!std::atomic_compare_exchange_weak(&futex, &expected, 1)) { | ||||||
| /// COZ_PRE_BLOCK(); | ||||||
| /// syscall(SYS_futex, &futex, FUTEX_WAIT, ...); | ||||||
| /// COZ_POST_BLOCK(); | ||||||
| /// } | ||||||
| /// } | ||||||
| /// ``` | ||||||
| #define COZ_PRE_BLOCK() _call_coz_pre_block() | ||||||
|
|
||||||
| /// Call after unblocking. If skip_delays is true, all delays inserted during | ||||||
| /// the blocked period will be skipped. | ||||||
| /// | ||||||
| /// Example: | ||||||
| /// ``` | ||||||
| /// lock() { | ||||||
| /// int expected = 0; | ||||||
| /// if (!std::atomic_compare_exchange_weak(&futex, &expected, 1)) { | ||||||
| /// COZ_PRE_BLOCK(); | ||||||
| /// syscall(SYS_futex, &futex, FUTEX_WAIT, ...); | ||||||
| /// COZ_POST_BLOCK(); | ||||||
| /// } | ||||||
| /// } | ||||||
| /// ``` | ||||||
| #define COZ_POST_BLOCK(skip_delays) _call_coz_post_block(skip_delays) | ||||||
|
|
||||||
| /// Ensure a thread has executed all the required delays before possibly | ||||||
| /// unblocking another thread. | ||||||
| /// | ||||||
| /// Example: | ||||||
| /// ``` | ||||||
| /// // Unlocking the futex. | ||||||
| /// unlock() { | ||||||
| /// let have_waiters = ...; | ||||||
| /// std::atomic_store(&futex, 0); | ||||||
| /// if (have_waiters) { | ||||||
| /// COZ_WAKE_OTHER(); | ||||||
| /// syscall(SYS_FUTEX, &futex, FUTEX_WAKE, ...); | ||||||
| /// } | ||||||
| /// } | ||||||
| /// ``` | ||||||
| #define COZ_WAKE_OTHER() _call_coz_wake_other() | ||||||
|
|
||||||
| #if defined(__cplusplus) | ||||||
| } | ||||||
| #endif | ||||||
|
|
||||||
| #else | ||||||
|
|
||||||
| #define _COZ_NOOP() do {} while(0) | ||||||
| #define COZ_PROGRESS_NAMED(name) _COZ_NOOP() | ||||||
| #define COZ_PROGRESS() _COZ_NOOP() | ||||||
|
||||||
| #define COZ_PROGRESS() _COZ_NOOP() | |
| #define COZ_PROGRESS _COZ_NOOP() |
Copilot
AI
Jan 4, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parameter name inconsistency: The macro is defined with parameter name 'skip_delay' (singular), but everywhere else in the codebase it's called 'skip_delays' (plural). This should be 'skip_delays' to maintain consistency with the function signatures in libcoz.cpp and the documentation.
| #define COZ_POST_BLOCK(skip_delay) _COZ_NOOP() | |
| #define COZ_POST_BLOCK(skip_delays) _COZ_NOOP() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The initialization logic is inverted. When dlsym is NULL, initialized is set to true, which means the function will never attempt to look up the symbol. This should be 'initialized = false' or 'initialized = 0' to properly initialize and allow symbol lookup when dlsym is available.