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

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

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/debug/trace_event.h ('k') | base/debug/trace_event_unittest.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) 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 #include "base/debug/trace_event.h" 5 #include "base/debug/trace_event.h"
6 6
7 #if defined(OS_WIN)
8 #include "base/debug/trace_event_win.h"
9 #endif
10 #include "base/format_macros.h" 7 #include "base/format_macros.h"
8 #include "base/file_path.h"
9 #include "base/file_util.h"
10 #include "base/path_service.h"
11 #include "base/process_util.h" 11 #include "base/process_util.h"
12 #include "base/stringprintf.h" 12 #include "base/stringprintf.h"
13 #include "base/threading/platform_thread.h"
13 #include "base/utf_string_conversions.h" 14 #include "base/utf_string_conversions.h"
14 #include "base/time.h" 15 #include "base/time.h"
15 16
16 #define USE_UNRELIABLE_NOW 17 #define USE_UNRELIABLE_NOW
17 18
18 namespace base { 19 namespace base {
19 namespace debug { 20 namespace debug {
20 21
21 // Controls the number of trace events we will buffer in-memory 22 static const char* kEventTypeNames[] = {
22 // before throwing them away. 23 "BEGIN",
23 const size_t kTraceEventBufferSize = 500000; 24 "END",
24 const size_t kTraceEventBatchSize = 1000; 25 "INSTANT"
26 };
25 27
26 #define TRACE_EVENT_MAX_CATEGORIES 42 28 static const FilePath::CharType* kLogFileName =
29 FILE_PATH_LITERAL("trace_%d.log");
27 30
28 static TraceCategory g_categories[TRACE_EVENT_MAX_CATEGORIES] = { 31 // static
29 { "tracing already shutdown", false }, 32 TraceLog* TraceLog::GetInstance() {
30 { "tracing categories exhausted; must increase TRACE_EVENT_MAX_CATEGORIES", 33 return Singleton<TraceLog, DefaultSingletonTraits<TraceLog> >::get();
31 false }
32 };
33 static const TraceCategory* const g_category_already_shutdown =
34 &g_categories[0];
35 static const TraceCategory* const g_category_categories_exhausted =
36 &g_categories[1];
37 static int g_category_index = 2; // skip initial 2 error categories
38
39 ////////////////////////////////////////////////////////////////////////////////
40 //
41 // TraceValue
42 //
43 ////////////////////////////////////////////////////////////////////////////////
44
45 void TraceValue::Destroy() {
46 if (type_ == TRACE_TYPE_STRING) {
47 value_.as_string_refptr->Release();
48 value_.as_string_refptr = NULL;
49 }
50 type_ = TRACE_TYPE_UNDEFINED;
51 value_.as_uint = 0ull;
52 } 34 }
53 35
54 TraceValue& TraceValue::operator=(const TraceValue& rhs) { 36 // static
55 if (this == &rhs) 37 bool TraceLog::IsTracing() {
56 return *this; 38 return TraceLog::GetInstance()->enabled_;
39 }
57 40
58 Destroy(); 41 // static
42 bool TraceLog::StartTracing() {
43 return TraceLog::GetInstance()->Start();
44 }
59 45
60 type_ = rhs.type_; 46 // static
61 switch(type_) { 47 void TraceLog::StopTracing() {
62 case TRACE_TYPE_UNDEFINED: 48 return TraceLog::GetInstance()->Stop();
63 return *this; 49 }
64 case TRACE_TYPE_BOOL: 50
65 value_.as_bool = rhs.value_.as_bool; 51 void TraceLog::Trace(const std::string& name,
66 return *this; 52 EventType type,
67 case TRACE_TYPE_UINT: 53 const void* id,
68 value_.as_uint = rhs.value_.as_uint; 54 const std::wstring& extra,
69 return *this; 55 const char* file,
70 case TRACE_TYPE_INT: 56 int line) {
71 value_.as_int = rhs.value_.as_int; 57 if (!enabled_)
72 return *this; 58 return;
73 case TRACE_TYPE_DOUBLE: 59 Trace(name, type, id, WideToUTF8(extra), file, line);
74 value_.as_double = rhs.value_.as_double; 60 }
75 return *this; 61
76 case TRACE_TYPE_POINTER: 62 void TraceLog::Trace(const std::string& name,
77 value_.as_pointer = rhs.value_.as_pointer; 63 EventType type,
78 return *this; 64 const void* id,
79 case TRACE_TYPE_STRING: 65 const std::string& extra,
80 value_.as_string_refptr = rhs.value_.as_string_refptr; 66 const char* file,
81 value_.as_string_refptr->AddRef(); 67 int line) {
82 return *this; 68 if (!enabled_)
83 default: 69 return;
84 NOTREACHED(); 70
85 return *this; 71 #ifdef USE_UNRELIABLE_NOW
72 TimeTicks tick = TimeTicks::HighResNow();
73 #else
74 TimeTicks tick = TimeTicks::Now();
75 #endif
76 TimeDelta delta = tick - trace_start_time_;
77 int64 usec = delta.InMicroseconds();
78 std::string msg =
79 StringPrintf("{'pid':'0x%lx', 'tid':'0x%lx', 'type':'%s', "
80 "'name':'%s', 'id':'%p', 'extra':'%s', 'file':'%s', "
81 "'line_number':'%d', 'usec_begin': %" PRId64 "},\n",
82 static_cast<unsigned long>(base::GetCurrentProcId()),
83 static_cast<unsigned long>(PlatformThread::CurrentId()),
84 kEventTypeNames[type],
85 name.c_str(),
86 id,
87 extra.c_str(),
88 file,
89 line,
90 usec);
91
92 Log(msg);
93 }
94
95 TraceLog::TraceLog() : enabled_(false), log_file_(NULL) {
96 base::ProcessHandle proc = base::GetCurrentProcessHandle();
97 #if !defined(OS_MACOSX)
98 process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(proc));
99 #else
100 // The default port provider is sufficient to get data for the current
101 // process.
102 process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(proc,
103 NULL));
104 #endif
105 }
106
107 TraceLog::~TraceLog() {
108 Stop();
109 }
110
111 bool TraceLog::OpenLogFile() {
112 FilePath::StringType pid_filename =
113 StringPrintf(kLogFileName, base::GetCurrentProcId());
114 FilePath log_file_path;
115 if (!PathService::Get(base::DIR_EXE, &log_file_path))
116 return false;
117 log_file_path = log_file_path.Append(pid_filename);
118 log_file_ = file_util::OpenFile(log_file_path, "a");
119 if (!log_file_) {
120 // try the current directory
121 log_file_ = file_util::OpenFile(FilePath(pid_filename), "a");
122 if (!log_file_) {
123 return false;
124 }
125 }
126 return true;
127 }
128
129 void TraceLog::CloseLogFile() {
130 if (log_file_) {
131 file_util::CloseFile(log_file_);
86 } 132 }
87 } 133 }
88 134
89 void TraceValue::AppendAsJSON(std::string* out) const { 135 bool TraceLog::Start() {
90 char temp_string[128]; 136 if (enabled_)
91 std::string::size_type start_pos; 137 return true;
92 switch (type_) { 138 enabled_ = OpenLogFile();
93 case TRACE_TYPE_BOOL: 139 if (enabled_) {
94 *out += as_bool()? "true" : "false"; 140 Log("var raw_trace_events = [\n");
95 break; 141 trace_start_time_ = TimeTicks::Now();
96 case TRACE_TYPE_UINT: 142 timer_.Start(TimeDelta::FromMilliseconds(250), this, &TraceLog::Heartbeat);
97 base::snprintf(temp_string, arraysize(temp_string), "%llu", 143 }
98 static_cast<unsigned long long>(as_uint())); 144 return enabled_;
99 *out += temp_string; 145 }
100 break; 146
101 case TRACE_TYPE_INT: 147 void TraceLog::Stop() {
102 base::snprintf(temp_string, arraysize(temp_string), "%lld", 148 if (enabled_) {
103 static_cast<long long>(as_int())); 149 enabled_ = false;
104 *out += temp_string; 150 Log("];\n");
105 break; 151 CloseLogFile();
106 case TRACE_TYPE_DOUBLE: 152 timer_.Stop();
107 base::snprintf(temp_string, arraysize(temp_string), "%f", as_double());
108 *out += temp_string;
109 break;
110 case TRACE_TYPE_POINTER:
111 base::snprintf(temp_string, arraysize(temp_string), "%llu",
112 static_cast<unsigned long long>(
113 reinterpret_cast<intptr_t>(
114 as_pointer())));
115 *out += temp_string;
116 break;
117 case TRACE_TYPE_STRING:
118 *out += "\"";
119 start_pos = out->size();
120 *out += as_string();
121 // replace " character with '
122 while ((start_pos = out->find_first_of('\"', start_pos)) !=
123 std::string::npos)
124 (*out)[start_pos] = '\'';
125 *out += "\"";
126 break;
127 default:
128 NOTREACHED() << "Don't know how to print this value";
129 break;
130 } 153 }
131 } 154 }
132 155
133 //////////////////////////////////////////////////////////////////////////////// 156 void TraceLog::Heartbeat() {
134 // 157 std::string cpu = StringPrintf("%.0f", process_metrics_->GetCPUUsage());
135 // TraceEvent 158 TRACE_EVENT_INSTANT("heartbeat.cpu", 0, cpu);
136 //
137 ////////////////////////////////////////////////////////////////////////////////
138
139 namespace {
140
141 const char* GetPhaseStr(TraceEventPhase phase) {
142 switch(phase) {
143 case TRACE_EVENT_PHASE_BEGIN:
144 return "B";
145 case TRACE_EVENT_PHASE_INSTANT:
146 return "I";
147 case TRACE_EVENT_PHASE_END:
148 return "E";
149 default:
150 NOTREACHED() << "Invalid phase argument";
151 return "?";
152 }
153 } 159 }
154 160
155 } // namespace 161 void TraceLog::Log(const std::string& msg) {
162 AutoLock lock(file_lock_);
156 163
157 TraceEvent::TraceEvent() 164 fprintf(log_file_, "%s", msg.c_str());
158 : process_id(0),
159 thread_id(0),
160 phase(TRACE_EVENT_PHASE_BEGIN),
161 category(NULL),
162 name(NULL) {
163 memset(arg_names, 0, sizeof(arg_names));
164 }
165
166 TraceEvent::~TraceEvent() {
167 }
168
169 void TraceEvent::AppendEventsAsJSON(const std::vector<TraceEvent>& events,
170 size_t start,
171 size_t count,
172 std::string* out) {
173 *out += "[";
174 for (size_t i = 0; i < count && start + i < events.size(); ++i) {
175 if (i > 0)
176 *out += ",";
177 events[i + start].AppendAsJSON(out);
178 }
179 *out += "]";
180 }
181
182 void TraceEvent::AppendAsJSON(std::string* out) const {
183 const char* phase_str = GetPhaseStr(phase);
184 int64 time_int64 = timestamp.ToInternalValue();
185 // Category name checked at category creation time.
186 DCHECK(!strchr(name, '"'));
187 StringAppendF(out,
188 "{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%lld,"
189 "\"ph\":\"%s\",\"name\":\"%s\",\"args\":{",
190 category->name,
191 static_cast<int>(process_id),
192 static_cast<int>(thread_id),
193 static_cast<long long>(time_int64),
194 phase_str,
195 name);
196
197 // Output argument names and values, stop at first NULL argument name.
198 for (size_t i = 0; i < kTraceMaxNumArgs && arg_names[i]; ++i) {
199 if (i > 0)
200 *out += ",";
201 *out += "\"";
202 *out += arg_names[i];
203 *out += "\":";
204 arg_values[i].AppendAsJSON(out);
205 }
206 *out += "}}";
207 }
208
209 ////////////////////////////////////////////////////////////////////////////////
210 //
211 // TraceLog
212 //
213 ////////////////////////////////////////////////////////////////////////////////
214
215 // static
216 TraceLog* TraceLog::GetInstance() {
217 return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog> >::get();
218 }
219
220 TraceLog::TraceLog()
221 : enabled_(false) {
222 logged_events_.reserve(1024);
223 }
224
225 TraceLog::~TraceLog() {
226 }
227
228 const TraceCategory* TraceLog::GetCategory(const char* name) {
229 TraceLog* tracelog = GetInstance();
230 if (!tracelog){
231 CHECK(!g_category_already_shutdown->enabled);
232 return g_category_already_shutdown;
233 }
234 return tracelog->GetCategoryInternal(name);
235 }
236
237 const TraceCategory* TraceLog::GetCategoryInternal(const char* name) {
238 AutoLock lock(lock_);
239 DCHECK(!strchr(name, '"')) << "Names may not contain double quote char";
240
241 // Search for pre-existing category matching this name
242 for (int i = 0; i < g_category_index; i++) {
243 if (strcmp(g_categories[i].name, name) == 0)
244 return &g_categories[i];
245 }
246
247 // Create a new category
248 DCHECK(g_category_index < TRACE_EVENT_MAX_CATEGORIES) <<
249 "must increase TRACE_EVENT_MAX_CATEGORIES";
250 if (g_category_index < TRACE_EVENT_MAX_CATEGORIES) {
251 int new_index = g_category_index++;
252 g_categories[new_index].name = name;
253 DCHECK(!g_categories[new_index].enabled);
254 g_categories[new_index].enabled = enabled_;
255 return &g_categories[new_index];
256 } else {
257 return g_category_categories_exhausted;
258 }
259 }
260
261 void TraceLog::SetEnabled(bool enabled) {
262 {
263 AutoLock lock(lock_);
264 if (enabled == enabled_)
265 return;
266 enabled_ = enabled;
267 for (int i = 0; i < g_category_index; i++) {
268 //TODO(scheib): If changed to enable specific categories instead of all
269 // check GetCategoryInternal creation code that users TraceLog::enabled_
270 g_categories[i].enabled = enabled;
271 }
272 } // release lock
273 if (!enabled)
274 Flush();
275 }
276
277 float TraceLog::GetBufferPercentFull() const {
278 return (float)((double)logged_events_.size()/(double)kTraceEventBufferSize);
279 }
280
281 void TraceLog::SetOutputCallback(const TraceLog::OutputCallback& cb) {
282 Flush();
283 AutoLock lock(lock_);
284 output_callback_ = cb;
285 }
286
287 void TraceLog::SetBufferFullCallback(const TraceLog::BufferFullCallback& cb) {
288 AutoLock lock(lock_);
289 buffer_full_callback_ = cb;
290 }
291
292 void TraceLog::Flush() {
293 std::vector<TraceEvent> previous_logged_events;
294 OutputCallback output_callback_copy;
295 {
296 AutoLock lock(lock_);
297 previous_logged_events.swap(logged_events_);
298 output_callback_copy = output_callback_;
299 } // release lock
300
301 if (output_callback_copy.is_null())
302 return;
303
304 for (size_t i = 0;
305 i < previous_logged_events.size();
306 i += kTraceEventBatchSize) {
307 scoped_refptr<RefCountedString> json_events_str_ptr =
308 new RefCountedString();
309 TraceEvent::AppendEventsAsJSON(previous_logged_events,
310 i,
311 kTraceEventBatchSize,
312 &(json_events_str_ptr->data));
313 output_callback_copy.Run(json_events_str_ptr.get());
314 }
315 }
316
317 void TraceLog::AddTraceEvent(TraceEventPhase phase,
318 const char* file, int line,
319 const TraceCategory* category,
320 const char* name,
321 const char* arg1_name, TraceValue arg1_val,
322 const char* arg2_name, TraceValue arg2_val) {
323 DCHECK(file && name);
324 #ifdef USE_UNRELIABLE_NOW
325 TimeTicks now = TimeTicks::HighResNow();
326 #else
327 TimeTicks now = TimeTicks::Now();
328 #endif
329 BufferFullCallback buffer_full_callback_copy;
330 {
331 AutoLock lock(lock_);
332 if (!enabled_ || !category->enabled)
333 return;
334 if (logged_events_.size() >= kTraceEventBufferSize)
335 return;
336 logged_events_.push_back(TraceEvent());
337 TraceEvent& event = logged_events_.back();
338 event.process_id = static_cast<unsigned long>(base::GetCurrentProcId());
339 event.thread_id = PlatformThread::CurrentId();
340 event.timestamp = now;
341 event.phase = phase;
342 event.category = category;
343 event.name = name;
344 event.arg_names[0] = arg1_name;
345 event.arg_values[0] = arg1_val;
346 event.arg_names[1] = arg2_name;
347 event.arg_values[1] = arg2_val;
348 COMPILE_ASSERT(kTraceMaxNumArgs == 2, TraceEvent_arg_count_out_of_sync);
349
350 if (logged_events_.size() == kTraceEventBufferSize) {
351 buffer_full_callback_copy = buffer_full_callback_;
352 }
353 } // release lock
354
355 if (!buffer_full_callback_copy.is_null())
356 buffer_full_callback_copy.Run();
357 }
358
359 void TraceLog::AddTraceEventEtw(TraceEventPhase phase,
360 const char* file, int line,
361 const char* name,
362 const void* id,
363 const char* extra) {
364 // Legacy trace points on windows called to ETW
365 #if defined(OS_WIN)
366 TraceEventETWProvider::Trace(name, phase, id, extra);
367 #endif
368
369 // Also add new trace event behavior
370 static const TraceCategory* category = GetCategory("ETW Trace Event");
371 if (category->enabled) {
372 TraceLog* tracelog = TraceLog::GetInstance();
373 if (!tracelog)
374 return;
375 tracelog->AddTraceEvent(phase, file, line, category, name,
376 "id", id,
377 "extra", extra ? extra : "");
378 }
379 }
380
381 void TraceLog::Resurrect() {
382 StaticMemorySingletonTraits<TraceLog>::Resurrect();
383 } 165 }
384 166
385 } // namespace debug 167 } // namespace debug
386 } // namespace base 168 } // namespace base
OLDNEW
« no previous file with comments | « base/debug/trace_event.h ('k') | base/debug/trace_event_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698