OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 // Trace events are for tracking application performance. | |
6 // | |
7 // Events are issued against categories. Whereas LOG's | |
8 // categories are statically defined, TRACE categories are created | |
9 // implicitly with a string. For example: | |
10 // GPU_TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent") | |
11 // | |
12 // Events can be INSTANT, or can be pairs of BEGIN and END: | |
13 // GPU_TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly") | |
14 // doSomethingCostly() | |
15 // GPU_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 // GPU_TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly"); | |
21 // ... | |
22 // } | |
23 // | |
24 // Additional parameters can be associated with an event: | |
25 // void doSomethingCostly2(int howMuch) { | |
26 // GPU_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 | |
41 #ifndef GPU_TRACE_EVENT_H_ | |
42 #define GPU_TRACE_EVENT_H_ | |
43 #pragma once | |
44 | |
45 #include "build/build_config.h" | |
46 | |
47 #include <string> | |
48 | |
49 #include "base/scoped_ptr.h" | |
50 #include "base/scoped_vector.h" | |
51 #include "base/atomicops.h" | |
52 #include "base/singleton.h" | |
53 #include "base/time.h" | |
54 #include "base/timer.h" | |
55 #include "base/callback.h" | |
56 #include <vector> | |
57 | |
58 | |
59 // Implementation detail: trace event macros create temporary variables | |
60 // to keep instrumentation overhead low. These macros give each temporary | |
61 // variable a unique name based on the line number to prevent name collissions. | |
62 #define GPU_TRACE_EVENT_UNIQUE_IDENTIFIER3(a,b) a##b | |
63 #define GPU_TRACE_EVENT_UNIQUE_IDENTIFIER2(a,b) \ | |
64 GPU_TRACE_EVENT_UNIQUE_IDENTIFIER3(a,b) | |
65 #define GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(name_prefix) \ | |
66 GPU_TRACE_EVENT_UNIQUE_IDENTIFIER2(name_prefix, __LINE__) | |
67 | |
68 // Records a pair of begin and end events called "name" for the current | |
69 // scope, with 0, 1 or 2 associated arguments. If the category is not | |
70 // enabled, then this does nothing. | |
71 #define GPU_TRACE_EVENT0(category, name) \ | |
72 GPU_TRACE_EVENT1(category, name, NULL, NULL) | |
73 #define GPU_TRACE_EVENT1(category, name, arg1name, arg1val) \ | |
74 GPU_TRACE_EVENT2(category, name, arg1name, arg1val, NULL, NULL) | |
75 #define GPU_TRACE_EVENT2(category, name, arg1name, arg1val, arg2name, arg2val) \ | |
76 static gpu::TraceCategory* \ | |
77 GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \ | |
78 gpu::TraceLog::GetInstance()->GetCategory(category); \ | |
79 if (base::subtle::Acquire_Load(\ | |
80 &(GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic))->enabled_)) { \ | |
81 gpu::TraceLog::GetInstance()->AddTraceEvent( \ | |
82 gpu::GPU_TRACE_EVENT_PHASE_BEGIN, \ | |
83 __FILE__, __LINE__, \ | |
84 GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \ | |
85 name, \ | |
86 arg1name, arg1val, \ | |
87 arg2name, arg2val); \ | |
88 } \ | |
89 gpu::internal::TraceEndOnScopeClose __profileScope ## __LINE ( \ | |
90 __FILE__, __LINE__, \ | |
91 GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), name); | |
92 | |
93 // Records a single event called "name" immediately, with 0, 1 or 2 | |
94 // associated arguments. If the category is not enabled, then this | |
95 // does nothing. | |
96 #define GPU_TRACE_EVENT_INSTANT0(category, name) \ | |
97 GPU_TRACE_EVENT_INSTANT1(category, name, NULL, NULL) | |
98 #define GPU_TRACE_EVENT_INSTANT1(category, name, arg1name, arg1val) \ | |
99 GPU_TRACE_EVENT_INSTANT2(category, name, arg1name, arg1val, NULL, NULL) | |
100 #define GPU_TRACE_EVENT_INSTANT2(category, name, arg1name, arg1val, \ | |
101 arg2name, arg2val) \ | |
102 static gpu::TraceCategory* \ | |
103 GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \ | |
104 gpu::TraceLog::GetInstance()->GetCategory(category); \ | |
105 if (base::subtle::Acquire_Load( \ | |
106 &(GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic))->enabled_)) { \ | |
107 gpu::TraceLog::GetInstance()->AddTraceEvent( \ | |
108 gpu::GPU_TRACE_EVENT_PHASE_INSTANT, \ | |
109 __FILE__, __LINE__, \ | |
110 GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \ | |
111 name, \ | |
112 arg1name, arg1val, \ | |
113 arg2name, arg2val); \ | |
114 } | |
115 | |
116 // Records a single BEGIN event called "name" immediately, with 0, 1 or 2 | |
117 // associated arguments. If the category is not enabled, then this | |
118 // does nothing. | |
119 #define GPU_TRACE_EVENT_BEGIN0(category, name) \ | |
120 GPU_TRACE_EVENT_BEGIN1(category, name, NULL, NULL) | |
121 #define GPU_TRACE_EVENT_BEGIN1(category, name, arg1name, arg1val) \ | |
122 GPU_TRACE_EVENT_BEGIN2(category, name, arg1name, arg1val, NULL, NULL) | |
123 #define GPU_TRACE_EVENT_BEGIN2(category, name, arg1name, arg1val, \ | |
124 arg2name, arg2val) \ | |
125 static gpu::TraceCategory* \ | |
126 GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \ | |
127 gpu::TraceLog::GetInstance()->GetCategory(category); \ | |
128 if (base::subtle::Acquire_Load( \ | |
129 &(GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic))->enabled_)) { \ | |
130 gpu::TraceLog::GetInstance()->AddTraceEvent( \ | |
131 gpu::GPU_TRACE_EVENT_PHASE_BEGIN, \ | |
132 __FILE__, __LINE__, \ | |
133 GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \ | |
134 name, \ | |
135 arg1name, arg1val, \ | |
136 arg2name, arg2val); \ | |
137 } | |
138 | |
139 // Records a single END event for "name" immediately. If the category | |
140 // is not enabled, then this does nothing. | |
141 #define GPU_TRACE_EVENT_END0(category, name) \ | |
142 static gpu::TraceCategory* \ | |
143 GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \ | |
144 gpu::TraceLog::GetInstance()->GetCategory(category); \ | |
145 if (base::subtle::Acquire_Load( \ | |
146 &(GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic))->enabled_)) { \ | |
147 gpu::TraceLog::GetInstance()->AddTraceEvent( \ | |
148 gpu::GPU_TRACE_EVENT_PHASE_END, \ | |
149 __FILE__, __LINE__, \ | |
150 GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \ | |
151 name, \ | |
152 arg1name, arg1val, \ | |
153 arg2name, arg2val); \ | |
154 } | |
155 | |
156 | |
157 namespace gpu { | |
158 | |
159 // Categories allow enabling/disabling of streams of trace events | |
160 // Don't manipulate the category object directly, as this may lead | |
161 // to threading issues. Use the TraceLog methods instead. | |
162 class TraceCategory { | |
163 public: | |
164 TraceCategory(const char* name, bool enabled); | |
165 ~TraceCategory(); | |
166 | |
167 const char* name() const { return name_; } | |
168 | |
169 // NEVER read these directly, let the macros do it for you | |
170 volatile base::subtle::Atomic32 enabled_; | |
171 protected: | |
172 const char* name_; | |
173 }; | |
174 | |
175 #define TRACE_MAX_NUM_ARGS 2 | |
176 | |
177 enum TraceEventPhase { | |
178 GPU_TRACE_EVENT_PHASE_BEGIN, | |
179 GPU_TRACE_EVENT_PHASE_END, | |
180 GPU_TRACE_EVENT_PHASE_INSTANT | |
181 }; | |
182 | |
183 // Output records are "Events" and can be obtained via the | |
184 // OutputCallback whenever the logging system decides to flush. This | |
185 // can happen at any time, on any thread, or you can programatically | |
186 // force it to happen. | |
187 struct TraceEvent { | |
188 static void AppendAsJSON(std::string* out, | |
189 const std::vector<TraceEvent>& events); | |
190 void AppendAsJSON(std::string* out) const; | |
191 | |
192 | |
193 unsigned long processId; | |
194 unsigned long threadId; | |
195 base::TimeTicks timestamp; | |
196 TraceEventPhase phase; | |
197 TraceCategory* category; | |
198 const char* name; | |
199 const char* argNames[TRACE_MAX_NUM_ARGS]; | |
200 std::string argValues[TRACE_MAX_NUM_ARGS]; | |
201 }; | |
202 | |
203 | |
204 class TraceLog { | |
205 public: | |
206 | |
greggman
2011/03/15 00:19:50
remove this line blank (try gcl lint cl)
| |
207 static TraceLog* GetInstance(); | |
208 | |
209 // Global enable of tracing. Currently enables all categories or not. | |
210 // TODO(nduca) Replaced with an Enable/DisableCategory() that | |
211 // implicitly controls the global logging state. | |
212 void SetEnabled(bool enabled); | |
213 | |
214 // When enough events are collected, they are handed (in bulk) to | |
215 // the output callback. If no callback is set, the output will be | |
216 // silently dropped. | |
217 typedef Callback1<const std::string& /* json_events */>::Type OutputCallback; | |
218 void SetOutputCallback(OutputCallback* cb); | |
219 | |
220 // Forwards data collected by a child process to the registered | |
221 // output callback. | |
222 void AddRemotelyCollectedData(const std::string& json_events); | |
223 | |
224 // Flushes all logged data to the callback. | |
225 void Flush(); | |
226 | |
227 // Called by GPU_TRACE_EVENT* macros, don't call this directly. | |
228 TraceCategory* GetCategory(const char* name); | |
229 | |
230 // Called by GPU_TRACE_EVENT* macros, don't call this directly. | |
231 void AddTraceEvent(TraceEventPhase phase, | |
232 const char* file, int line, | |
233 TraceCategory* category, | |
234 const char* name, | |
235 const char* arg1name, const char* arg1val, | |
236 const char* arg2name, const char* arg2val); | |
237 | |
238 private: | |
239 // This allows constructor and destructor to be private and usable only | |
240 // by the Singleton class. | |
241 friend struct StaticMemorySingletonTraits<TraceLog>; | |
242 | |
243 TraceLog(); | |
244 ~TraceLog(); | |
245 void FlushWithLockAlreadyHeld(); | |
246 | |
247 // TODO(nduca): switch to per-thread tace buffers to reduce thread | |
greggman
2011/03/15 00:19:50
tace -> trace
nduca
2011/03/15 01:21:40
Done.
| |
248 // synchronization. | |
249 base::Lock lock_; | |
250 bool enabled_; | |
251 ScopedVector<TraceCategory> categories_; | |
252 scoped_ptr<OutputCallback> output_callback_; | |
253 std::vector<TraceEvent> logged_events_; | |
254 | |
255 DISALLOW_COPY_AND_ASSIGN(TraceLog); | |
256 }; | |
257 | |
258 namespace internal { | |
259 | |
260 // Used by GPU_TRACE_EVENTx macro. Do not use directly. | |
261 class TraceEndOnScopeClose { | |
262 public: | |
263 TraceEndOnScopeClose(const char* file, int line, | |
264 TraceCategory* category, | |
265 const char* name) | |
266 : file_(file) | |
267 , line_(line) | |
268 , category_(category) | |
269 , name_(name) { } | |
270 | |
271 ~TraceEndOnScopeClose() { | |
272 if (base::subtle::Acquire_Load(&category_->enabled_)) | |
273 gpu::TraceLog::GetInstance()->AddTraceEvent( | |
274 gpu::GPU_TRACE_EVENT_PHASE_END, | |
275 file_, line_, | |
276 category_, | |
277 name_, | |
278 NULL, NULL, NULL, NULL); | |
279 } | |
280 | |
281 private: | |
282 const char* file_; | |
283 int line_; | |
284 TraceCategory* category_; | |
285 const char* name_; | |
286 }; | |
287 | |
288 } // namespace internal | |
289 | |
290 } // namespace gpu | |
291 | |
292 #endif // GPU_TRACE_EVENT_H_ | |
OLD | NEW |