• 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 #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   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 
pid()66   int pid() const { return pid_; }
tid()67   int tid() const { return tid_; }
phase()68   char phase() const { return phase_; }
category_enabled_flag()69   const uint8_t* category_enabled_flag() const {
70     return category_enabled_flag_;
71   }
name()72   const char* name() const { return name_; }
scope()73   const char* scope() const { return scope_; }
id()74   uint64_t id() const { return id_; }
bind_id()75   uint64_t bind_id() const { return bind_id_; }
num_args()76   int num_args() const { return num_args_; }
arg_names()77   const char** arg_names() { return arg_names_; }
arg_types()78   uint8_t* arg_types() { return arg_types_; }
arg_values()79   ArgValue* arg_values() { return arg_values_; }
arg_convertables()80   std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables() {
81     return arg_convertables_;
82   }
flags()83   unsigned int flags() const { return flags_; }
ts()84   int64_t ts() { return ts_; }
tts()85   int64_t tts() { return tts_; }
duration()86   uint64_t duration() { return duration_; }
cpu_duration()87   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);
IsFull()140   bool IsFull() const { return next_free_ == kChunkSize; }
141   TraceObject* AddTraceEvent(size_t* event_index);
GetEventAt(size_t index)142   TraceObject* GetEventAt(size_t index) { return &chunk_[index]; }
143 
seq()144   uint32_t seq() const { return seq_; }
size()145   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   TraceBuffer() = default;
162   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 
TraceConfig()201   TraceConfig() : enable_systrace_(false), enable_argument_filter_(false) {}
GetTraceRecordMode()202   TraceRecordMode GetTraceRecordMode() const { return record_mode_; }
GetEnabledCategories()203   const StringList& GetEnabledCategories() const {
204     return included_categories_;
205   }
IsSystraceEnabled()206   bool IsSystraceEnabled() const { return enable_systrace_; }
IsArgumentFilterEnabled()207   bool IsArgumentFilterEnabled() const { return enable_argument_filter_; }
208 
SetTraceRecordMode(TraceRecordMode mode)209   void SetTraceRecordMode(TraceRecordMode mode) { record_mode_ = mode; }
EnableSystrace()210   void EnableSystrace() { enable_systrace_ = true; }
EnableArgumentFilter()211   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
V8_PLATFORM_NON_EXPORTED_BASE(v8::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 #endif  // !defined(V8_USE_PERFETTO)
286 
287   void AddTraceStateObserver(
288       v8::TracingController::TraceStateObserver* observer) override;
289   void RemoveTraceStateObserver(
290       v8::TracingController::TraceStateObserver* observer) override;
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   std::unordered_set<v8::TracingController::TraceStateObserver*> observers_;
311 
312 #if defined(V8_USE_PERFETTO)
313   std::ostream* output_stream_ = nullptr;
314   std::unique_ptr<perfetto::trace_processor::TraceProcessorStorage>
315       trace_processor_;
316   TraceEventListener* listener_for_testing_ = nullptr;
317   std::unique_ptr<perfetto::TracingSession> tracing_session_;
318 #else   // !defined(V8_USE_PERFETTO)
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_
334