/src/node/deps/v8/include/libplatform/v8-tracing.h
Line | Count | Source (jump to first uncovered line) |
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 | | #ifndef V8_LIBPLATFORM_V8_TRACING_H_ |
6 | | #define V8_LIBPLATFORM_V8_TRACING_H_ |
7 | | |
8 | | #include <atomic> |
9 | | #include <fstream> |
10 | | #include <memory> |
11 | | #include <unordered_set> |
12 | | #include <vector> |
13 | | |
14 | | #include "libplatform/libplatform-export.h" |
15 | | #include "v8-platform.h" // NOLINT(build/include_directory) |
16 | | |
17 | | namespace perfetto { |
18 | | namespace trace_processor { |
19 | | class TraceProcessorStorage; |
20 | | } |
21 | | class TracingSession; |
22 | | } |
23 | | |
24 | | namespace v8 { |
25 | | |
26 | | namespace base { |
27 | | class Mutex; |
28 | | } // namespace base |
29 | | |
30 | | namespace platform { |
31 | | namespace tracing { |
32 | | |
33 | | class TraceEventListener; |
34 | | |
35 | | const int kTraceMaxNumArgs = 2; |
36 | | |
37 | | class V8_PLATFORM_EXPORT TraceObject { |
38 | | public: |
39 | | union ArgValue { |
40 | | uint64_t as_uint; |
41 | | int64_t as_int; |
42 | | double as_double; |
43 | | const void* as_pointer; |
44 | | const char* as_string; |
45 | | }; |
46 | | |
47 | 0 | TraceObject() = default; |
48 | | ~TraceObject(); |
49 | | void Initialize( |
50 | | char phase, const uint8_t* category_enabled_flag, const char* name, |
51 | | const char* scope, uint64_t id, uint64_t bind_id, int num_args, |
52 | | const char** arg_names, const uint8_t* arg_types, |
53 | | const uint64_t* arg_values, |
54 | | std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables, |
55 | | unsigned int flags, int64_t timestamp, int64_t cpu_timestamp); |
56 | | void UpdateDuration(int64_t timestamp, int64_t cpu_timestamp); |
57 | | void InitializeForTesting( |
58 | | char phase, const uint8_t* category_enabled_flag, const char* name, |
59 | | const char* scope, uint64_t id, uint64_t bind_id, int num_args, |
60 | | const char** arg_names, const uint8_t* arg_types, |
61 | | const uint64_t* arg_values, |
62 | | std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables, |
63 | | unsigned int flags, int pid, int tid, int64_t ts, int64_t tts, |
64 | | uint64_t duration, uint64_t cpu_duration); |
65 | | |
66 | 0 | int pid() const { return pid_; } |
67 | 0 | int tid() const { return tid_; } |
68 | 0 | char phase() const { return phase_; } |
69 | 0 | const uint8_t* category_enabled_flag() const { |
70 | 0 | return category_enabled_flag_; |
71 | 0 | } |
72 | 0 | const char* name() const { return name_; } |
73 | 0 | const char* scope() const { return scope_; } |
74 | 0 | uint64_t id() const { return id_; } |
75 | 0 | uint64_t bind_id() const { return bind_id_; } |
76 | 0 | int num_args() const { return num_args_; } |
77 | 0 | const char** arg_names() { return arg_names_; } |
78 | 0 | uint8_t* arg_types() { return arg_types_; } |
79 | 0 | ArgValue* arg_values() { return arg_values_; } |
80 | 0 | std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables() { |
81 | 0 | return arg_convertables_; |
82 | 0 | } |
83 | 0 | unsigned int flags() const { return flags_; } |
84 | 0 | int64_t ts() { return ts_; } |
85 | 0 | int64_t tts() { return tts_; } |
86 | 0 | uint64_t duration() { return duration_; } |
87 | 0 | uint64_t cpu_duration() { return cpu_duration_; } |
88 | | |
89 | | private: |
90 | | int pid_; |
91 | | int tid_; |
92 | | char phase_; |
93 | | const char* name_; |
94 | | const char* scope_; |
95 | | const uint8_t* category_enabled_flag_; |
96 | | uint64_t id_; |
97 | | uint64_t bind_id_; |
98 | | int num_args_ = 0; |
99 | | const char* arg_names_[kTraceMaxNumArgs]; |
100 | | uint8_t arg_types_[kTraceMaxNumArgs]; |
101 | | ArgValue arg_values_[kTraceMaxNumArgs]; |
102 | | std::unique_ptr<v8::ConvertableToTraceFormat> |
103 | | arg_convertables_[kTraceMaxNumArgs]; |
104 | | char* parameter_copy_storage_ = nullptr; |
105 | | unsigned int flags_; |
106 | | int64_t ts_; |
107 | | int64_t tts_; |
108 | | uint64_t duration_; |
109 | | uint64_t cpu_duration_; |
110 | | |
111 | | // Disallow copy and assign |
112 | | TraceObject(const TraceObject&) = delete; |
113 | | void operator=(const TraceObject&) = delete; |
114 | | }; |
115 | | |
116 | | class V8_PLATFORM_EXPORT TraceWriter { |
117 | | public: |
118 | | TraceWriter() = default; |
119 | | virtual ~TraceWriter() = default; |
120 | | virtual void AppendTraceEvent(TraceObject* trace_event) = 0; |
121 | | virtual void Flush() = 0; |
122 | | |
123 | | static TraceWriter* CreateJSONTraceWriter(std::ostream& stream); |
124 | | static TraceWriter* CreateJSONTraceWriter(std::ostream& stream, |
125 | | const std::string& tag); |
126 | | |
127 | | static TraceWriter* CreateSystemInstrumentationTraceWriter(); |
128 | | |
129 | | private: |
130 | | // Disallow copy and assign |
131 | | TraceWriter(const TraceWriter&) = delete; |
132 | | void operator=(const TraceWriter&) = delete; |
133 | | }; |
134 | | |
135 | | class V8_PLATFORM_EXPORT TraceBufferChunk { |
136 | | public: |
137 | | explicit TraceBufferChunk(uint32_t seq); |
138 | | |
139 | | void Reset(uint32_t new_seq); |
140 | 0 | bool IsFull() const { return next_free_ == kChunkSize; } |
141 | | TraceObject* AddTraceEvent(size_t* event_index); |
142 | 0 | TraceObject* GetEventAt(size_t index) { return &chunk_[index]; } |
143 | | |
144 | 0 | uint32_t seq() const { return seq_; } |
145 | 0 | size_t size() const { return next_free_; } |
146 | | |
147 | | static const size_t kChunkSize = 64; |
148 | | |
149 | | private: |
150 | | size_t next_free_ = 0; |
151 | | TraceObject chunk_[kChunkSize]; |
152 | | uint32_t seq_; |
153 | | |
154 | | // Disallow copy and assign |
155 | | TraceBufferChunk(const TraceBufferChunk&) = delete; |
156 | | void operator=(const TraceBufferChunk&) = delete; |
157 | | }; |
158 | | |
159 | | class V8_PLATFORM_EXPORT TraceBuffer { |
160 | | public: |
161 | 0 | TraceBuffer() = default; |
162 | 0 | virtual ~TraceBuffer() = default; |
163 | | |
164 | | virtual TraceObject* AddTraceEvent(uint64_t* handle) = 0; |
165 | | virtual TraceObject* GetEventByHandle(uint64_t handle) = 0; |
166 | | virtual bool Flush() = 0; |
167 | | |
168 | | static const size_t kRingBufferChunks = 1024; |
169 | | |
170 | | static TraceBuffer* CreateTraceBufferRingBuffer(size_t max_chunks, |
171 | | TraceWriter* trace_writer); |
172 | | |
173 | | private: |
174 | | // Disallow copy and assign |
175 | | TraceBuffer(const TraceBuffer&) = delete; |
176 | | void operator=(const TraceBuffer&) = delete; |
177 | | }; |
178 | | |
179 | | // Options determines how the trace buffer stores data. |
180 | | enum TraceRecordMode { |
181 | | // Record until the trace buffer is full. |
182 | | RECORD_UNTIL_FULL, |
183 | | |
184 | | // Record until the user ends the trace. The trace buffer is a fixed size |
185 | | // and we use it as a ring buffer during recording. |
186 | | RECORD_CONTINUOUSLY, |
187 | | |
188 | | // Record until the trace buffer is full, but with a huge buffer size. |
189 | | RECORD_AS_MUCH_AS_POSSIBLE, |
190 | | |
191 | | // Echo to console. Events are discarded. |
192 | | ECHO_TO_CONSOLE, |
193 | | }; |
194 | | |
195 | | class V8_PLATFORM_EXPORT TraceConfig { |
196 | | public: |
197 | | typedef std::vector<std::string> StringList; |
198 | | |
199 | | static TraceConfig* CreateDefaultTraceConfig(); |
200 | | |
201 | 0 | TraceConfig() : enable_systrace_(false), enable_argument_filter_(false) {} |
202 | 0 | TraceRecordMode GetTraceRecordMode() const { return record_mode_; } |
203 | 0 | const StringList& GetEnabledCategories() const { |
204 | 0 | return included_categories_; |
205 | 0 | } |
206 | 0 | bool IsSystraceEnabled() const { return enable_systrace_; } |
207 | 0 | bool IsArgumentFilterEnabled() const { return enable_argument_filter_; } |
208 | | |
209 | 0 | void SetTraceRecordMode(TraceRecordMode mode) { record_mode_ = mode; } |
210 | 0 | void EnableSystrace() { enable_systrace_ = true; } |
211 | 0 | void EnableArgumentFilter() { enable_argument_filter_ = true; } |
212 | | |
213 | | void AddIncludedCategory(const char* included_category); |
214 | | |
215 | | bool IsCategoryGroupEnabled(const char* category_group) const; |
216 | | |
217 | | private: |
218 | | TraceRecordMode record_mode_; |
219 | | bool enable_systrace_ : 1; |
220 | | bool enable_argument_filter_ : 1; |
221 | | StringList included_categories_; |
222 | | |
223 | | // Disallow copy and assign |
224 | | TraceConfig(const TraceConfig&) = delete; |
225 | | void operator=(const TraceConfig&) = delete; |
226 | | }; |
227 | | |
228 | | #if defined(_MSC_VER) |
229 | | #define V8_PLATFORM_NON_EXPORTED_BASE(code) \ |
230 | | __pragma(warning(suppress : 4275)) code |
231 | | #else |
232 | | #define V8_PLATFORM_NON_EXPORTED_BASE(code) code |
233 | | #endif // defined(_MSC_VER) |
234 | | |
235 | | class V8_PLATFORM_EXPORT TracingController |
236 | | : public V8_PLATFORM_NON_EXPORTED_BASE(v8::TracingController) { |
237 | | public: |
238 | | TracingController(); |
239 | | ~TracingController() override; |
240 | | |
241 | | #if defined(V8_USE_PERFETTO) |
242 | | // Must be called before StartTracing() if V8_USE_PERFETTO is true. Provides |
243 | | // the output stream for the JSON trace data. |
244 | | void InitializeForPerfetto(std::ostream* output_stream); |
245 | | // Provide an optional listener for testing that will receive trace events. |
246 | | // Must be called before StartTracing(). |
247 | | void SetTraceEventListenerForTesting(TraceEventListener* listener); |
248 | | #else // defined(V8_USE_PERFETTO) |
249 | | // The pointer returned from GetCategoryGroupEnabled() points to a value with |
250 | | // zero or more of the following bits. Used in this class only. The |
251 | | // TRACE_EVENT macros should only use the value as a bool. These values must |
252 | | // be in sync with macro values in TraceEvent.h in Blink. |
253 | | enum CategoryGroupEnabledFlags { |
254 | | // Category group enabled for the recording mode. |
255 | | ENABLED_FOR_RECORDING = 1 << 0, |
256 | | // Category group enabled by SetEventCallbackEnabled(). |
257 | | ENABLED_FOR_EVENT_CALLBACK = 1 << 2, |
258 | | // Category group enabled to export events to ETW. |
259 | | ENABLED_FOR_ETW_EXPORT = 1 << 3 |
260 | | }; |
261 | | |
262 | | // Takes ownership of |trace_buffer|. |
263 | | void Initialize(TraceBuffer* trace_buffer); |
264 | | |
265 | | // v8::TracingController implementation. |
266 | | const uint8_t* GetCategoryGroupEnabled(const char* category_group) override; |
267 | | uint64_t AddTraceEvent( |
268 | | char phase, const uint8_t* category_enabled_flag, const char* name, |
269 | | const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, |
270 | | const char** arg_names, const uint8_t* arg_types, |
271 | | const uint64_t* arg_values, |
272 | | std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables, |
273 | | unsigned int flags) override; |
274 | | uint64_t AddTraceEventWithTimestamp( |
275 | | char phase, const uint8_t* category_enabled_flag, const char* name, |
276 | | const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, |
277 | | const char** arg_names, const uint8_t* arg_types, |
278 | | const uint64_t* arg_values, |
279 | | std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables, |
280 | | unsigned int flags, int64_t timestamp) override; |
281 | | void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, |
282 | | const char* name, uint64_t handle) override; |
283 | | |
284 | | static const char* GetCategoryGroupName(const uint8_t* category_enabled_flag); |
285 | | |
286 | | void AddTraceStateObserver( |
287 | | v8::TracingController::TraceStateObserver* observer) override; |
288 | | void RemoveTraceStateObserver( |
289 | | v8::TracingController::TraceStateObserver* observer) override; |
290 | | #endif // !defined(V8_USE_PERFETTO) |
291 | | |
292 | | void StartTracing(TraceConfig* trace_config); |
293 | | void StopTracing(); |
294 | | |
295 | | protected: |
296 | | #if !defined(V8_USE_PERFETTO) |
297 | | virtual int64_t CurrentTimestampMicroseconds(); |
298 | | virtual int64_t CurrentCpuTimestampMicroseconds(); |
299 | | #endif // !defined(V8_USE_PERFETTO) |
300 | | |
301 | | private: |
302 | | #if !defined(V8_USE_PERFETTO) |
303 | | void UpdateCategoryGroupEnabledFlag(size_t category_index); |
304 | | void UpdateCategoryGroupEnabledFlags(); |
305 | | #endif // !defined(V8_USE_PERFETTO) |
306 | | |
307 | | std::unique_ptr<base::Mutex> mutex_; |
308 | | std::unique_ptr<TraceConfig> trace_config_; |
309 | | std::atomic_bool recording_{false}; |
310 | | |
311 | | #if defined(V8_USE_PERFETTO) |
312 | | std::ostream* output_stream_ = nullptr; |
313 | | std::unique_ptr<perfetto::trace_processor::TraceProcessorStorage> |
314 | | trace_processor_; |
315 | | TraceEventListener* listener_for_testing_ = nullptr; |
316 | | std::unique_ptr<perfetto::TracingSession> tracing_session_; |
317 | | #else // !defined(V8_USE_PERFETTO) |
318 | | std::unordered_set<v8::TracingController::TraceStateObserver*> observers_; |
319 | | std::unique_ptr<TraceBuffer> trace_buffer_; |
320 | | #endif // !defined(V8_USE_PERFETTO) |
321 | | |
322 | | // Disallow copy and assign |
323 | | TracingController(const TracingController&) = delete; |
324 | | void operator=(const TracingController&) = delete; |
325 | | }; |
326 | | |
327 | | #undef V8_PLATFORM_NON_EXPORTED_BASE |
328 | | |
329 | | } // namespace tracing |
330 | | } // namespace platform |
331 | | } // namespace v8 |
332 | | |
333 | | #endif // V8_LIBPLATFORM_V8_TRACING_H_ |