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