OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Trace events to track application performance. Events consist of a name | 5 // Trace events are for tracking application performance. |
6 // a type (BEGIN, END or INSTANT), a tracking id and extra string data. | |
7 // In addition, the current process id, thread id, a timestamp down to the | |
8 // microsecond and a file and line number of the calling location. | |
9 // | 6 // |
10 // The current implementation logs these events into a log file of the form | 7 // Events are issued against categories. Whereas LOG's |
11 // trace_<pid>.log where it's designed to be post-processed to generate a | 8 // categories are statically defined, TRACE categories are created |
12 // trace report. In the future, it may use another mechansim to facilitate | 9 // implicitly with a string. For example: |
13 // real-time analysis. | 10 // TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent") |
11 // | |
12 // Events can be INSTANT, or can be pairs of BEGIN and END: | |
13 // TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly") | |
14 // doSomethingCostly() | |
15 // TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly") | |
16 // | |
17 // A common use case is to trace entire function scopes. This | |
18 // issues a trace BEGIN and END automatically: | |
19 // void doSomethingCostly() { | |
20 // TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly"); | |
21 // ... | |
22 // } | |
23 // | |
24 // Additional parameters can be associated with an event: | |
25 // void doSomethingCostly2(int howMuch) { | |
26 // TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly", | |
27 // "howMuch", StringPrintf("%i", howMuch).c_str()); | |
28 // ... | |
29 // } | |
30 // | |
31 // The trace system will automatically add to this information the | |
32 // current process id, thread id, a timestamp down to the | |
33 // microsecond, as well as the file and line number of the calling location. | |
34 // | |
35 // By default, trace collection is compiled in, but turned off at runtime. | |
36 // Collecting trace data is the responsibility of the embedding | |
37 // application. In Chrome's case, navigating to about:gpu will turn on | |
38 // tracing and display data collected across all active processes. | |
39 // | |
40 // On Windows, the TRACE_EVENT output to ETW. | |
14 | 41 |
15 #ifndef BASE_DEBUG_TRACE_EVENT_H_ | 42 #ifndef BASE_DEBUG_TRACE_EVENT_H_ |
16 #define BASE_DEBUG_TRACE_EVENT_H_ | 43 #define BASE_DEBUG_TRACE_EVENT_H_ |
17 #pragma once | 44 #pragma once |
18 | 45 |
19 #include "build/build_config.h" | 46 #include "build/build_config.h" |
20 | 47 |
21 #if defined(OS_WIN) | |
22 // On Windows we always pull in an alternative implementation | |
23 // which logs to Event Tracing for Windows. | |
24 // | |
25 // Note that the Windows implementation is always enabled, irrespective the | |
26 // value of the CHROMIUM_ENABLE_TRACE_EVENT define. The Windows implementation | |
27 // is controlled by Event Tracing for Windows, which will turn tracing on only | |
28 // if there is someone listening for the events it generates. | |
29 #include "base/debug/trace_event_win.h" | |
30 #else // defined(OS_WIN) | |
31 | |
32 #include <string> | 48 #include <string> |
33 | 49 |
50 #include "base/atomicops.h" | |
51 #include "base/callback.h" | |
34 #include "base/memory/scoped_ptr.h" | 52 #include "base/memory/scoped_ptr.h" |
53 #include "base/memory/scoped_vector.h" | |
35 #include "base/memory/singleton.h" | 54 #include "base/memory/singleton.h" |
36 #include "base/synchronization/lock.h" | |
37 #include "base/time.h" | 55 #include "base/time.h" |
38 #include "base/timer.h" | 56 #include "base/timer.h" |
39 | 57 #include <vector> |
40 #ifndef CHROMIUM_ENABLE_TRACE_EVENT | 58 |
41 #define TRACE_EVENT_BEGIN(name, id, extra) ((void) 0) | 59 // Older style trace macros with explicit id and extra data |
42 #define TRACE_EVENT_END(name, id, extra) ((void) 0) | 60 // Only these macros result in publishing data to ETW as currently implemented. |
43 #define TRACE_EVENT_INSTANT(name, id, extra) ((void) 0) | 61 #define TRACE_EVENT_BEGIN_ETW(name, id, extra) \ |
44 | 62 base::debug::TraceLog::GetInstance()->AddTraceEventEtw( \ |
45 #else // CHROMIUM_ENABLE_TRACE_EVENT | 63 base::debug::TRACE_EVENT_PHASE_BEGIN, \ |
46 // Use the following macros rather than using the TraceLog class directly as the | 64 __FILE__, __LINE__, name, reinterpret_cast<const void*>(id), extra); |
47 // underlying implementation may change in the future. Here's a sample usage: | 65 |
48 // TRACE_EVENT_BEGIN("v8.run", documentId, scriptLocation); | 66 #define TRACE_EVENT_END_ETW(name, id, extra) \ |
49 // RunScript(script); | 67 base::debug::TraceLog::GetInstance()->AddTraceEventEtw( \ |
50 // TRACE_EVENT_END("v8.run", documentId, scriptLocation); | 68 base::debug::TRACE_EVENT_PHASE_END, \ |
51 | 69 __FILE__, __LINE__, name, reinterpret_cast<const void*>(id), extra); |
52 // Record that an event (of name, id) has begun. All BEGIN events should have | 70 |
53 // corresponding END events with a matching (name, id). | 71 #define TRACE_EVENT_INSTANT_ETW(name, id, extra) \ |
54 #define TRACE_EVENT_BEGIN(name, id, extra) \ | 72 base::debug::TraceLog::GetInstance()->AddTraceEventEtw( \ |
55 base::debug::TraceLog::GetInstance()->Trace( \ | 73 base::debug::TRACE_EVENT_PHASE_INSTANT, \ |
56 name, \ | 74 __FILE__, __LINE__, name, reinterpret_cast<const void*>(id), extra); |
57 base::debug::TraceLog::EVENT_BEGIN, \ | 75 |
58 reinterpret_cast<const void*>(id), \ | 76 |
59 extra, \ | 77 // Implementation detail: trace event macros create temporary variables |
60 __FILE__, \ | 78 // to keep instrumentation overhead low. These macros give each temporary |
61 __LINE__) | 79 // variable a unique name based on the line number to prevent name collissions. |
62 | 80 #define TRACE_EVENT_UNIQUE_IDENTIFIER3(a,b) a##b |
63 // Record that an event (of name, id) has ended. All END events should have | 81 #define TRACE_EVENT_UNIQUE_IDENTIFIER2(a,b) \ |
64 // corresponding BEGIN events with a matching (name, id). | 82 TRACE_EVENT_UNIQUE_IDENTIFIER3(a,b) |
65 #define TRACE_EVENT_END(name, id, extra) \ | 83 #define TRACE_EVENT_UNIQUE_IDENTIFIER(name_prefix) \ |
66 base::debug::TraceLog::GetInstance()->Trace( \ | 84 TRACE_EVENT_UNIQUE_IDENTIFIER2(name_prefix, __LINE__) |
67 name, \ | 85 |
68 base::debug::TraceLog::EVENT_END, \ | 86 // Records a pair of begin and end events called "name" for the current |
69 reinterpret_cast<const void*>(id), \ | 87 // scope, with 0, 1 or 2 associated arguments. If the category is not |
70 extra, \ | 88 // enabled, then this does nothing. |
71 __FILE__, \ | 89 #define TRACE_EVENT0(category, name) \ |
72 __LINE__) | 90 TRACE_EVENT1(category, name, NULL, NULL) |
73 | 91 #define TRACE_EVENT1(category, name, arg1name, arg1val) \ |
74 // Record that an event (of name, id) with no duration has happened. | 92 TRACE_EVENT2(category, name, arg1name, arg1val, NULL, NULL) |
75 #define TRACE_EVENT_INSTANT(name, id, extra) \ | 93 #define TRACE_EVENT2(category, name, arg1name, arg1val, arg2name, arg2val) \ |
Sigurður Ásgeirsson
2011/04/15 17:41:45
If I'm reading this correctly, these static pointe
scheib
2011/04/27 21:20:10
Done. Categories come from a static pool. A test f
| |
76 base::debug::TraceLog::GetInstance()->Trace( \ | 94 static base::debug::TraceCategory* \ |
77 name, \ | 95 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \ |
78 base::debug::TraceLog::EVENT_INSTANT, \ | 96 base::debug::TraceLog::GetInstance()->GetCategory(category); \ |
79 reinterpret_cast<const void*>(id), \ | 97 if (base::subtle::Acquire_Load(\ |
80 extra, \ | 98 &(TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic))->enabled_)) { \ |
81 __FILE__, \ | 99 base::debug::TraceLog::GetInstance()->AddTraceEvent( \ |
82 __LINE__) | 100 base::debug::TRACE_EVENT_PHASE_BEGIN, \ |
Sigurður Ásgeirsson
2011/04/15 17:41:45
a unittest to validate arguments are not evaluated
scheib
2011/04/27 21:20:10
Good test, captured in http://crbug.com/80709 can
| |
83 #endif // CHROMIUM_ENABLE_TRACE_EVENT | 101 __FILE__, __LINE__, \ |
102 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \ | |
103 name, \ | |
104 arg1name, arg1val, \ | |
105 arg2name, arg2val); \ | |
106 } \ | |
107 base::debug::internal::TraceEndOnScopeClose __profileScope ## __LINE ( \ | |
108 __FILE__, __LINE__, \ | |
109 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), name); | |
110 | |
111 // Records a single event called "name" immediately, with 0, 1 or 2 | |
112 // associated arguments. If the category is not enabled, then this | |
113 // does nothing. | |
114 #define TRACE_EVENT_INSTANT0(category, name) \ | |
115 TRACE_EVENT_INSTANT1(category, name, NULL, NULL) | |
116 #define TRACE_EVENT_INSTANT1(category, name, arg1name, arg1val) \ | |
117 TRACE_EVENT_INSTANT2(category, name, arg1name, arg1val, NULL, NULL) | |
118 #define TRACE_EVENT_INSTANT2(category, name, arg1name, arg1val, \ | |
119 arg2name, arg2val) \ | |
120 static base::debug::TraceCategory* \ | |
121 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \ | |
122 base::debug::TraceLog::GetInstance()->GetCategory(category); \ | |
123 if (base::subtle::Acquire_Load( \ | |
124 &(TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic))->enabled_)) { \ | |
125 base::debug::TraceLog::GetInstance()->AddTraceEvent( \ | |
126 base::debug::TRACE_EVENT_PHASE_INSTANT, \ | |
127 __FILE__, __LINE__, \ | |
128 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \ | |
129 name, \ | |
130 arg1name, arg1val, \ | |
131 arg2name, arg2val); \ | |
132 } | |
133 | |
134 // Records a single BEGIN event called "name" immediately, with 0, 1 or 2 | |
135 // associated arguments. If the category is not enabled, then this | |
136 // does nothing. | |
137 #define TRACE_EVENT_BEGIN0(category, name) \ | |
138 TRACE_EVENT_BEGIN1(category, name, NULL, NULL) | |
139 #define TRACE_EVENT_BEGIN1(category, name, arg1name, arg1val) \ | |
140 TRACE_EVENT_BEGIN2(category, name, arg1name, arg1val, NULL, NULL) | |
141 #define TRACE_EVENT_BEGIN2(category, name, arg1name, arg1val, \ | |
142 arg2name, arg2val) \ | |
143 static base::debug::TraceCategory* \ | |
144 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \ | |
145 base::debug::TraceLog::GetInstance()->GetCategory(category); \ | |
146 if (base::subtle::Acquire_Load( \ | |
147 &(TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic))->enabled_)) { \ | |
148 base::debug::TraceLog::GetInstance()->AddTraceEvent( \ | |
149 base::debug::TRACE_EVENT_PHASE_BEGIN, \ | |
150 __FILE__, __LINE__, \ | |
151 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \ | |
152 name, \ | |
153 arg1name, arg1val, \ | |
154 arg2name, arg2val); \ | |
155 } | |
156 | |
157 // Records a single END event for "name" immediately. If the category | |
158 // is not enabled, then this does nothing. | |
159 #define TRACE_EVENT_END0(category, name) \ | |
160 TRACE_EVENT_END1(category, name, NULL, NULL) | |
161 #define TRACE_EVENT_END1(category, name, arg1name, arg1val) \ | |
162 TRACE_EVENT_END2(category, name, arg1name, arg1val, NULL, NULL) | |
163 #define TRACE_EVENT_END2(category, name, arg1name, arg1val, \ | |
164 arg2name, arg2val) \ | |
165 static base::debug::TraceCategory* \ | |
166 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \ | |
167 base::debug::TraceLog::GetInstance()->GetCategory(category); \ | |
168 if (base::subtle::Acquire_Load( \ | |
169 &(TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic))->enabled_)) { \ | |
170 base::debug::TraceLog::GetInstance()->AddTraceEvent( \ | |
171 base::debug::TRACE_EVENT_PHASE_END, \ | |
172 __FILE__, __LINE__, \ | |
173 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \ | |
174 name, \ | |
175 arg1name, arg1val, \ | |
176 arg2name, arg2val); \ | |
177 } | |
84 | 178 |
85 namespace base { | 179 namespace base { |
86 | 180 |
87 class ProcessMetrics; | |
88 | |
89 namespace debug { | 181 namespace debug { |
90 | 182 |
183 // Categories allow enabling/disabling of streams of trace events | |
184 // Don't manipulate the category object directly, as this may lead | |
185 // to threading issues. Use the TraceLog methods instead. | |
186 class TraceCategory { | |
187 public: | |
188 TraceCategory(const char* name, bool enabled); | |
189 ~TraceCategory(); | |
190 | |
191 const char* name() const { return name_; } | |
192 | |
193 // NEVER read these directly, let the macros do it for you | |
194 volatile base::subtle::Atomic32 enabled_; | |
Sigurður Ásgeirsson
2011/04/15 17:41:45
maybe wrap this in an inline accessor used by the
scheib
2011/04/27 21:20:10
Removed, it was not needed. Just a volatile bool n
| |
195 protected: | |
196 const char* name_; | |
197 }; | |
198 | |
199 #define TRACE_MAX_NUM_ARGS 2 | |
200 | |
201 enum TraceEventPhase { | |
202 TRACE_EVENT_PHASE_BEGIN, | |
203 TRACE_EVENT_PHASE_END, | |
204 TRACE_EVENT_PHASE_INSTANT | |
205 }; | |
206 | |
207 // Output records are "Events" and can be obtained via the | |
208 // OutputCallback whenever the logging system decides to flush. This | |
Sigurður Ásgeirsson
2011/04/15 17:41:45
logging system -> tracing system?
scheib
2011/04/27 21:20:10
Done.
| |
209 // can happen at any time, on any thread, or you can programatically | |
210 // force it to happen. | |
211 struct TraceEvent { | |
212 static void AppendAsJSON(std::string* out, | |
Sigurður Ásgeirsson
2011/04/15 17:41:45
one line comment for method purpose and/or usage?
scheib
2011/04/27 21:20:10
Done.
| |
213 const std::vector<TraceEvent>& events, | |
214 size_t start, | |
215 size_t count); | |
216 TraceEvent(); | |
217 ~TraceEvent(); | |
218 void AppendAsJSON(std::string* out) const; | |
219 | |
220 | |
221 unsigned long processId; | |
Sigurður Ásgeirsson
2011/04/15 17:41:45
nit: process_id, thread_id, arg_names, arg_values
scheib
2011/04/27 21:20:10
Done.
| |
222 unsigned long threadId; | |
223 TimeTicks timestamp; | |
224 TraceEventPhase phase; | |
225 TraceCategory* category; | |
226 const char* name; | |
227 const char* argNames[TRACE_MAX_NUM_ARGS]; | |
228 std::string argValues[TRACE_MAX_NUM_ARGS]; | |
229 }; | |
230 | |
231 | |
91 class TraceLog { | 232 class TraceLog { |
92 public: | 233 public: |
93 enum EventType { | |
94 EVENT_BEGIN, | |
95 EVENT_END, | |
96 EVENT_INSTANT | |
97 }; | |
98 | 234 |
99 static TraceLog* GetInstance(); | 235 static TraceLog* GetInstance(); |
100 | 236 |
101 // Is tracing currently enabled. | 237 // Global enable of tracing. Currently enables all categories or not. |
102 static bool IsTracing(); | 238 // TODO(nduca) Replaced with an Enable/DisableCategory() that |
Sigurður Ásgeirsson
2011/04/15 17:41:45
missing colon after TODO,
nduca->shceib?
Replaced
scheib
2011/04/27 21:20:10
Done.
| |
103 // Start logging trace events. | 239 // implicitly controls the global logging state. |
Sigurður Ásgeirsson
2011/04/15 17:41:45
control->controls?
scheib
2011/04/27 21:20:10
Done.
| |
104 static bool StartTracing(); | 240 void SetEnabled(bool enabled); |
105 // Stop logging trace events. | 241 |
106 static void StopTracing(); | 242 // When enough events are collected, they are handed (in bulk) to |
107 | 243 // the output callback. If no callback is set, the output will be |
108 // Log a trace event of (name, type, id) with the optional extra string. | 244 // silently dropped. |
Sigurður Ásgeirsson
2011/04/15 17:41:45
Add a note that this takes ownership of the callba
scheib
2011/04/27 21:20:10
Done.
| |
109 void Trace(const std::string& name, | 245 typedef Callback1<const std::string& /* json_events */>::Type OutputCallback; |
110 EventType type, | 246 void SetOutputCallback(OutputCallback* cb); |
111 const void* id, | 247 |
112 const std::wstring& extra, | 248 // Forwards data collected by a child process to the registered |
113 const char* file, | 249 // output callback. |
Sigurður Ásgeirsson
2011/04/15 17:41:45
nit: one space only after //
scheib
2011/04/27 21:20:10
Done.
| |
114 int line); | 250 void AddRemotelyCollectedData(const std::string& json_events); |
115 void Trace(const std::string& name, | 251 |
116 EventType type, | 252 // Flushes all logged data to the callback. |
117 const void* id, | 253 void Flush(); |
118 const std::string& extra, | 254 |
119 const char* file, | 255 // Called by TRACE_EVENT* macros, don't call this directly. |
120 int line); | 256 TraceCategory* GetCategory(const char* name); |
257 | |
258 // Called by TRACE_EVENT* macros, don't call this directly. | |
259 void AddTraceEvent(TraceEventPhase phase, | |
260 const char* file, int line, | |
261 TraceCategory* category, | |
262 const char* name, | |
263 const char* arg1name, const char* arg1val, | |
264 const char* arg2name, const char* arg2val); | |
265 void AddTraceEventEtw(TraceEventPhase phase, | |
266 const char* file, int line, | |
267 const char* name, | |
268 const void* id, | |
269 const char* extra); | |
270 void AddTraceEventEtw(TraceEventPhase phase, | |
271 const char* file, int line, | |
272 const char* name, | |
273 const void* id, | |
274 const std::string& extra) { | |
275 AddTraceEventEtw(phase, file, line, name, id, extra.c_str()); | |
276 } | |
121 | 277 |
122 private: | 278 private: |
123 // This allows constructor and destructor to be private and usable only | 279 // This allows constructor and destructor to be private and usable only |
124 // by the Singleton class. | 280 // by the Singleton class. |
125 friend struct DefaultSingletonTraits<TraceLog>; | 281 friend struct StaticMemorySingletonTraits<TraceLog>; |
126 | 282 |
127 TraceLog(); | 283 TraceLog(); |
128 ~TraceLog(); | 284 ~TraceLog(); |
129 bool OpenLogFile(); | 285 void FlushWithLockAlreadyHeld(); |
130 void CloseLogFile(); | 286 |
131 bool Start(); | 287 // TODO(nduca): switch to per-thread tace buffers to reduce thread |
Sigurður Ásgeirsson
2011/04/15 17:41:45
tace->trace?
scheib
2011/04/27 21:20:10
Done.
| |
132 void Stop(); | 288 // synchronization. |
133 void Heartbeat(); | 289 Lock lock_; |
134 void Log(const std::string& msg); | |
135 | |
136 bool enabled_; | 290 bool enabled_; |
137 FILE* log_file_; | 291 ScopedVector<TraceCategory> categories_; |
138 base::Lock file_lock_; | 292 scoped_ptr<OutputCallback> output_callback_; |
139 TimeTicks trace_start_time_; | 293 std::vector<TraceEvent> logged_events_; |
140 scoped_ptr<base::ProcessMetrics> process_metrics_; | 294 |
141 RepeatingTimer<TraceLog> timer_; | 295 DISALLOW_COPY_AND_ASSIGN(TraceLog); |
142 }; | 296 }; |
297 | |
298 namespace internal { | |
299 | |
300 // Used by TRACE_EVENTx macro. Do not use directly. | |
301 class TraceEndOnScopeClose { | |
302 public: | |
303 TraceEndOnScopeClose(const char* file, int line, | |
304 TraceCategory* category, | |
305 const char* name) | |
306 : file_(file) | |
307 , line_(line) | |
308 , category_(category) | |
309 , name_(name) { } | |
310 | |
311 ~TraceEndOnScopeClose() { | |
312 if (base::subtle::Acquire_Load(&category_->enabled_)) | |
313 base::debug::TraceLog::GetInstance()->AddTraceEvent( | |
314 base::debug::TRACE_EVENT_PHASE_END, | |
315 file_, line_, | |
316 category_, | |
317 name_, | |
318 NULL, NULL, NULL, NULL); | |
319 } | |
320 | |
321 private: | |
322 const char* file_; | |
323 int line_; | |
324 TraceCategory* category_; | |
325 const char* name_; | |
326 }; | |
327 | |
328 } // namespace internal | |
143 | 329 |
144 } // namespace debug | 330 } // namespace debug |
145 } // namespace base | 331 } // namespace base |
146 | 332 |
147 #endif // defined(OS_WIN) | |
148 | |
149 #endif // BASE_DEBUG_TRACE_EVENT_H_ | 333 #endif // BASE_DEBUG_TRACE_EVENT_H_ |
OLD | NEW |