]>
Commit | Line | Data |
---|---|---|
8ad57564 JH |
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 | */ | |
54 | struct 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 | */ | |
91 | struct 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 | */ | |
107 | struct 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 | */ | |
115 | void tr2_start_timer(enum trace2_timer_id tid); | |
116 | void 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 | */ | |
124 | void 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 | */ | |
130 | void 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 | */ | |
138 | void tr2_emit_final_timers(tr2_tgt_evt_timer_t *fn_apply); | |
139 | ||
140 | #endif /* TR2_TMR_H */ |