• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef INCLUDE_PERFETTO_TRACING_INTERNAL_WRITE_TRACK_EVENT_ARGS_H_
18 #define INCLUDE_PERFETTO_TRACING_INTERNAL_WRITE_TRACK_EVENT_ARGS_H_
19 
20 #include "perfetto/base/compiler.h"
21 #include "perfetto/tracing/event_context.h"
22 #include "perfetto/tracing/traced_proto.h"
23 #include "perfetto/tracing/track_event_args.h"
24 
25 namespace perfetto {
26 namespace internal {
27 
28 // No arguments means that we don't have to write anything.
WriteTrackEventArgs(EventContext)29 PERFETTO_ALWAYS_INLINE inline void WriteTrackEventArgs(EventContext) {}
30 
31 namespace {
32 
33 // A template helper for determining whether a type can be used as a track event
34 // lambda, i.e., it has the signature "void(EventContext)". This is achieved by
35 // checking that we can pass an EventContext value (the inner declval) into a T
36 // instance (the outer declval). If this is a valid expression, the result
37 // evaluates to sizeof(0), i.e., true.
38 // TODO(skyostil): Replace this with std::is_convertible<std::function<...>>
39 // once we have C++14.
40 template <typename T>
41 static constexpr bool IsValidTraceLambdaImpl(
42     typename std::enable_if<static_cast<bool>(
43         sizeof(std::declval<T>()(std::declval<EventContext>()), 0))>::type* =
44         nullptr) {
45   return true;
46 }
47 
48 template <typename T>
IsValidTraceLambdaImpl(...)49 static constexpr bool IsValidTraceLambdaImpl(...) {
50   return false;
51 }
52 
53 template <typename T>
IsValidTraceLambda()54 static constexpr bool IsValidTraceLambda() {
55   return IsValidTraceLambdaImpl<T>(nullptr);
56 }
57 
58 template <typename T>
59 static constexpr bool IsValidTraceLambdaTakingReferenceImpl(
60     typename std::enable_if<static_cast<bool>(
61         sizeof(std::declval<T>()(std::declval<EventContext&>()), 0))>::type* =
62         nullptr) {
63   return true;
64 }
65 
66 template <typename T>
IsValidTraceLambdaTakingReferenceImpl(...)67 static constexpr bool IsValidTraceLambdaTakingReferenceImpl(...) {
68   return false;
69 }
70 
71 template <typename T>
IsValidTraceLambdaTakingReference()72 static constexpr bool IsValidTraceLambdaTakingReference() {
73   return IsValidTraceLambdaTakingReferenceImpl<T>(nullptr);
74 }
75 
76 template <typename T>
77 static constexpr bool IsFieldMetadataTypeImpl(
78     typename std::enable_if<
79         std::is_base_of<protozero::proto_utils::FieldMetadataBase,
80                         T>::value>::type* = nullptr) {
81   return true;
82 }
83 
84 template <typename T>
IsFieldMetadataTypeImpl(...)85 static constexpr bool IsFieldMetadataTypeImpl(...) {
86   return false;
87 }
88 
89 template <typename T>
IsFieldMetadataType()90 static constexpr bool IsFieldMetadataType() {
91   return IsFieldMetadataTypeImpl<T>(nullptr);
92 }
93 
94 }  // namespace
95 
96 // Write an old-style lambda taking an EventContext (without a reference)
97 // as it will consume EventContext via std::move, it can only be the last
98 // argument.
99 template <typename ArgumentFunction,
100           typename ArgFunctionCheck = typename std::enable_if<
101               IsValidTraceLambda<ArgumentFunction>()>::type>
WriteTrackEventArgs(EventContext event_ctx,const ArgumentFunction & arg_function)102 PERFETTO_ALWAYS_INLINE void WriteTrackEventArgs(
103     EventContext event_ctx,
104     const ArgumentFunction& arg_function) {
105   arg_function(std::move(event_ctx));
106 }
107 
108 // Forward-declare the specification for writing untyped arguments to ensure
109 // that typed specification could recursively pick it up.
110 template <typename ArgValue, typename... Args>
111 PERFETTO_ALWAYS_INLINE void WriteTrackEventArgs(EventContext event_ctx,
112                                                 const char* arg_name,
113                                                 ArgValue&& arg_value,
114                                                 Args&&... args);
115 
116 template <typename FieldMetadataType,
117           typename ArgValue,
118           typename... Args,
119           typename FieldMetadataTypeCheck = typename std::enable_if<
120               IsFieldMetadataType<FieldMetadataType>()>::type>
121 PERFETTO_ALWAYS_INLINE void WriteTrackEventArgs(EventContext event_ctx,
122                                                 FieldMetadataType field_name,
123                                                 ArgValue&& arg_value,
124                                                 Args&&... args);
125 
126 template <typename ArgumentFunction,
127           typename... Args,
128           typename ArgFunctionCheck = typename std::enable_if<
129               IsValidTraceLambdaTakingReference<ArgumentFunction>()>::type>
WriteTrackEventArgs(EventContext event_ctx,const ArgumentFunction & arg_function,Args &&...args)130 PERFETTO_ALWAYS_INLINE void WriteTrackEventArgs(
131     EventContext event_ctx,
132     const ArgumentFunction& arg_function,
133     Args&&... args) {
134   // |arg_function| will capture EventContext by reference, so std::move isn't
135   // needed.
136   arg_function(event_ctx);
137 
138   WriteTrackEventArgs(std::move(event_ctx), std::forward<Args>(args)...);
139 }
140 
141 // Write one typed message and recursively write the rest of the arguments.
142 template <typename FieldMetadataType,
143           typename ArgValue,
144           typename... Args,
145           typename FieldMetadataTypeCheck>
WriteTrackEventArgs(EventContext event_ctx,FieldMetadataType field_name,ArgValue && arg_value,Args &&...args)146 PERFETTO_ALWAYS_INLINE void WriteTrackEventArgs(EventContext event_ctx,
147                                                 FieldMetadataType field_name,
148                                                 ArgValue&& arg_value,
149                                                 Args&&... args) {
150   static_assert(std::is_base_of<protozero::proto_utils::FieldMetadataBase,
151                                 FieldMetadataType>::value,
152                 "");
153   static_assert(
154       std::is_base_of<protos::pbzero::TrackEvent,
155                       typename FieldMetadataType::message_type>::value,
156       "Only fields of TrackEvent (and TrackEvent's extensions) can "
157       "be passed to TRACE_EVENT");
158   auto track_event_proto = event_ctx.Wrap(
159       event_ctx.event<typename FieldMetadataType::message_type>());
160   WriteTracedProtoField(track_event_proto, field_name,
161                         std::forward<ArgValue>(arg_value));
162   WriteTrackEventArgs(std::move(event_ctx), std::forward<Args>(args)...);
163 }
164 
165 // Write one debug annotation and recursively write the rest of the arguments.
166 template <typename ArgValue, typename... Args>
WriteTrackEventArgs(EventContext event_ctx,const char * arg_name,ArgValue && arg_value,Args &&...args)167 PERFETTO_ALWAYS_INLINE void WriteTrackEventArgs(EventContext event_ctx,
168                                                 const char* arg_name,
169                                                 ArgValue&& arg_value,
170                                                 Args&&... args) {
171   event_ctx.AddDebugAnnotation(arg_name, std::forward<ArgValue>(arg_value));
172   WriteTrackEventArgs(std::move(event_ctx), std::forward<Args>(args)...);
173 }
174 
175 // Write one debug annotation and recursively write the rest of the arguments.
176 template <typename ArgValue, typename... Args>
WriteTrackEventArgs(EventContext event_ctx,DynamicString arg_name,ArgValue && arg_value,Args &&...args)177 PERFETTO_ALWAYS_INLINE void WriteTrackEventArgs(EventContext event_ctx,
178                                                 DynamicString arg_name,
179                                                 ArgValue&& arg_value,
180                                                 Args&&... args) {
181   event_ctx.AddDebugAnnotation(arg_name, std::forward<ArgValue>(arg_value));
182   WriteTrackEventArgs(std::move(event_ctx), std::forward<Args>(args)...);
183 }
184 
185 }  // namespace internal
186 }  // namespace perfetto
187 
188 #endif  // INCLUDE_PERFETTO_TRACING_INTERNAL_WRITE_TRACK_EVENT_ARGS_H_
189