diff --git a/src/config.c b/src/config.c index c51b9c3..0478ca7 100644 --- a/src/config.c +++ b/src/config.c @@ -29,7 +29,7 @@ void pact_init_config(pact_config_t *config) config->pebs_period = PACT_PEBS_SAMPLE_PERIOD; config->bin_width = PACT_INITIAL_BIN_WIDTH; config->bin_count = PACT_INITIAL_BIN_COUNT; - config->cooling_alpha = 1.0; /* 1.0 = no cooling (default) */ + config->cooling_alpha = 1.0; /* 1.0 = no cooling (default) */ config->cooling_trigger_samples = 200000; /* target_pid is required; -1 here means "not yet supplied" — CLI diff --git a/src/logging.h b/src/logging.h index b1c16b0..8d5b855 100644 --- a/src/logging.h +++ b/src/logging.h @@ -86,132 +86,87 @@ void log_pebs_aggregator(pact_context_t *pact, const char *function, int workloa * PACT_UNUSED so the empty bodies need no per-parameter (void) casts, while * the signatures still type-check every call and keep arguments "used" (so * variables passed only to log_*() do not draw unused-variable warnings). */ -static inline void init_logging(pact_context_t *pact PACT_UNUSED, - const char *filename PACT_UNUSED, +static inline void init_logging(pact_context_t *pact PACT_UNUSED, const char *filename PACT_UNUSED, const char *format PACT_UNUSED) -{ -} +{} -static inline void cleanup_logging(pact_context_t *pact PACT_UNUSED) -{ -} +static inline void cleanup_logging(pact_context_t *pact PACT_UNUSED) {} -static inline void log_event(pact_context_t *pact PACT_UNUSED, - const char *event_type PACT_UNUSED, - const char *function PACT_UNUSED, - const char *format PACT_UNUSED, ...) -{ -} +static inline void log_event(pact_context_t *pact PACT_UNUSED, const char *event_type PACT_UNUSED, + const char *function PACT_UNUSED, const char *format PACT_UNUSED, ...) +{} static inline void log_pebs_sample(pact_context_t *pact PACT_UNUSED, - const char *function PACT_UNUSED, - int workload_id PACT_UNUSED, - uint64_t addr PACT_UNUSED, - uint8_t tier PACT_UNUSED, + const char *function PACT_UNUSED, int workload_id PACT_UNUSED, + uint64_t addr PACT_UNUSED, uint8_t tier PACT_UNUSED, uint32_t attributed_stalls PACT_UNUSED) -{ -} +{} static inline void log_coro_event(pact_context_t *pact PACT_UNUSED, const char *function PACT_UNUSED, - const char *coro_name PACT_UNUSED, - const char *event PACT_UNUSED, + const char *coro_name PACT_UNUSED, const char *event PACT_UNUSED, uint64_t elapsed_cycles PACT_UNUSED) -{ -} +{} -static inline void log_pac_calculation(pact_context_t *pact PACT_UNUSED, - const char *function PACT_UNUSED, - uint64_t page_addr PACT_UNUSED, - uint32_t frequency PACT_UNUSED, - uint64_t total_samples PACT_UNUSED, - uint64_t stalls PACT_UNUSED, - uint64_t attributed_stalls PACT_UNUSED, - uint8_t tier PACT_UNUSED, - double mlp PACT_UNUSED) -{ -} +static inline void +log_pac_calculation(pact_context_t *pact PACT_UNUSED, const char *function PACT_UNUSED, + uint64_t page_addr PACT_UNUSED, uint32_t frequency PACT_UNUSED, + uint64_t total_samples PACT_UNUSED, uint64_t stalls PACT_UNUSED, + uint64_t attributed_stalls PACT_UNUSED, uint8_t tier PACT_UNUSED, + double mlp PACT_UNUSED) +{} static inline void log_ring_buffer_op(pact_context_t *pact PACT_UNUSED, - const char *function PACT_UNUSED, - const char *op PACT_UNUSED, - const char *buffer_name PACT_UNUSED, - size_t count PACT_UNUSED, - size_t current_size PACT_UNUSED, - size_t capacity PACT_UNUSED) -{ -} + const char *function PACT_UNUSED, const char *op PACT_UNUSED, + const char *buffer_name PACT_UNUSED, size_t count PACT_UNUSED, + size_t current_size PACT_UNUSED, size_t capacity PACT_UNUSED) +{} static inline void log_workload_info(pact_context_t *pact PACT_UNUSED, - const char *function PACT_UNUSED, - int workload_id PACT_UNUSED, - pid_t pid PACT_UNUSED, - const char *name PACT_UNUSED, + const char *function PACT_UNUSED, int workload_id PACT_UNUSED, + pid_t pid PACT_UNUSED, const char *name PACT_UNUSED, const char *cores PACT_UNUSED) -{ -} - -static inline void log_migration_stats(pact_context_t *pact PACT_UNUSED, - const char *function PACT_UNUSED, - int workload_id PACT_UNUSED, - uint64_t new_promotions PACT_UNUSED, - uint64_t new_demotions PACT_UNUSED, - uint64_t avg_promotion_pac PACT_UNUSED, - uint64_t avg_demotion_pac PACT_UNUSED, - uint64_t repromotions_pact_pact PACT_UNUSED, - uint64_t repromotions_pact_other PACT_UNUSED, - uint64_t repromotions_other_pact PACT_UNUSED, - uint64_t repromotions_other_other PACT_UNUSED, - uint64_t redemotions_pact_pact PACT_UNUSED, - uint64_t redemotions_pact_other PACT_UNUSED, - uint64_t redemotions_other_pact PACT_UNUSED, - uint64_t redemotions_other_other PACT_UNUSED) -{ -} - -static inline void log_pmu(pact_context_t *pact PACT_UNUSED, - const char *function PACT_UNUSED, - int workload_id PACT_UNUSED, - double fast_tier_mlp PACT_UNUSED, - double slow_tier_mlp PACT_UNUSED, - uint64_t llc_misses_fast PACT_UNUSED, +{} + +static inline void log_migration_stats( + pact_context_t *pact PACT_UNUSED, const char *function PACT_UNUSED, int workload_id PACT_UNUSED, + uint64_t new_promotions PACT_UNUSED, uint64_t new_demotions PACT_UNUSED, + uint64_t avg_promotion_pac PACT_UNUSED, uint64_t avg_demotion_pac PACT_UNUSED, + uint64_t repromotions_pact_pact PACT_UNUSED, uint64_t repromotions_pact_other PACT_UNUSED, + uint64_t repromotions_other_pact PACT_UNUSED, uint64_t repromotions_other_other PACT_UNUSED, + uint64_t redemotions_pact_pact PACT_UNUSED, uint64_t redemotions_pact_other PACT_UNUSED, + uint64_t redemotions_other_pact PACT_UNUSED, uint64_t redemotions_other_other PACT_UNUSED) +{} + +static inline void log_pmu(pact_context_t *pact PACT_UNUSED, const char *function PACT_UNUSED, + int workload_id PACT_UNUSED, double fast_tier_mlp PACT_UNUSED, + double slow_tier_mlp PACT_UNUSED, uint64_t llc_misses_fast PACT_UNUSED, uint64_t llc_misses_slow PACT_UNUSED, uint64_t fast_tier_events PACT_UNUSED, uint64_t slow_tier_events PACT_UNUSED) -{ -} +{} static inline void log_pac_update(pact_context_t *pact PACT_UNUSED, - const char *function PACT_UNUSED, - int workload_id PACT_UNUSED, - uint64_t page_addr PACT_UNUSED, - uint64_t pac_value PACT_UNUSED, - const char *tier_str PACT_UNUSED, - int bin_index PACT_UNUSED) -{ -} + const char *function PACT_UNUSED, int workload_id PACT_UNUSED, + uint64_t page_addr PACT_UNUSED, uint64_t pac_value PACT_UNUSED, + const char *tier_str PACT_UNUSED, int bin_index PACT_UNUSED) +{} static inline void log_migration_event(pact_context_t *pact PACT_UNUSED, const char *function PACT_UNUSED, int workload_id PACT_UNUSED, const char *operation PACT_UNUSED, - uint64_t page_addr PACT_UNUSED, - int from_tier PACT_UNUSED, + uint64_t page_addr PACT_UNUSED, int from_tier PACT_UNUSED, int to_tier PACT_UNUSED) -{ -} - -static inline void log_pebs_aggregator(pact_context_t *pact PACT_UNUSED, - const char *function PACT_UNUSED, - int workload_id PACT_UNUSED, - uint64_t theory_samples PACT_UNUSED, - uint64_t processed_samples PACT_UNUSED, - uint64_t perf_dropped_events PACT_UNUSED, - uint64_t perf_dropped_samples PACT_UNUSED, - uint64_t agg_dropped_events_agg_full PACT_UNUSED, - uint64_t agg_dropped_events_update_full PACT_UNUSED) -{ -} +{} + +static inline void log_pebs_aggregator( + pact_context_t *pact PACT_UNUSED, const char *function PACT_UNUSED, int workload_id PACT_UNUSED, + uint64_t theory_samples PACT_UNUSED, uint64_t processed_samples PACT_UNUSED, + uint64_t perf_dropped_events PACT_UNUSED, uint64_t perf_dropped_samples PACT_UNUSED, + uint64_t agg_dropped_events_agg_full PACT_UNUSED, + uint64_t agg_dropped_events_update_full PACT_UNUSED) +{} #endif /* PACT_ENABLE_LOGGING */ diff --git a/src/ring-buffer.h b/src/ring-buffer.h index 655026f..ee0df70 100644 --- a/src/ring-buffer.h +++ b/src/ring-buffer.h @@ -46,144 +46,144 @@ * @param type The data type of the elements to be stored in the buffer. * @param name A suffix to be added to all function and type names to make them unique. */ -#define DEFINE_RING_BUFFER(type, name) \ - \ - typedef struct { \ - /* Read-only after create(): isolated on its own line. */ \ - type *buffer; \ - size_t size; \ - size_t mask; \ - /* Producer-owned head and consumer-owned tail, each on its own line. */ \ - alignas(RING_BUFFER_CACHELINE) _Atomic size_t head; \ - alignas(RING_BUFFER_CACHELINE) _Atomic size_t tail; \ - char _pad_end[RING_BUFFER_CACHELINE - sizeof(_Atomic size_t)]; \ - } ring_buffer_##name##_t; \ - \ - static inline ring_buffer_##name##_t *ring_buffer_##name##_create(size_t size) \ - { \ - /* Ensure size is a power of 2 for efficient masking */ \ - if (size < 2) { \ - size = 2; \ - } \ - if ((size & (size - 1)) != 0) { \ - size_t new_size = 1; \ - while (new_size < size) \ - new_size <<= 1; \ - size = new_size; \ - } \ - \ +#define DEFINE_RING_BUFFER(type, name) \ + \ + typedef struct { \ + /* Read-only after create(): isolated on its own line. */ \ + type *buffer; \ + size_t size; \ + size_t mask; \ + /* Producer-owned head and consumer-owned tail, each on its own line. */ \ + alignas(RING_BUFFER_CACHELINE) _Atomic size_t head; \ + alignas(RING_BUFFER_CACHELINE) _Atomic size_t tail; \ + char _pad_end[RING_BUFFER_CACHELINE - sizeof(_Atomic size_t)]; \ + } ring_buffer_##name##_t; \ + \ + static inline ring_buffer_##name##_t *ring_buffer_##name##_create(size_t size) \ + { \ + /* Ensure size is a power of 2 for efficient masking */ \ + if (size < 2) { \ + size = 2; \ + } \ + if ((size & (size - 1)) != 0) { \ + size_t new_size = 1; \ + while (new_size < size) \ + new_size <<= 1; \ + size = new_size; \ + } \ + \ /* aligned_alloc needs size a multiple of alignment; sizeof(struct) is \ - * a multiple of RING_BUFFER_CACHELINE because of the alignas above. */ \ - ring_buffer_##name##_t *rb = aligned_alloc(RING_BUFFER_CACHELINE, \ - sizeof(ring_buffer_##name##_t)); \ - if (!rb) \ - return NULL; \ - memset(rb, 0, sizeof(*rb)); \ - \ - rb->buffer = calloc(size, sizeof(type)); \ - if (!rb->buffer) { \ - free(rb); \ - return NULL; \ - } \ - \ - rb->size = size; \ - rb->mask = size - 1; \ - atomic_store_explicit(&rb->head, 0, memory_order_relaxed); \ - atomic_store_explicit(&rb->tail, 0, memory_order_relaxed); \ - \ - return rb; \ - } \ - \ - static inline void ring_buffer_##name##_destroy(ring_buffer_##name##_t *rb) \ - { \ - if (!rb) \ - return; \ - free(rb->buffer); \ - free(rb); \ - } \ - \ - /* Producer side. */ \ - static inline bool ring_buffer_##name##_push(ring_buffer_##name##_t *rb, type value) \ - { \ - size_t head = atomic_load_explicit(&rb->head, memory_order_relaxed); \ - size_t next_head = (head + 1) & rb->mask; \ - if (next_head == atomic_load_explicit(&rb->tail, memory_order_acquire)) { \ - return false; /* Buffer is Full */ \ - } \ - rb->buffer[head] = value; \ - atomic_store_explicit(&rb->head, next_head, memory_order_release); \ - return true; \ - } \ - \ - /* Consumer side. */ \ - static inline bool ring_buffer_##name##_pop(ring_buffer_##name##_t *rb, type *value) \ - { \ - size_t tail = atomic_load_explicit(&rb->tail, memory_order_relaxed); \ - if (tail == atomic_load_explicit(&rb->head, memory_order_acquire)) { \ - return false; /* Buffer is Empty */ \ - } \ - *value = rb->buffer[tail]; \ - atomic_store_explicit(&rb->tail, (tail + 1) & rb->mask, memory_order_release); \ - return true; \ - } \ - \ - /* Consumer side: inspect the front element without consuming it. */ \ - static inline bool ring_buffer_##name##_peek(ring_buffer_##name##_t *rb, type *value) \ - { \ - size_t tail = atomic_load_explicit(&rb->tail, memory_order_relaxed); \ - if (tail == atomic_load_explicit(&rb->head, memory_order_acquire)) { \ - return false; /* Buffer is Empty */ \ - } \ - *value = rb->buffer[tail]; \ - return true; \ - } \ - \ + * a multiple of RING_BUFFER_CACHELINE because of the alignas above. */ \ + ring_buffer_##name##_t *rb = \ + aligned_alloc(RING_BUFFER_CACHELINE, sizeof(ring_buffer_##name##_t)); \ + if (!rb) \ + return NULL; \ + memset(rb, 0, sizeof(*rb)); \ + \ + rb->buffer = calloc(size, sizeof(type)); \ + if (!rb->buffer) { \ + free(rb); \ + return NULL; \ + } \ + \ + rb->size = size; \ + rb->mask = size - 1; \ + atomic_store_explicit(&rb->head, 0, memory_order_relaxed); \ + atomic_store_explicit(&rb->tail, 0, memory_order_relaxed); \ + \ + return rb; \ + } \ + \ + static inline void ring_buffer_##name##_destroy(ring_buffer_##name##_t *rb) \ + { \ + if (!rb) \ + return; \ + free(rb->buffer); \ + free(rb); \ + } \ + \ + /* Producer side. */ \ + static inline bool ring_buffer_##name##_push(ring_buffer_##name##_t *rb, type value) \ + { \ + size_t head = atomic_load_explicit(&rb->head, memory_order_relaxed); \ + size_t next_head = (head + 1) & rb->mask; \ + if (next_head == atomic_load_explicit(&rb->tail, memory_order_acquire)) { \ + return false; /* Buffer is Full */ \ + } \ + rb->buffer[head] = value; \ + atomic_store_explicit(&rb->head, next_head, memory_order_release); \ + return true; \ + } \ + \ + /* Consumer side. */ \ + static inline bool ring_buffer_##name##_pop(ring_buffer_##name##_t *rb, type *value) \ + { \ + size_t tail = atomic_load_explicit(&rb->tail, memory_order_relaxed); \ + if (tail == atomic_load_explicit(&rb->head, memory_order_acquire)) { \ + return false; /* Buffer is Empty */ \ + } \ + *value = rb->buffer[tail]; \ + atomic_store_explicit(&rb->tail, (tail + 1) & rb->mask, memory_order_release); \ + return true; \ + } \ + \ + /* Consumer side: inspect the front element without consuming it. */ \ + static inline bool ring_buffer_##name##_peek(ring_buffer_##name##_t *rb, type *value) \ + { \ + size_t tail = atomic_load_explicit(&rb->tail, memory_order_relaxed); \ + if (tail == atomic_load_explicit(&rb->head, memory_order_acquire)) { \ + return false; /* Buffer is Empty */ \ + } \ + *value = rb->buffer[tail]; \ + return true; \ + } \ + \ /* Consumer side: snapshot head once (acquire), drain up to `max`, then \ - * publish the new tail once (release). */ \ - static inline int ring_buffer_##name##_pop_batch(ring_buffer_##name##_t *rb, type *values, \ - int max) \ - { \ - size_t tail = atomic_load_explicit(&rb->tail, memory_order_relaxed); \ - size_t head = atomic_load_explicit(&rb->head, memory_order_acquire); \ - int count = 0; \ - while (count < max && tail != head) { \ - values[count++] = rb->buffer[tail]; \ - tail = (tail + 1) & rb->mask; \ - } \ - if (count > 0) { \ - atomic_store_explicit(&rb->tail, tail, memory_order_release); \ - } \ - return count; \ - } \ - \ + * publish the new tail once (release). */ \ + static inline int ring_buffer_##name##_pop_batch(ring_buffer_##name##_t *rb, type *values, \ + int max) \ + { \ + size_t tail = atomic_load_explicit(&rb->tail, memory_order_relaxed); \ + size_t head = atomic_load_explicit(&rb->head, memory_order_acquire); \ + int count = 0; \ + while (count < max && tail != head) { \ + values[count++] = rb->buffer[tail]; \ + tail = (tail + 1) & rb->mask; \ + } \ + if (count > 0) { \ + atomic_store_explicit(&rb->tail, tail, memory_order_release); \ + } \ + return count; \ + } \ + \ /* Producer side: snapshot tail once (acquire), fill up to `n`, then \ - * publish the new head once (release). */ \ - static inline int ring_buffer_##name##_push_batch(ring_buffer_##name##_t *rb, type *values, \ - int n) \ - { \ - size_t head = atomic_load_explicit(&rb->head, memory_order_relaxed); \ - size_t tail = atomic_load_explicit(&rb->tail, memory_order_acquire); \ - int count = 0; \ - while (count < n) { \ - size_t next_head = (head + 1) & rb->mask; \ - if (next_head == tail) \ - break; \ - rb->buffer[head] = values[count++]; \ - head = next_head; \ - } \ - if (count > 0) { \ - atomic_store_explicit(&rb->head, head, memory_order_release); \ - } \ - return count; \ - } \ - \ + * publish the new head once (release). */ \ + static inline int ring_buffer_##name##_push_batch(ring_buffer_##name##_t *rb, type *values, \ + int n) \ + { \ + size_t head = atomic_load_explicit(&rb->head, memory_order_relaxed); \ + size_t tail = atomic_load_explicit(&rb->tail, memory_order_acquire); \ + int count = 0; \ + while (count < n) { \ + size_t next_head = (head + 1) & rb->mask; \ + if (next_head == tail) \ + break; \ + rb->buffer[head] = values[count++]; \ + head = next_head; \ + } \ + if (count > 0) { \ + atomic_store_explicit(&rb->head, head, memory_order_release); \ + } \ + return count; \ + } \ + \ /* Approximate occupancy. Safe to call from either side; uses acquire loads \ - * so a consumer using it as a drain gate sees published producer writes. */ \ - static inline size_t ring_buffer_##name##_size(ring_buffer_##name##_t *rb) \ - { \ - size_t head = atomic_load_explicit(&rb->head, memory_order_acquire); \ - size_t tail = atomic_load_explicit(&rb->tail, memory_order_acquire); \ - return (head - tail) & rb->mask; \ + * so a consumer using it as a drain gate sees published producer writes. */ \ + static inline size_t ring_buffer_##name##_size(ring_buffer_##name##_t *rb) \ + { \ + size_t head = atomic_load_explicit(&rb->head, memory_order_acquire); \ + size_t tail = atomic_load_explicit(&rb->tail, memory_order_acquire); \ + return (head - tail) & rb->mask; \ } #endif // RING_BUFFER_H