3 // Copyright 2014 by Henrik RydgÄrd
4 // http://www.github.com/hrydgard/minitrace
5 // Released under the MIT license.
7 // Ultra-light dependency free library for performance tracing C/C++ applications.
8 // Produces traces compatible with Google Chrome's trace viewer.
9 // Simply open "about:tracing" in Chrome and load the produced JSON.
11 // This contains far less template magic than the original libraries from Chrome
12 // because this is meant to be usable from C.
14 // See README.md for a tutorial.
16 // The trace format is documented here:
17 // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit
19 // http://www.altdevblogaday.com/2012/08/21/using-chrometracing-to-view-your-inline-profiling-data/
26 // If MTR_ENABLED is not defined, Minitrace does nothing and has near zero overhead.
27 // Preferably, set this flag in your build system. If you can't just uncomment this line.
28 // #define MTR_ENABLED
30 // By default, will collect up to 1000000 events, then you must flush.
31 // It's recommended that you simply call mtr_flush on a background thread
32 // occasionally. It's safe...ish.
33 #define INTERNAL_MINITRACE_BUFFER_SIZE 1000000
39 // Initializes Minitrace. Must be called very early during startup of your executable,
40 // before any MTR_ statements.
41 void mtr_init(const char *json_file);
42 // Same as above, but allows passing in a custom stream (FILE *), as returned by
43 // fopen(). It should be opened for writing, preferably in binary mode to avoid
44 // processing of line endings (i.e. the "wb" mode).
45 void mtr_init_from_stream(void *stream);
47 // Shuts down minitrace cleanly, flushing the trace buffer.
48 void mtr_shutdown(void);
50 // Lets you enable and disable Minitrace at runtime.
51 // May cause strange discontinuities in the output.
52 // Minitrace is enabled on startup by default.
56 // Flushes the collected data to disk, clearing the buffer for new data.
59 // Returns the current time in seconds. Used internally by Minitrace. No caching.
60 double mtr_time_s(void);
62 // Registers a handler that will flush the trace on Ctrl+C.
63 // Works on Linux and MacOSX, and in Win32 console applications.
64 void mtr_register_sigint_handler(void);
66 // Utility function that should rarely be used.
67 // If str is semi dynamic, store it permanently in a small pool so we don't need to malloc it.
68 // The pool fills up fast though and performance isn't great.
69 // Returns a fixed string if the pool is full.
70 const char *mtr_pool_string(const char *str);
72 // Commented-out types will be supported in the future.
74 MTR_ARG_TYPE_NONE = 0,
75 MTR_ARG_TYPE_INT = 1, // I
76 // MTR_ARG_TYPE_FLOAT = 2, // TODO
77 // MTR_ARG_TYPE_DOUBLE = 3, // TODO
78 MTR_ARG_TYPE_STRING_CONST = 8, // C
79 MTR_ARG_TYPE_STRING_COPY = 9,
80 // MTR_ARG_TYPE_JSON_COPY = 10,
83 // TODO: Add support for more than one argument (metadata) per event
84 // Having more costs speed and memory.
85 #define MTR_MAX_ARGS 1
87 // Only use the macros to call these.
88 void internal_mtr_raw_event(const char *category, const char *name, char ph, void *id);
89 void internal_mtr_raw_event_arg(const char *category, const char *name, char ph, void *id, mtr_arg_type arg_type, const char *arg_name, void *arg_value);
93 // c - category. Can be filtered by in trace viewer (or at least that's the intention).
94 // A good use is to pass __FILE__, there are macros further below that will do it for you.
95 // n - name. Pass __FUNCTION__ in most cases, unless you are marking up parts of one.
97 // Scopes. In C++, use MTR_SCOPE. In C, always match them within the same scope.
98 #define MTR_BEGIN(c, n) internal_mtr_raw_event(c, n, 'B', 0)
99 #define MTR_END(c, n) internal_mtr_raw_event(c, n, 'E', 0)
100 #define MTR_SCOPE(c, n) MTRScopedTrace ____mtr_scope(c, n)
101 #define MTR_SCOPE_LIMIT(c, n, l) MTRScopedTraceLimit ____mtr_scope(c, n, l)
103 // Async events. Can span threads. ID identifies which events to connect in the view.
104 #define MTR_START(c, n, id) internal_mtr_raw_event(c, n, 'S', (void *)(id))
105 #define MTR_STEP(c, n, id, step) internal_mtr_raw_event_arg(c, n, 'T', (void *)(id), MTR_ARG_TYPE_STRING_CONST, "step", (void *)(step))
106 #define MTR_FINISH(c, n, id) internal_mtr_raw_event(c, n, 'F', (void *)(id))
108 // Flow events. Like async events, but displayed in a more fancy way in the viewer.
109 #define MTR_FLOW_START(c, n, id) internal_mtr_raw_event(c, n, 's', (void *)(id))
110 #define MTR_FLOW_STEP(c, n, id, step) internal_mtr_raw_event_arg(c, n, 't', (void *)(id), MTR_ARG_TYPE_STRING_CONST, "step", (void *)(step))
111 #define MTR_FLOW_FINISH(c, n, id) internal_mtr_raw_event(c, n, 'f', (void *)(id))
113 // The same macros, but with a single named argument which shows up as metadata in the viewer.
115 // _C is for a const string arg.
116 // _S will copy the string, freeing on flush (expensive but sometimes necessary).
117 // but required if the string was generated dynamically.
119 // Note that it's fine to match BEGIN_S with END and BEGIN with END_S, etc.
120 #define MTR_BEGIN_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval))
121 #define MTR_END_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval))
122 #define MTR_SCOPE_C(c, n, aname, astrval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval))
124 #define MTR_BEGIN_S(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval))
125 #define MTR_END_S(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval))
126 #define MTR_SCOPE_S(c, n, aname, astrval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval))
128 #define MTR_BEGIN_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval))
129 #define MTR_END_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval))
130 #define MTR_SCOPE_I(c, n, aname, aintval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval))
132 // Instant events. For things with no duration.
133 #define MTR_INSTANT(c, n) internal_mtr_raw_event(c, n, 'I', 0)
134 #define MTR_INSTANT_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'I', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval))
135 #define MTR_INSTANT_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'I', 0, MTR_ARG_TYPE_INT, aname, (void *)(aintval))
137 // Counters (can't do multi-value counters yet)
138 #define MTR_COUNTER(c, n, val) internal_mtr_raw_event_arg(c, n, 'C', 0, MTR_ARG_TYPE_INT, n, (void *)(intptr_t)(val))
140 // Metadata. Call at the start preferably. Must be const strings.
142 #define MTR_META_PROCESS_NAME(n) internal_mtr_raw_event_arg("", "process_name", 'M', 0, MTR_ARG_TYPE_STRING_COPY, "name", (void *)(n))
143 #define MTR_META_THREAD_NAME(n) internal_mtr_raw_event_arg("", "thread_name", 'M', 0, MTR_ARG_TYPE_STRING_COPY, "name", (void *)(n))
144 #define MTR_META_THREAD_SORT_INDEX(i) internal_mtr_raw_event_arg("", "thread_sort_index", 'M', 0, MTR_ARG_TYPE_INT, "sort_index", (void *)(i))
148 #define MTR_BEGIN(c, n)
149 #define MTR_END(c, n)
150 #define MTR_SCOPE(c, n)
151 #define MTR_START(c, n, id)
152 #define MTR_STEP(c, n, id, step)
153 #define MTR_FINISH(c, n, id)
154 #define MTR_FLOW_START(c, n, id)
155 #define MTR_FLOW_STEP(c, n, id, step)
156 #define MTR_FLOW_FINISH(c, n, id)
157 #define MTR_INSTANT(c, n)
159 #define MTR_BEGIN_C(c, n, aname, astrval)
160 #define MTR_END_C(c, n, aname, astrval)
161 #define MTR_SCOPE_C(c, n, aname, astrval)
163 #define MTR_BEGIN_S(c, n, aname, astrval)
164 #define MTR_END_S(c, n, aname, astrval)
165 #define MTR_SCOPE_S(c, n, aname, astrval)
167 #define MTR_BEGIN_I(c, n, aname, aintval)
168 #define MTR_END_I(c, n, aname, aintval)
169 #define MTR_SCOPE_I(c, n, aname, aintval)
171 #define MTR_INSTANT(c, n)
172 #define MTR_INSTANT_C(c, n, aname, astrval)
173 #define MTR_INSTANT_I(c, n, aname, aintval)
175 // Counters (can't do multi-value counters yet)
176 #define MTR_COUNTER(c, n, val)
178 // Metadata. Call at the start preferably. Must be const strings.
180 #define MTR_META_PROCESS_NAME(n)
182 #define MTR_META_THREAD_NAME(n)
183 #define MTR_META_THREAD_SORT_INDEX(i)
187 // Shortcuts for simple function timing with automatic categories and names.
189 #define MTR_BEGIN_FUNC() MTR_BEGIN(__FILE__, __FUNCTION__)
190 #define MTR_END_FUNC() MTR_END(__FILE__, __FUNCTION__)
191 #define MTR_SCOPE_FUNC() MTR_SCOPE(__FILE__, __FUNCTION__)
192 #define MTR_INSTANT_FUNC() MTR_INSTANT(__FILE__, __FUNCTION__)
193 #define MTR_SCOPE_FUNC_LIMIT_S(l) MTRScopedTraceLimit ____mtr_scope(__FILE__, __FUNCTION__, l)
194 #define MTR_SCOPE_FUNC_LIMIT_MS(l) MTRScopedTraceLimit ____mtr_scope(__FILE__, __FUNCTION__, (double)l * 0.000001)
196 // Same, but with a single argument of the usual types.
197 #define MTR_BEGIN_FUNC_S(aname, arg) MTR_BEGIN_S(__FILE__, __FUNCTION__, aname, arg)
198 #define MTR_END_FUNC_S(aname, arg) MTR_END_S(__FILE__, __FUNCTION__, aname, arg)
199 #define MTR_SCOPE_FUNC_S(aname, arg) MTR_SCOPE_S(__FILE__, __FUNCTION__, aname, arg)
201 #define MTR_BEGIN_FUNC_C(aname, arg) MTR_BEGIN_C(__FILE__, __FUNCTION__, aname, arg)
202 #define MTR_END_FUNC_C(aname, arg) MTR_END_C(__FILE__, __FUNCTION__, aname, arg)
203 #define MTR_SCOPE_FUNC_C(aname, arg) MTR_SCOPE_C(__FILE__, __FUNCTION__, aname, arg)
205 #define MTR_BEGIN_FUNC_I(aname, arg) MTR_BEGIN_I(__FILE__, __FUNCTION__, aname, arg)
206 #define MTR_END_FUNC_I(aname, arg) MTR_END_I(__FILE__, __FUNCTION__, aname, arg)
207 #define MTR_SCOPE_FUNC_I(aname, arg) MTR_SCOPE_I(__FILE__, __FUNCTION__, aname, arg)
213 // These are optimized to use X events (combined B and E). Much easier to do in C++ than in C.
214 class MTRScopedTrace {
216 MTRScopedTrace(const char *category, const char *name)
217 : category_(category), name_(name) {
218 start_time_ = mtr_time_s();
221 internal_mtr_raw_event(category_, name_, 'X', &start_time_);
225 const char *category_;
230 // Only outputs a block if execution time exceeded the limit.
231 // TODO: This will effectively call mtr_time_s twice at the end, which is bad.
232 class MTRScopedTraceLimit {
234 MTRScopedTraceLimit(const char *category, const char *name, double limit_s)
235 : category_(category), name_(name), limit_(limit_s) {
236 start_time_ = mtr_time_s();
238 ~MTRScopedTraceLimit() {
239 double end_time = mtr_time_s();
240 if (end_time - start_time_ >= limit_) {
241 internal_mtr_raw_event(category_, name_, 'X', &start_time_);
246 const char *category_;
252 class MTRScopedTraceArg {
254 MTRScopedTraceArg(const char *category, const char *name, mtr_arg_type arg_type, const char *arg_name, void *arg_value)
255 : category_(category), name_(name) {
256 internal_mtr_raw_event_arg(category, name, 'B', 0, arg_type, arg_name, arg_value);
258 ~MTRScopedTraceArg() {
259 internal_mtr_raw_event(category_, name_, 'E', 0);
263 const char *category_;