Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 automaticlaly add to this information the | |
|
Ken Russell (switch to Gerrit)
2011/02/25 00:56:36
typo: automaticlaly
| |
| 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 | |
|
rvargas (doing something else)
2011/02/25 23:38:33
Is this really going to be the case?.
nduca
2011/03/02 04:15:12
This is a bit of a typo. The real answer is that t
| |
| 38 // tracing and display data collected across all active processes. | |
| 39 // | |
| 40 // On Windows, the TRACE_EVENT_*_LEGACY macros 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 |
| 34 #include "base/scoped_ptr.h" | 50 #include "base/scoped_ptr.h" |
| 51 #include "base/scoped_vector.h" | |
| 52 #include "base/atomicops.h" | |
| 35 #include "base/singleton.h" | 53 #include "base/singleton.h" |
| 36 #include "base/synchronization/lock.h" | |
| 37 #include "base/time.h" | 54 #include "base/time.h" |
| 38 #include "base/timer.h" | 55 #include "base/timer.h" |
| 39 | 56 #include "base/callback.h" |
| 40 #ifndef CHROMIUM_ENABLE_TRACE_EVENT | 57 #include <vector> |
| 41 #define TRACE_EVENT_BEGIN(name, id, extra) ((void) 0) | 58 |
| 42 #define TRACE_EVENT_END(name, id, extra) ((void) 0) | 59 #define UNIQUE_IDENTIFIER3(a,b) a##b |
|
brettw
2011/02/25 18:30:03
I don't think it's a good idea to leak these gener
| |
| 43 #define TRACE_EVENT_INSTANT(name, id, extra) ((void) 0) | 60 #define UNIQUE_IDENTIFIER2(a,b) UNIQUE_IDENTIFIER3(a,b) // __LINE__ eval forced |
|
Ken Russell (switch to Gerrit)
2011/02/25 00:56:36
Is this forced evaluation of the __LINE__ macro gu
| |
| 44 | 61 #define UNIQUE_IDENTIFIER(name_prefix) UNIQUE_IDENTIFIER2(name_prefix, __LINE__) |
| 45 #else // CHROMIUM_ENABLE_TRACE_EVENT | 62 |
| 46 // Use the following macros rather than using the TraceLog class directly as the | 63 // Records a begin and end event called "name" for the beginning and |
| 47 // underlying implementation may change in the future. Here's a sample usage: | 64 // end of the current scope, with one associated argument. If the |
|
Ken Russell (switch to Gerrit)
2011/02/25 00:56:36
"with one associated argument" -- is this accurate
| |
| 48 // TRACE_EVENT_BEGIN("v8.run", documentId, scriptLocation); | 65 // category is not enabled, then this does nothing.# |
| 49 // RunScript(script); | 66 #define TRACE_EVENT0(category, name) \ |
| 50 // TRACE_EVENT_END("v8.run", documentId, scriptLocation); | 67 TRACE_EVENT1(category, name, NULL, NULL) |
| 51 | 68 #define TRACE_EVENT1(category, name, arg1name, arg1val) \ |
| 52 // Record that an event (of name, id) has begun. All BEGIN events should have | 69 TRACE_EVENT2(category, name, arg1name, arg1val, NULL, NULL) |
| 53 // corresponding END events with a matching (name, id). | 70 #define TRACE_EVENT2(category, name, arg1name, arg1val, arg2name, arg2val) \ |
| 54 #define TRACE_EVENT_BEGIN(name, id, extra) \ | 71 static base::debug::TraceCategory* UNIQUE_IDENTIFIER(catstatic) = \ |
|
brettw
2011/02/25 18:30:03
Is this static really necessary? Can you just call
nduca
2011/03/02 04:15:12
I should probably have been more clear in the code
| |
| 55 base::debug::TraceLog::GetInstance()->Trace( \ | 72 base::debug::TraceLog::GetInstance()->GetCategory(category); \ |
| 56 name, \ | 73 if (base::subtle::Acquire_Load(&(UNIQUE_IDENTIFIER(catstatic))->enabled_)) \ |
| 57 base::debug::TraceLog::EVENT_BEGIN, \ | 74 base::debug::TraceLog::GetInstance()->AddTraceEvent( \ |
| 58 reinterpret_cast<const void*>(id), \ | 75 base::debug::TRACE_EVENT_PHASE_BEGIN, \ |
|
brettw
2011/02/25 18:30:03
Indent wrapped lines 4 spaces. Same elsewhere.
| |
| 59 extra, \ | 76 __FILE__, __LINE__, \ |
| 60 __FILE__, \ | 77 UNIQUE_IDENTIFIER(catstatic), \ |
| 61 __LINE__) | 78 name, \ |
| 62 | 79 arg1name, arg1val, \ |
| 63 // Record that an event (of name, id) has ended. All END events should have | 80 arg2name, arg2val); \ |
| 64 // corresponding BEGIN events with a matching (name, id). | 81 base::debug::TraceEndOnScopeClose __profileScope ## __LINE (__FILE__, \ |
| 65 #define TRACE_EVENT_END(name, id, extra) \ | 82 __LINE__, UNIQUE_IDENTIFIER(catstatic), name); |
| 66 base::debug::TraceLog::GetInstance()->Trace( \ | 83 |
| 67 name, \ | 84 // Records a single event called "name" immediately, with one |
| 68 base::debug::TraceLog::EVENT_END, \ | 85 // associated argument. If the category is not enabled, then this |
|
Ken Russell (switch to Gerrit)
2011/02/25 00:56:36
Same question here.
| |
| 69 reinterpret_cast<const void*>(id), \ | 86 // does nothing. |
| 70 extra, \ | 87 #define TRACE_EVENT_INSTANT0(category, name) \ |
| 71 __FILE__, \ | 88 TRACE_EVENT_INSTANT1(category, name, NULL, NULL) |
| 72 __LINE__) | 89 #define TRACE_EVENT_INSTANT1(category, name, arg1name, arg1val) \ |
| 73 | 90 TRACE_EVENT_INSTANT2(category, name, arg1name, arg1val, NULL, NULL) |
| 74 // Record that an event (of name, id) with no duration has happened. | 91 #define TRACE_EVENT_INSTANT2(category, name, arg1name, arg1val, \ |
| 75 #define TRACE_EVENT_INSTANT(name, id, extra) \ | 92 arg2name, arg2val) \ |
| 76 base::debug::TraceLog::GetInstance()->Trace( \ | 93 static base::debug::TraceCategory* UNIQUE_IDENTIFIER(catstatic) = \ |
| 77 name, \ | 94 base::debug::TraceLog::GetInstance()->GetCategory(category); \ |
| 78 base::debug::TraceLog::EVENT_INSTANT, \ | 95 if (base::subtle::Acquire_Load(&(UNIQUE_IDENTIFIER(catstatic))->enabled_)) \ |
| 79 reinterpret_cast<const void*>(id), \ | 96 base::debug::TraceLog::GetInstance()->AddTraceEvent( \ |
| 80 extra, \ | 97 base::debug::TRACE_EVENT_PHASE_INSTANT, \ |
| 81 __FILE__, \ | 98 __FILE__, __LINE__, \ |
| 82 __LINE__) | 99 UNIQUE_IDENTIFIER(catstatic), \ |
| 83 #endif // CHROMIUM_ENABLE_TRACE_EVENT | 100 name, \ |
| 101 arg1name, arg1val, \ | |
| 102 arg2name, arg2val); \ | |
| 103 | |
| 104 | |
| 105 // Use these when you want to issue BEGIN and ENDs across ordinary | |
| 106 // scope boundaries. | |
| 107 #define TRACE_EVENT_BEGIN0(category, name) \ | |
| 108 TRACE_EVENT_BEGIN1(category, name, NULL, NULL) | |
| 109 #define TRACE_EVENT_BEGIN1(category, name, arg1name, arg1val) \ | |
| 110 TRACE_EVENT_BEGIN2(category, name, arg1name, arg1val, NULL, NULL) | |
| 111 #define TRACE_EVENT_BEGIN2(category, name, arg1name, arg1val, \ | |
| 112 arg2name, arg2val) \ | |
| 113 static base::debug::TraceCategory* UNIQUE_IDENTIFIER(catstatic) = \ | |
| 114 base::debug::TraceLog::GetInstance()->GetCategory(category); \ | |
| 115 if (base::subtle::Acquire_Load(&(UNIQUE_IDENTIFIER(catstatic))->enabled_)) \ | |
| 116 base::debug::TraceLog::GetInstance()->AddTraceEvent( \ | |
| 117 base::debug::TRACE_EVENT_PHASE_BEGIN, \ | |
| 118 __FILE__, __LINE__, \ | |
| 119 UNIQUE_IDENTIFIER(catstatic), \ | |
| 120 name, \ | |
| 121 arg1name, arg1val, \ | |
| 122 arg2name, arg2val); | |
| 123 | |
| 124 #define TRACE_EVENT_END(category, name) \ | |
| 125 static base::debug::TraceCategory* UNIQUE_IDENTIFIER(catstatic) = \ | |
| 126 base::debug::TraceLog::GetInstance()->GetCategory(category); \ | |
| 127 if (base::subtle::Acquire_Load(&(UNIQUE_IDENTIFIER(catstatic))->enabled_)) \ | |
|
brettw
2011/02/25 18:30:03
Multi-line conditions should use {}
| |
| 128 base::debug::TraceLog::GetInstance()->AddTraceEvent( \ | |
| 129 base::debug::TRACE_EVENT_PHASE_END, \ | |
| 130 __FILE__, __LINE__, \ | |
| 131 UNIQUE_IDENTIFIER(catstatic), \ | |
| 132 name, \ | |
| 133 arg1name, arg1val, \ | |
| 134 arg2name, arg2val); | |
| 135 | |
| 136 | |
| 137 // LEGACY trace macro support | |
| 138 #define TRACE_EVENT_BEGIN_LEGACY(name, id, extra) \ | |
| 139 base::debug::TraceLog::GetInstance()->AddTraceEventLegacy( \ | |
| 140 base::debug::TRACE_EVENT_PHASE_BEGIN, \ | |
| 141 __FILE__, __LINE__, name, reinterpret_cast<const void*>(id), extra); | |
| 142 | |
| 143 #define TRACE_EVENT_END_LEGACY(name, id, extra) \ | |
| 144 base::debug::TraceLog::GetInstance()->AddTraceEventLegacy( \ | |
| 145 base::debug::TRACE_EVENT_PHASE_END, \ | |
| 146 __FILE__, __LINE__, name, reinterpret_cast<const void*>(id), extra); | |
| 147 | |
| 148 #define TRACE_EVENT_INSTANT_LEGACY(name, id, extra) \ | |
| 149 base::debug::TraceLog::GetInstance()->AddTraceEventLegacy( \ | |
| 150 base::debug::TRACE_EVENT_PHASE_INSTANT, \ | |
| 151 __FILE__, __LINE__, name, reinterpret_cast<const void*>(id), extra); | |
| 84 | 152 |
| 85 namespace base { | 153 namespace base { |
| 86 | 154 |
| 87 class ProcessMetrics; | |
| 88 | |
| 89 namespace debug { | 155 namespace debug { |
| 90 | 156 |
| 157 // Categories allow enabling/disabling of streams of trace events | |
| 158 // Don't manipulate the category object directly, as this may lead | |
| 159 // to threading issues. Use the TraceLog methods instead. | |
| 160 class TraceCategory { | |
| 161 public: | |
|
brettw
2011/02/25 18:30:03
Indent these one char.
| |
| 162 TraceCategory(const char* name, bool enabled); | |
| 163 ~TraceCategory(); | |
| 164 | |
| 165 const char* name() const { return name_; } | |
| 166 | |
| 167 // NEVER read these directly, let the macros do it for you | |
| 168 volatile base::subtle::Atomic32 enabled_; | |
| 169 protected: | |
| 170 const char* name_; | |
| 171 }; | |
| 172 | |
| 173 #define TRACE_MAX_NUM_ARGS 2 | |
| 174 | |
| 175 enum TraceEventPhase { | |
| 176 TRACE_EVENT_PHASE_BEGIN, | |
| 177 TRACE_EVENT_PHASE_END, | |
| 178 TRACE_EVENT_PHASE_INSTANT | |
| 179 }; | |
| 180 | |
| 181 // Output records are "Events" and can be obtained via the | |
| 182 // OutputCallback whenever the logging system decides to flush. This | |
| 183 // can happen at any time, on any thread, or you can programatically | |
| 184 // force it to happen. | |
| 185 struct TraceEvent { | |
| 186 static void AppendAsJSON(std::string& out, | |
|
Ken Russell (switch to Gerrit)
2011/02/25 00:56:36
The Google C++ style guide says that all reference
| |
| 187 const std::vector<TraceEvent>& events); | |
| 188 void AppendAsJSON(std::string& out) const; | |
|
Ken Russell (switch to Gerrit)
2011/02/25 00:56:36
Same here.
| |
| 189 | |
| 190 | |
| 191 unsigned long processId; | |
| 192 unsigned long threadId; | |
| 193 TimeTicks timestamp; | |
| 194 TraceEventPhase phase; | |
| 195 TraceCategory* category; | |
| 196 const char* name; | |
| 197 const char* argNames[TRACE_MAX_NUM_ARGS]; | |
| 198 std::string argValues[TRACE_MAX_NUM_ARGS]; | |
| 199 }; | |
| 200 | |
| 201 | |
| 91 class TraceLog { | 202 class TraceLog { |
| 92 public: | 203 public: |
| 93 enum EventType { | |
| 94 EVENT_BEGIN, | |
| 95 EVENT_END, | |
| 96 EVENT_INSTANT | |
| 97 }; | |
| 98 | 204 |
| 99 static TraceLog* GetInstance(); | 205 static TraceLog* GetInstance(); |
| 100 | 206 |
| 101 // Is tracing currently enabled. | 207 // Global enable of tracing. Currently enables all categories or not. |
| 102 static bool IsTracing(); | 208 // TODO(nduca) Replaced with an Enable/DisableCategory() that |
| 103 // Start logging trace events. | 209 // implicitly controls the global logging state. |
| 104 static bool StartTracing(); | 210 void SetEnabled(bool enabled); |
| 105 // Stop logging trace events. | 211 |
| 106 static void StopTracing(); | 212 // When enough events are collected, they are handed (in bulk) to |
| 107 | 213 // 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. | 214 // silently dropped. |
| 109 void Trace(const std::string& name, | 215 typedef Callback1<const std::string& /* json_events */>::Type OutputCallback; |
| 110 EventType type, | 216 void SetOutputCallback(OutputCallback* cb); |
| 111 const void* id, | 217 |
| 112 const std::wstring& extra, | 218 // Forwards data collected by a child process to the registered |
| 113 const char* file, | 219 // output callback. |
| 114 int line); | 220 void AddRemotelyCollectedData(const std::string& json_events); |
| 115 void Trace(const std::string& name, | 221 |
| 116 EventType type, | 222 // Flushes all logged data to the callback. |
| 117 const void* id, | 223 void Flush(); |
| 118 const std::string& extra, | 224 |
| 119 const char* file, | 225 // Called by TRACE_EVENT* macros, don't call this directly. |
| 120 int line); | 226 TraceCategory* GetCategory(const char* name); |
| 227 | |
| 228 // Called by TRACE_EVENT* macros, don't call this directly. | |
| 229 void AddTraceEvent(TraceEventPhase phase, | |
| 230 const char* file, int line, | |
| 231 TraceCategory* category, | |
| 232 const char* name, | |
| 233 const char* arg1name, const char* arg1val, | |
| 234 const char* arg2name, const char* arg2val); | |
| 235 void AddTraceEventLegacy(TraceEventPhase phase, | |
| 236 const char* file, int line, | |
| 237 const char* name, | |
| 238 const void* id, | |
| 239 const char* extra); | |
| 121 | 240 |
| 122 private: | 241 private: |
| 123 // This allows constructor and destructor to be private and usable only | 242 // This allows constructor and destructor to be private and usable only |
| 124 // by the Singleton class. | 243 // by the Singleton class. |
| 125 friend struct DefaultSingletonTraits<TraceLog>; | 244 friend struct StaticMemorySingletonTraits<TraceLog>; |
| 126 | 245 |
| 127 TraceLog(); | 246 TraceLog(); |
| 128 ~TraceLog(); | 247 ~TraceLog(); |
| 129 bool OpenLogFile(); | 248 void FlushWithLockAlreadyHeld(); |
| 130 void CloseLogFile(); | 249 |
| 131 bool Start(); | 250 // Guards access to everything right now. If I can get this working, |
| 132 void Stop(); | 251 // there are a ton of things we can to reduce thread synchronization. |
|
Ken Russell (switch to Gerrit)
2011/02/25 00:56:36
Perhaps a TODO(nduca): here then?
| |
| 133 void Heartbeat(); | 252 Lock lock_; |
| 134 void Log(const std::string& msg); | |
| 135 | |
| 136 bool enabled_; | 253 bool enabled_; |
| 137 FILE* log_file_; | 254 ScopedVector<TraceCategory> categories_; |
| 138 base::Lock file_lock_; | 255 scoped_ptr<OutputCallback> output_callback_; |
| 139 TimeTicks trace_start_time_; | 256 std::vector<TraceEvent> logged_events_; |
| 140 scoped_ptr<base::ProcessMetrics> process_metrics_; | 257 |
| 141 RepeatingTimer<TraceLog> timer_; | 258 DISALLOW_COPY_AND_ASSIGN(TraceLog); |
| 259 }; | |
| 260 | |
| 261 | |
| 262 class TraceEndOnScopeClose { | |
|
Ken Russell (switch to Gerrit)
2011/02/25 00:56:36
This class isn't supposed to be accessed externall
| |
| 263 public: | |
|
brettw
2011/02/25 18:30:03
Indent these one char.
| |
| 264 TraceEndOnScopeClose(const char* file, int line, | |
| 265 TraceCategory* category, | |
|
brettw
2011/02/25 18:30:03
Params should be aligned (should be under the cons
| |
| 266 const char* name) | |
| 267 : file_(file), | |
|
brettw
2011/02/25 18:30:03
: should only be indented 4 spaces (4 fewer than n
| |
| 268 line_(line), | |
| 269 category_(category), | |
| 270 name_(name) { | |
| 271 } | |
| 272 ~TraceEndOnScopeClose() { | |
| 273 if (base::subtle::Acquire_Load(&category_->enabled_)) | |
| 274 base::debug::TraceLog::GetInstance()->AddTraceEvent( | |
| 275 base::debug::TRACE_EVENT_PHASE_END, | |
| 276 file_, line_, | |
| 277 category_, | |
| 278 name_, | |
| 279 NULL, NULL, NULL, NULL); | |
| 280 } | |
| 281 protected: | |
|
Ken Russell (switch to Gerrit)
2011/02/25 00:56:36
Why are these protected and not private?
| |
| 282 const char* file_; | |
| 283 int line_; | |
| 284 TraceCategory* category_; | |
| 285 const char* name_; | |
| 142 }; | 286 }; |
| 143 | 287 |
| 144 } // namespace debug | 288 } // namespace debug |
| 145 } // namespace base | 289 } // namespace base |
| 146 | 290 |
| 147 #endif // defined(OS_WIN) | |
| 148 | |
| 149 #endif // BASE_DEBUG_TRACE_EVENT_H_ | 291 #endif // BASE_DEBUG_TRACE_EVENT_H_ |
| OLD | NEW |