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 |