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