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