• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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_HEAP_CPPGC_TRACE_EVENT_H_
6 #define V8_HEAP_CPPGC_TRACE_EVENT_H_
7 
8 #if !CPPGC_IS_STANDALONE
9 #include "src/tracing/trace-event.h"
10 using ConvertableToTraceFormat = v8::ConvertableToTraceFormat;
11 #else
12 // This is a subset of stc/tracing/trace-event.h required to support
13 // tracing in the cppgc standalone library using TracingController.
14 
15 #include "base/trace_event/common/trace_event_common.h"
16 #include "include/cppgc/platform.h"
17 #include "src/base/atomicops.h"
18 #include "src/base/macros.h"
19 
20 // This header file defines implementation details of how the trace macros in
21 // trace_event_common.h collect and store trace events. Anything not
22 // implementation-specific should go in trace_macros_common.h instead of here.
23 
24 // The pointer returned from GetCategoryGroupEnabled() points to a
25 // value with zero or more of the following bits. Used in this class only.
26 // The TRACE_EVENT macros should only use the value as a bool.
27 // These values must be in sync with macro values in trace_log.h in
28 // chromium.
29 enum CategoryGroupEnabledFlags {
30   // Category group enabled for the recording mode.
31   kEnabledForRecording_CategoryGroupEnabledFlags = 1 << 0,
32   // Category group enabled by SetEventCallbackEnabled().
33   kEnabledForEventCallback_CategoryGroupEnabledFlags = 1 << 2,
34 };
35 
36 #define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
37   TRACE_EVENT_API_LOAD_CATEGORY_GROUP_ENABLED() &                        \
38       (kEnabledForRecording_CategoryGroupEnabledFlags |                  \
39        kEnabledForEventCallback_CategoryGroupEnabledFlags)
40 
41 ////////////////////////////////////////////////////////////////////////////////
42 // Implementation specific tracing API definitions.
43 
44 // Get a pointer to the enabled state of the given trace category. Only
45 // long-lived literal strings should be given as the category group. The
46 // returned pointer can be held permanently in a local static for example. If
47 // the unsigned char is non-zero, tracing is enabled. If tracing is enabled,
48 // TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled
49 // between the load of the tracing state and the call to
50 // TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out
51 // for best performance when tracing is disabled.
52 // const uint8_t*
53 //     TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group)
54 #define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED \
55   platform->GetTracingController()->GetCategoryGroupEnabled
56 
57 // Add a trace event to the platform tracing system.
58 // uint64_t TRACE_EVENT_API_ADD_TRACE_EVENT(
59 //                    char phase,
60 //                    const uint8_t* category_group_enabled,
61 //                    const char* name,
62 //                    const char* scope,
63 //                    uint64_t id,
64 //                    uint64_t bind_id,
65 //                    int num_args,
66 //                    const char** arg_names,
67 //                    const uint8_t* arg_types,
68 //                    const uint64_t* arg_values,
69 //                    unsigned int flags)
70 #define TRACE_EVENT_API_ADD_TRACE_EVENT cppgc::internal::AddTraceEventImpl
71 
72 // Defines atomic operations used internally by the tracing system.
73 #define TRACE_EVENT_API_ATOMIC_WORD v8::base::AtomicWord
74 #define TRACE_EVENT_API_ATOMIC_LOAD(var) v8::base::Relaxed_Load(&(var))
75 #define TRACE_EVENT_API_ATOMIC_STORE(var, value) \
76   v8::base::Relaxed_Store(&(var), (value))
77 #define TRACE_EVENT_API_LOAD_CATEGORY_GROUP_ENABLED()                \
78   v8::base::Relaxed_Load(reinterpret_cast<const v8::base::Atomic8*>( \
79       INTERNAL_TRACE_EVENT_UID(category_group_enabled)))
80 
81 ////////////////////////////////////////////////////////////////////////////////
82 
83 // Implementation detail: trace event macros create temporary variables
84 // to keep instrumentation overhead low. These macros give each temporary
85 // variable a unique name based on the line number to prevent name collisions.
86 #define INTERNAL_TRACE_EVENT_UID3(a, b) cppgc_trace_event_unique_##a##b
87 #define INTERNAL_TRACE_EVENT_UID2(a, b) INTERNAL_TRACE_EVENT_UID3(a, b)
88 #define INTERNAL_TRACE_EVENT_UID(name_prefix) \
89   INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__)
90 
91 // Implementation detail: internal macro to create static category.
92 // No barriers are needed, because this code is designed to operate safely
93 // even when the unsigned char* points to garbage data (which may be the case
94 // on processors without cache coherency).
95 #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(             \
96     category_group, atomic, category_group_enabled)                          \
97   category_group_enabled =                                                   \
98       reinterpret_cast<const uint8_t*>(TRACE_EVENT_API_ATOMIC_LOAD(atomic)); \
99   if (!category_group_enabled) {                                             \
100     category_group_enabled =                                                 \
101         TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group);          \
102     TRACE_EVENT_API_ATOMIC_STORE(                                            \
103         atomic, reinterpret_cast<TRACE_EVENT_API_ATOMIC_WORD>(               \
104                     category_group_enabled));                                \
105   }
106 
107 #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group)             \
108   static TRACE_EVENT_API_ATOMIC_WORD INTERNAL_TRACE_EVENT_UID(atomic) = 0; \
109   const uint8_t* INTERNAL_TRACE_EVENT_UID(category_group_enabled);         \
110   INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(                 \
111       category_group, INTERNAL_TRACE_EVENT_UID(atomic),                    \
112       INTERNAL_TRACE_EVENT_UID(category_group_enabled));
113 
114 // Implementation detail: internal macro to create static category and add
115 // event if the category is enabled.
116 #define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...)    \
117   DCHECK_NOT_NULL(name);                                                     \
118   do {                                                                       \
119     cppgc::Platform* platform = stats_collector_->platform_;                 \
120     INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                  \
121     if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {  \
122       cppgc::internal::AddTraceEvent(                                        \
123           phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,     \
124           nullptr /* scope */, 0 /* id */, 0 /* bind_id */, flags, platform, \
125           ##__VA_ARGS__);                                                    \
126     }                                                                        \
127   } while (false)
128 
129 namespace cppgc {
130 namespace internal {
131 
132 using ConvertableToTraceFormat = v8::ConvertableToTraceFormat;
133 
134 class TraceEventHelper {
135  public:
136   V8_EXPORT_PRIVATE static TracingController* GetTracingController();
137 };
138 
AddTraceEventImpl(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,int32_t num_args,const char ** arg_names,const uint8_t * arg_types,const uint64_t * arg_values,unsigned int flags,Platform * platform)139 static V8_INLINE uint64_t AddTraceEventImpl(
140     char phase, const uint8_t* category_group_enabled, const char* name,
141     const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
142     const char** arg_names, const uint8_t* arg_types,
143     const uint64_t* arg_values, unsigned int flags, Platform* platform) {
144   std::unique_ptr<ConvertableToTraceFormat> arg_convertables[2];
145   if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
146     arg_convertables[0].reset(reinterpret_cast<ConvertableToTraceFormat*>(
147         static_cast<intptr_t>(arg_values[0])));
148   }
149   if (num_args > 1 && arg_types[1] == TRACE_VALUE_TYPE_CONVERTABLE) {
150     arg_convertables[1].reset(reinterpret_cast<ConvertableToTraceFormat*>(
151         static_cast<intptr_t>(arg_values[1])));
152   }
153   DCHECK_LE(num_args, 2);
154   TracingController* controller = platform->GetTracingController();
155   return controller->AddTraceEvent(phase, category_group_enabled, name, scope,
156                                    id, bind_id, num_args, arg_names, arg_types,
157                                    arg_values, arg_convertables, flags);
158 }
159 
160 // Define SetTraceValue for each allowed type. It stores the type and value
161 // in the return arguments. This allows this API to avoid declaring any
162 // structures so that it is portable to third_party libraries.
163 // This is the base implementation for integer types (including bool) and enums.
164 template <typename T>
165 static V8_INLINE typename std::enable_if<
166     std::is_integral<T>::value || std::is_enum<T>::value, void>::type
SetTraceValue(T arg,unsigned char * type,uint64_t * value)167 SetTraceValue(T arg, unsigned char* type, uint64_t* value) {
168   *type = std::is_same<T, bool>::value
169               ? TRACE_VALUE_TYPE_BOOL
170               : std::is_signed<T>::value ? TRACE_VALUE_TYPE_INT
171                                          : TRACE_VALUE_TYPE_UINT;
172   *value = static_cast<uint64_t>(arg);
173 }
174 
175 #define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, value_type_id)        \
176   static V8_INLINE void SetTraceValue(actual_type arg, unsigned char* type, \
177                                       uint64_t* value) {                    \
178     *type = value_type_id;                                                  \
179     *value = 0;                                                             \
180     STATIC_ASSERT(sizeof(arg) <= sizeof(*value));                           \
181     memcpy(value, &arg, sizeof(arg));                                       \
182   }
INTERNAL_DECLARE_SET_TRACE_VALUE(double,TRACE_VALUE_TYPE_DOUBLE)183 INTERNAL_DECLARE_SET_TRACE_VALUE(double, TRACE_VALUE_TYPE_DOUBLE)
184 INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, TRACE_VALUE_TYPE_STRING)
185 #undef INTERNAL_DECLARE_SET_TRACE_VALUE
186 
187 // These AddTraceEvent template functions are defined here instead of in
188 // the macro, because the arg_values could be temporary objects, such as
189 // std::string. In order to store pointers to the internal c_str and pass
190 // through to the tracing API, the arg_values must live throughout these
191 // procedures.
192 
193 static V8_INLINE uint64_t AddTraceEvent(char phase,
194                                         const uint8_t* category_group_enabled,
195                                         const char* name, const char* scope,
196                                         uint64_t id, uint64_t bind_id,
197                                         unsigned int flags,
198                                         Platform* platform) {
199   return TRACE_EVENT_API_ADD_TRACE_EVENT(
200       phase, category_group_enabled, name, scope, id, bind_id, 0 /* num_args */,
201       nullptr, nullptr, nullptr, flags, platform);
202 }
203 
204 template <class ARG1_TYPE>
AddTraceEvent(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,unsigned int flags,Platform * platform,const char * arg1_name,ARG1_TYPE && arg1_val)205 static V8_INLINE uint64_t AddTraceEvent(
206     char phase, const uint8_t* category_group_enabled, const char* name,
207     const char* scope, uint64_t id, uint64_t bind_id, unsigned int flags,
208     Platform* platform, const char* arg1_name, ARG1_TYPE&& arg1_val) {
209   const int num_args = 1;
210   uint8_t arg_type;
211   uint64_t arg_value;
212   SetTraceValue(std::forward<ARG1_TYPE>(arg1_val), &arg_type, &arg_value);
213   return TRACE_EVENT_API_ADD_TRACE_EVENT(
214       phase, category_group_enabled, name, scope, id, bind_id, num_args,
215       &arg1_name, &arg_type, &arg_value, flags, platform);
216 }
217 
218 template <class ARG1_TYPE, class ARG2_TYPE>
AddTraceEvent(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,unsigned int flags,Platform * platform,const char * arg1_name,ARG1_TYPE && arg1_val,const char * arg2_name,ARG2_TYPE && arg2_val)219 static V8_INLINE uint64_t AddTraceEvent(
220     char phase, const uint8_t* category_group_enabled, const char* name,
221     const char* scope, uint64_t id, uint64_t bind_id, unsigned int flags,
222     Platform* platform, const char* arg1_name, ARG1_TYPE&& arg1_val,
223     const char* arg2_name, ARG2_TYPE&& arg2_val) {
224   const int num_args = 2;
225   const char* arg_names[2] = {arg1_name, arg2_name};
226   unsigned char arg_types[2];
227   uint64_t arg_values[2];
228   SetTraceValue(std::forward<ARG1_TYPE>(arg1_val), &arg_types[0],
229                 &arg_values[0]);
230   SetTraceValue(std::forward<ARG2_TYPE>(arg2_val), &arg_types[1],
231                 &arg_values[1]);
232   return TRACE_EVENT_API_ADD_TRACE_EVENT(
233       phase, category_group_enabled, name, scope, id, bind_id, num_args,
234       arg_names, arg_types, arg_values, flags, platform);
235 }
236 
237 }  // namespace internal
238 }  // namespace cppgc
239 
240 #endif  // !CPPGC_IS_STANDALONE
241 
242 #endif  // V8_HEAP_CPPGC_TRACE_EVENT_H_
243