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/atomicops.h"
11 : #include "src/base/platform/mutex.h"
12 :
13 : namespace v8 {
14 : namespace platform {
15 : namespace tracing {
16 :
17 : #define MAX_CATEGORY_GROUPS 200
18 :
19 : // Parallel arrays g_category_groups and g_category_group_enabled are separate
20 : // so that a pointer to a member of g_category_group_enabled can be easily
21 : // converted to an index into g_category_groups. This allows macros to deal
22 : // only with char enabled pointers from g_category_group_enabled, and we can
23 : // convert internally to determine the category name from the char enabled
24 : // pointer.
25 : const char* g_category_groups[MAX_CATEGORY_GROUPS] = {
26 : "toplevel", "tracing already shutdown",
27 : "tracing categories exhausted; must increase MAX_CATEGORY_GROUPS",
28 : "__metadata"};
29 :
30 : // The enabled flag is char instead of bool so that the API can be used from C.
31 : unsigned char g_category_group_enabled[MAX_CATEGORY_GROUPS] = {0};
32 : // Indexes here have to match the g_category_groups array indexes above.
33 : const int g_category_already_shutdown = 1;
34 : const int g_category_categories_exhausted = 2;
35 : // Metadata category not used in V8.
36 : // const int g_category_metadata = 3;
37 : const int g_num_builtin_categories = 4;
38 :
39 : // Skip default categories.
40 : v8::base::AtomicWord g_category_index = g_num_builtin_categories;
41 :
42 162123 : TracingController::TracingController() {}
43 :
44 159616 : TracingController::~TracingController() { StopTracing(); }
45 :
46 54041 : void TracingController::Initialize(TraceBuffer* trace_buffer) {
47 : trace_buffer_.reset(trace_buffer);
48 54041 : mutex_.reset(new base::Mutex());
49 54041 : }
50 :
51 161 : uint64_t TracingController::AddTraceEvent(
52 : char phase, const uint8_t* category_enabled_flag, const char* name,
53 : const char* scope, uint64_t id, uint64_t bind_id, int num_args,
54 : const char** arg_names, const uint8_t* arg_types,
55 : const uint64_t* arg_values,
56 : std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
57 : unsigned int flags) {
58 : uint64_t handle;
59 161 : TraceObject* trace_object = trace_buffer_->AddTraceEvent(&handle);
60 161 : if (trace_object) {
61 : trace_object->Initialize(phase, category_enabled_flag, name, scope, id,
62 : bind_id, num_args, arg_names, arg_types,
63 161 : arg_values, arg_convertables, flags);
64 : }
65 161 : return handle;
66 : }
67 :
68 0 : void TracingController::UpdateTraceEventDuration(
69 : const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {
70 0 : TraceObject* trace_object = trace_buffer_->GetEventByHandle(handle);
71 0 : if (!trace_object) return;
72 0 : trace_object->UpdateDuration();
73 : }
74 :
75 1487004 : const uint8_t* TracingController::GetCategoryGroupEnabled(
76 : const char* category_group) {
77 1487004 : if (!trace_buffer_) {
78 : DCHECK(!g_category_group_enabled[g_category_already_shutdown]);
79 : return &g_category_group_enabled[g_category_already_shutdown];
80 : }
81 274 : return GetCategoryGroupEnabledInternal(category_group);
82 : }
83 :
84 156 : const char* TracingController::GetCategoryGroupName(
85 : const uint8_t* category_group_enabled) {
86 : // Calculate the index of the category group by finding
87 : // category_group_enabled in g_category_group_enabled array.
88 : uintptr_t category_begin =
89 156 : reinterpret_cast<uintptr_t>(g_category_group_enabled);
90 156 : uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
91 : // Check for out of bounds category pointers.
92 : DCHECK(category_ptr >= category_begin &&
93 : category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled +
94 : MAX_CATEGORY_GROUPS));
95 : uintptr_t category_index =
96 156 : (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]);
97 156 : return g_category_groups[category_index];
98 : }
99 :
100 35 : void TracingController::StartTracing(TraceConfig* trace_config) {
101 : trace_config_.reset(trace_config);
102 35 : std::unordered_set<v8::TracingController::TraceStateObserver*> observers_copy;
103 : {
104 : base::LockGuard<base::Mutex> lock(mutex_.get());
105 35 : mode_ = RECORDING_MODE;
106 35 : UpdateCategoryGroupEnabledFlags();
107 : observers_copy = observers_;
108 : }
109 76 : for (auto o : observers_copy) {
110 6 : o->OnTraceEnabled();
111 : }
112 35 : }
113 :
114 53250 : void TracingController::StopTracing() {
115 53250 : if (mode_ == DISABLED) {
116 53215 : return;
117 : }
118 : DCHECK(trace_buffer_);
119 35 : mode_ = DISABLED;
120 35 : UpdateCategoryGroupEnabledFlags();
121 35 : std::unordered_set<v8::TracingController::TraceStateObserver*> observers_copy;
122 : {
123 : base::LockGuard<base::Mutex> lock(mutex_.get());
124 : observers_copy = observers_;
125 : }
126 81 : for (auto o : observers_copy) {
127 11 : o->OnTraceDisabled();
128 : }
129 35 : trace_buffer_->Flush();
130 : }
131 :
132 376 : void TracingController::UpdateCategoryGroupEnabledFlag(size_t category_index) {
133 : unsigned char enabled_flag = 0;
134 376 : const char* category_group = g_category_groups[category_index];
135 561 : if (mode_ == RECORDING_MODE &&
136 185 : trace_config_->IsCategoryGroupEnabled(category_group)) {
137 : enabled_flag |= ENABLED_FOR_RECORDING;
138 : }
139 :
140 : // TODO(fmeawad): EventCallback and ETW modes are not yet supported in V8.
141 : // TODO(primiano): this is a temporary workaround for catapult:#2341,
142 : // to guarantee that metadata events are always added even if the category
143 : // filter is "-*". See crbug.com/618054 for more details and long-term fix.
144 376 : if (mode_ == RECORDING_MODE && !strcmp(category_group, "__metadata")) {
145 : enabled_flag |= ENABLED_FOR_RECORDING;
146 : }
147 :
148 : base::Relaxed_Store(reinterpret_cast<base::Atomic8*>(
149 : g_category_group_enabled + category_index),
150 376 : enabled_flag);
151 376 : }
152 :
153 70 : void TracingController::UpdateCategoryGroupEnabledFlags() {
154 : size_t category_index = base::Relaxed_Load(&g_category_index);
155 70 : for (size_t i = 0; i < category_index; i++) UpdateCategoryGroupEnabledFlag(i);
156 70 : }
157 :
158 274 : const uint8_t* TracingController::GetCategoryGroupEnabledInternal(
159 : const char* category_group) {
160 : // Check that category groups does not contain double quote
161 : DCHECK(!strchr(category_group, '"'));
162 :
163 : // The g_category_groups is append only, avoid using a lock for the fast path.
164 : size_t current_category_index = v8::base::Acquire_Load(&g_category_index);
165 :
166 : // Search for pre-existing category group.
167 1564 : for (size_t i = 0; i < current_category_index; ++i) {
168 1519 : if (strcmp(g_category_groups[i], category_group) == 0) {
169 229 : return &g_category_group_enabled[i];
170 : }
171 : }
172 :
173 : unsigned char* category_group_enabled = nullptr;
174 : size_t category_index = base::Acquire_Load(&g_category_index);
175 265 : for (size_t i = 0; i < category_index; ++i) {
176 220 : if (strcmp(g_category_groups[i], category_group) == 0) {
177 0 : return &g_category_group_enabled[i];
178 : }
179 : }
180 :
181 : // Create a new category group.
182 : // Check that there is a slot for the new category_group.
183 : DCHECK(category_index < MAX_CATEGORY_GROUPS);
184 45 : if (category_index < MAX_CATEGORY_GROUPS) {
185 : // Don't hold on to the category_group pointer, so that we can create
186 : // category groups with strings not known at compile time (this is
187 : // required by SetWatchEvent).
188 45 : const char* new_group = strdup(category_group);
189 45 : g_category_groups[category_index] = new_group;
190 : DCHECK(!g_category_group_enabled[category_index]);
191 : // Note that if both included and excluded patterns in the
192 : // TraceConfig are empty, we exclude nothing,
193 : // thereby enabling this category group.
194 45 : UpdateCategoryGroupEnabledFlag(category_index);
195 45 : category_group_enabled = &g_category_group_enabled[category_index];
196 : // Update the max index now.
197 45 : base::Release_Store(&g_category_index, category_index + 1);
198 : } else {
199 : category_group_enabled =
200 : &g_category_group_enabled[g_category_categories_exhausted];
201 : }
202 45 : return category_group_enabled;
203 : }
204 :
205 53994 : void TracingController::AddTraceStateObserver(
206 : v8::TracingController::TraceStateObserver* observer) {
207 : {
208 : base::LockGuard<base::Mutex> lock(mutex_.get());
209 : observers_.insert(observer);
210 107988 : if (mode_ != RECORDING_MODE) return;
211 : }
212 : // Fire the observer if recording is already in progress.
213 11 : observer->OnTraceEnabled();
214 : }
215 :
216 53168 : void TracingController::RemoveTraceStateObserver(
217 : v8::TracingController::TraceStateObserver* observer) {
218 : base::LockGuard<base::Mutex> lock(mutex_.get());
219 : DCHECK(observers_.find(observer) != observers_.end());
220 : observers_.erase(observer);
221 53168 : }
222 :
223 : } // namespace tracing
224 : } // namespace platform
225 : } // namespace v8
|