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 are for tracking application performance. | 5 // Trace events to track application performance. Events consist of a name |
| 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. |
6 // | 9 // |
7 // Events are issued against categories. Whereas LOG's | 10 // The current implementation logs these events into a log file of the form |
8 // categories are statically defined, TRACE categories are created | 11 // trace_<pid>.log where it's designed to be post-processed to generate a |
9 // implicitly with a string. For example: | 12 // trace report. In the future, it may use another mechansim to facilitate |
10 // TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent") | 13 // real-time analysis. |
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 | 14 |
40 #ifndef BASE_DEBUG_TRACE_EVENT_H_ | 15 #ifndef BASE_DEBUG_TRACE_EVENT_H_ |
41 #define BASE_DEBUG_TRACE_EVENT_H_ | 16 #define BASE_DEBUG_TRACE_EVENT_H_ |
42 #pragma once | 17 #pragma once |
43 | 18 |
44 #include "build/build_config.h" | 19 #include "build/build_config.h" |
45 | 20 |
| 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 |
46 #include <string> | 32 #include <string> |
47 #include <vector> | |
48 | 33 |
49 #include "base/callback.h" | 34 #include "base/memory/scoped_ptr.h" |
50 #include "base/memory/singleton.h" | 35 #include "base/memory/singleton.h" |
51 #include "base/string_util.h" | 36 #include "base/synchronization/lock.h" |
| 37 #include "base/time.h" |
52 #include "base/timer.h" | 38 #include "base/timer.h" |
53 | 39 |
54 // Older style trace macros with explicit id and extra data | 40 #ifndef CHROMIUM_ENABLE_TRACE_EVENT |
55 // Only these macros result in publishing data to ETW as currently implemented. | 41 #define TRACE_EVENT_BEGIN(name, id, extra) ((void) 0) |
56 #define TRACE_EVENT_BEGIN_ETW(name, id, extra) \ | 42 #define TRACE_EVENT_END(name, id, extra) ((void) 0) |
57 base::debug::TraceLog::AddTraceEventEtw( \ | 43 #define TRACE_EVENT_INSTANT(name, id, extra) ((void) 0) |
58 base::debug::TRACE_EVENT_PHASE_BEGIN, \ | |
59 __FILE__, __LINE__, name, reinterpret_cast<const void*>(id), extra); | |
60 | 44 |
61 #define TRACE_EVENT_END_ETW(name, id, extra) \ | 45 #else // CHROMIUM_ENABLE_TRACE_EVENT |
62 base::debug::TraceLog::AddTraceEventEtw( \ | 46 // Use the following macros rather than using the TraceLog class directly as the |
63 base::debug::TRACE_EVENT_PHASE_END, \ | 47 // underlying implementation may change in the future. Here's a sample usage: |
64 __FILE__, __LINE__, name, reinterpret_cast<const void*>(id), extra); | 48 // TRACE_EVENT_BEGIN("v8.run", documentId, scriptLocation); |
| 49 // RunScript(script); |
| 50 // TRACE_EVENT_END("v8.run", documentId, scriptLocation); |
65 | 51 |
66 #define TRACE_EVENT_INSTANT_ETW(name, id, extra) \ | 52 // Record that an event (of name, id) has begun. All BEGIN events should have |
67 base::debug::TraceLog::AddTraceEventEtw( \ | 53 // corresponding END events with a matching (name, id). |
68 base::debug::TRACE_EVENT_PHASE_INSTANT, \ | 54 #define TRACE_EVENT_BEGIN(name, id, extra) \ |
69 __FILE__, __LINE__, name, reinterpret_cast<const void*>(id), extra); | 55 base::debug::TraceLog::GetInstance()->Trace( \ |
| 56 name, \ |
| 57 base::debug::TraceLog::EVENT_BEGIN, \ |
| 58 reinterpret_cast<const void*>(id), \ |
| 59 extra, \ |
| 60 __FILE__, \ |
| 61 __LINE__) |
70 | 62 |
| 63 // Record that an event (of name, id) has ended. All END events should have |
| 64 // corresponding BEGIN events with a matching (name, id). |
| 65 #define TRACE_EVENT_END(name, id, extra) \ |
| 66 base::debug::TraceLog::GetInstance()->Trace( \ |
| 67 name, \ |
| 68 base::debug::TraceLog::EVENT_END, \ |
| 69 reinterpret_cast<const void*>(id), \ |
| 70 extra, \ |
| 71 __FILE__, \ |
| 72 __LINE__) |
71 | 73 |
72 // Implementation detail: trace event macros create temporary variables | 74 // Record that an event (of name, id) with no duration has happened. |
73 // to keep instrumentation overhead low. These macros give each temporary | 75 #define TRACE_EVENT_INSTANT(name, id, extra) \ |
74 // variable a unique name based on the line number to prevent name collissions. | 76 base::debug::TraceLog::GetInstance()->Trace( \ |
75 #define TRACE_EVENT_UNIQUE_IDENTIFIER3(a,b) a##b | 77 name, \ |
76 #define TRACE_EVENT_UNIQUE_IDENTIFIER2(a,b) \ | 78 base::debug::TraceLog::EVENT_INSTANT, \ |
77 TRACE_EVENT_UNIQUE_IDENTIFIER3(a,b) | 79 reinterpret_cast<const void*>(id), \ |
78 #define TRACE_EVENT_UNIQUE_IDENTIFIER(name_prefix) \ | 80 extra, \ |
79 TRACE_EVENT_UNIQUE_IDENTIFIER2(name_prefix, __LINE__) | 81 __FILE__, \ |
80 | 82 __LINE__) |
81 // Records a pair of begin and end events called "name" for the current | 83 #endif // CHROMIUM_ENABLE_TRACE_EVENT |
82 // scope, with 0, 1 or 2 associated arguments. If the category is not | |
83 // enabled, then this does nothing. | |
84 // - category and name strings must have application lifetime (statics or | |
85 // literals). They may not include " chars. | |
86 #define TRACE_EVENT0(category, name) \ | |
87 TRACE_EVENT1(category, name, NULL, 0) | |
88 #define TRACE_EVENT1(category, name, arg1_name, arg1_val) \ | |
89 TRACE_EVENT2(category, name, arg1_name, arg1_val, NULL, 0) | |
90 #define TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ | |
91 static const base::debug::TraceCategory* \ | |
92 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \ | |
93 base::debug::TraceLog::GetCategory(category); \ | |
94 if (TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic)->enabled) { \ | |
95 base::debug::TraceLog::GetInstance()->AddTraceEvent( \ | |
96 base::debug::TRACE_EVENT_PHASE_BEGIN, \ | |
97 __FILE__, __LINE__, \ | |
98 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \ | |
99 name, \ | |
100 arg1_name, arg1_val, \ | |
101 arg2_name, arg2_val); \ | |
102 } \ | |
103 base::debug::internal::TraceEndOnScopeClose \ | |
104 TRACE_EVENT_UNIQUE_IDENTIFIER(profileScope) ( \ | |
105 __FILE__, __LINE__, \ | |
106 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), name); | |
107 | |
108 // Records a single event called "name" immediately, with 0, 1 or 2 | |
109 // associated arguments. If the category is not enabled, then this | |
110 // does nothing. | |
111 // - category and name strings must have application lifetime (statics or | |
112 // literals). They may not include " chars. | |
113 #define TRACE_EVENT_INSTANT0(category, name) \ | |
114 TRACE_EVENT_INSTANT1(category, name, NULL, 0) | |
115 #define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ | |
116 TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, NULL, 0) | |
117 #define TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \ | |
118 arg2_name, arg2_val) \ | |
119 static const base::debug::TraceCategory* \ | |
120 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \ | |
121 base::debug::TraceLog::GetCategory(category); \ | |
122 if (TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic)->enabled) { \ | |
123 base::debug::TraceLog::GetInstance()->AddTraceEvent( \ | |
124 base::debug::TRACE_EVENT_PHASE_INSTANT, \ | |
125 __FILE__, __LINE__, \ | |
126 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \ | |
127 name, \ | |
128 arg1_name, arg1_val, \ | |
129 arg2_name, arg2_val); \ | |
130 } | |
131 | |
132 // Records a single BEGIN event called "name" immediately, with 0, 1 or 2 | |
133 // associated arguments. If the category is not enabled, then this | |
134 // does nothing. | |
135 // - category and name strings must have application lifetime (statics or | |
136 // literals). They may not include " chars. | |
137 #define TRACE_EVENT_BEGIN0(category, name) \ | |
138 TRACE_EVENT_BEGIN1(category, name, NULL, 0) | |
139 #define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \ | |
140 TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, NULL, 0) | |
141 #define TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, \ | |
142 arg2_name, arg2_val) \ | |
143 static const base::debug::TraceCategory* \ | |
144 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \ | |
145 base::debug::TraceLog::GetCategory(category); \ | |
146 if (TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic)->enabled) { \ | |
147 base::debug::TraceLog::GetInstance()->AddTraceEvent( \ | |
148 base::debug::TRACE_EVENT_PHASE_BEGIN, \ | |
149 __FILE__, __LINE__, \ | |
150 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \ | |
151 name, \ | |
152 arg1_name, arg1_val, \ | |
153 arg2_name, arg2_val); \ | |
154 } | |
155 | |
156 // Records a single END event for "name" immediately. If the category | |
157 // is not enabled, then this does nothing. | |
158 // - category and name strings must have application lifetime (statics or | |
159 // literals). They may not include " chars. | |
160 #define TRACE_EVENT_END0(category, name) \ | |
161 TRACE_EVENT_END1(category, name, NULL, 0) | |
162 #define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \ | |
163 TRACE_EVENT_END2(category, name, arg1_name, arg1_val, NULL, 0) | |
164 #define TRACE_EVENT_END2(category, name, arg1_name, arg1_val, \ | |
165 arg2_name, arg2_val) \ | |
166 static const base::debug::TraceCategory* \ | |
167 TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \ | |
168 base::debug::TraceLog::GetCategory(category); \ | |
169 if (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 arg1_name, arg1_val, \ | |
176 arg2_name, arg2_val); \ | |
177 } | |
178 | 84 |
179 namespace base { | 85 namespace base { |
180 | 86 |
| 87 class ProcessMetrics; |
| 88 |
181 namespace debug { | 89 namespace debug { |
182 | 90 |
183 // Categories allow enabling/disabling of streams of trace events | |
184 struct TraceCategory { | |
185 const char* name; | |
186 volatile bool enabled; | |
187 }; | |
188 | |
189 const size_t kTraceMaxNumArgs = 2; | |
190 | |
191 // Phase indicates the nature of an event entry. E.g. part of a begin/end pair. | |
192 enum TraceEventPhase { | |
193 TRACE_EVENT_PHASE_BEGIN, | |
194 TRACE_EVENT_PHASE_END, | |
195 TRACE_EVENT_PHASE_INSTANT | |
196 }; | |
197 | |
198 // Simple union of values. This is much lighter weight than base::Value, which | |
199 // requires dynamic allocation and a vtable. To keep the trace runtime overhead | |
200 // low, we want constant size storage here. | |
201 class BASE_API TraceValue { | |
202 public: | |
203 enum Type { | |
204 TRACE_TYPE_UNDEFINED, | |
205 TRACE_TYPE_BOOL, | |
206 TRACE_TYPE_UINT, | |
207 TRACE_TYPE_INT, | |
208 TRACE_TYPE_DOUBLE, | |
209 TRACE_TYPE_POINTER, | |
210 TRACE_TYPE_STRING | |
211 }; | |
212 | |
213 TraceValue() : type_(TRACE_TYPE_UNDEFINED) { | |
214 value_.as_uint = 0ull; | |
215 } | |
216 TraceValue(bool rhs) : type_(TRACE_TYPE_BOOL) { | |
217 value_.as_bool = rhs; | |
218 } | |
219 TraceValue(uint64 rhs) : type_(TRACE_TYPE_UINT) { | |
220 value_.as_uint = rhs; | |
221 } | |
222 TraceValue(uint32 rhs) : type_(TRACE_TYPE_UINT) { | |
223 value_.as_uint = rhs; | |
224 } | |
225 TraceValue(uint16 rhs) : type_(TRACE_TYPE_UINT) { | |
226 value_.as_uint = rhs; | |
227 } | |
228 TraceValue(uint8 rhs) : type_(TRACE_TYPE_UINT) { | |
229 value_.as_uint = rhs; | |
230 } | |
231 TraceValue(int64 rhs) : type_(TRACE_TYPE_INT) { | |
232 value_.as_int = rhs; | |
233 } | |
234 TraceValue(int32 rhs) : type_(TRACE_TYPE_INT) { | |
235 value_.as_int = rhs; | |
236 } | |
237 TraceValue(int16 rhs) : type_(TRACE_TYPE_INT) { | |
238 value_.as_int = rhs; | |
239 } | |
240 TraceValue(int8 rhs) : type_(TRACE_TYPE_INT) { | |
241 value_.as_int = rhs; | |
242 } | |
243 TraceValue(double rhs) : type_(TRACE_TYPE_DOUBLE) { | |
244 value_.as_double = rhs; | |
245 } | |
246 TraceValue(const void* rhs) : type_(TRACE_TYPE_POINTER) { | |
247 value_.as_pointer = rhs; | |
248 } | |
249 TraceValue(const char* rhs) : type_(TRACE_TYPE_STRING) { | |
250 value_.as_string_refptr = new RefCountedString(); | |
251 value_.as_string_refptr->AddRef(); | |
252 DCHECK(value_.as_string_refptr->HasOneRef()); | |
253 value_.as_string_refptr->data = rhs; | |
254 } | |
255 TraceValue(const TraceValue& rhs) : type_(TRACE_TYPE_UNDEFINED) { | |
256 operator=(rhs); | |
257 } | |
258 ~TraceValue() { | |
259 Destroy(); | |
260 } | |
261 | |
262 TraceValue& operator=(const TraceValue& rhs); | |
263 | |
264 void Destroy(); | |
265 | |
266 void AppendAsJSON(std::string* out) const; | |
267 | |
268 Type type() const { | |
269 return type_; | |
270 } | |
271 uint64 as_uint() const { | |
272 return value_.as_uint; | |
273 } | |
274 bool as_bool() const { | |
275 return value_.as_bool; | |
276 } | |
277 int64 as_int() const { | |
278 return value_.as_int; | |
279 } | |
280 double as_double() const { | |
281 return value_.as_double; | |
282 } | |
283 const void* as_pointer() const { | |
284 return value_.as_pointer; | |
285 } | |
286 const char* as_string() const { | |
287 return value_.as_string_refptr->data.c_str(); | |
288 } | |
289 | |
290 typedef RefCountedData<std::string> RefCountedString; | |
291 | |
292 private: | |
293 union Value { | |
294 bool as_bool; | |
295 uint64 as_uint; | |
296 int64 as_int; | |
297 double as_double; | |
298 const void* as_pointer; | |
299 RefCountedString* as_string_refptr; | |
300 }; | |
301 | |
302 Type type_; | |
303 Value value_; | |
304 }; | |
305 | |
306 // Output records are "Events" and can be obtained via the | |
307 // OutputCallback whenever the tracing system decides to flush. This | |
308 // can happen at any time, on any thread, or you can programatically | |
309 // force it to happen. | |
310 struct TraceEvent { | |
311 TraceEvent(); | |
312 ~TraceEvent(); | |
313 | |
314 // Serialize event data to JSON | |
315 static void AppendEventsAsJSON(const std::vector<TraceEvent>& events, | |
316 size_t start, | |
317 size_t count, | |
318 std::string* out); | |
319 void AppendAsJSON(std::string* out) const; | |
320 | |
321 | |
322 unsigned long process_id; | |
323 unsigned long thread_id; | |
324 TimeTicks timestamp; | |
325 TraceEventPhase phase; | |
326 const TraceCategory* category; | |
327 const char* name; | |
328 const char* arg_names[kTraceMaxNumArgs]; | |
329 TraceValue arg_values[kTraceMaxNumArgs]; | |
330 }; | |
331 | |
332 | |
333 class BASE_API TraceLog { | 91 class BASE_API TraceLog { |
334 public: | 92 public: |
| 93 enum EventType { |
| 94 EVENT_BEGIN, |
| 95 EVENT_END, |
| 96 EVENT_INSTANT |
| 97 }; |
| 98 |
335 static TraceLog* GetInstance(); | 99 static TraceLog* GetInstance(); |
336 | 100 |
337 // Global enable of tracing. Currently enables all categories or not. | 101 // Is tracing currently enabled. |
338 // TODO(scheib): Replace with an Enable/DisableCategory() that | 102 static bool IsTracing(); |
339 // implicitly controls the global logging state. | 103 // Start logging trace events. |
340 void SetEnabled(bool enabled); | 104 static bool StartTracing(); |
341 bool IsEnabled() { return enabled_; } | 105 // Stop logging trace events. |
| 106 static void StopTracing(); |
342 | 107 |
343 float GetBufferPercentFull() const; | 108 // Log a trace event of (name, type, id) with the optional extra string. |
344 | 109 void Trace(const std::string& name, |
345 // When enough events are collected, they are handed (in bulk) to | 110 EventType type, |
346 // the output callback. If no callback is set, the output will be | 111 const void* id, |
347 // silently dropped. The callback must be thread safe. | 112 const std::wstring& extra, |
348 typedef RefCountedData<std::string> RefCountedString; | 113 const char* file, |
349 typedef base::Callback<void(RefCountedString*)> OutputCallback; | 114 int line); |
350 void SetOutputCallback(const OutputCallback& cb); | 115 void Trace(const std::string& name, |
351 | 116 EventType type, |
352 // The trace buffer does not flush dynamically, so when it fills up, | 117 const void* id, |
353 // subsequent trace events will be dropped. This callback is generated when | 118 const std::string& extra, |
354 // the trace buffer is full. The callback must be thread safe. | 119 const char* file, |
355 typedef base::Callback<void(void)> BufferFullCallback; | 120 int line); |
356 void SetBufferFullCallback(const BufferFullCallback& cb); | |
357 | |
358 // Flushes all logged data to the callback. | |
359 void Flush(); | |
360 | |
361 // Called by TRACE_EVENT* macros, don't call this directly. | |
362 static const TraceCategory* GetCategory(const char* name); | |
363 | |
364 // Called by TRACE_EVENT* macros, don't call this directly. | |
365 void AddTraceEvent(TraceEventPhase phase, | |
366 const char* file, int line, | |
367 const TraceCategory* category, | |
368 const char* name, | |
369 const char* arg1_name, TraceValue arg1_val, | |
370 const char* arg2_name, TraceValue arg2_val); | |
371 static void AddTraceEventEtw(TraceEventPhase phase, | |
372 const char* file, int line, | |
373 const char* name, | |
374 const void* id, | |
375 const char* extra); | |
376 static void AddTraceEventEtw(TraceEventPhase phase, | |
377 const char* file, int line, | |
378 const char* name, | |
379 const void* id, | |
380 const std::string& extra) { | |
381 AddTraceEventEtw(phase, file, line, name, id, extra.c_str()); | |
382 } | |
383 | |
384 // Exposed for unittesting only, allows resurrecting our | |
385 // singleton instance post-AtExit processing. | |
386 static void Resurrect(); | |
387 | 121 |
388 private: | 122 private: |
389 // This allows constructor and destructor to be private and usable only | 123 // This allows constructor and destructor to be private and usable only |
390 // by the Singleton class. | 124 // by the Singleton class. |
391 friend struct StaticMemorySingletonTraits<TraceLog>; | 125 friend struct DefaultSingletonTraits<TraceLog>; |
392 | 126 |
393 TraceLog(); | 127 TraceLog(); |
394 ~TraceLog(); | 128 ~TraceLog(); |
395 const TraceCategory* GetCategoryInternal(const char* name); | 129 bool OpenLogFile(); |
| 130 void CloseLogFile(); |
| 131 bool Start(); |
| 132 void Stop(); |
| 133 void Heartbeat(); |
| 134 void Log(const std::string& msg); |
396 | 135 |
397 // TODO(nduca): switch to per-thread trace buffers to reduce thread | |
398 // synchronization. | |
399 Lock lock_; | |
400 bool enabled_; | 136 bool enabled_; |
401 OutputCallback output_callback_; | 137 FILE* log_file_; |
402 BufferFullCallback buffer_full_callback_; | 138 base::Lock file_lock_; |
403 std::vector<TraceEvent> logged_events_; | 139 TimeTicks trace_start_time_; |
404 | 140 scoped_ptr<base::ProcessMetrics> process_metrics_; |
405 DISALLOW_COPY_AND_ASSIGN(TraceLog); | 141 RepeatingTimer<TraceLog> timer_; |
406 }; | 142 }; |
407 | 143 |
408 namespace internal { | |
409 | |
410 // Used by TRACE_EVENTx macro. Do not use directly. | |
411 class BASE_API TraceEndOnScopeClose { | |
412 public: | |
413 TraceEndOnScopeClose(const char* file, int line, | |
414 const TraceCategory* category, | |
415 const char* name) | |
416 : file_(file) | |
417 , line_(line) | |
418 , category_(category) | |
419 , name_(name) { } | |
420 | |
421 ~TraceEndOnScopeClose() { | |
422 if (category_->enabled) | |
423 base::debug::TraceLog::GetInstance()->AddTraceEvent( | |
424 base::debug::TRACE_EVENT_PHASE_END, | |
425 file_, line_, | |
426 category_, | |
427 name_, | |
428 NULL, 0, NULL, 0); | |
429 } | |
430 | |
431 private: | |
432 const char* file_; | |
433 int line_; | |
434 const TraceCategory* category_; | |
435 const char* name_; | |
436 }; | |
437 | |
438 } // namespace internal | |
439 | |
440 } // namespace debug | 144 } // namespace debug |
441 } // namespace base | 145 } // namespace base |
442 | 146 |
| 147 #endif // defined(OS_WIN) |
| 148 |
443 #endif // BASE_DEBUG_TRACE_EVENT_H_ | 149 #endif // BASE_DEBUG_TRACE_EVENT_H_ |
OLD | NEW |