Git fork
at reftables-rust 140 lines 4.1 kB view raw
1#ifndef TR2_TMR_H 2#define TR2_TMR_H 3 4#include "trace2.h" 5#include "trace2/tr2_tgt.h" 6 7/* 8 * Define a mechanism to allow "stopwatch" timers. 9 * 10 * Timers can be used to measure "interesting" activity that does not 11 * fit the "region" model, such as code called from many different 12 * regions (like zlib) and/or where data for individual calls are not 13 * interesting or are too numerous to be efficiently logged. 14 * 15 * Timer values are accumulated during program execution and emitted 16 * to the Trace2 logs at program exit. 17 * 18 * To make this model efficient, we define a compile-time fixed set of 19 * timers and timer ids using a "timer block" array in thread-local 20 * storage. This gives us constant time access to each timer within 21 * each thread, since we want start/stop operations to be as fast as 22 * possible. This lets us avoid the complexities of dynamically 23 * allocating a timer on the first use by a thread and/or possibly 24 * sharing that timer definition with other concurrent threads. 25 * However, this does require that we define time the set of timers at 26 * compile time. 27 * 28 * Each thread uses the timer block in its thread-local storage to 29 * compute partial sums for each timer (without locking). When a 30 * thread exits, those partial sums are (under lock) added to the 31 * global final sum. 32 * 33 * Using this "timer block" model costs ~48 bytes per timer per thread 34 * (we have about six uint64 fields per timer). This does increase 35 * the size of the thread-local storage block, but it is allocated (at 36 * thread create time) and not on the thread stack, so I'm not worried 37 * about the size. 38 * 39 * Partial sums for each timer are optionally emitted when a thread 40 * exits. 41 * 42 * Final sums for each timer are emitted between the "exit" and 43 * "atexit" events. 44 * 45 * A parallel "timer metadata" table contains the "category" and "name" 46 * fields for each timer. This eliminates the need to include those 47 * args in the various timer APIs. 48 */ 49 50/* 51 * The definition of an individual timer and used by an individual 52 * thread. 53 */ 54struct tr2_timer { 55 /* 56 * Total elapsed time for this timer in this thread in nanoseconds. 57 */ 58 uint64_t total_ns; 59 60 /* 61 * The maximum and minimum interval values observed for this 62 * timer in this thread. 63 */ 64 uint64_t min_ns; 65 uint64_t max_ns; 66 67 /* 68 * The value of the clock when this timer was started in this 69 * thread. (Undefined when the timer is not active in this 70 * thread.) 71 */ 72 uint64_t start_ns; 73 74 /* 75 * Number of times that this timer has been started and stopped 76 * in this thread. (Recursive starts are ignored.) 77 */ 78 uint64_t interval_count; 79 80 /* 81 * Number of nested starts on the stack in this thread. (We 82 * ignore recursive starts and use this to track the recursive 83 * calls.) 84 */ 85 unsigned int recursion_count; 86}; 87 88/* 89 * Metadata for a timer. 90 */ 91struct tr2_timer_metadata { 92 const char *category; 93 const char *name; 94 95 /* 96 * True if we should emit per-thread events for this timer 97 * when individual threads exit. 98 */ 99 unsigned int want_per_thread_events:1; 100}; 101 102/* 103 * A compile-time fixed-size block of timers to insert into 104 * thread-local storage. This wrapper is used to avoid quirks 105 * of C and the usual need to pass an array size argument. 106 */ 107struct tr2_timer_block { 108 struct tr2_timer timer[TRACE2_NUMBER_OF_TIMERS]; 109}; 110 111/* 112 * Private routines used by trace2.c to actually start/stop an 113 * individual timer in the current thread. 114 */ 115void tr2_start_timer(enum trace2_timer_id tid); 116void tr2_stop_timer(enum trace2_timer_id tid); 117 118/* 119 * Add the current thread's timer data to the global totals. 120 * This is called during thread-exit. 121 * 122 * Caller must be holding the tr2tls_mutex. 123 */ 124void tr2_update_final_timers(void); 125 126/* 127 * Emit per-thread timer data for the current thread. 128 * This is called during thread-exit. 129 */ 130void tr2_emit_per_thread_timers(tr2_tgt_evt_timer_t *fn_apply); 131 132/* 133 * Emit global total timer values. 134 * This is called during atexit handling. 135 * 136 * Caller must be holding the tr2tls_mutex. 137 */ 138void tr2_emit_final_timers(tr2_tgt_evt_timer_t *fn_apply); 139 140#endif /* TR2_TMR_H */