git/trace2/tr2_tmr.h

#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 {};

/*
 * Metadata for a timer.
 */
struct tr2_timer_metadata {};

/*
 * 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 {};

/*
 * 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 */