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