Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: base/debug/trace_event.h

Issue 6933035: Revert 84284 - Merge gpu_trace_event back into base/debug/trace_event.Initial land attempt at htt... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/base.gypi ('k') | base/debug/trace_event.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 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 bool operator!=(const TraceValue& rhs) const {
264 return !operator==(rhs);
265 }
266
267 void Destroy();
268
269 void AppendAsJSON(std::string* out) const;
270
271 Type type() const {
272 return type_;
273 }
274 uint64 as_uint() const {
275 return value_.as_uint;
276 }
277 bool as_bool() const {
278 return value_.as_bool;
279 }
280 int64 as_int() const {
281 return value_.as_int;
282 }
283 double as_double() const {
284 return value_.as_double;
285 }
286 const void* as_pointer() const {
287 return value_.as_pointer;
288 }
289 const char* as_string() const {
290 return value_.as_string_refptr->data.c_str();
291 }
292
293 typedef RefCountedData<std::string> RefCountedString;
294
295 private:
296 union Value {
297 bool as_bool;
298 uint64 as_uint;
299 int64 as_int;
300 double as_double;
301 const void* as_pointer;
302 RefCountedString* as_string_refptr;
303 };
304
305 bool operator==(const TraceValue& rhs) const;
306
307 Type type_;
308 Value value_;
309 };
310
311 // Output records are "Events" and can be obtained via the
312 // OutputCallback whenever the tracing system decides to flush. This
313 // can happen at any time, on any thread, or you can programatically
314 // force it to happen.
315 struct TraceEvent {
316 TraceEvent();
317 ~TraceEvent();
318
319 // Serialize event data to JSON
320 static void AppendEventsAsJSON(const std::vector<TraceEvent>& events,
321 size_t start,
322 size_t count,
323 std::string* out);
324 void AppendAsJSON(std::string* out) const;
325
326
327 unsigned long process_id;
328 unsigned long thread_id;
329 TimeTicks timestamp;
330 TraceEventPhase phase;
331 const TraceCategory* category;
332 const char* name;
333 const char* arg_names[kTraceMaxNumArgs];
334 TraceValue arg_values[kTraceMaxNumArgs];
335 };
336
337
338 class BASE_API TraceLog { 91 class BASE_API TraceLog {
339 public: 92 public:
93 enum EventType {
94 EVENT_BEGIN,
95 EVENT_END,
96 EVENT_INSTANT
97 };
98
340 static TraceLog* GetInstance(); 99 static TraceLog* GetInstance();
341 100
342 // Global enable of tracing. Currently enables all categories or not. 101 // Is tracing currently enabled.
343 // TODO(scheib): Replace with an Enable/DisableCategory() that 102 static bool IsTracing();
344 // implicitly controls the global logging state. 103 // Start logging trace events.
345 void SetEnabled(bool enabled); 104 static bool StartTracing();
346 bool IsEnabled() { return enabled_; } 105 // Stop logging trace events.
106 static void StopTracing();
347 107
348 float GetBufferPercentFull() const; 108 // Log a trace event of (name, type, id) with the optional extra string.
349 109 void Trace(const std::string& name,
350 // When enough events are collected, they are handed (in bulk) to 110 EventType type,
351 // the output callback. If no callback is set, the output will be 111 const void* id,
352 // silently dropped. The callback must be thread safe. 112 const std::wstring& extra,
353 typedef RefCountedData<std::string> RefCountedString; 113 const char* file,
354 typedef base::Callback<void(RefCountedString*)> OutputCallback; 114 int line);
355 void SetOutputCallback(const OutputCallback& cb); 115 void Trace(const std::string& name,
356 116 EventType type,
357 // The trace buffer does not flush dynamically, so when it fills up, 117 const void* id,
358 // subsequent trace events will be dropped. This callback is generated when 118 const std::string& extra,
359 // the trace buffer is full. The callback must be thread safe. 119 const char* file,
360 typedef base::Callback<void(void)> BufferFullCallback; 120 int line);
361 void SetBufferFullCallback(const BufferFullCallback& cb);
362
363 // Flushes all logged data to the callback.
364 void Flush();
365
366 // Called by TRACE_EVENT* macros, don't call this directly.
367 static const TraceCategory* GetCategory(const char* name);
368
369 // Called by TRACE_EVENT* macros, don't call this directly.
370 void AddTraceEvent(TraceEventPhase phase,
371 const char* file, int line,
372 const TraceCategory* category,
373 const char* name,
374 const char* arg1_name, TraceValue arg1_val,
375 const char* arg2_name, TraceValue arg2_val);
376 static void AddTraceEventEtw(TraceEventPhase phase,
377 const char* file, int line,
378 const char* name,
379 const void* id,
380 const char* extra);
381 static void AddTraceEventEtw(TraceEventPhase phase,
382 const char* file, int line,
383 const char* name,
384 const void* id,
385 const std::string& extra) {
386 AddTraceEventEtw(phase, file, line, name, id, extra.c_str());
387 }
388
389 // Exposed for unittesting only, allows resurrecting our
390 // singleton instance post-AtExit processing.
391 static void Resurrect();
392 121
393 private: 122 private:
394 // This allows constructor and destructor to be private and usable only 123 // This allows constructor and destructor to be private and usable only
395 // by the Singleton class. 124 // by the Singleton class.
396 friend struct StaticMemorySingletonTraits<TraceLog>; 125 friend struct DefaultSingletonTraits<TraceLog>;
397 126
398 TraceLog(); 127 TraceLog();
399 ~TraceLog(); 128 ~TraceLog();
400 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);
401 135
402 // TODO(nduca): switch to per-thread trace buffers to reduce thread
403 // synchronization.
404 Lock lock_;
405 bool enabled_; 136 bool enabled_;
406 OutputCallback output_callback_; 137 FILE* log_file_;
407 BufferFullCallback buffer_full_callback_; 138 base::Lock file_lock_;
408 std::vector<TraceEvent> logged_events_; 139 TimeTicks trace_start_time_;
409 140 scoped_ptr<base::ProcessMetrics> process_metrics_;
410 DISALLOW_COPY_AND_ASSIGN(TraceLog); 141 RepeatingTimer<TraceLog> timer_;
411 }; 142 };
412 143
413 namespace internal {
414
415 // Used by TRACE_EVENTx macro. Do not use directly.
416 class TraceEndOnScopeClose {
417 public:
418 TraceEndOnScopeClose(const char* file, int line,
419 const TraceCategory* category,
420 const char* name)
421 : file_(file)
422 , line_(line)
423 , category_(category)
424 , name_(name) { }
425
426 ~TraceEndOnScopeClose() {
427 if (category_->enabled)
428 base::debug::TraceLog::GetInstance()->AddTraceEvent(
429 base::debug::TRACE_EVENT_PHASE_END,
430 file_, line_,
431 category_,
432 name_,
433 NULL, 0, NULL, 0);
434 }
435
436 private:
437 const char* file_;
438 int line_;
439 const TraceCategory* category_;
440 const char* name_;
441 };
442
443 } // namespace internal
444
445 } // namespace debug 144 } // namespace debug
446 } // namespace base 145 } // namespace base
447 146
147 #endif // defined(OS_WIN)
148
448 #endif // BASE_DEBUG_TRACE_EVENT_H_ 149 #endif // BASE_DEBUG_TRACE_EVENT_H_
OLDNEW
« no previous file with comments | « base/base.gypi ('k') | base/debug/trace_event.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698