Git fork
at reftables-rust 168 lines 4.4 kB view raw
1#include "git-compat-util.h" 2#include "trace2/tr2_tgt.h" 3#include "trace2/tr2_tls.h" 4#include "trace2/tr2_tmr.h" 5#include "trace.h" 6 7#define MY_MAX(a, b) ((a) > (b) ? (a) : (b)) 8#define MY_MIN(a, b) ((a) < (b) ? (a) : (b)) 9 10/* 11 * A global timer block to aggregate values from the partial sums from 12 * each thread. 13 */ 14static struct tr2_timer_block final_timer_block; /* access under tr2tls_mutex */ 15 16/* 17 * Define metadata for each stopwatch timer. 18 * 19 * This array must match "enum trace2_timer_id" and the values 20 * in "struct tr2_timer_block.timer[*]". 21 */ 22static struct tr2_timer_metadata tr2_timer_metadata[TRACE2_NUMBER_OF_TIMERS] = { 23 [TRACE2_TIMER_ID_TEST1] = { 24 .category = "test", 25 .name = "test1", 26 .want_per_thread_events = 0, 27 }, 28 [TRACE2_TIMER_ID_TEST2] = { 29 .category = "test", 30 .name = "test2", 31 .want_per_thread_events = 1, 32 }, 33 34 /* Add additional metadata before here. */ 35}; 36 37void tr2_start_timer(enum trace2_timer_id tid) 38{ 39 struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); 40 struct tr2_timer *t = &ctx->timer_block.timer[tid]; 41 42 t->recursion_count++; 43 if (t->recursion_count > 1) 44 return; /* ignore recursive starts */ 45 46 t->start_ns = getnanotime(); 47} 48 49void tr2_stop_timer(enum trace2_timer_id tid) 50{ 51 struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); 52 struct tr2_timer *t = &ctx->timer_block.timer[tid]; 53 uint64_t ns_now; 54 uint64_t ns_interval; 55 56 assert(t->recursion_count > 0); 57 58 t->recursion_count--; 59 if (t->recursion_count) 60 return; /* still in recursive call(s) */ 61 62 ns_now = getnanotime(); 63 ns_interval = ns_now - t->start_ns; 64 65 t->total_ns += ns_interval; 66 67 /* 68 * min_ns was initialized to zero (in the xcalloc()) rather 69 * than UINT_MAX when the block of timers was allocated, 70 * so we should always set both the min_ns and max_ns values 71 * the first time that the timer is used. 72 */ 73 if (!t->interval_count) { 74 t->min_ns = ns_interval; 75 t->max_ns = ns_interval; 76 } else { 77 t->min_ns = MY_MIN(ns_interval, t->min_ns); 78 t->max_ns = MY_MAX(ns_interval, t->max_ns); 79 } 80 81 t->interval_count++; 82 83 ctx->used_any_timer = 1; 84 if (tr2_timer_metadata[tid].want_per_thread_events) 85 ctx->used_any_per_thread_timer = 1; 86} 87 88void tr2_update_final_timers(void) 89{ 90 struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); 91 enum trace2_timer_id tid; 92 93 if (!ctx->used_any_timer) 94 return; 95 96 /* 97 * Accessing `final_timer_block` requires holding `tr2tls_mutex`. 98 * We assume that our caller is holding the lock. 99 */ 100 101 for (tid = 0; tid < TRACE2_NUMBER_OF_TIMERS; tid++) { 102 struct tr2_timer *t_final = &final_timer_block.timer[tid]; 103 struct tr2_timer *t = &ctx->timer_block.timer[tid]; 104 105 /* 106 * `t->recursion_count` could technically be non-zero, which 107 * would constitute a bug. Reporting the bug would potentially 108 * cause an infinite recursion, though, so let's ignore it. 109 */ 110 111 if (!t->interval_count) 112 continue; /* this timer was not used by this thread */ 113 114 t_final->total_ns += t->total_ns; 115 116 /* 117 * final_timer_block.timer[tid].min_ns was initialized to 118 * was initialized to zero rather than UINT_MAX, so we should 119 * always set both the min_ns and max_ns values the first time 120 * that we add a partial sum into it. 121 */ 122 if (!t_final->interval_count) { 123 t_final->min_ns = t->min_ns; 124 t_final->max_ns = t->max_ns; 125 } else { 126 t_final->min_ns = MY_MIN(t_final->min_ns, t->min_ns); 127 t_final->max_ns = MY_MAX(t_final->max_ns, t->max_ns); 128 } 129 130 t_final->interval_count += t->interval_count; 131 } 132} 133 134void tr2_emit_per_thread_timers(tr2_tgt_evt_timer_t *fn_apply) 135{ 136 struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); 137 enum trace2_timer_id tid; 138 139 if (!ctx->used_any_per_thread_timer) 140 return; 141 142 /* 143 * For each timer, if the timer wants per-thread events and 144 * this thread used it, emit it. 145 */ 146 for (tid = 0; tid < TRACE2_NUMBER_OF_TIMERS; tid++) 147 if (tr2_timer_metadata[tid].want_per_thread_events && 148 ctx->timer_block.timer[tid].interval_count) 149 fn_apply(&tr2_timer_metadata[tid], 150 &ctx->timer_block.timer[tid], 151 0); 152} 153 154void tr2_emit_final_timers(tr2_tgt_evt_timer_t *fn_apply) 155{ 156 enum trace2_timer_id tid; 157 158 /* 159 * Accessing `final_timer_block` requires holding `tr2tls_mutex`. 160 * We assume that our caller is holding the lock. 161 */ 162 163 for (tid = 0; tid < TRACE2_NUMBER_OF_TIMERS; tid++) 164 if (final_timer_block.timer[tid].interval_count) 165 fn_apply(&tr2_timer_metadata[tid], 166 &final_timer_block.timer[tid], 167 1); 168}