#ifndef TR2_CTR_H #define TR2_CTR_H #include "trace2.h" #include "trace2/tr2_tgt.h" /* * Define a mechanism to allow global "counters". * * Counters can be used count interesting activity that does not fit * the "region and data" model, such as code called from many * different regions and/or where you want to count a number of items, * but don't have control of when the last item will be processed, * such as counter the number of calls to `lstat()`. * * Counters differ from Trace2 "data" events. Data events are emitted * immediately and are appropriate for documenting loop counters at * the end of a region, for example. Counter values are accumulated * during the program and final counter values are emitted at program * exit. * * To make this model efficient, we define a compile-time fixed set of * counters and counter ids using a fixed size "counter block" array * in thread-local storage. This gives us constant time, lock-free * access to each counter within each thread. This lets us avoid the * complexities of dynamically allocating a counter and sharing that * definition with other threads. * * Each thread uses the counter block in its thread-local storage to * increment partial sums for each counter (without locking). When a * thread exits, those partial sums are (under lock) added to the * global final sum. * * Partial sums for each counter are optionally emitted when a thread * exits. * * Final sums for each counter are emitted between the "exit" and * "atexit" events. * * A parallel "counter metadata" table contains the "category" and * "name" fields for each counter. This eliminates the need to * include those args in the various counter APIs. */ /* * The definition of an individual counter as used by an individual * thread (and later in aggregation). */ struct tr2_counter { uint64_t value; }; /* * Metadata for a counter. */ struct tr2_counter_metadata { const char *category; const char *name; /* * True if we should emit per-thread events for this counter * when individual threads exit. */ unsigned int want_per_thread_events:1; }; /* * A compile-time fixed block of counters 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_counter_block { struct tr2_counter counter[TRACE2_NUMBER_OF_COUNTERS]; }; /* * Private routines used by trace2.c to increment a counter for the * current thread. */ void tr2_counter_increment(enum trace2_counter_id cid, uint64_t value); /* * Add the current thread's counter data to the global totals. * This is called during thread-exit. * * Caller must be holding the tr2tls_mutex. */ void tr2_update_final_counters(void); /* * Emit per-thread counter data for the current thread. * This is called during thread-exit. */ void tr2_emit_per_thread_counters(tr2_tgt_evt_counter_t *fn_apply); /* * Emit global counter values. * This is called during atexit handling. * * Caller must be holding the tr2tls_mutex. */ void tr2_emit_final_counters(tr2_tgt_evt_counter_t *fn_apply); #endif /* TR2_CTR_H */