| 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 |