| #ifndef TR2_TMR_H | |
| #define TR2_TMR_H | |
| #include "trace2.h" | |
| #include "trace2/tr2_tgt.h" | |
| /* | |
| * Define a mechanism to allow "stopwatch" timers. | |
| * | |
| * Timers can be used to measure "interesting" activity that does not | |
| * fit the "region" model, such as code called from many different | |
| * regions (like zlib) and/or where data for individual calls are not | |
| * interesting or are too numerous to be efficiently logged. | |
| * | |
| * Timer values are accumulated during program execution and emitted | |
| * to the Trace2 logs at program exit. | |
| * | |
| * To make this model efficient, we define a compile-time fixed set of | |
| * timers and timer ids using a "timer block" array in thread-local | |
| * storage. This gives us constant time access to each timer within | |
| * each thread, since we want start/stop operations to be as fast as | |
| * possible. This lets us avoid the complexities of dynamically | |
| * allocating a timer on the first use by a thread and/or possibly | |
| * sharing that timer definition with other concurrent threads. | |
| * However, this does require that we define time the set of timers at | |
| * compile time. | |
| * | |
| * Each thread uses the timer block in its thread-local storage to | |
| * compute partial sums for each timer (without locking). When a | |
| * thread exits, those partial sums are (under lock) added to the | |
| * global final sum. | |
| * | |
| * Using this "timer block" model costs ~48 bytes per timer per thread | |
| * (we have about six uint64 fields per timer). This does increase | |
| * the size of the thread-local storage block, but it is allocated (at | |
| * thread create time) and not on the thread stack, so I'm not worried | |
| * about the size. | |
| * | |
| * Partial sums for each timer are optionally emitted when a thread | |
| * exits. | |
| * | |
| * Final sums for each timer are emitted between the "exit" and | |
| * "atexit" events. | |
| * | |
| * A parallel "timer metadata" table contains the "category" and "name" | |
| * fields for each timer. This eliminates the need to include those | |
| * args in the various timer APIs. | |
| */ | |
| /* | |
| * The definition of an individual timer and used by an individual | |
| * thread. | |
| */ | |
| struct tr2_timer { | |
| /* | |
| * Total elapsed time for this timer in this thread in nanoseconds. | |
| */ | |
| uint64_t total_ns; | |
| /* | |
| * The maximum and minimum interval values observed for this | |
| * timer in this thread. | |
| */ | |
| uint64_t min_ns; | |
| uint64_t max_ns; | |
| /* | |
| * The value of the clock when this timer was started in this | |
| * thread. (Undefined when the timer is not active in this | |
| * thread.) | |
| */ | |
| uint64_t start_ns; | |
| /* | |
| * Number of times that this timer has been started and stopped | |
| * in this thread. (Recursive starts are ignored.) | |
| */ | |
| uint64_t interval_count; | |
| /* | |
| * Number of nested starts on the stack in this thread. (We | |
| * ignore recursive starts and use this to track the recursive | |
| * calls.) | |
| */ | |
| unsigned int recursion_count; | |
| }; | |
| /* | |
| * Metadata for a timer. | |
| */ | |
| struct tr2_timer_metadata { | |
| const char *category; | |
| const char *name; | |
| /* | |
| * True if we should emit per-thread events for this timer | |
| * when individual threads exit. | |
| */ | |
| unsigned int want_per_thread_events:1; | |
| }; | |
| /* | |
| * A compile-time fixed-size block of timers to insert into | |
| * thread-local storage. This wrapper is used to avoid quirks | |
| * of C and the usual need to pass an array size argument. | |
| */ | |
| struct tr2_timer_block { | |
| struct tr2_timer timer[TRACE2_NUMBER_OF_TIMERS]; | |
| }; | |
| /* | |
| * Private routines used by trace2.c to actually start/stop an | |
| * individual timer in the current thread. | |
| */ | |
| void tr2_start_timer(enum trace2_timer_id tid); | |
| void tr2_stop_timer(enum trace2_timer_id tid); | |
| /* | |
| * Add the current thread's timer data to the global totals. | |
| * This is called during thread-exit. | |
| * | |
| * Caller must be holding the tr2tls_mutex. | |
| */ | |
| void tr2_update_final_timers(void); | |
| /* | |
| * Emit per-thread timer data for the current thread. | |
| * This is called during thread-exit. | |
| */ | |
| void tr2_emit_per_thread_timers(tr2_tgt_evt_timer_t *fn_apply); | |
| /* | |
| * Emit global total timer values. | |
| * This is called during atexit handling. | |
| * | |
| * Caller must be holding the tr2tls_mutex. | |
| */ | |
| void tr2_emit_final_timers(tr2_tgt_evt_timer_t *fn_apply); | |
| #endif /* TR2_TMR_H */ |