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_COMPONENT 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, 55 bool filter_debug_annotations = false) event_(event)56 : event_(event), 57 incremental_state_(incremental_state), 58 filter_debug_annotations_(filter_debug_annotations) {} 59 60 ~EventContext(); 61 GetIncrementalState()62 internal::TrackEventIncrementalState* GetIncrementalState() const { 63 return incremental_state_; 64 } 65 66 // Disclaimer: Experimental method, subject to change. 67 // Exposed publicly to emit some TrackEvent fields in Chromium only in local 68 // tracing. Long-term, we really shouldn't be (ab)using the 69 // filter_debug_annotation setting for this. 70 // 71 // TODO(kraskevich): Come up with a more precise name once we have more than 72 // one usecase. ShouldFilterDebugAnnotations()73 bool ShouldFilterDebugAnnotations() const { 74 if (tls_state_) { 75 return tls_state_->filter_debug_annotations; 76 } 77 // In Chromium tls_state_ is nullptr, so we need to get this information 78 // from a separate field. 79 return filter_debug_annotations_; 80 } 81 82 // Get a TrackEvent message to write typed arguments to. 83 // 84 // event() is a template method to allow callers to specify a subclass of 85 // TrackEvent instead. Those subclasses correspond to TrackEvent message with 86 // application-specific extensions. More information in 87 // design-docs/extensions.md. 88 template <typename EventType = protos::pbzero::TrackEvent> event()89 EventType* event() const { 90 // As the method does downcasting, we check that a target subclass does 91 // not add new fields. 92 static_assert( 93 sizeof(EventType) == sizeof(protos::pbzero::TrackEvent), 94 "Event type must be binary-compatible with protos::pbzero::TrackEvent"); 95 return static_cast<EventType*>(event_); 96 } 97 98 // Convert a raw pointer to protozero message to TracedProto which captures 99 // the reference to this EventContext. 100 template <typename MessageType> Wrap(MessageType * message)101 TracedProto<MessageType> Wrap(MessageType* message) { 102 static_assert(std::is_base_of<protozero::Message, MessageType>::value, 103 "TracedProto can be used only with protozero messages"); 104 105 return TracedProto<MessageType>(message, this); 106 } 107 108 // Add a new `debug_annotation` proto message and populate it from |value| 109 // using perfetto::TracedValue API. Users should generally prefer passing 110 // values directly to TRACE_EVENT (i.e. TRACE_EVENT(..., "arg", value, ...);) 111 // but in rare cases (e.g. when an argument should be written conditionally) 112 // EventContext::AddDebugAnnotation provides an explicit equivalent. 113 template <typename EventNameType, typename T> AddDebugAnnotation(EventNameType && name,T && value)114 void AddDebugAnnotation(EventNameType&& name, T&& value) { 115 if (tls_state_ && tls_state_->filter_debug_annotations) 116 return; 117 auto annotation = AddDebugAnnotation(std::forward<EventNameType>(name)); 118 WriteIntoTracedValue(internal::CreateTracedValueFromProto(annotation, this), 119 std::forward<T>(value)); 120 } 121 122 // Read arbitrary user data that is associated with the thread-local per 123 // instance state of the track event. `key` must be non-null and unique 124 // per TrackEventTlsStateUserData subclass. 125 TrackEventTlsStateUserData* GetTlsUserData(const void* key); 126 127 // Set arbitrary user data that is associated with the thread-local per 128 // instance state of the track event. `key` must be non-null and unique 129 // per TrackEventTlsStateUserData subclass. 130 void SetTlsUserData(const void* key, 131 std::unique_ptr<TrackEventTlsStateUserData> data); 132 133 private: 134 template <typename, size_t, typename, typename> 135 friend class TrackEventInternedDataIndex; 136 friend class internal::TrackEventInternal; 137 138 using TracePacketHandle = 139 ::protozero::MessageHandle<protos::pbzero::TracePacket>; 140 141 EventContext(TraceWriterBase* trace_writer, 142 TracePacketHandle, 143 internal::TrackEventIncrementalState*, 144 internal::TrackEventTlsState*); 145 EventContext(const EventContext&) = delete; 146 147 protos::pbzero::DebugAnnotation* AddDebugAnnotation(const char* name); 148 protos::pbzero::DebugAnnotation* AddDebugAnnotation( 149 ::perfetto::DynamicString name); 150 151 TraceWriterBase* trace_writer_ = nullptr; 152 TracePacketHandle trace_packet_; 153 protos::pbzero::TrackEvent* event_; 154 internal::TrackEventIncrementalState* incremental_state_; 155 // TODO(mohitms): Make it const-reference instead of pointer, once we 156 // are certain that it cannot be nullptr. Once we switch to client library in 157 // chrome, we can make that happen. 158 internal::TrackEventTlsState* tls_state_ = nullptr; 159 // TODO(kraskevich): Come up with a more precise name once we have more than 160 // one usecase. 161 // TODO(kraskevich): Remove once Chromium has fully switched to client lib. 162 const bool filter_debug_annotations_ = false; 163 }; 164 165 } // namespace perfetto 166 167 #endif // INCLUDE_PERFETTO_TRACING_EVENT_CONTEXT_H_ 168