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 
24 namespace perfetto {
25 namespace internal {
26 
27 // Helper function handling filling provided |EventContext| from the provided
28 // arguments, which include:
29 // - Lambda functions,
30 // - Debug annotations.
31 //
32 // TRACE_EVENT parameters which do not translate to directly writing something
33 // into TrackEvent proto (like tracks and timestamps are _not_ covered by this
34 // function).
35 template <typename... Args, typename TypeCheck = void>
36 void WriteTrackEventArgs(EventContext event_context, Args&&... args);
37 
38 // No arguments means that we don't have to write anything.
39 template <>
WriteTrackEventArgs(EventContext)40 PERFETTO_ALWAYS_INLINE inline void WriteTrackEventArgs(EventContext) {}
41 
42 namespace {
43 
44 // A template helper for determining whether a type can be used as a track event
45 // lambda, i.e., it has the signature "void(EventContext)". This is achieved by
46 // checking that we can pass an EventContext value (the inner declval) into a T
47 // instance (the outer declval). If this is a valid expression, the result
48 // evaluates to sizeof(0), i.e., true.
49 // TODO(skyostil): Replace this with std::is_convertible<std::function<...>>
50 // once we have C++14.
51 template <typename T>
52 static constexpr bool IsValidTraceLambdaImpl(
53     typename std::enable_if<static_cast<bool>(
54         sizeof(std::declval<T>()(std::declval<EventContext>()), 0))>::type* =
55         nullptr) {
56   return true;
57 }
58 
59 template <typename T>
IsValidTraceLambdaImpl(...)60 static constexpr bool IsValidTraceLambdaImpl(...) {
61   return false;
62 }
63 
64 template <typename T>
IsValidTraceLambda()65 static constexpr bool IsValidTraceLambda() {
66   return IsValidTraceLambdaImpl<T>(nullptr);
67 }
68 
69 }  // namespace
70 
71 // Write a lambda.
72 // TODO(altimin): At the moment lambda takes EventContext, which is
73 // non-copyable, so only one lambda is supported and it has to be the last
74 // argument.
75 template <typename ArgumentFunction,
76           typename ArgFunctionCheck = typename std::enable_if<
77               IsValidTraceLambda<ArgumentFunction>()>::type>
WriteTrackEventArgs(EventContext event_ctx,ArgumentFunction arg_function)78 PERFETTO_ALWAYS_INLINE void WriteTrackEventArgs(EventContext event_ctx,
79                                                 ArgumentFunction arg_function) {
80   arg_function(std::move(event_ctx));
81 }
82 
83 // Write one debug annotation and recursively write the rest of the arguments.
84 template <typename ArgValue, typename... Args>
WriteTrackEventArgs(EventContext event_ctx,const char * arg_name,ArgValue && arg_value,Args &&...args)85 PERFETTO_ALWAYS_INLINE void WriteTrackEventArgs(EventContext event_ctx,
86                                                 const char* arg_name,
87                                                 ArgValue&& arg_value,
88                                                 Args&&... args) {
89   TrackEventInternal::AddDebugAnnotation(&event_ctx, arg_name,
90                                          std::forward<ArgValue>(arg_value));
91   WriteTrackEventArgs(std::move(event_ctx), std::forward<Args>(args)...);
92 }
93 
94 // Write one typed message and recursively write the rest of the arguments.
95 template <typename FieldMetadataType,
96           typename ArgValue,
97           typename... Args,
98           typename Check = base::enable_if_t<
99               std::is_base_of<protozero::proto_utils::FieldMetadataBase,
100                               FieldMetadataType>::value>>
WriteTrackEventArgs(EventContext event_ctx,protozero::proto_utils::internal::FieldMetadataHelper<FieldMetadataType> field_name,ArgValue && arg_value,Args &&...args)101 PERFETTO_ALWAYS_INLINE void WriteTrackEventArgs(
102     EventContext event_ctx,
103     protozero::proto_utils::internal::FieldMetadataHelper<FieldMetadataType>
104         field_name,
105     ArgValue&& arg_value,
106     Args&&... args) {
107   static_assert(
108       std::is_base_of<protos::pbzero::TrackEvent,
109                       typename FieldMetadataType::message_type>::value,
110       "Only fields of TrackEvent (and TrackEvent's extensions) can "
111       "be passed to TRACE_EVENT");
112   WriteIntoTracedProto(
113       event_ctx.Wrap(
114           event_ctx.event<typename FieldMetadataType::message_type>()),
115       field_name, std::forward<ArgValue>(arg_value));
116   WriteTrackEventArgs(std::move(event_ctx), std::forward<Args>(args)...);
117 }
118 
119 }  // namespace internal
120 }  // namespace perfetto
121 
122 #endif  // INCLUDE_PERFETTO_TRACING_INTERNAL_WRITE_TRACK_EVENT_ARGS_H_
123