OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <stdio.h> |
| 6 #include <string.h> |
| 7 |
| 8 #include "include/libplatform/v8-tracing.h" |
| 9 |
| 10 #include "src/base/platform/mutex.h" |
| 11 |
| 12 namespace v8 { |
| 13 namespace platform { |
| 14 namespace tracing { |
| 15 |
| 16 #define MAX_CATEGORY_GROUPS 200 |
| 17 |
| 18 // Parallel arrays g_category_groups and g_category_group_enabled are separate |
| 19 // so that a pointer to a member of g_category_group_enabled can be easily |
| 20 // converted to an index into g_category_groups. This allows macros to deal |
| 21 // only with char enabled pointers from g_category_group_enabled, and we can |
| 22 // convert internally to determine the category name from the char enabled |
| 23 // pointer. |
| 24 const char* g_category_groups[MAX_CATEGORY_GROUPS] = { |
| 25 "toplevel", "tracing already shutdown", |
| 26 "tracing categories exhausted; must increase MAX_CATEGORY_GROUPS", |
| 27 "__metadata"}; |
| 28 |
| 29 // The enabled flag is char instead of bool so that the API can be used from C. |
| 30 unsigned char g_category_group_enabled[MAX_CATEGORY_GROUPS] = {0}; |
| 31 // Indexes here have to match the g_category_groups array indexes above. |
| 32 const int g_category_already_shutdown = 1; |
| 33 const int g_category_categories_exhausted = 2; |
| 34 // Metadata category not used in V8. |
| 35 // const int g_category_metadata = 3; |
| 36 const int g_num_builtin_categories = 4; |
| 37 |
| 38 // Skip default categories. |
| 39 v8::base::AtomicWord g_category_index = g_num_builtin_categories; |
| 40 |
| 41 void TracingController::Initialize(TraceBuffer* trace_buffer) { |
| 42 trace_buffer_.reset(trace_buffer); |
| 43 } |
| 44 |
| 45 uint64_t TracingController::AddTraceEvent( |
| 46 char phase, const uint8_t* category_enabled_flag, const char* name, |
| 47 const char* scope, uint64_t id, uint64_t bind_id, int num_args, |
| 48 const char** arg_names, const uint8_t* arg_types, |
| 49 const uint64_t* arg_values, unsigned int flags) { |
| 50 uint64_t handle; |
| 51 TraceObject* trace_object = trace_buffer_->AddTraceEvent(&handle); |
| 52 if (trace_object) { |
| 53 trace_object->Initialize(phase, category_enabled_flag, name, scope, id, |
| 54 bind_id, num_args, arg_names, arg_types, |
| 55 arg_values, flags); |
| 56 } |
| 57 return handle; |
| 58 } |
| 59 |
| 60 void TracingController::UpdateTraceEventDuration( |
| 61 const uint8_t* category_enabled_flag, const char* name, uint64_t handle) { |
| 62 TraceObject* trace_object = trace_buffer_->GetEventByHandle(handle); |
| 63 if (!trace_object) return; |
| 64 trace_object->UpdateDuration(); |
| 65 } |
| 66 |
| 67 const uint8_t* TracingController::GetCategoryGroupEnabled( |
| 68 const char* category_group) { |
| 69 if (!trace_buffer_) { |
| 70 DCHECK(!g_category_group_enabled[g_category_already_shutdown]); |
| 71 return &g_category_group_enabled[g_category_already_shutdown]; |
| 72 } |
| 73 return GetCategoryGroupEnabledInternal(category_group); |
| 74 } |
| 75 |
| 76 const char* TracingController::GetCategoryGroupName( |
| 77 const uint8_t* category_group_enabled) { |
| 78 // Calculate the index of the category group by finding |
| 79 // category_group_enabled in g_category_group_enabled array. |
| 80 uintptr_t category_begin = |
| 81 reinterpret_cast<uintptr_t>(g_category_group_enabled); |
| 82 uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled); |
| 83 // Check for out of bounds category pointers. |
| 84 DCHECK(category_ptr >= category_begin && |
| 85 category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled + |
| 86 MAX_CATEGORY_GROUPS)); |
| 87 uintptr_t category_index = |
| 88 (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]); |
| 89 return g_category_groups[category_index]; |
| 90 } |
| 91 |
| 92 void TracingController::StartTracing(TraceConfig* trace_config) { |
| 93 trace_config_.reset(trace_config); |
| 94 mode_ = RECORDING_MODE; |
| 95 UpdateCategoryGroupEnabledFlags(); |
| 96 } |
| 97 |
| 98 void TracingController::StopTracing() { |
| 99 mode_ = DISABLED; |
| 100 UpdateCategoryGroupEnabledFlags(); |
| 101 trace_buffer_->Flush(); |
| 102 } |
| 103 |
| 104 void TracingController::UpdateCategoryGroupEnabledFlag(size_t category_index) { |
| 105 unsigned char enabled_flag = 0; |
| 106 const char* category_group = g_category_groups[category_index]; |
| 107 if (mode_ == RECORDING_MODE && |
| 108 trace_config_->IsCategoryGroupEnabled(category_group)) { |
| 109 enabled_flag |= ENABLED_FOR_RECORDING; |
| 110 } |
| 111 |
| 112 // TODO(fmeawad): EventCallback and ETW modes are not yet supported in V8. |
| 113 // TODO(primiano): this is a temporary workaround for catapult:#2341, |
| 114 // to guarantee that metadata events are always added even if the category |
| 115 // filter is "-*". See crbug.com/618054 for more details and long-term fix. |
| 116 if (mode_ == RECORDING_MODE && !strcmp(category_group, "__metadata")) { |
| 117 enabled_flag |= ENABLED_FOR_RECORDING; |
| 118 } |
| 119 |
| 120 g_category_group_enabled[category_index] = enabled_flag; |
| 121 } |
| 122 |
| 123 void TracingController::UpdateCategoryGroupEnabledFlags() { |
| 124 size_t category_index = base::NoBarrier_Load(&g_category_index); |
| 125 for (size_t i = 0; i < category_index; i++) UpdateCategoryGroupEnabledFlag(i); |
| 126 } |
| 127 |
| 128 const uint8_t* TracingController::GetCategoryGroupEnabledInternal( |
| 129 const char* category_group) { |
| 130 // Check that category groups does not contain double quote |
| 131 DCHECK(!strchr(category_group, '"')); |
| 132 |
| 133 // The g_category_groups is append only, avoid using a lock for the fast path. |
| 134 size_t current_category_index = v8::base::Acquire_Load(&g_category_index); |
| 135 |
| 136 // Search for pre-existing category group. |
| 137 for (size_t i = 0; i < current_category_index; ++i) { |
| 138 if (strcmp(g_category_groups[i], category_group) == 0) { |
| 139 return &g_category_group_enabled[i]; |
| 140 } |
| 141 } |
| 142 |
| 143 unsigned char* category_group_enabled = NULL; |
| 144 size_t category_index = base::Acquire_Load(&g_category_index); |
| 145 for (size_t i = 0; i < category_index; ++i) { |
| 146 if (strcmp(g_category_groups[i], category_group) == 0) { |
| 147 return &g_category_group_enabled[i]; |
| 148 } |
| 149 } |
| 150 |
| 151 // Create a new category group. |
| 152 // Check that there is a slot for the new category_group. |
| 153 DCHECK(category_index < MAX_CATEGORY_GROUPS); |
| 154 if (category_index < MAX_CATEGORY_GROUPS) { |
| 155 // Don't hold on to the category_group pointer, so that we can create |
| 156 // category groups with strings not known at compile time (this is |
| 157 // required by SetWatchEvent). |
| 158 const char* new_group = strdup(category_group); |
| 159 g_category_groups[category_index] = new_group; |
| 160 DCHECK(!g_category_group_enabled[category_index]); |
| 161 // Note that if both included and excluded patterns in the |
| 162 // TraceConfig are empty, we exclude nothing, |
| 163 // thereby enabling this category group. |
| 164 UpdateCategoryGroupEnabledFlag(category_index); |
| 165 category_group_enabled = &g_category_group_enabled[category_index]; |
| 166 // Update the max index now. |
| 167 base::Release_Store(&g_category_index, category_index + 1); |
| 168 } else { |
| 169 category_group_enabled = |
| 170 &g_category_group_enabled[g_category_categories_exhausted]; |
| 171 } |
| 172 return category_group_enabled; |
| 173 } |
| 174 |
| 175 } // namespace tracing |
| 176 } // namespace platform |
| 177 } // namespace v8 |
OLD | NEW |