1// Copyright (c) 2014 Google Inc.
2//
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5
6// This header file defines implementation details of how the trace macros in
7// SkTraceEventCommon.h collect and store trace events. Anything not
8// implementation-specific should go in SkTraceEventCommon.h instead of here.
9
10#ifndef SkTraceEvent_DEFINED
11#define SkTraceEvent_DEFINED
12
13#include "SkAtomics.h"
14#include "SkEventTracer.h"
15#include "SkTraceEventCommon.h"
16
17////////////////////////////////////////////////////////////////////////////////
18// Implementation specific tracing API definitions.
19
20// Makes it easier to add traces with a simple TRACE_EVENT0("skia", TRACE_FUNC).
21#if defined(_MSC_VER)
22    #define TRACE_FUNC __FUNCSIG__
23#else
24    #define TRACE_FUNC __PRETTY_FUNCTION__
25#endif
26
27// By default, const char* argument values are assumed to have long-lived scope
28// and will not be copied. Use this macro to force a const char* to be copied.
29#define TRACE_STR_COPY(str) \
30    skia::tracing_internals::TraceStringWithCopy(str)
31
32
33#define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
34    *INTERNAL_TRACE_EVENT_UID(category_group_enabled) & \
35        (SkEventTracer::kEnabledForRecording_CategoryGroupEnabledFlags | \
36         SkEventTracer::kEnabledForEventCallback_CategoryGroupEnabledFlags)
37
38// Get a pointer to the enabled state of the given trace category. Only
39// long-lived literal strings should be given as the category group. The
40// returned pointer can be held permanently in a local static for example. If
41// the unsigned char is non-zero, tracing is enabled. If tracing is enabled,
42// TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled
43// between the load of the tracing state and the call to
44// TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out
45// for best performance when tracing is disabled.
46// const uint8_t*
47//     TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group)
48#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED \
49    SkEventTracer::GetInstance()->getCategoryGroupEnabled
50
51// Add a trace event to the platform tracing system.
52// SkEventTracer::Handle TRACE_EVENT_API_ADD_TRACE_EVENT(
53//                    char phase,
54//                    const uint8_t* category_group_enabled,
55//                    const char* name,
56//                    uint64_t id,
57//                    int num_args,
58//                    const char** arg_names,
59//                    const uint8_t* arg_types,
60//                    const uint64_t* arg_values,
61//                    unsigned char flags)
62#define TRACE_EVENT_API_ADD_TRACE_EVENT \
63    SkEventTracer::GetInstance()->addTraceEvent
64
65// Set the duration field of a COMPLETE trace event.
66// void TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
67//     const uint8_t* category_group_enabled,
68//     const char* name,
69//     SkEventTracer::Handle id)
70#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION \
71    SkEventTracer::GetInstance()->updateTraceEventDuration
72
73#define TRACE_EVENT_API_ATOMIC_WORD intptr_t
74#define TRACE_EVENT_API_ATOMIC_LOAD(var) sk_atomic_load(&var, sk_memory_order_relaxed)
75#define TRACE_EVENT_API_ATOMIC_STORE(var, value) \
76    sk_atomic_store(&var, value, sk_memory_order_relaxed)
77
78// Defines visibility for classes in trace_event.h
79#define TRACE_EVENT_API_CLASS_EXPORT SK_API
80
81// We prepend this string to all category names, so that ALL Skia trace events are
82// disabled by default when tracing in Chrome.
83#define TRACE_CATEGORY_PREFIX "disabled-by-default-"
84
85////////////////////////////////////////////////////////////////////////////////
86
87// Implementation detail: trace event macros create temporary variables
88// to keep instrumentation overhead low. These macros give each temporary
89// variable a unique name based on the line number to prevent name collisions.
90#define INTERNAL_TRACE_EVENT_UID3(a,b) \
91    trace_event_unique_##a##b
92#define INTERNAL_TRACE_EVENT_UID2(a,b) \
93    INTERNAL_TRACE_EVENT_UID3(a,b)
94#define INTERNAL_TRACE_EVENT_UID(name_prefix) \
95    INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__)
96
97// Implementation detail: internal macro to create static category.
98// No barriers are needed, because this code is designed to operate safely
99// even when the unsigned char* points to garbage data (which may be the case
100// on processors without cache coherency).
101#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES( \
102    category_group, atomic, category_group_enabled) \
103    category_group_enabled = \
104        reinterpret_cast<const uint8_t*>(TRACE_EVENT_API_ATOMIC_LOAD(atomic)); \
105    if (!category_group_enabled) { \
106      category_group_enabled = TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group); \
107      TRACE_EVENT_API_ATOMIC_STORE(atomic, \
108          reinterpret_cast<TRACE_EVENT_API_ATOMIC_WORD>(category_group_enabled)); \
109    }
110
111#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group) \
112    static TRACE_EVENT_API_ATOMIC_WORD INTERNAL_TRACE_EVENT_UID(atomic) = 0; \
113    const uint8_t* INTERNAL_TRACE_EVENT_UID(category_group_enabled); \
114    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES( \
115        TRACE_CATEGORY_PREFIX category_group, \
116        INTERNAL_TRACE_EVENT_UID(atomic), \
117        INTERNAL_TRACE_EVENT_UID(category_group_enabled));
118
119// Implementation detail: internal macro to create static category and add
120// event if the category is enabled.
121#define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...) \
122    do { \
123      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
124      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
125        skia::tracing_internals::AddTraceEvent( \
126            phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
127            skia::tracing_internals::kNoEventId, flags, ##__VA_ARGS__); \
128      } \
129    } while (0)
130
131// Implementation detail: internal macro to create static category and add
132// event if the category is enabled.
133#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category_group, name, id, \
134                                         flags, ...) \
135    do { \
136      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
137      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
138        unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
139        skia::tracing_internals::TraceID trace_event_trace_id( \
140            id, &trace_event_flags); \
141        skia::tracing_internals::AddTraceEvent( \
142            phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
143            name, trace_event_trace_id.data(), trace_event_flags, \
144            ##__VA_ARGS__); \
145      } \
146    } while (0)
147
148// Implementation detail: internal macro to create static category and add begin
149// event if the category is enabled. Also adds the end event when the scope
150// ends.
151#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, ...) \
152    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
153    skia::tracing_internals::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \
154    if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
155      SkEventTracer::Handle h = skia::tracing_internals::AddTraceEvent( \
156          TRACE_EVENT_PHASE_COMPLETE, \
157          INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
158          name, skia::tracing_internals::kNoEventId, \
159          TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \
160      INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \
161          INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \
162    }
163
164namespace skia {
165namespace tracing_internals {
166
167// Specify these values when the corresponding argument of AddTraceEvent is not
168// used.
169const int kZeroNumArgs = 0;
170const uint64_t kNoEventId = 0;
171
172// TraceID encapsulates an ID that can either be an integer or pointer. Pointers
173// are by default mangled with the Process ID so that they are unlikely to
174// collide when the same pointer is used on different processes.
175class TraceID {
176public:
177    TraceID(const void* id, unsigned char* flags)
178            : data_(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(id))) {
179        *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
180    }
181    TraceID(uint64_t id, unsigned char* flags)
182        : data_(id) { (void)flags; }
183    TraceID(unsigned int id, unsigned char* flags)
184        : data_(id) { (void)flags; }
185    TraceID(unsigned short id, unsigned char* flags)
186        : data_(id) { (void)flags; }
187    TraceID(unsigned char id, unsigned char* flags)
188        : data_(id) { (void)flags; }
189    TraceID(long long id, unsigned char* flags)
190        : data_(static_cast<uint64_t>(id)) { (void)flags; }
191    TraceID(long id, unsigned char* flags)
192        : data_(static_cast<uint64_t>(id)) { (void)flags; }
193    TraceID(int id, unsigned char* flags)
194        : data_(static_cast<uint64_t>(id)) { (void)flags; }
195    TraceID(short id, unsigned char* flags)
196        : data_(static_cast<uint64_t>(id)) { (void)flags; }
197    TraceID(signed char id, unsigned char* flags)
198        : data_(static_cast<uint64_t>(id)) { (void)flags; }
199
200    uint64_t data() const { return data_; }
201
202private:
203    uint64_t data_;
204};
205
206// Simple union to store various types as uint64_t.
207union TraceValueUnion {
208  bool as_bool;
209  uint64_t as_uint;
210  long long as_int;
211  double as_double;
212  const void* as_pointer;
213  const char* as_string;
214};
215
216// Simple container for const char* that should be copied instead of retained.
217class TraceStringWithCopy {
218 public:
219  explicit TraceStringWithCopy(const char* str) : str_(str) {}
220  operator const char* () const { return str_; }
221 private:
222  const char* str_;
223};
224
225// Define SetTraceValue for each allowed type. It stores the type and
226// value in the return arguments. This allows this API to avoid declaring any
227// structures so that it is portable to third_party libraries.
228#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \
229                                         union_member, \
230                                         value_type_id) \
231    static inline void SetTraceValue( \
232        actual_type arg, \
233        unsigned char* type, \
234        uint64_t* value) { \
235      TraceValueUnion type_value; \
236      type_value.union_member = arg; \
237      *type = value_type_id; \
238      *value = type_value.as_uint; \
239    }
240// Simpler form for int types that can be safely casted.
241#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \
242                                             value_type_id) \
243    static inline void SetTraceValue( \
244        actual_type arg, \
245        unsigned char* type, \
246        uint64_t* value) { \
247      *type = value_type_id; \
248      *value = static_cast<uint64_t>(arg); \
249    }
250
251INTERNAL_DECLARE_SET_TRACE_VALUE_INT(uint64_t, TRACE_VALUE_TYPE_UINT)
252INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT)
253INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT)
254INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT)
255INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT)
256INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long, TRACE_VALUE_TYPE_INT)
257INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT)
258INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT)
259INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT)
260INTERNAL_DECLARE_SET_TRACE_VALUE(bool, as_bool, TRACE_VALUE_TYPE_BOOL)
261INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE)
262INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer, TRACE_VALUE_TYPE_POINTER)
263INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string, TRACE_VALUE_TYPE_STRING)
264INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, as_string,
265                                 TRACE_VALUE_TYPE_COPY_STRING)
266
267#undef INTERNAL_DECLARE_SET_TRACE_VALUE
268#undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT
269
270// These AddTraceEvent and AddTraceEvent template
271// functions are defined here instead of in the macro, because the arg_values
272// could be temporary objects, such as std::string. In order to store
273// pointers to the internal c_str and pass through to the tracing API,
274// the arg_values must live throughout these procedures.
275
276static inline SkEventTracer::Handle
277AddTraceEvent(
278    char phase,
279    const uint8_t* category_group_enabled,
280    const char* name,
281    uint64_t id,
282    unsigned char flags) {
283  return TRACE_EVENT_API_ADD_TRACE_EVENT(
284      phase, category_group_enabled, name, id,
285      kZeroNumArgs, nullptr, nullptr, nullptr, flags);
286}
287
288template<class ARG1_TYPE>
289static inline SkEventTracer::Handle
290AddTraceEvent(
291    char phase,
292    const uint8_t* category_group_enabled,
293    const char* name,
294    uint64_t id,
295    unsigned char flags,
296    const char* arg1_name,
297    const ARG1_TYPE& arg1_val) {
298  const int num_args = 1;
299  uint8_t arg_types[1];
300  uint64_t arg_values[1];
301  SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
302  return TRACE_EVENT_API_ADD_TRACE_EVENT(
303      phase, category_group_enabled, name, id,
304      num_args, &arg1_name, arg_types, arg_values, flags);
305}
306
307template<class ARG1_TYPE, class ARG2_TYPE>
308static inline SkEventTracer::Handle
309AddTraceEvent(
310    char phase,
311    const uint8_t* category_group_enabled,
312    const char* name,
313    uint64_t id,
314    unsigned char flags,
315    const char* arg1_name,
316    const ARG1_TYPE& arg1_val,
317    const char* arg2_name,
318    const ARG2_TYPE& arg2_val) {
319  const int num_args = 2;
320  const char* arg_names[2] = { arg1_name, arg2_name };
321  unsigned char arg_types[2];
322  uint64_t arg_values[2];
323  SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
324  SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
325  return TRACE_EVENT_API_ADD_TRACE_EVENT(
326      phase, category_group_enabled, name, id,
327      num_args, arg_names, arg_types, arg_values, flags);
328}
329
330// Used by TRACE_EVENTx macros. Do not use directly.
331class TRACE_EVENT_API_CLASS_EXPORT ScopedTracer {
332 public:
333  // Note: members of data_ intentionally left uninitialized. See Initialize.
334  ScopedTracer() : p_data_(nullptr) {}
335
336  ~ScopedTracer() {
337    if (p_data_ && *data_.category_group_enabled)
338      TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
339          data_.category_group_enabled, data_.name, data_.event_handle);
340  }
341
342  void Initialize(const uint8_t* category_group_enabled,
343                  const char* name,
344                  SkEventTracer::Handle event_handle) {
345    data_.category_group_enabled = category_group_enabled;
346    data_.name = name;
347    data_.event_handle = event_handle;
348    p_data_ = &data_;
349  }
350
351 private:
352  // This Data struct workaround is to avoid initializing all the members
353  // in Data during construction of this object, since this object is always
354  // constructed, even when tracing is disabled. If the members of Data were
355  // members of this class instead, compiler warnings occur about potential
356  // uninitialized accesses.
357  struct Data {
358    const uint8_t* category_group_enabled;
359    const char* name;
360    SkEventTracer::Handle event_handle;
361  };
362  Data* p_data_;
363  Data data_;
364};
365
366}  // namespace tracing_internals
367}  // namespace skia
368
369#endif
370