Skip to content

Commit

Permalink
Add pre_block/post_block/wake_other
Browse files Browse the repository at this point in the history
Fixes #44
  • Loading branch information
vlovich committed Oct 21, 2022
1 parent e81e746 commit dbda214
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 18 deletions.
128 changes: 111 additions & 17 deletions include/coz.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,29 +37,55 @@ 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
// 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;
}

if(!_initialized) {
if(dlsym) {
// Locate the _coz_get_counter method
void* p = dlsym(RTLD_DEFAULT, "_coz_get_counter");
if (fn) return fn(type, name);
else return 0;
}

// Use memcpy to avoid pedantic GCC complaint about storing function pointer in void*
memcpy(&fn, &p, sizeof(p));
}
static void _call_coz_pre_block() {
static unsigned char initialized = dlsym == 0;
static void (*fn)();

_initialized = 1;
if (!initialized) {
void* p = dlsym(RTLD_DEFAULT, "_coz_pre_block");
memcpy(&fn, &p, sizeof(p));
initialized = true;
}
if (fn) return fn();
}

// Call the function, or return null if profiler is not found
if(fn) return fn(type, name);
else return 0;
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
Expand All @@ -80,12 +106,80 @@ static coz_counter_t* _call_coz_get_counter(int type, const char* name) {
#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
Expand Down
12 changes: 12 additions & 0 deletions libcoz/libcoz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ extern "C" coz_counter_t* _coz_get_counter(progress_point_type t, const char* na
}
}

extern "C" void _coz_pre_block() {
profiler::get_instance().pre_block();
}

extern "C" void _coz_post_block(bool skip_delays) {
profiler::get_instance().post_block(skip_delays);
}

extern "C" void _coz_wake_other() {
profiler::get_instance().catch_up();
}

/**
* Read a link's contents and return it as a string
*/
Expand Down
3 changes: 2 additions & 1 deletion libcoz/profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ class profiler {
state->pre_block_time = _global_delay.load();
}

/// Call after unblocking. If by_thread is true, delays will be skipped
/// Call after unblocking. If skip_delays is true, all delays inserted
/// during the blocked period will be skipped.
void post_block(bool skip_delays) {
thread_state* state = get_thread_state();
if(!state)
Expand Down

0 comments on commit dbda214

Please sign in to comment.