1 /* 2 * Copyright (C) 2019 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_EVENT_CONTEXT_H_ 18 #define INCLUDE_PERFETTO_TRACING_EVENT_CONTEXT_H_ 19 20 #include "perfetto/protozero/message_handle.h" 21 #include "perfetto/tracing/internal/track_event_internal.h" 22 #include "perfetto/tracing/traced_proto.h" 23 #include "protos/perfetto/trace/trace_packet.pbzero.h" 24 25 namespace perfetto { 26 namespace protos { 27 namespace pbzero { 28 class DebugAnnotation; 29 } // namespace pbzero 30 } // namespace protos 31 32 namespace internal { 33 class TrackEventInternal; 34 } 35 36 // Allows adding custom arguments into track events. Example: 37 // 38 // TRACE_EVENT_BEGIN("category", "Title", 39 // [](perfetto::EventContext ctx) { 40 // auto* log = ctx.event()->set_log_message(); 41 // log->set_body_iid(1234); 42 // 43 // ctx.AddDebugAnnotation("name", 1234); 44 // }); 45 // 46 class PERFETTO_EXPORT EventContext { 47 public: 48 EventContext(EventContext&&) = default; 49 50 // For Chromium during the transition phase to the client library. 51 // TODO(eseckler): Remove once Chromium has switched to client lib entirely. 52 explicit EventContext( 53 protos::pbzero::TrackEvent* event, 54 internal::TrackEventIncrementalState* incremental_state = nullptr) event_(event)55 : event_(event), incremental_state_(incremental_state) {} 56 57 ~EventContext(); 58 GetIncrementalState()59 internal::TrackEventIncrementalState* GetIncrementalState() const { 60 return incremental_state_; 61 } 62 63 // Get a TrackEvent message to write typed arguments to. 64 // 65 // event() is a template method to allow callers to specify a subclass of 66 // TrackEvent instead. Those subclasses correspond to TrackEvent message with 67 // application-specific extensions. More information in 68 // design-docs/extensions.md. 69 template <typename EventType = protos::pbzero::TrackEvent> event()70 EventType* event() const { 71 // As the method does downcasting, we check that a target subclass does 72 // not add new fields. 73 static_assert( 74 sizeof(EventType) == sizeof(protos::pbzero::TrackEvent), 75 "Event type must be binary-compatible with protos::pbzero::TrackEvent"); 76 return static_cast<EventType*>(event_); 77 } 78 79 // Convert a raw pointer to protozero message to TracedProto which captures 80 // the reference to this EventContext. 81 template <typename MessageType> Wrap(MessageType * message)82 TracedProto<MessageType> Wrap(MessageType* message) { 83 static_assert(std::is_base_of<protozero::Message, MessageType>::value, 84 "TracedProto can be used only with protozero messages"); 85 86 return TracedProto<MessageType>(message, this); 87 } 88 89 // Add a new `debug_annotation` proto message and populate it from |value| 90 // using perfetto::TracedValue API. Users should generally prefer passing 91 // values directly to TRACE_EVENT (i.e. TRACE_EVENT(..., "arg", value, ...);) 92 // but in rare cases (e.g. when an argument should be written conditionally) 93 // EventContext::AddDebugAnnotation provides an explicit equivalent. 94 template <typename T> AddDebugAnnotation(const char * name,T && value)95 void AddDebugAnnotation(const char* name, T&& value) { 96 if (tls_state_ && tls_state_->filter_debug_annotations) 97 return; 98 auto annotation = AddDebugAnnotation(name); 99 WriteIntoTracedValue(internal::CreateTracedValueFromProto(annotation, this), 100 std::forward<T>(value)); 101 } 102 103 private: 104 template <typename, size_t, typename, typename> 105 friend class TrackEventInternedDataIndex; 106 friend class internal::TrackEventInternal; 107 108 using TracePacketHandle = 109 ::protozero::MessageHandle<protos::pbzero::TracePacket>; 110 111 EventContext(TracePacketHandle, 112 internal::TrackEventIncrementalState*, 113 const internal::TrackEventTlsState*); 114 EventContext(const EventContext&) = delete; 115 116 protos::pbzero::DebugAnnotation* AddDebugAnnotation(const char* name); 117 118 TracePacketHandle trace_packet_; 119 protos::pbzero::TrackEvent* event_; 120 internal::TrackEventIncrementalState* incremental_state_; 121 // TODO(mohitms): Make it const-reference instead of pointer, once we 122 // are certain that it cannot be nullptr. Once we switch to client library in 123 // chrome, we can make that happen. 124 const internal::TrackEventTlsState* tls_state_ = nullptr; 125 }; 126 127 } // namespace perfetto 128 129 #endif // INCLUDE_PERFETTO_TRACING_EVENT_CONTEXT_H_ 130