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

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

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