Line data Source code
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 68 : TracingController::TracingController() {}
42 :
43 68 : TracingController::~TracingController() {}
44 :
45 34 : void TracingController::Initialize(TraceBuffer* trace_buffer) {
46 : trace_buffer_.reset(trace_buffer);
47 34 : mutex_.reset(new base::Mutex());
48 34 : }
49 :
50 188 : uint64_t TracingController::AddTraceEvent(
51 : char phase, const uint8_t* category_enabled_flag, const char* name,
52 : const char* scope, uint64_t id, uint64_t bind_id, int num_args,
53 : const char** arg_names, const uint8_t* arg_types,
54 : const uint64_t* arg_values,
55 : std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
56 : unsigned int flags) {
57 : uint64_t handle;
58 188 : TraceObject* trace_object = trace_buffer_->AddTraceEvent(&handle);
59 188 : if (trace_object) {
60 : trace_object->Initialize(phase, category_enabled_flag, name, scope, id,
61 : bind_id, num_args, arg_names, arg_types,
62 188 : arg_values, arg_convertables, flags);
63 : }
64 188 : return handle;
65 : }
66 :
67 0 : void TracingController::UpdateTraceEventDuration(
68 : const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {
69 0 : TraceObject* trace_object = trace_buffer_->GetEventByHandle(handle);
70 0 : if (!trace_object) return;
71 0 : trace_object->UpdateDuration();
72 : }
73 :
74 333 : const uint8_t* TracingController::GetCategoryGroupEnabled(
75 : const char* category_group) {
76 333 : if (!trace_buffer_) {
77 : DCHECK(!g_category_group_enabled[g_category_already_shutdown]);
78 : return &g_category_group_enabled[g_category_already_shutdown];
79 : }
80 333 : return GetCategoryGroupEnabledInternal(category_group);
81 : }
82 :
83 182 : const char* TracingController::GetCategoryGroupName(
84 : const uint8_t* category_group_enabled) {
85 : // Calculate the index of the category group by finding
86 : // category_group_enabled in g_category_group_enabled array.
87 : uintptr_t category_begin =
88 182 : reinterpret_cast<uintptr_t>(g_category_group_enabled);
89 182 : uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
90 : // Check for out of bounds category pointers.
91 : DCHECK(category_ptr >= category_begin &&
92 : category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled +
93 : MAX_CATEGORY_GROUPS));
94 : uintptr_t category_index =
95 182 : (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]);
96 182 : return g_category_groups[category_index];
97 : }
98 :
99 41 : void TracingController::StartTracing(TraceConfig* trace_config) {
100 : trace_config_.reset(trace_config);
101 41 : std::unordered_set<Platform::TraceStateObserver*> observers_copy;
102 : {
103 : base::LockGuard<base::Mutex> lock(mutex_.get());
104 41 : mode_ = RECORDING_MODE;
105 41 : UpdateCategoryGroupEnabledFlags();
106 : observers_copy = observers_;
107 : }
108 89 : for (auto o : observers_copy) {
109 7 : o->OnTraceEnabled();
110 : }
111 41 : }
112 :
113 41 : void TracingController::StopTracing() {
114 41 : mode_ = DISABLED;
115 41 : UpdateCategoryGroupEnabledFlags();
116 41 : std::unordered_set<Platform::TraceStateObserver*> observers_copy;
117 : {
118 : base::LockGuard<base::Mutex> lock(mutex_.get());
119 : observers_copy = observers_;
120 : }
121 95 : for (auto o : observers_copy) {
122 13 : o->OnTraceDisabled();
123 : }
124 41 : trace_buffer_->Flush();
125 41 : }
126 :
127 456 : void TracingController::UpdateCategoryGroupEnabledFlag(size_t category_index) {
128 : unsigned char enabled_flag = 0;
129 456 : const char* category_group = g_category_groups[category_index];
130 678 : if (mode_ == RECORDING_MODE &&
131 222 : trace_config_->IsCategoryGroupEnabled(category_group)) {
132 : enabled_flag |= ENABLED_FOR_RECORDING;
133 : }
134 :
135 : // TODO(fmeawad): EventCallback and ETW modes are not yet supported in V8.
136 : // TODO(primiano): this is a temporary workaround for catapult:#2341,
137 : // to guarantee that metadata events are always added even if the category
138 : // filter is "-*". See crbug.com/618054 for more details and long-term fix.
139 456 : if (mode_ == RECORDING_MODE && !strcmp(category_group, "__metadata")) {
140 : enabled_flag |= ENABLED_FOR_RECORDING;
141 : }
142 :
143 456 : g_category_group_enabled[category_index] = enabled_flag;
144 456 : }
145 :
146 82 : void TracingController::UpdateCategoryGroupEnabledFlags() {
147 : size_t category_index = base::NoBarrier_Load(&g_category_index);
148 82 : for (size_t i = 0; i < category_index; i++) UpdateCategoryGroupEnabledFlag(i);
149 82 : }
150 :
151 333 : const uint8_t* TracingController::GetCategoryGroupEnabledInternal(
152 : const char* category_group) {
153 : // Check that category groups does not contain double quote
154 : DCHECK(!strchr(category_group, '"'));
155 :
156 : // The g_category_groups is append only, avoid using a lock for the fast path.
157 : size_t current_category_index = v8::base::Acquire_Load(&g_category_index);
158 :
159 : // Search for pre-existing category group.
160 2012 : for (size_t i = 0; i < current_category_index; ++i) {
161 1954 : if (strcmp(g_category_groups[i], category_group) == 0) {
162 275 : return &g_category_group_enabled[i];
163 : }
164 : }
165 :
166 : unsigned char* category_group_enabled = NULL;
167 : size_t category_index = base::Acquire_Load(&g_category_index);
168 357 : for (size_t i = 0; i < category_index; ++i) {
169 299 : if (strcmp(g_category_groups[i], category_group) == 0) {
170 0 : return &g_category_group_enabled[i];
171 : }
172 : }
173 :
174 : // Create a new category group.
175 : // Check that there is a slot for the new category_group.
176 : DCHECK(category_index < MAX_CATEGORY_GROUPS);
177 58 : if (category_index < MAX_CATEGORY_GROUPS) {
178 : // Don't hold on to the category_group pointer, so that we can create
179 : // category groups with strings not known at compile time (this is
180 : // required by SetWatchEvent).
181 58 : const char* new_group = strdup(category_group);
182 58 : g_category_groups[category_index] = new_group;
183 : DCHECK(!g_category_group_enabled[category_index]);
184 : // Note that if both included and excluded patterns in the
185 : // TraceConfig are empty, we exclude nothing,
186 : // thereby enabling this category group.
187 58 : UpdateCategoryGroupEnabledFlag(category_index);
188 58 : category_group_enabled = &g_category_group_enabled[category_index];
189 : // Update the max index now.
190 58 : base::Release_Store(&g_category_index, category_index + 1);
191 : } else {
192 : category_group_enabled =
193 : &g_category_group_enabled[g_category_categories_exhausted];
194 : }
195 58 : return category_group_enabled;
196 : }
197 :
198 20 : void TracingController::AddTraceStateObserver(
199 : Platform::TraceStateObserver* observer) {
200 : {
201 : base::LockGuard<base::Mutex> lock(mutex_.get());
202 : observers_.insert(observer);
203 40 : if (mode_ != RECORDING_MODE) return;
204 : }
205 : // Fire the observer if recording is already in progress.
206 13 : observer->OnTraceEnabled();
207 : }
208 :
209 20 : void TracingController::RemoveTraceStateObserver(
210 : Platform::TraceStateObserver* observer) {
211 : base::LockGuard<base::Mutex> lock(mutex_.get());
212 : DCHECK(observers_.find(observer) != observers_.end());
213 : observers_.erase(observer);
214 20 : }
215 :
216 : } // namespace tracing
217 : } // namespace platform
218 : } // namespace v8
|