Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_impl.h" | 5 #include "base/debug/trace_event_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/debug/leak_annotations.h" | 10 #include "base/debug/leak_annotations.h" |
| 11 #include "base/debug/trace_event.h" | 11 #include "base/debug/trace_event.h" |
| 12 #include "base/file_util.h" | |
| 13 #include "base/format_macros.h" | 12 #include "base/format_macros.h" |
| 14 #include "base/lazy_instance.h" | 13 #include "base/lazy_instance.h" |
| 15 #include "base/memory/singleton.h" | 14 #include "base/memory/singleton.h" |
| 16 #include "base/process_util.h" | 15 #include "base/process_util.h" |
| 17 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
| 18 #include "base/stringprintf.h" | 17 #include "base/stringprintf.h" |
| 19 #include "base/string_tokenizer.h" | 18 #include "base/string_tokenizer.h" |
| 20 #include "base/string_util.h" | 19 #include "base/string_util.h" |
| 21 #include "base/sys_info.h" | 20 #include "base/sys_info.h" |
| 22 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | 21 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 63 unsigned char g_category_enabled[TRACE_EVENT_MAX_CATEGORIES] = { 0 }; | 62 unsigned char g_category_enabled[TRACE_EVENT_MAX_CATEGORIES] = { 0 }; |
| 64 const int g_category_already_shutdown = 0; | 63 const int g_category_already_shutdown = 0; |
| 65 const int g_category_categories_exhausted = 1; | 64 const int g_category_categories_exhausted = 1; |
| 66 const int g_category_metadata = 2; | 65 const int g_category_metadata = 2; |
| 67 int g_category_index = 3; // skip initial 3 categories | 66 int g_category_index = 3; // skip initial 3 categories |
| 68 | 67 |
| 69 // The most-recently captured name of the current thread | 68 // The most-recently captured name of the current thread |
| 70 LazyInstance<ThreadLocalPointer<const char> >::Leaky | 69 LazyInstance<ThreadLocalPointer<const char> >::Leaky |
| 71 g_current_thread_name = LAZY_INSTANCE_INITIALIZER; | 70 g_current_thread_name = LAZY_INSTANCE_INITIALIZER; |
| 72 | 71 |
| 73 void AppendValueAsJSON(unsigned char type, | |
| 74 TraceEvent::TraceValue value, | |
| 75 std::string* out) { | |
| 76 std::string::size_type start_pos; | |
| 77 switch (type) { | |
| 78 case TRACE_VALUE_TYPE_BOOL: | |
| 79 *out += value.as_bool ? "true" : "false"; | |
| 80 break; | |
| 81 case TRACE_VALUE_TYPE_UINT: | |
| 82 StringAppendF(out, "%" PRIu64, static_cast<uint64>(value.as_uint)); | |
| 83 break; | |
| 84 case TRACE_VALUE_TYPE_INT: | |
| 85 StringAppendF(out, "%" PRId64, static_cast<int64>(value.as_int)); | |
| 86 break; | |
| 87 case TRACE_VALUE_TYPE_DOUBLE: | |
| 88 StringAppendF(out, "%f", value.as_double); | |
| 89 break; | |
| 90 case TRACE_VALUE_TYPE_POINTER: | |
| 91 // JSON only supports double and int numbers. | |
| 92 // So as not to lose bits from a 64-bit pointer, output as a hex string. | |
| 93 StringAppendF(out, "\"%" PRIx64 "\"", static_cast<uint64>( | |
| 94 reinterpret_cast<intptr_t>( | |
| 95 value.as_pointer))); | |
| 96 break; | |
| 97 case TRACE_VALUE_TYPE_STRING: | |
| 98 case TRACE_VALUE_TYPE_COPY_STRING: | |
| 99 *out += "\""; | |
| 100 start_pos = out->size(); | |
| 101 *out += value.as_string ? value.as_string : "NULL"; | |
| 102 // insert backslash before special characters for proper json format. | |
| 103 while ((start_pos = out->find_first_of("\\\"", start_pos)) != | |
| 104 std::string::npos) { | |
| 105 out->insert(start_pos, 1, '\\'); | |
| 106 // skip inserted escape character and following character. | |
| 107 start_pos += 2; | |
| 108 } | |
| 109 *out += "\""; | |
| 110 break; | |
| 111 default: | |
| 112 NOTREACHED() << "Don't know how to print this value"; | |
| 113 break; | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 } // namespace | 72 } // namespace |
| 118 | 73 |
| 119 //////////////////////////////////////////////////////////////////////////////// | 74 //////////////////////////////////////////////////////////////////////////////// |
| 120 // | 75 // |
| 121 // TraceEvent | 76 // TraceEvent |
| 122 // | 77 // |
| 123 //////////////////////////////////////////////////////////////////////////////// | 78 //////////////////////////////////////////////////////////////////////////////// |
| 124 | 79 |
| 125 namespace { | 80 namespace { |
| 126 | 81 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 218 if (arg_is_copy[i]) | 173 if (arg_is_copy[i]) |
| 219 CopyTraceEventParameter(&ptr, &arg_values_[i].as_string, end); | 174 CopyTraceEventParameter(&ptr, &arg_values_[i].as_string, end); |
| 220 } | 175 } |
| 221 DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end; | 176 DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end; |
| 222 } | 177 } |
| 223 } | 178 } |
| 224 | 179 |
| 225 TraceEvent::~TraceEvent() { | 180 TraceEvent::~TraceEvent() { |
| 226 } | 181 } |
| 227 | 182 |
| 183 // static | |
| 184 void TraceEvent::AppendValueAsJSON(unsigned char type, | |
| 185 TraceEvent::TraceValue value, | |
| 186 std::string* out) { | |
| 187 std::string::size_type start_pos; | |
| 188 switch (type) { | |
| 189 case TRACE_VALUE_TYPE_BOOL: | |
| 190 *out += value.as_bool ? "true" : "false"; | |
| 191 break; | |
| 192 case TRACE_VALUE_TYPE_UINT: | |
| 193 StringAppendF(out, "%" PRIu64, static_cast<uint64>(value.as_uint)); | |
| 194 break; | |
| 195 case TRACE_VALUE_TYPE_INT: | |
| 196 StringAppendF(out, "%" PRId64, static_cast<int64>(value.as_int)); | |
| 197 break; | |
| 198 case TRACE_VALUE_TYPE_DOUBLE: | |
| 199 StringAppendF(out, "%f", value.as_double); | |
| 200 break; | |
| 201 case TRACE_VALUE_TYPE_POINTER: | |
| 202 // JSON only supports double and int numbers. | |
| 203 // So as not to lose bits from a 64-bit pointer, output as a hex string. | |
| 204 StringAppendF(out, "\"%" PRIx64 "\"", static_cast<uint64>( | |
| 205 reinterpret_cast<intptr_t>( | |
| 206 value.as_pointer))); | |
| 207 break; | |
| 208 case TRACE_VALUE_TYPE_STRING: | |
| 209 case TRACE_VALUE_TYPE_COPY_STRING: | |
| 210 *out += "\""; | |
| 211 start_pos = out->size(); | |
| 212 *out += value.as_string ? value.as_string : "NULL"; | |
| 213 // insert backslash before special characters for proper json format. | |
| 214 while ((start_pos = out->find_first_of("\\\"", start_pos)) != | |
| 215 std::string::npos) { | |
| 216 out->insert(start_pos, 1, '\\'); | |
| 217 // skip inserted escape character and following character. | |
| 218 start_pos += 2; | |
| 219 } | |
| 220 *out += "\""; | |
| 221 break; | |
| 222 default: | |
| 223 NOTREACHED() << "Don't know how to print this value"; | |
| 224 break; | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 void TraceEvent::AppendEventsAsJSON(const std::vector<TraceEvent>& events, | 228 void TraceEvent::AppendEventsAsJSON(const std::vector<TraceEvent>& events, |
| 229 size_t start, | 229 size_t start, |
| 230 size_t count, | 230 size_t count, |
| 231 std::string* out) { | 231 std::string* out) { |
| 232 for (size_t i = 0; i < count && start + i < events.size(); ++i) { | 232 for (size_t i = 0; i < count && start + i < events.size(); ++i) { |
| 233 if (i > 0) | 233 if (i > 0) |
| 234 *out += ","; | 234 *out += ","; |
| 235 events[i + start].AppendAsJSON(out); | 235 events[i + start].AppendAsJSON(out); |
| 236 } | 236 } |
| 237 } | 237 } |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 536 dispatching_to_observer_list_ = false; | 536 dispatching_to_observer_list_ = false; |
| 537 | 537 |
| 538 enabled_ = false; | 538 enabled_ = false; |
| 539 included_categories_.clear(); | 539 included_categories_.clear(); |
| 540 excluded_categories_.clear(); | 540 excluded_categories_.clear(); |
| 541 watch_category_ = NULL; | 541 watch_category_ = NULL; |
| 542 watch_event_name_ = ""; | 542 watch_event_name_ = ""; |
| 543 for (int i = 0; i < g_category_index; i++) | 543 for (int i = 0; i < g_category_index; i++) |
| 544 g_category_enabled[i] = 0; | 544 g_category_enabled[i] = 0; |
| 545 AddThreadNameMetadataEvents(); | 545 AddThreadNameMetadataEvents(); |
| 546 #if defined(OS_ANDROID) | |
| 546 AddClockSyncMetadataEvents(); | 547 AddClockSyncMetadataEvents(); |
| 548 #endif | |
| 547 } | 549 } |
| 548 | 550 |
| 549 void TraceLog::SetEnabled(bool enabled) { | 551 void TraceLog::SetEnabled(bool enabled) { |
| 550 if (enabled) | 552 if (enabled) |
| 551 SetEnabled(std::vector<std::string>(), std::vector<std::string>()); | 553 SetEnabled(std::vector<std::string>(), std::vector<std::string>()); |
| 552 else | 554 else |
| 553 SetDisabled(); | 555 SetDisabled(); |
| 554 } | 556 } |
| 555 | 557 |
| 556 void TraceLog::AddEnabledStateObserver(EnabledStateChangedObserver* listener) { | 558 void TraceLog::AddEnabledStateObserver(EnabledStateChangedObserver* listener) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 597 const char* name, | 599 const char* name, |
| 598 unsigned long long id, | 600 unsigned long long id, |
| 599 int num_args, | 601 int num_args, |
| 600 const char** arg_names, | 602 const char** arg_names, |
| 601 const unsigned char* arg_types, | 603 const unsigned char* arg_types, |
| 602 const unsigned long long* arg_values, | 604 const unsigned long long* arg_values, |
| 603 int threshold_begin_id, | 605 int threshold_begin_id, |
| 604 long long threshold, | 606 long long threshold, |
| 605 unsigned char flags) { | 607 unsigned char flags) { |
| 606 DCHECK(name); | 608 DCHECK(name); |
| 609 | |
| 610 #if defined(OS_ANDROID) | |
| 611 if (IsATraceEnabled()) { | |
|
jbates
2012/10/30 20:22:14
This if looks redundant
Xianzhu
2012/10/30 21:45:01
Done.
| |
| 612 SendToATrace(phase, GetCategoryName(category_enabled), name, | |
| 613 num_args, arg_names, arg_types, arg_values); | |
| 614 } | |
| 615 #endif | |
| 616 | |
| 607 TimeTicks now = TimeTicks::NowFromSystemTraceTime(); | 617 TimeTicks now = TimeTicks::NowFromSystemTraceTime(); |
| 608 NotificationHelper notifier(this); | 618 NotificationHelper notifier(this); |
| 609 int ret_begin_id = -1; | 619 int ret_begin_id = -1; |
| 610 { | 620 { |
| 611 AutoLock lock(lock_); | 621 AutoLock lock(lock_); |
| 612 if (!*category_enabled) | 622 if (!*category_enabled) |
| 613 return -1; | 623 return -1; |
| 614 if (logged_events_.size() >= kTraceEventBufferSize) | 624 if (logged_events_.size() >= kTraceEventBufferSize) |
| 615 return -1; | 625 return -1; |
| 616 | 626 |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 734 notifier.SendNotificationIfAny(); | 744 notifier.SendNotificationIfAny(); |
| 735 } | 745 } |
| 736 } | 746 } |
| 737 | 747 |
| 738 void TraceLog::CancelWatchEvent() { | 748 void TraceLog::CancelWatchEvent() { |
| 739 AutoLock lock(lock_); | 749 AutoLock lock(lock_); |
| 740 watch_category_ = NULL; | 750 watch_category_ = NULL; |
| 741 watch_event_name_ = ""; | 751 watch_event_name_ = ""; |
| 742 } | 752 } |
| 743 | 753 |
| 744 void TraceLog::AddClockSyncMetadataEvents() { | |
| 745 #if defined(OS_ANDROID) | |
| 746 // Since Android does not support sched_setaffinity, we cannot establish clock | |
| 747 // sync unless the scheduler clock is set to global. If the trace_clock file | |
| 748 // can't be read, we will assume the kernel doesn't support tracing and do | |
| 749 // nothing. | |
| 750 std::string clock_mode; | |
| 751 if (!file_util::ReadFileToString( | |
| 752 FilePath("/sys/kernel/debug/tracing/trace_clock"), | |
| 753 &clock_mode)) | |
| 754 return; | |
| 755 | |
| 756 if (clock_mode != "local [global]\n") { | |
| 757 DLOG(WARNING) << | |
| 758 "The kernel's tracing clock must be set to global in order for " << | |
| 759 "trace_event to be synchronized with . Do this by\n" << | |
| 760 " echo global > /sys/kerel/debug/tracing/trace_clock"; | |
| 761 return; | |
| 762 } | |
| 763 | |
| 764 // Android's kernel trace system has a trace_marker feature: this is a file on | |
| 765 // debugfs that takes the written data and pushes it onto the trace | |
| 766 // buffer. So, to establish clock sync, we write our monotonic clock into that | |
| 767 // trace buffer. | |
| 768 TimeTicks now = TimeTicks::NowFromSystemTraceTime(); | |
| 769 | |
| 770 double now_in_seconds = now.ToInternalValue() / 1000000.0; | |
| 771 std::string marker = | |
| 772 StringPrintf("trace_event_clock_sync: parent_ts=%f\n", | |
| 773 now_in_seconds); | |
| 774 if (file_util::WriteFile( | |
| 775 FilePath("/sys/kernel/debug/tracing/trace_marker"), | |
| 776 marker.c_str(), marker.size()) == -1) { | |
| 777 DLOG(WARNING) << "Couldn't write to /sys/kernel/debug/tracing/trace_marker"; | |
| 778 return; | |
| 779 } | |
| 780 #endif | |
| 781 } | |
| 782 | |
| 783 void TraceLog::AddThreadNameMetadataEvents() { | 754 void TraceLog::AddThreadNameMetadataEvents() { |
| 784 lock_.AssertAcquired(); | 755 lock_.AssertAcquired(); |
| 785 for(base::hash_map<int, std::string>::iterator it = thread_names_.begin(); | 756 for(base::hash_map<int, std::string>::iterator it = thread_names_.begin(); |
| 786 it != thread_names_.end(); | 757 it != thread_names_.end(); |
| 787 it++) { | 758 it++) { |
| 788 if (!it->second.empty()) { | 759 if (!it->second.empty()) { |
| 789 int num_args = 1; | 760 int num_args = 1; |
| 790 const char* arg_name = "name"; | 761 const char* arg_name = "name"; |
| 791 unsigned char arg_type; | 762 unsigned char arg_type; |
| 792 unsigned long long arg_value; | 763 unsigned long long arg_value; |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 815 // Create a FNV hash from the process ID for XORing. | 786 // Create a FNV hash from the process ID for XORing. |
| 816 // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details. | 787 // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details. |
| 817 unsigned long long offset_basis = 14695981039346656037ull; | 788 unsigned long long offset_basis = 14695981039346656037ull; |
| 818 unsigned long long fnv_prime = 1099511628211ull; | 789 unsigned long long fnv_prime = 1099511628211ull; |
| 819 unsigned long long pid = static_cast<unsigned long long>(process_id_); | 790 unsigned long long pid = static_cast<unsigned long long>(process_id_); |
| 820 process_id_hash_ = (offset_basis ^ pid) * fnv_prime; | 791 process_id_hash_ = (offset_basis ^ pid) * fnv_prime; |
| 821 } | 792 } |
| 822 | 793 |
| 823 } // namespace debug | 794 } // namespace debug |
| 824 } // namespace base | 795 } // namespace base |
| OLD | NEW |