• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TracingController()41 TracingController::TracingController() {}
42 
~TracingController()43 TracingController::~TracingController() {}
44 
Initialize(TraceBuffer * trace_buffer)45 void TracingController::Initialize(TraceBuffer* trace_buffer) {
46   trace_buffer_.reset(trace_buffer);
47   mutex_.reset(new base::Mutex());
48 }
49 
AddTraceEvent(char phase,const uint8_t * category_enabled_flag,const char * name,const char * scope,uint64_t id,uint64_t bind_id,int num_args,const char ** arg_names,const uint8_t * arg_types,const uint64_t * arg_values,std::unique_ptr<v8::ConvertableToTraceFormat> * arg_convertables,unsigned int flags)50 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   TraceObject* trace_object = trace_buffer_->AddTraceEvent(&handle);
59   if (trace_object) {
60     trace_object->Initialize(phase, category_enabled_flag, name, scope, id,
61                              bind_id, num_args, arg_names, arg_types,
62                              arg_values, arg_convertables, flags);
63   }
64   return handle;
65 }
66 
UpdateTraceEventDuration(const uint8_t * category_enabled_flag,const char * name,uint64_t handle)67 void TracingController::UpdateTraceEventDuration(
68     const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {
69   TraceObject* trace_object = trace_buffer_->GetEventByHandle(handle);
70   if (!trace_object) return;
71   trace_object->UpdateDuration();
72 }
73 
GetCategoryGroupEnabled(const char * category_group)74 const uint8_t* TracingController::GetCategoryGroupEnabled(
75     const char* category_group) {
76   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   return GetCategoryGroupEnabledInternal(category_group);
81 }
82 
GetCategoryGroupName(const uint8_t * category_group_enabled)83 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       reinterpret_cast<uintptr_t>(g_category_group_enabled);
89   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       (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]);
96   return g_category_groups[category_index];
97 }
98 
StartTracing(TraceConfig * trace_config)99 void TracingController::StartTracing(TraceConfig* trace_config) {
100   trace_config_.reset(trace_config);
101   std::unordered_set<Platform::TraceStateObserver*> observers_copy;
102   {
103     base::LockGuard<base::Mutex> lock(mutex_.get());
104     mode_ = RECORDING_MODE;
105     UpdateCategoryGroupEnabledFlags();
106     observers_copy = observers_;
107   }
108   for (auto o : observers_copy) {
109     o->OnTraceEnabled();
110   }
111 }
112 
StopTracing()113 void TracingController::StopTracing() {
114   mode_ = DISABLED;
115   UpdateCategoryGroupEnabledFlags();
116   std::unordered_set<Platform::TraceStateObserver*> observers_copy;
117   {
118     base::LockGuard<base::Mutex> lock(mutex_.get());
119     observers_copy = observers_;
120   }
121   for (auto o : observers_copy) {
122     o->OnTraceDisabled();
123   }
124   trace_buffer_->Flush();
125 }
126 
UpdateCategoryGroupEnabledFlag(size_t category_index)127 void TracingController::UpdateCategoryGroupEnabledFlag(size_t category_index) {
128   unsigned char enabled_flag = 0;
129   const char* category_group = g_category_groups[category_index];
130   if (mode_ == RECORDING_MODE &&
131       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   if (mode_ == RECORDING_MODE && !strcmp(category_group, "__metadata")) {
140     enabled_flag |= ENABLED_FOR_RECORDING;
141   }
142 
143   g_category_group_enabled[category_index] = enabled_flag;
144 }
145 
UpdateCategoryGroupEnabledFlags()146 void TracingController::UpdateCategoryGroupEnabledFlags() {
147   size_t category_index = base::NoBarrier_Load(&g_category_index);
148   for (size_t i = 0; i < category_index; i++) UpdateCategoryGroupEnabledFlag(i);
149 }
150 
GetCategoryGroupEnabledInternal(const char * category_group)151 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   for (size_t i = 0; i < current_category_index; ++i) {
161     if (strcmp(g_category_groups[i], category_group) == 0) {
162       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   for (size_t i = 0; i < category_index; ++i) {
169     if (strcmp(g_category_groups[i], category_group) == 0) {
170       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   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     const char* new_group = strdup(category_group);
182     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     UpdateCategoryGroupEnabledFlag(category_index);
188     category_group_enabled = &g_category_group_enabled[category_index];
189     // Update the max index now.
190     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   return category_group_enabled;
196 }
197 
AddTraceStateObserver(Platform::TraceStateObserver * observer)198 void TracingController::AddTraceStateObserver(
199     Platform::TraceStateObserver* observer) {
200   {
201     base::LockGuard<base::Mutex> lock(mutex_.get());
202     observers_.insert(observer);
203     if (mode_ != RECORDING_MODE) return;
204   }
205   // Fire the observer if recording is already in progress.
206   observer->OnTraceEnabled();
207 }
208 
RemoveTraceStateObserver(Platform::TraceStateObserver * observer)209 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 }
215 
216 }  // namespace tracing
217 }  // namespace platform
218 }  // namespace v8
219