1 /* 2 * Copyright (C) 2024 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 #pragma once 18 19 #include <android-base/logging.h> 20 #include <stdint.h> 21 22 #include <optional> 23 #include <vector> 24 25 #include "perfetto/public/producer.h" 26 #include "perfetto/public/te_category_macros.h" 27 #include "perfetto/public/te_macros.h" 28 #include "perfetto/public/track_event.h" 29 30 #include "perfetto/public/abi/pb_decoder_abi.h" 31 #include "perfetto/public/pb_utils.h" 32 #include "perfetto/public/tracing_session.h" 33 34 /** 35 * The objects declared here are intended to be managed by Java. 36 * This means the Java Garbage Collector is responsible for freeing the 37 * underlying native resources. 38 * 39 * The static methods prefixed with `delete_` are special. They are designed to be 40 * invoked by Java through the `NativeAllocationRegistry` when the 41 * corresponding Java object becomes unreachable. These methods act as 42 * callbacks to ensure proper deallocation of native resources. 43 */ 44 namespace tracing_perfetto { 45 /** 46 * @brief Represents extra data associated with a trace event. 47 * This class manages a collection of PerfettoTeHlExtra pointers. 48 */ 49 class Extra; 50 51 /** 52 * @brief Emits a trace event. 53 * @param type The type of the event. 54 * @param cat The category of the event. 55 * @param name The name of the event. 56 * @param arg_ptr Pointer to Extra data. 57 */ 58 void trace_event(int type, const PerfettoTeCategory* cat, const char* name, 59 Extra* extra); 60 61 /** 62 * @brief Gets the process track UUID. 63 */ 64 uint64_t get_process_track_uuid(); 65 66 /** 67 * @brief Gets the thread track UUID for a given PID. 68 */ 69 uint64_t get_thread_track_uuid(pid_t tid); 70 71 /** 72 * @brief Holder for all the other classes in the file. 73 */ 74 class Extra { 75 public: 76 Extra(); 77 void push_extra(PerfettoTeHlExtra* extra); 78 void pop_extra(); 79 void clear_extras(); 80 static void delete_extra(Extra* extra); 81 82 PerfettoTeHlExtra* const* get() const; 83 84 private: 85 DISALLOW_COPY_AND_ASSIGN(Extra); 86 87 // These PerfettoTeHlExtra pointers are really pointers to all the other 88 // types of extras: Category, DebugArg, Counter etc. Those objects are 89 // individually managed by Java. 90 std::vector<PerfettoTeHlExtra*> extras_; 91 }; 92 93 /** 94 * @brief Represents a trace event category. 95 */ 96 class Category { 97 public: 98 Category(const std::string& name, const std::string& tag, 99 const std::string& severity); 100 101 ~Category(); 102 103 void register_category(); 104 105 void unregister_category(); 106 107 bool is_category_enabled(); 108 109 static void delete_category(Category* category); 110 111 const PerfettoTeCategory* get() const; 112 113 private: 114 DISALLOW_COPY_AND_ASSIGN(Category); 115 PerfettoTeCategory category_; 116 const std::string name_; 117 const std::string tag_; 118 const std::string severity_; 119 }; 120 121 /** 122 * @brief Represents one end of a flow between two events. 123 */ 124 class Flow { 125 public: 126 Flow(); 127 128 void set_process_flow(uint64_t id); 129 void set_process_terminating_flow(uint64_t id); 130 static void delete_flow(Flow* flow); 131 132 const PerfettoTeHlExtraFlow* get() const; 133 134 private: 135 DISALLOW_COPY_AND_ASSIGN(Flow); 136 PerfettoTeHlExtraFlow flow_; 137 }; 138 139 /** 140 * @brief Represents a named track. 141 */ 142 class NamedTrack { 143 public: 144 NamedTrack(uint64_t id, uint64_t parent_uuid, const std::string& name); 145 146 static void delete_track(NamedTrack* track); 147 148 const PerfettoTeHlExtraNamedTrack* get() const; 149 150 private: 151 DISALLOW_COPY_AND_ASSIGN(NamedTrack); 152 const std::string name_; 153 PerfettoTeHlExtraNamedTrack track_; 154 }; 155 156 /** 157 * @brief Represents a registered track. 158 */ 159 class RegisteredTrack { 160 public: 161 RegisteredTrack(uint64_t id, uint64_t parent_uuid, const std::string& name, 162 bool is_counter); 163 ~RegisteredTrack(); 164 165 void register_track(); 166 void unregister_track(); 167 static void delete_track(RegisteredTrack* track); 168 169 const PerfettoTeHlExtraRegisteredTrack* get() const; 170 171 private: 172 DISALLOW_COPY_AND_ASSIGN(RegisteredTrack); 173 PerfettoTeRegisteredTrack registered_track_; 174 PerfettoTeHlExtraRegisteredTrack track_; 175 const std::string name_; 176 const uint64_t id_; 177 const uint64_t parent_uuid_; 178 const bool is_counter_; 179 }; 180 181 /** 182 * @brief Represents a counter track event. 183 * @tparam T The data type of the counter (int64_t or double). 184 */ 185 template <typename T> 186 class Counter { 187 public: 188 template <typename> 189 struct always_false : std::false_type {}; 190 191 struct TypeMap { 192 using type = std::invoke_result_t<decltype([]() { 193 if constexpr (std::is_same_v<T, int64_t>) { 194 return std::type_identity<PerfettoTeHlExtraCounterInt64>{}; 195 } else if constexpr (std::is_same_v<T, double>) { 196 return std::type_identity<PerfettoTeHlExtraCounterDouble>{}; 197 } else { 198 return std::type_identity<void>{}; 199 } 200 })>::type; 201 202 static constexpr int enum_value = []() { 203 if constexpr (std::is_same_v<T, int64_t>) { 204 return PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_INT64; 205 } else if constexpr (std::is_same_v<T, double>) { 206 return PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_DOUBLE; 207 } else { 208 static_assert(always_false<T>::value, "Unsupported type"); 209 return 0; // Never reached, just to satisfy return type 210 } 211 }(); 212 }; 213 Counter()214 Counter() { 215 static_assert(!std::is_same_v<typename TypeMap::type, void>, 216 "Unsupported type for Counter"); 217 218 typename TypeMap::type counter; 219 counter.header = {TypeMap::enum_value}; 220 counter_ = std::move(counter); 221 } 222 set_value(T value)223 void set_value(T value) { 224 if constexpr (std::is_same_v<T, int64_t>) { 225 counter_.value = value; 226 } else if constexpr (std::is_same_v<T, double>) { 227 counter_.value = value; 228 } 229 } 230 delete_counter(Counter * counter)231 static void delete_counter(Counter* counter) { 232 delete counter; 233 } 234 get()235 const TypeMap::type* get() const { 236 return &counter_; 237 } 238 239 private: 240 DISALLOW_COPY_AND_ASSIGN(Counter); 241 TypeMap::type counter_; 242 }; 243 244 /** 245 * @brief Represents a debug argument for a trace event. 246 * @tparam T The data type of the argument (bool, int64_t, double, const char*). 247 */ 248 template <typename T> 249 class DebugArg { 250 public: 251 template <typename> 252 struct always_false : std::false_type {}; 253 254 struct TypeMap { 255 using type = std::invoke_result_t<decltype([]() { 256 if constexpr (std::is_same_v<T, bool>) { 257 return std::type_identity<PerfettoTeHlExtraDebugArgBool>{}; 258 } else if constexpr (std::is_same_v<T, int64_t>) { 259 return std::type_identity<PerfettoTeHlExtraDebugArgInt64>{}; 260 } else if constexpr (std::is_same_v<T, double>) { 261 return std::type_identity<PerfettoTeHlExtraDebugArgDouble>{}; 262 } else if constexpr (std::is_same_v<T, const char*>) { 263 return std::type_identity<PerfettoTeHlExtraDebugArgString>{}; 264 } else { 265 return std::type_identity<void>{}; 266 } 267 })>::type; 268 269 static constexpr int enum_value = []() { 270 if constexpr (std::is_same_v<T, bool>) { 271 return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_BOOL; 272 } else if constexpr (std::is_same_v<T, int64_t>) { 273 return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_INT64; 274 } else if constexpr (std::is_same_v<T, double>) { 275 return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_DOUBLE; 276 } else if constexpr (std::is_same_v<T, const char*>) { 277 return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_STRING; 278 } else { 279 static_assert(always_false<T>::value, "Unsupported type"); 280 return 0; // Never reached, just to satisfy return type 281 } 282 }(); 283 }; 284 DebugArg(const std::string & name)285 DebugArg(const std::string& name) : name_(name) { 286 static_assert(!std::is_same_v<typename TypeMap::type, void>, 287 "Unsupported type for DebugArg"); 288 289 typename TypeMap::type arg; 290 arg.header = {TypeMap::enum_value}; 291 arg.name = name_.c_str(); 292 arg_ = std::move(arg); 293 } 294 set_value(T value)295 void set_value(T value) { 296 if constexpr (std::is_same_v<T, const char*>) { 297 arg_.value = value; 298 } else if constexpr (std::is_same_v<T, int64_t>) { 299 arg_.value = value; 300 } else if constexpr (std::is_same_v<T, bool>) { 301 arg_.value = value; 302 } else if constexpr (std::is_same_v<T, double>) { 303 arg_.value = value; 304 } 305 } 306 delete_arg(DebugArg * arg)307 static void delete_arg(DebugArg* arg) { 308 delete arg; 309 } 310 get()311 const TypeMap::type* get() const { 312 return &arg_; 313 } 314 315 private: 316 DISALLOW_COPY_AND_ASSIGN(DebugArg); 317 TypeMap::type arg_; 318 const std::string name_; 319 }; 320 321 template <typename T> 322 class ProtoField { 323 public: 324 template <typename> 325 struct always_false : std::false_type {}; 326 327 struct TypeMap { 328 using type = std::invoke_result_t<decltype([]() { 329 if constexpr (std::is_same_v<T, int64_t>) { 330 return std::type_identity<PerfettoTeHlProtoFieldVarInt>{}; 331 } else if constexpr (std::is_same_v<T, double>) { 332 return std::type_identity<PerfettoTeHlProtoFieldDouble>{}; 333 } else if constexpr (std::is_same_v<T, const char*>) { 334 return std::type_identity<PerfettoTeHlProtoFieldCstr>{}; 335 } else { 336 return std::type_identity<void>{}; 337 } 338 })>::type; 339 340 static constexpr PerfettoTeHlProtoFieldType enum_value = []() { 341 if constexpr (std::is_same_v<T, int64_t>) { 342 return PERFETTO_TE_HL_PROTO_TYPE_VARINT; 343 } else if constexpr (std::is_same_v<T, double>) { 344 return PERFETTO_TE_HL_PROTO_TYPE_DOUBLE; 345 } else if constexpr (std::is_same_v<T, const char*>) { 346 return PERFETTO_TE_HL_PROTO_TYPE_CSTR; 347 } else { 348 static_assert(always_false<T>::value, "Unsupported type"); 349 return 0; // Never reached, just to satisfy return type 350 } 351 }(); 352 }; 353 ProtoField()354 ProtoField() { 355 static_assert(!std::is_same_v<typename TypeMap::type, void>, 356 "Unsupported type for ProtoField"); 357 358 typename TypeMap::type arg; 359 arg.header.type = TypeMap::enum_value; 360 arg_ = std::move(arg); 361 } 362 set_value(uint32_t id,T value)363 void set_value(uint32_t id, T value) { 364 if constexpr (std::is_same_v<T, int64_t>) { 365 arg_.header.id = id; 366 arg_.value = value; 367 } else if constexpr (std::is_same_v<T, double>) { 368 arg_.header.id = id; 369 arg_.value = value; 370 } else if constexpr (std::is_same_v<T, const char*>) { 371 arg_.header.id = id; 372 arg_.str = value; 373 } 374 } 375 delete_field(ProtoField * field)376 static void delete_field(ProtoField* field) { 377 delete field; 378 } 379 get()380 const TypeMap::type* get() const { 381 return &arg_; 382 } 383 384 private: 385 DISALLOW_COPY_AND_ASSIGN(ProtoField); 386 TypeMap::type arg_; 387 }; 388 389 class ProtoFieldNested { 390 public: 391 ProtoFieldNested(); 392 393 void add_field(PerfettoTeHlProtoField* field); 394 void set_id(uint32_t id); 395 static void delete_field(ProtoFieldNested* field); 396 397 const PerfettoTeHlProtoFieldNested* get() const; 398 399 private: 400 DISALLOW_COPY_AND_ASSIGN(ProtoFieldNested); 401 PerfettoTeHlProtoFieldNested field_; 402 // These PerfettoTeHlProtoField pointers are really pointers to all the other 403 // types of protos: PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldVarInt, 404 // PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldNested. Those objects are 405 // individually managed by Java. 406 std::vector<PerfettoTeHlProtoField*> fields_; 407 }; 408 409 class Proto { 410 public: 411 Proto(); 412 413 void add_field(PerfettoTeHlProtoField* field); 414 void clear_fields(); 415 static void delete_proto(Proto* proto); 416 417 const PerfettoTeHlExtraProtoFields* get() const; 418 419 private: 420 DISALLOW_COPY_AND_ASSIGN(Proto); 421 PerfettoTeHlExtraProtoFields proto_; 422 // These PerfettoTeHlProtoField pointers are really pointers to all the other 423 // types of protos: PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldVarInt, 424 // PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldNested. Those objects are 425 // individually managed by Java. 426 std::vector<PerfettoTeHlProtoField*> fields_; 427 }; 428 429 class Session { 430 public: 431 Session(bool is_backend_in_process, void* buf, size_t len); 432 ~Session(); 433 Session(const Session&) = delete; 434 Session& operator=(const Session&) = delete; 435 436 bool FlushBlocking(uint32_t timeout_ms); 437 void StopBlocking(); 438 std::vector<uint8_t> ReadBlocking(); 439 440 static void delete_session(Session* session); 441 442 struct PerfettoTracingSessionImpl* session_ = nullptr; 443 }; 444 445 /** 446 * @brief Activates a trigger. 447 * @param name The name of the trigger. 448 * @param ttl_ms The time-to-live of the trigger in milliseconds. 449 */ 450 void activate_trigger(const char* name, uint32_t ttl_ms); 451 } // namespace tracing_perfetto 452