OLD | NEW |
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 #include "base/debug/trace_event.h" | 5 #include "base/debug/trace_event.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/format_macros.h" | 10 #include "base/format_macros.h" |
(...skipping 25 matching lines...) Expand all Loading... |
36 | 36 |
37 // Controls the number of trace events we will buffer in-memory | 37 // Controls the number of trace events we will buffer in-memory |
38 // before throwing them away. | 38 // before throwing them away. |
39 const size_t kTraceEventBufferSize = 500000; | 39 const size_t kTraceEventBufferSize = 500000; |
40 const size_t kTraceEventBatchSize = 1000; | 40 const size_t kTraceEventBatchSize = 1000; |
41 | 41 |
42 #define TRACE_EVENT_MAX_CATEGORIES 100 | 42 #define TRACE_EVENT_MAX_CATEGORIES 100 |
43 | 43 |
44 namespace { | 44 namespace { |
45 | 45 |
| 46 // Specify these values when the corresponding argument of AddTraceEvent is not |
| 47 // used. |
| 48 static const char* kNoArgName = NULL; |
| 49 static const int kNoArgValue = 0; |
| 50 static const int kNoThreshholdBeginId = -1; |
| 51 static const int64 kNoThresholdValue = 0; |
| 52 static const int kNoEventId = 0; |
| 53 |
46 TraceCategory g_categories[TRACE_EVENT_MAX_CATEGORIES] = { | 54 TraceCategory g_categories[TRACE_EVENT_MAX_CATEGORIES] = { |
47 { "tracing already shutdown", false }, | 55 { "tracing already shutdown", false }, |
48 { "tracing categories exhausted; must increase TRACE_EVENT_MAX_CATEGORIES", | 56 { "tracing categories exhausted; must increase TRACE_EVENT_MAX_CATEGORIES", |
49 false }, | 57 false }, |
50 { "__metadata", | 58 { "__metadata", |
51 false } | 59 false } |
52 }; | 60 }; |
53 const TraceCategory* const g_category_already_shutdown = | 61 const TraceCategory* const g_category_already_shutdown = |
54 &g_categories[0]; | 62 &g_categories[0]; |
55 const TraceCategory* const g_category_categories_exhausted = | 63 const TraceCategory* const g_category_categories_exhausted = |
56 &g_categories[1]; | 64 &g_categories[1]; |
57 const TraceCategory* const g_category_metadata = | 65 const TraceCategory* const g_category_metadata = |
58 &g_categories[2]; | 66 &g_categories[2]; |
59 int g_category_index = 3; // skip initial 3 categories | 67 int g_category_index = 3; // skip initial 3 categories |
60 | 68 |
61 // The most-recently captured name of the current thread | 69 // The most-recently captured name of the current thread |
62 LazyInstance<ThreadLocalPointer<const char>, | 70 LazyInstance<ThreadLocalPointer<const char>, |
63 LeakyLazyInstanceTraits<ThreadLocalPointer<const char> > > | 71 LeakyLazyInstanceTraits<ThreadLocalPointer<const char> > > |
64 g_current_thread_name = LAZY_INSTANCE_INITIALIZER; | 72 g_current_thread_name = LAZY_INSTANCE_INITIALIZER; |
65 | 73 |
66 } // namespace | 74 } // namespace |
67 | 75 |
68 //////////////////////////////////////////////////////////////////////////////// | 76 //////////////////////////////////////////////////////////////////////////////// |
69 // | 77 // |
70 // TraceValue | 78 // TraceValue |
71 // | 79 // |
72 //////////////////////////////////////////////////////////////////////////////// | 80 //////////////////////////////////////////////////////////////////////////////// |
73 | 81 |
74 void TraceValue::AppendAsJSON(std::string* out) const { | 82 void TraceValue::AppendAsJSON(std::string* out) const { |
75 char temp_string[128]; | |
76 std::string::size_type start_pos; | 83 std::string::size_type start_pos; |
77 switch (type_) { | 84 switch (type_) { |
78 case TRACE_TYPE_BOOL: | 85 case TRACE_TYPE_BOOL: |
79 *out += as_bool() ? "true" : "false"; | 86 *out += as_bool() ? "true" : "false"; |
80 break; | 87 break; |
81 case TRACE_TYPE_UINT: | 88 case TRACE_TYPE_UINT: |
82 base::snprintf(temp_string, arraysize(temp_string), "%llu", | 89 StringAppendF(out, "%" PRIu64, as_uint()); |
83 static_cast<unsigned long long>(as_uint())); | |
84 *out += temp_string; | |
85 break; | 90 break; |
86 case TRACE_TYPE_INT: | 91 case TRACE_TYPE_INT: |
87 base::snprintf(temp_string, arraysize(temp_string), "%lld", | 92 StringAppendF(out, "%" PRId64, as_int()); |
88 static_cast<long long>(as_int())); | |
89 *out += temp_string; | |
90 break; | 93 break; |
91 case TRACE_TYPE_DOUBLE: | 94 case TRACE_TYPE_DOUBLE: |
92 base::snprintf(temp_string, arraysize(temp_string), "%f", as_double()); | 95 StringAppendF(out, "%f", as_double()); |
93 *out += temp_string; | |
94 break; | 96 break; |
95 case TRACE_TYPE_POINTER: | 97 case TRACE_TYPE_POINTER: |
96 base::snprintf(temp_string, arraysize(temp_string), "%llu", | 98 // JSON only supports double and int numbers. |
97 static_cast<unsigned long long>( | 99 // So as not to lose bits from a 64-bit pointer, output as a hex string. |
98 reinterpret_cast<intptr_t>( | 100 StringAppendF(out, "\"%" PRIx64 "\"", static_cast<uint64>( |
99 as_pointer()))); | 101 reinterpret_cast<intptr_t>( |
100 *out += temp_string; | 102 as_pointer()))); |
101 break; | 103 break; |
102 case TRACE_TYPE_STRING: | 104 case TRACE_TYPE_STRING: |
103 case TRACE_TYPE_STATIC_STRING: | 105 case TRACE_TYPE_STATIC_STRING: |
104 *out += "\""; | 106 *out += "\""; |
105 start_pos = out->size(); | 107 start_pos = out->size(); |
106 *out += as_string() ? as_string() : "NULL"; | 108 *out += as_string() ? as_string() : "NULL"; |
107 // insert backslash before special characters for proper json format. | 109 // insert backslash before special characters for proper json format. |
108 while ((start_pos = out->find_first_of("\\\"", start_pos)) != | 110 while ((start_pos = out->find_first_of("\\\"", start_pos)) != |
109 std::string::npos) { | 111 std::string::npos) { |
110 out->insert(start_pos, 1, '\\'); | 112 out->insert(start_pos, 1, '\\'); |
111 // skip inserted escape character and following character. | 113 // skip inserted escape character and following character. |
112 start_pos += 2; | 114 start_pos += 2; |
113 } | 115 } |
114 *out += "\""; | 116 *out += "\""; |
115 break; | 117 break; |
116 default: | 118 default: |
117 NOTREACHED() << "Don't know how to print this value"; | 119 NOTREACHED() << "Don't know how to print this value"; |
118 break; | 120 break; |
119 } | 121 } |
120 } | 122 } |
121 | 123 |
122 //////////////////////////////////////////////////////////////////////////////// | 124 //////////////////////////////////////////////////////////////////////////////// |
123 // | 125 // |
| 126 // TraceID |
| 127 // |
| 128 //////////////////////////////////////////////////////////////////////////////// |
| 129 |
| 130 TraceID::TraceID(void* rhs) { |
| 131 data_ = base::debug::TraceLog::GetInstance()->GetIntraProcessID( |
| 132 static_cast<uint64>(reinterpret_cast<uintptr_t>(rhs))); |
| 133 } |
| 134 |
| 135 //////////////////////////////////////////////////////////////////////////////// |
| 136 // |
124 // TraceEvent | 137 // TraceEvent |
125 // | 138 // |
126 //////////////////////////////////////////////////////////////////////////////// | 139 //////////////////////////////////////////////////////////////////////////////// |
127 | 140 |
128 namespace { | 141 namespace { |
129 | 142 |
130 size_t GetAllocLength(const char* str) { return str ? strlen(str) + 1 : 0; } | 143 size_t GetAllocLength(const char* str) { return str ? strlen(str) + 1 : 0; } |
131 | 144 |
132 // Copies |*member| into |*buffer|, sets |*member| to point to this new | 145 // Copies |*member| into |*buffer|, sets |*member| to point to this new |
133 // location, and then advances |*buffer| by the amount written. | 146 // location, and then advances |*buffer| by the amount written. |
134 void CopyTraceEventParameter(char** buffer, | 147 void CopyTraceEventParameter(char** buffer, |
135 const char** member, | 148 const char** member, |
136 const char* end) { | 149 const char* end) { |
137 if (*member) { | 150 if (*member) { |
138 size_t written = strlcpy(*buffer, *member, end - *buffer) + 1; | 151 size_t written = strlcpy(*buffer, *member, end - *buffer) + 1; |
139 DCHECK_LE(static_cast<int>(written), end - *buffer); | 152 DCHECK_LE(static_cast<int>(written), end - *buffer); |
140 *member = *buffer; | 153 *member = *buffer; |
141 *buffer += written; | 154 *buffer += written; |
142 } | 155 } |
143 } | 156 } |
144 | 157 |
145 } // namespace | 158 } // namespace |
146 | 159 |
147 TraceEvent::TraceEvent() | 160 TraceEvent::TraceEvent() |
148 : process_id_(0), | 161 : id_(0u), |
| 162 category_(NULL), |
| 163 name_(NULL), |
149 thread_id_(0), | 164 thread_id_(0), |
150 phase_(TRACE_EVENT_PHASE_BEGIN), | 165 phase_(TRACE_EVENT_PHASE_BEGIN), |
151 category_(NULL), | 166 flags_(0) { |
152 name_(NULL) { | |
153 arg_names_[0] = NULL; | 167 arg_names_[0] = NULL; |
154 arg_names_[1] = NULL; | 168 arg_names_[1] = NULL; |
155 } | 169 } |
156 | 170 |
157 TraceEvent::TraceEvent(unsigned long process_id, | 171 TraceEvent::TraceEvent(int thread_id, |
158 unsigned long thread_id, | |
159 TimeTicks timestamp, | 172 TimeTicks timestamp, |
160 TraceEventPhase phase, | 173 TraceEventPhase phase, |
161 const TraceCategory* category, | 174 const TraceCategory* category, |
162 const char* name, | 175 const char* name, |
| 176 TraceID id, |
163 const char* arg1_name, const TraceValue& arg1_val, | 177 const char* arg1_name, const TraceValue& arg1_val, |
164 const char* arg2_name, const TraceValue& arg2_val, | 178 const char* arg2_name, const TraceValue& arg2_val, |
165 bool copy) | 179 TraceEventFlags flags) |
166 : process_id_(process_id), | 180 : timestamp_(timestamp), |
| 181 id_(id), |
| 182 category_(category), |
| 183 name_(name), |
167 thread_id_(thread_id), | 184 thread_id_(thread_id), |
168 timestamp_(timestamp), | |
169 phase_(phase), | 185 phase_(phase), |
170 category_(category), | 186 flags_(flags) { |
171 name_(name) { | |
172 COMPILE_ASSERT(kTraceMaxNumArgs == 2, TraceEvent_arg_count_out_of_sync); | 187 COMPILE_ASSERT(kTraceMaxNumArgs == 2, TraceEvent_arg_count_out_of_sync); |
173 arg_names_[0] = arg1_name; | 188 arg_names_[0] = arg1_name; |
174 arg_names_[1] = arg2_name; | 189 arg_names_[1] = arg2_name; |
175 arg_values_[0] = arg1_val; | 190 arg_values_[0] = arg1_val; |
176 arg_values_[1] = arg2_val; | 191 arg_values_[1] = arg2_val; |
177 | 192 |
| 193 bool copy = !!(flags & TRACE_EVENT_FLAG_COPY); |
178 size_t alloc_size = 0; | 194 size_t alloc_size = 0; |
179 if (copy) { | 195 if (copy) { |
180 alloc_size += GetAllocLength(name); | 196 alloc_size += GetAllocLength(name); |
181 alloc_size += GetAllocLength(arg1_name); | 197 alloc_size += GetAllocLength(arg1_name); |
182 alloc_size += GetAllocLength(arg2_name); | 198 alloc_size += GetAllocLength(arg2_name); |
183 } | 199 } |
184 | 200 |
185 bool arg1_is_copy = (arg1_val.type() == TraceValue::TRACE_TYPE_STRING); | 201 bool arg1_is_copy = (arg1_val.type() == TraceValue::TRACE_TYPE_STRING); |
186 bool arg2_is_copy = (arg2_val.type() == TraceValue::TRACE_TYPE_STRING); | 202 bool arg2_is_copy = (arg2_val.type() == TraceValue::TRACE_TYPE_STRING); |
187 | 203 |
(...skipping 18 matching lines...) Expand all Loading... |
206 CopyTraceEventParameter(&ptr, arg_values_[0].as_assignable_string(), end); | 222 CopyTraceEventParameter(&ptr, arg_values_[0].as_assignable_string(), end); |
207 if (arg2_is_copy) | 223 if (arg2_is_copy) |
208 CopyTraceEventParameter(&ptr, arg_values_[1].as_assignable_string(), end); | 224 CopyTraceEventParameter(&ptr, arg_values_[1].as_assignable_string(), end); |
209 DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end; | 225 DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end; |
210 } | 226 } |
211 } | 227 } |
212 | 228 |
213 TraceEvent::~TraceEvent() { | 229 TraceEvent::~TraceEvent() { |
214 } | 230 } |
215 | 231 |
216 const char* TraceEvent::GetPhaseString(TraceEventPhase phase) { | |
217 switch(phase) { | |
218 case TRACE_EVENT_PHASE_BEGIN: | |
219 return "B"; | |
220 case TRACE_EVENT_PHASE_INSTANT: | |
221 return "I"; | |
222 case TRACE_EVENT_PHASE_END: | |
223 return "E"; | |
224 case TRACE_EVENT_PHASE_METADATA: | |
225 return "M"; | |
226 case TRACE_EVENT_PHASE_COUNTER: | |
227 return "C"; | |
228 default: | |
229 NOTREACHED() << "Invalid phase argument"; | |
230 return "?"; | |
231 } | |
232 } | |
233 | |
234 TraceEventPhase TraceEvent::GetPhase(const char* phase) { | |
235 switch(*phase) { | |
236 case 'B': | |
237 return TRACE_EVENT_PHASE_BEGIN; | |
238 case 'I': | |
239 return TRACE_EVENT_PHASE_INSTANT; | |
240 case 'E': | |
241 return TRACE_EVENT_PHASE_END; | |
242 case 'M': | |
243 return TRACE_EVENT_PHASE_METADATA; | |
244 case 'C': | |
245 return TRACE_EVENT_PHASE_COUNTER; | |
246 default: | |
247 NOTREACHED() << "Invalid phase name"; | |
248 return TRACE_EVENT_PHASE_METADATA; | |
249 } | |
250 } | |
251 | |
252 void TraceEvent::AppendEventsAsJSON(const std::vector<TraceEvent>& events, | 232 void TraceEvent::AppendEventsAsJSON(const std::vector<TraceEvent>& events, |
253 size_t start, | 233 size_t start, |
254 size_t count, | 234 size_t count, |
255 std::string* out) { | 235 std::string* out) { |
256 for (size_t i = 0; i < count && start + i < events.size(); ++i) { | 236 for (size_t i = 0; i < count && start + i < events.size(); ++i) { |
257 if (i > 0) | 237 if (i > 0) |
258 *out += ","; | 238 *out += ","; |
259 events[i + start].AppendAsJSON(out); | 239 events[i + start].AppendAsJSON(out); |
260 } | 240 } |
261 } | 241 } |
262 | 242 |
263 void TraceEvent::AppendAsJSON(std::string* out) const { | 243 void TraceEvent::AppendAsJSON(std::string* out) const { |
264 const char* phase_str = GetPhaseString(phase_); | 244 const char phase_char = GetPhaseChar(phase_); |
265 int64 time_int64 = timestamp_.ToInternalValue(); | 245 int64 time_int64 = timestamp_.ToInternalValue(); |
| 246 int process_id = TraceLog::GetInstance()->process_id(); |
266 // Category name checked at category creation time. | 247 // Category name checked at category creation time. |
267 DCHECK(!strchr(name_, '"')); | 248 DCHECK(!strchr(name_, '"')); |
268 StringAppendF(out, | 249 StringAppendF(out, |
269 "{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%lld," | 250 "{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 "," |
270 "\"ph\":\"%s\",\"name\":\"%s\",\"args\":{", | 251 "\"ph\":\"%c\",\"name\":\"%s\",\"args\":{", |
271 category_->name, | 252 category_->name, |
272 static_cast<int>(process_id_), | 253 process_id, |
273 static_cast<int>(thread_id_), | 254 thread_id_, |
274 static_cast<long long>(time_int64), | 255 time_int64, |
275 phase_str, | 256 phase_char, |
276 name_); | 257 name_); |
277 | 258 |
278 // Output argument names and values, stop at first NULL argument name. | 259 // Output argument names and values, stop at first NULL argument name. |
279 for (size_t i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) { | 260 for (size_t i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) { |
280 if (i > 0) | 261 if (i > 0) |
281 *out += ","; | 262 *out += ","; |
282 *out += "\""; | 263 *out += "\""; |
283 *out += arg_names_[i]; | 264 *out += arg_names_[i]; |
284 *out += "\":"; | 265 *out += "\":"; |
285 arg_values_[i].AppendAsJSON(out); | 266 arg_values_[i].AppendAsJSON(out); |
286 } | 267 } |
287 *out += "}}"; | 268 *out += "}"; |
| 269 |
| 270 // If id_ is set, print it out as a hex string so we don't loose any |
| 271 // bits (it might be a 64-bit pointer). |
| 272 if (flags_ & TRACE_EVENT_FLAG_HAS_ID) |
| 273 StringAppendF(out, ",\"id\":\"%" PRIx64 "\"", id_.data()); |
| 274 *out += "}"; |
288 } | 275 } |
289 | 276 |
290 //////////////////////////////////////////////////////////////////////////////// | 277 //////////////////////////////////////////////////////////////////////////////// |
291 // | 278 // |
292 // TraceResultBuffer | 279 // TraceResultBuffer |
293 // | 280 // |
294 //////////////////////////////////////////////////////////////////////////////// | 281 //////////////////////////////////////////////////////////////////////////////// |
295 | 282 |
296 TraceResultBuffer::OutputCallback | 283 TraceResultBuffer::OutputCallback |
297 TraceResultBuffer::SimpleOutput::GetCallback() { | 284 TraceResultBuffer::SimpleOutput::GetCallback() { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 // | 322 // |
336 //////////////////////////////////////////////////////////////////////////////// | 323 //////////////////////////////////////////////////////////////////////////////// |
337 | 324 |
338 // static | 325 // static |
339 TraceLog* TraceLog::GetInstance() { | 326 TraceLog* TraceLog::GetInstance() { |
340 return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog> >::get(); | 327 return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog> >::get(); |
341 } | 328 } |
342 | 329 |
343 TraceLog::TraceLog() | 330 TraceLog::TraceLog() |
344 : enabled_(false) { | 331 : enabled_(false) { |
| 332 SetProcessID(static_cast<int>(base::GetCurrentProcId())); |
345 } | 333 } |
346 | 334 |
347 TraceLog::~TraceLog() { | 335 TraceLog::~TraceLog() { |
348 } | 336 } |
349 | 337 |
350 const TraceCategory* TraceLog::GetCategory(const char* name) { | 338 const TraceCategory* TraceLog::GetCategory(const char* name) { |
351 TraceLog* tracelog = GetInstance(); | 339 TraceLog* tracelog = GetInstance(); |
352 if (!tracelog){ | 340 if (!tracelog){ |
353 DCHECK(!g_category_already_shutdown->enabled); | 341 DCHECK(!g_category_already_shutdown->enabled); |
354 return g_category_already_shutdown; | 342 return g_category_already_shutdown; |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 i, | 514 i, |
527 kTraceEventBatchSize, | 515 kTraceEventBatchSize, |
528 &(json_events_str_ptr->data)); | 516 &(json_events_str_ptr->data)); |
529 output_callback_copy.Run(json_events_str_ptr); | 517 output_callback_copy.Run(json_events_str_ptr); |
530 } | 518 } |
531 } | 519 } |
532 | 520 |
533 int TraceLog::AddTraceEvent(TraceEventPhase phase, | 521 int TraceLog::AddTraceEvent(TraceEventPhase phase, |
534 const TraceCategory* category, | 522 const TraceCategory* category, |
535 const char* name, | 523 const char* name, |
| 524 TraceID id, |
536 const char* arg1_name, TraceValue arg1_val, | 525 const char* arg1_name, TraceValue arg1_val, |
537 const char* arg2_name, TraceValue arg2_val, | 526 const char* arg2_name, TraceValue arg2_val, |
538 int threshold_begin_id, | 527 int threshold_begin_id, |
539 int64 threshold, | 528 int64 threshold, |
540 EventFlags flags) { | 529 TraceEventFlags flags) { |
541 DCHECK(name); | 530 DCHECK(name); |
542 TimeTicks now = TimeTicks::HighResNow(); | 531 TimeTicks now = TimeTicks::HighResNow(); |
543 BufferFullCallback buffer_full_callback_copy; | 532 BufferFullCallback buffer_full_callback_copy; |
544 int ret_begin_id = -1; | 533 int ret_begin_id = -1; |
545 { | 534 { |
546 AutoLock lock(lock_); | 535 AutoLock lock(lock_); |
547 if (!category->enabled) | 536 if (!category->enabled) |
548 return -1; | 537 return -1; |
549 if (logged_events_.size() >= kTraceEventBufferSize) | 538 if (logged_events_.size() >= kTraceEventBufferSize) |
550 return -1; | 539 return -1; |
551 | 540 |
552 PlatformThreadId thread_id = PlatformThread::CurrentId(); | 541 int thread_id = static_cast<int>(PlatformThread::CurrentId()); |
553 | 542 |
554 const char* new_name = PlatformThread::GetName(); | 543 const char* new_name = PlatformThread::GetName(); |
555 // Check if the thread name has been set or changed since the previous | 544 // Check if the thread name has been set or changed since the previous |
556 // call (if any), but don't bother if the new name is empty. Note this will | 545 // call (if any), but don't bother if the new name is empty. Note this will |
557 // not detect a thread name change within the same char* buffer address: we | 546 // not detect a thread name change within the same char* buffer address: we |
558 // favor common case performance over corner case correctness. | 547 // favor common case performance over corner case correctness. |
559 if (new_name != g_current_thread_name.Get().Get() && | 548 if (new_name != g_current_thread_name.Get().Get() && |
560 new_name && *new_name) { | 549 new_name && *new_name) { |
561 g_current_thread_name.Get().Set(new_name); | 550 g_current_thread_name.Get().Set(new_name); |
562 base::hash_map<PlatformThreadId, std::string>::iterator existing_name = | 551 base::hash_map<int, std::string>::iterator existing_name = |
563 thread_names_.find(thread_id); | 552 thread_names_.find(thread_id); |
564 if (existing_name == thread_names_.end()) { | 553 if (existing_name == thread_names_.end()) { |
565 // This is a new thread id, and a new name. | 554 // This is a new thread id, and a new name. |
566 thread_names_[thread_id] = new_name; | 555 thread_names_[thread_id] = new_name; |
567 } else { | 556 } else { |
568 // This is a thread id that we've seen before, but potentially with a | 557 // This is a thread id that we've seen before, but potentially with a |
569 // new name. | 558 // new name. |
570 std::vector<base::StringPiece> existing_names; | 559 std::vector<base::StringPiece> existing_names; |
571 Tokenize(existing_name->second, ",", &existing_names); | 560 Tokenize(existing_name->second, ",", &existing_names); |
572 bool found = std::find(existing_names.begin(), | 561 bool found = std::find(existing_names.begin(), |
573 existing_names.end(), | 562 existing_names.end(), |
574 new_name) != existing_names.end(); | 563 new_name) != existing_names.end(); |
575 if (!found) { | 564 if (!found) { |
576 existing_name->second.push_back(','); | 565 existing_name->second.push_back(','); |
577 existing_name->second.append(new_name); | 566 existing_name->second.append(new_name); |
578 } | 567 } |
579 } | 568 } |
580 } | 569 } |
581 | 570 |
582 if (threshold_begin_id > -1) { | 571 if (threshold_begin_id > -1) { |
583 DCHECK(phase == base::debug::TRACE_EVENT_PHASE_END); | 572 DCHECK(phase == TRACE_EVENT_PHASE_END); |
584 size_t begin_i = static_cast<size_t>(threshold_begin_id); | 573 size_t begin_i = static_cast<size_t>(threshold_begin_id); |
585 // Return now if there has been a flush since the begin event was posted. | 574 // Return now if there has been a flush since the begin event was posted. |
586 if (begin_i >= logged_events_.size()) | 575 if (begin_i >= logged_events_.size()) |
587 return -1; | 576 return -1; |
588 // Determine whether to drop the begin/end pair. | 577 // Determine whether to drop the begin/end pair. |
589 TimeDelta elapsed = now - logged_events_[begin_i].timestamp(); | 578 TimeDelta elapsed = now - logged_events_[begin_i].timestamp(); |
590 if (elapsed < TimeDelta::FromMicroseconds(threshold)) { | 579 if (elapsed < TimeDelta::FromMicroseconds(threshold)) { |
591 // Remove begin event and do not add end event. | 580 // Remove begin event and do not add end event. |
592 // This will be expensive if there have been other events in the | 581 // This will be expensive if there have been other events in the |
593 // mean time (should be rare). | 582 // mean time (should be rare). |
594 logged_events_.erase(logged_events_.begin() + begin_i); | 583 logged_events_.erase(logged_events_.begin() + begin_i); |
595 return -1; | 584 return -1; |
596 } | 585 } |
597 } | 586 } |
598 ret_begin_id = static_cast<int>(logged_events_.size()); | 587 ret_begin_id = static_cast<int>(logged_events_.size()); |
599 logged_events_.push_back( | 588 logged_events_.push_back( |
600 TraceEvent(static_cast<unsigned long>(base::GetCurrentProcId()), | 589 TraceEvent(thread_id, |
601 thread_id, | 590 now, phase, category, name, id, |
602 now, phase, category, name, | |
603 arg1_name, arg1_val, | 591 arg1_name, arg1_val, |
604 arg2_name, arg2_val, | 592 arg2_name, arg2_val, |
605 flags & EVENT_FLAG_COPY)); | 593 flags)); |
606 | 594 |
607 if (logged_events_.size() == kTraceEventBufferSize) { | 595 if (logged_events_.size() == kTraceEventBufferSize) { |
608 buffer_full_callback_copy = buffer_full_callback_; | 596 buffer_full_callback_copy = buffer_full_callback_; |
609 } | 597 } |
610 } // release lock | 598 } // release lock |
611 | 599 |
612 if (!buffer_full_callback_copy.is_null()) | 600 if (!buffer_full_callback_copy.is_null()) |
613 buffer_full_callback_copy.Run(); | 601 buffer_full_callback_copy.Run(); |
614 | 602 |
615 return ret_begin_id; | 603 return ret_begin_id; |
616 } | 604 } |
617 | 605 |
618 void TraceLog::AddTraceEventEtw(TraceEventPhase phase, | 606 void TraceLog::AddTraceEventEtw(TraceEventPhase phase, |
619 const char* name, | 607 const char* name, |
620 const void* id, | 608 const void* id, |
621 const char* extra) { | 609 const char* extra) { |
622 #if defined(OS_WIN) | 610 #if defined(OS_WIN) |
623 TraceEventETWProvider::Trace(name, phase, id, extra); | 611 TraceEventETWProvider::Trace(name, phase, id, extra); |
624 #endif | 612 #endif |
625 INTERNAL_TRACE_EVENT_ADD(phase, | 613 INTERNAL_TRACE_EVENT_ADD(phase, |
626 "ETW Trace Event", name, "id", id, "extra", TRACE_STR_COPY(extra), | 614 "ETW Trace Event", name, "id", id, "extra", TRACE_STR_COPY(extra), |
627 base::debug::TraceLog::EVENT_FLAG_COPY); | 615 TRACE_EVENT_FLAG_COPY); |
628 } | 616 } |
629 | 617 |
630 void TraceLog::AddTraceEventEtw(TraceEventPhase phase, | 618 void TraceLog::AddTraceEventEtw(TraceEventPhase phase, |
631 const char* name, | 619 const char* name, |
632 const void* id, | 620 const void* id, |
633 const std::string& extra) | 621 const std::string& extra) |
634 { | 622 { |
635 #if defined(OS_WIN) | 623 #if defined(OS_WIN) |
636 TraceEventETWProvider::Trace(name, phase, id, extra); | 624 TraceEventETWProvider::Trace(name, phase, id, extra); |
637 #endif | 625 #endif |
638 INTERNAL_TRACE_EVENT_ADD(phase, | 626 INTERNAL_TRACE_EVENT_ADD(phase, |
639 "ETW Trace Event", name, "id", id, "extra", extra, | 627 "ETW Trace Event", name, "id", id, "extra", extra, |
640 base::debug::TraceLog::EVENT_FLAG_COPY); | 628 TRACE_EVENT_FLAG_COPY); |
641 } | 629 } |
642 | 630 |
643 int TraceLog::AddCounterEvent(const TraceCategory* category, | 631 int TraceLog::AddCounterEvent(const TraceCategory* category, |
644 const char* name, | 632 const char* name, |
645 const char* value1_name, int32 value1_val, | 633 const char* value1_name, int32 value1_val, |
646 const char* value2_name, int32 value2_val, | 634 const char* value2_name, int32 value2_val, |
647 EventFlags flags) { | 635 TraceEventFlags flags) { |
648 return AddTraceEvent(TRACE_EVENT_PHASE_COUNTER, | 636 return AddTraceEvent(TRACE_EVENT_PHASE_COUNTER, |
649 category, | 637 category, |
650 name, | 638 name, |
| 639 0, |
651 value1_name, value1_val, | 640 value1_name, value1_val, |
652 value2_name, value2_val, | 641 value2_name, value2_val, |
653 -1, 0, | 642 -1, 0, |
654 flags); | 643 flags); |
655 } | 644 } |
656 | 645 |
657 void TraceLog::AddCurrentMetadataEvents() { | 646 void TraceLog::AddCurrentMetadataEvents() { |
658 lock_.AssertAcquired(); | 647 lock_.AssertAcquired(); |
659 for(base::hash_map<PlatformThreadId, std::string>::iterator it = | 648 for(base::hash_map<int, std::string>::iterator it = thread_names_.begin(); |
660 thread_names_.begin(); | |
661 it != thread_names_.end(); | 649 it != thread_names_.end(); |
662 it++) { | 650 it++) { |
663 if (!it->second.empty()) | 651 if (!it->second.empty()) |
664 logged_events_.push_back( | 652 logged_events_.push_back( |
665 TraceEvent(static_cast<unsigned long>(base::GetCurrentProcId()), | 653 TraceEvent(it->first, |
666 it->first, | 654 TimeTicks(), TRACE_EVENT_PHASE_METADATA, |
667 TimeTicks(), base::debug::TRACE_EVENT_PHASE_METADATA, | 655 g_category_metadata, "thread_name", 0, |
668 g_category_metadata, "thread_name", | |
669 "name", it->second, | 656 "name", it->second, |
670 NULL, 0, | 657 NULL, 0, |
671 false)); | 658 TRACE_EVENT_FLAG_NONE)); |
672 } | 659 } |
673 } | 660 } |
674 | 661 |
675 void TraceLog::DeleteForTesting() { | 662 void TraceLog::DeleteForTesting() { |
676 DeleteTraceLogForTesting::Delete(); | 663 DeleteTraceLogForTesting::Delete(); |
677 } | 664 } |
678 | 665 |
679 void TraceLog::Resurrect() { | 666 void TraceLog::Resurrect() { |
680 StaticMemorySingletonTraits<TraceLog>::Resurrect(); | 667 StaticMemorySingletonTraits<TraceLog>::Resurrect(); |
681 } | 668 } |
682 | 669 |
| 670 void TraceLog::SetProcessID(int process_id) { |
| 671 process_id_ = process_id; |
| 672 // Create a FNV hash from the process ID for XORing. |
| 673 // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details. |
| 674 uint64 offset_basis = 14695981039346656037ull; |
| 675 uint64 fnv_prime = 1099511628211ull; |
| 676 unsigned long long pid = static_cast<unsigned long long>(process_id_); |
| 677 process_id_hash_ = (offset_basis ^ pid) * fnv_prime; |
| 678 } |
| 679 |
683 namespace internal { | 680 namespace internal { |
684 | 681 |
685 void TraceEndOnScopeClose::Initialize(const TraceCategory* category, | 682 void TraceEndOnScopeClose::Initialize(const TraceCategory* category, |
686 const char* name) { | 683 const char* name) { |
687 data_.category = category; | 684 data_.category = category; |
688 data_.name = name; | 685 data_.name = name; |
689 p_data_ = &data_; | 686 p_data_ = &data_; |
690 } | 687 } |
691 | 688 |
692 void TraceEndOnScopeClose::AddEventIfEnabled() { | 689 void TraceEndOnScopeClose::AddEventIfEnabled() { |
693 // Only called when p_data_ is non-null. | 690 // Only called when p_data_ is non-null. |
694 if (p_data_->category->enabled) { | 691 if (p_data_->category->enabled) { |
695 base::debug::TraceLog::GetInstance()->AddTraceEvent( | 692 base::debug::TraceLog::GetInstance()->AddTraceEvent( |
696 base::debug::TRACE_EVENT_PHASE_END, | 693 TRACE_EVENT_PHASE_END, |
697 p_data_->category, | 694 p_data_->category, |
698 p_data_->name, | 695 p_data_->name, kNoEventId, |
699 NULL, 0, NULL, 0, | 696 kNoArgName, kNoArgValue, kNoArgName, kNoArgValue, |
700 -1, 0, TraceLog::EVENT_FLAG_NONE); | 697 kNoThreshholdBeginId, kNoThresholdValue, TRACE_EVENT_FLAG_NONE); |
701 } | 698 } |
702 } | 699 } |
703 | 700 |
704 void TraceEndOnScopeCloseThreshold::Initialize(const TraceCategory* category, | 701 void TraceEndOnScopeCloseThreshold::Initialize(const TraceCategory* category, |
705 const char* name, | 702 const char* name, |
706 int threshold_begin_id, | 703 int threshold_begin_id, |
707 int64 threshold) { | 704 int64 threshold) { |
708 data_.category = category; | 705 data_.category = category; |
709 data_.name = name; | 706 data_.name = name; |
710 data_.threshold_begin_id = threshold_begin_id; | 707 data_.threshold_begin_id = threshold_begin_id; |
711 data_.threshold = threshold; | 708 data_.threshold = threshold; |
712 p_data_ = &data_; | 709 p_data_ = &data_; |
713 } | 710 } |
714 | 711 |
715 void TraceEndOnScopeCloseThreshold::AddEventIfEnabled() { | 712 void TraceEndOnScopeCloseThreshold::AddEventIfEnabled() { |
716 // Only called when p_data_ is non-null. | 713 // Only called when p_data_ is non-null. |
717 if (p_data_->category->enabled) { | 714 if (p_data_->category->enabled) { |
718 base::debug::TraceLog::GetInstance()->AddTraceEvent( | 715 base::debug::TraceLog::GetInstance()->AddTraceEvent( |
719 base::debug::TRACE_EVENT_PHASE_END, | 716 TRACE_EVENT_PHASE_END, |
720 p_data_->category, | 717 p_data_->category, |
721 p_data_->name, | 718 p_data_->name, kNoEventId, |
722 NULL, 0, NULL, 0, | 719 kNoArgName, kNoArgValue, kNoArgName, kNoArgValue, |
723 p_data_->threshold_begin_id, p_data_->threshold, | 720 p_data_->threshold_begin_id, p_data_->threshold, |
724 TraceLog::EVENT_FLAG_NONE); | 721 TRACE_EVENT_FLAG_NONE); |
725 } | 722 } |
726 } | 723 } |
727 | 724 |
728 } // namespace internal | 725 } // namespace internal |
729 | 726 |
730 } // namespace debug | 727 } // namespace debug |
731 } // namespace base | 728 } // namespace base |
OLD | NEW |