1 // Copyright 2018 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_ 6 #define BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_ 7 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include <algorithm> 12 #include <memory> 13 #include <string> 14 #include <utility> 15 16 #include "base/base_export.h" 17 #include "base/memory/raw_ptr_exclusion.h" 18 #include "base/trace_event/common/trace_event_common.h" 19 #include "base/tracing_buildflags.h" 20 #include "third_party/perfetto/include/perfetto/protozero/scattered_heap_buffer.h" 21 #include "third_party/perfetto/include/perfetto/tracing/traced_value.h" 22 #include "third_party/perfetto/protos/perfetto/trace/track_event/debug_annotation.pbzero.h" 23 24 // Trace macro can have one or two optional arguments, each one of them 25 // identified by a name (a C string literal) and a value, which can be an 26 // integer, enum, floating point, boolean, string pointer or reference, or 27 // std::unique_ptr<ConvertableToTraceFormat> compatible values. Additionally, 28 // custom data types need to be supported, like time values or WTF::CString. 29 // 30 // TraceArguments is a helper class used to store 0 to 2 named arguments 31 // corresponding to an individual trace macro call. As efficiently as possible, 32 // and with the minimal amount of generated machine code (since this affects 33 // any TRACE macro call). Each argument has: 34 // 35 // - A name (C string literal, e.g "dumps") 36 // - An 8-bit type value, corresponding to the TRACE_VALUE_TYPE_XXX macros. 37 // - A value, stored in a TraceValue union 38 // 39 // IMPORTANT: For a TRACE_VALUE_TYPE_CONVERTABLE types, the TraceArguments 40 // instance owns the pointed ConvertableToTraceFormat object, i.e. it will 41 // delete it automatically on destruction. 42 // 43 // TraceArguments instances should be built using one of specialized 44 // constructors declared below. One cannot modify an instance once it has 45 // been built, except for move operations, Reset() and destruction. Examples: 46 // 47 // TraceArguments args; // No arguments. 48 // // args.size() == 0 49 // 50 // TraceArguments("foo", 100); 51 // // args.size() == 1 52 // // args.types()[0] == TRACE_VALUE_TYPE_INT 53 // // args.names()[0] == "foo" 54 // // args.values()[0].as_int == 100 55 // 56 // TraceArguments("bar", 1ULL); 57 // // args.size() == 1 58 // // args.types()[0] == TRACE_VALUE_TYPE_UINT 59 // // args.names()[0] == "bar" 60 // // args.values()[0].as_uint == 100 61 // 62 // TraceArguments("foo", "Hello", "bar", "World"); 63 // // args.size() == 2 64 // // args.types()[0] == TRACE_VALUE_TYPE_STRING 65 // // args.types()[1] == TRACE_VALUE_TYPE_STRING 66 // // args.names()[0] == "foo" 67 // // args.names()[1] == "bar" 68 // // args.values()[0].as_string == "Hello" 69 // // args.values()[1].as_string == "World" 70 // 71 // std::string some_string = ...; 72 // TraceArguments("str1", some_string); 73 // // args.size() == 1 74 // // args.types()[0] == TRACE_VALUE_TYPE_COPY_STRING 75 // // args.names()[0] == "str1" 76 // // args.values()[0].as_string == some_string.c_str() 77 // 78 // Note that TRACE_VALUE_TYPE_COPY_STRING corresponds to string pointers 79 // that point to temporary values that may disappear soon. The 80 // TraceArguments::CopyStringTo() method can be used to copy their content 81 // into a StringStorage memory block, and update the |as_string| value pointers 82 // to it to avoid keeping any dangling pointers. This is used by TraceEvent 83 // to keep copies of such strings in the log after their initialization values 84 // have disappeared. 85 // 86 // The TraceStringWithCopy helper class can be used to initialize a value 87 // from a regular string pointer with TRACE_VALUE_TYPE_COPY_STRING too, as in: 88 // 89 // const char str[] = "...."; 90 // TraceArguments("foo", str, "bar", TraceStringWithCopy(str)); 91 // // args.size() == 2 92 // // args.types()[0] == TRACE_VALUE_TYPE_STRING 93 // // args.types()[1] == TRACE_VALUE_TYPE_COPY_STRING 94 // // args.names()[0] == "foo" 95 // // args.names()[1] == "bar" 96 // // args.values()[0].as_string == str 97 // // args.values()[1].as_string == str 98 // 99 // StringStorage storage; 100 // args.CopyStringTo(&storage, false, nullptr, nullptr); 101 // // args.size() == 2 102 // // args.types()[0] == TRACE_VALUE_TYPE_STRING 103 // // args.types()[1] == TRACE_VALUE_TYPE_COPY_STRING 104 // // args.names()[0] == "foo" 105 // // args.names()[1] == "bar" 106 // // args.values()[0].as_string == str 107 // // args.values()[1].as_string == Address inside |storage|. 108 // 109 // Initialization from a std::unique_ptr<ConvertableToTraceFormat> 110 // is supported but will move ownership of the pointer objects to the 111 // TraceArguments instance: 112 // 113 // class MyConvertableType : 114 // public base::trace_event::AsConvertableToTraceFormat { 115 // ... 116 // }; 117 // 118 // { 119 // TraceArguments args("foo" , std::make_unique<MyConvertableType>(...)); 120 // // args.size() == 1 121 // // args.values()[0].as_convertable == address of MyConvertable object. 122 // } // Calls |args| destructor, which will delete the object too. 123 // 124 // Finally, it is possible to support initialization from custom values by 125 // specializing the TraceValue::Helper<> template struct as described below. 126 // 127 // This is how values of custom types like WTF::CString can be passed directly 128 // to trace macros. 129 130 namespace base { 131 132 class Time; 133 class TimeTicks; 134 class ThreadTicks; 135 136 namespace trace_event { 137 138 class TraceEventMemoryOverhead; 139 140 // For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided 141 // class must implement this interface. Note that unlike other values, 142 // these objects will be owned by the TraceArguments instance that points 143 // to them. 144 class BASE_EXPORT ConvertableToTraceFormat 145 #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY) 146 : public perfetto::DebugAnnotation 147 #endif 148 { 149 public: 150 ConvertableToTraceFormat() = default; 151 ConvertableToTraceFormat(const ConvertableToTraceFormat&) = delete; 152 ConvertableToTraceFormat& operator=(const ConvertableToTraceFormat&) = delete; 153 #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY) 154 ~ConvertableToTraceFormat() override = default; 155 #else 156 virtual ~ConvertableToTraceFormat() = default; 157 #endif 158 159 // Append the class info to the provided |out| string. The appended 160 // data must be a valid JSON object. Strings must be properly quoted, and 161 // escaped. There is no processing applied to the content after it is 162 // appended. 163 virtual void AppendAsTraceFormat(std::string* out) const = 0; 164 165 // Append the class info directly into the Perfetto-defined proto 166 // format; this is attempted first and if this returns true, 167 // AppendAsTraceFormat is not called. The ProtoAppender interface 168 // acts as a bridge to avoid proto/Perfetto dependencies in base. 169 class BASE_EXPORT ProtoAppender { 170 public: 171 virtual ~ProtoAppender() = default; 172 173 virtual void AddBuffer(uint8_t* begin, uint8_t* end) = 0; 174 // Copy all of the previous buffers registered with AddBuffer 175 // into the proto, with the given |field_id|. 176 virtual size_t Finalize(uint32_t field_id) = 0; 177 }; 178 virtual bool AppendToProto(ProtoAppender* appender) const; 179 180 virtual void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead); 181 182 #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY) 183 // DebugAnnotation implementation. 184 void Add(perfetto::protos::pbzero::DebugAnnotation*) const override; 185 #endif 186 }; 187 188 const int kTraceMaxNumArgs = 2; 189 190 // A union used to hold the values of individual trace arguments. 191 // 192 // This is a POD union for performance reason. Initialization from an 193 // explicit C++ trace argument should be performed with the Init() 194 // templated method described below. 195 // 196 // Initialization from custom types is possible by implementing a custom 197 // TraceValue::Helper<> instantiation as described below. 198 // 199 // IMPORTANT: Pointer storage inside a TraceUnion follows specific rules: 200 // 201 // - |as_pointer| is for raw pointers that should be treated as a simple 202 // address and will never be dereferenced. Associated with the 203 // TRACE_VALUE_TYPE_POINTER type. 204 // 205 // - |as_string| is for C-string pointers, associated with both 206 // TRACE_VALUE_TYPE_STRING and TRACE_VALUE_TYPE_COPY_STRING. The former 207 // indicates that the string pointer is persistent (e.g. a C string 208 // literal), while the second indicates that the pointer belongs to a 209 // temporary variable that may disappear soon. The TraceArguments class 210 // provides a CopyStringTo() method to copy these strings into a 211 // StringStorage instance, which is useful if the instance needs to 212 // survive longer than the temporaries. 213 // 214 // - |as_convertable| is equivalent to 215 // std::unique_ptr<ConvertableToTraceFormat>, except that it is a pointer 216 // to keep this union POD and avoid un-necessary declarations and potential 217 // code generation. This means that its ownership is passed to the 218 // TraceValue instance when Init(std::unique_ptr<ConvertableToTraceFormat>) 219 // is called, and that it will be deleted by the containing TraceArguments 220 // destructor, or Reset() method. 221 // 222 union BASE_EXPORT TraceValue { 223 bool as_bool; 224 unsigned long long as_uint; 225 long long as_int; 226 double as_double; 227 // This field is not a raw_ptr<> because it was filtered by the rewriter for: 228 // #union 229 RAW_PTR_EXCLUSION const void* as_pointer; 230 const char* as_string; 231 // This field is not a raw_ptr<> because it was filtered by the rewriter for: 232 // #union 233 RAW_PTR_EXCLUSION ConvertableToTraceFormat* as_convertable; 234 // This field is not a raw_ptr<> because it was filtered by the rewriter for: 235 // #union 236 RAW_PTR_EXCLUSION protozero::HeapBuffered< 237 perfetto::protos::pbzero::DebugAnnotation>* as_proto; 238 239 // Static method to create a new TraceValue instance from a given 240 // initialization value. Note that this deduces the TRACE_VALUE_TYPE_XXX 241 // type but doesn't return it, use ForType<T>::value for this. 242 // 243 // Usage example: 244 // auto v = TraceValue::Make(100); 245 // auto v2 = TraceValue::Make("Some text string"); 246 // 247 // IMPORTANT: Experience shows that the compiler generates worse code when 248 // using this method rather than calling Init() directly on an existing 249 // TraceValue union :-( 250 // 251 template <typename T> Make(T && value)252 static TraceValue Make(T&& value) { 253 TraceValue ret; 254 ret.Init(std::forward<T>(value)); 255 return ret; 256 } 257 258 // Output current value as a JSON string. |type| must be a valid 259 // TRACE_VALUE_TYPE_XXX value. 260 void AppendAsJSON(unsigned char type, std::string* out) const; 261 262 // Output current value as a string. If the output string is to be used 263 // in a JSON format use AppendAsJSON instead. |type| must be valid 264 // TRACE_VALUE_TYPE_XXX value. 265 void AppendAsString(unsigned char type, std::string* out) const; 266 267 private: 268 void Append(unsigned char type, bool as_json, std::string* out) const; 269 270 // InnerType<T>::type removes reference, cv-qualifications and decays 271 // function and arrays into pointers. Only used internally. 272 template <typename T> 273 struct InnerType { 274 using type = std::decay_t<T>; 275 }; 276 277 public: 278 // TraceValue::Helper is used to provide information about initialization 279 // value types and an initialization function. It is a struct that should 280 // provide the following for supported initialization value types: 281 // 282 // - kType: is a static TRACE_VALUE_TYPE_XXX constant. 283 // 284 // - SetValue(TraceValue*, T): is a static inline method that sets 285 // TraceValue value from a given T value. Second parameter type 286 // can also be const T& or T&& to restrict uses. 287 // 288 // IMPORTANT: The type T must be InnerType<Q>, where Q is the real C++ 289 // argument type. I.e. you should not have to deal with reference types 290 // in your specialization. 291 // 292 // Specializations are defined for integers, enums, floating point, pointers, 293 // constant C string literals and pointers, std::string, time values below. 294 // 295 // Specializations for custom types are possible provided that there exists 296 // a corresponding Helper specialization, for example: 297 // 298 // template <> 299 // struct base::trace_event::TraceValue::Helper<Foo> { 300 // static constexpr unsigned char kTypes = TRACE_VALUE_TYPE_COPY_STRING; 301 // static inline void SetValue(TraceValue* v, const Foo& value) { 302 // v->as_string = value.c_str(); 303 // } 304 // }; 305 // 306 // Will allow code like: 307 // 308 // Foo foo = ...; 309 // auto v = TraceValue::Make(foo); 310 // 311 // Or even: 312 // Foo foo = ...; 313 // TraceArguments args("foo_arg1", foo); 314 // 315 template <typename T, class = void> 316 struct Helper {}; 317 318 template <typename T> 319 struct HasHelperSupport { 320 private: 321 using Yes = char[1]; 322 using No = char[2]; 323 324 template <typename V> 325 static Yes& check_support( 326 decltype(TraceValue::Helper<typename InnerType<V>::type>::kType, 327 int())); 328 template <typename V> 329 static No& check_support(...); 330 331 public: 332 static constexpr bool value = sizeof(Yes) == sizeof(check_support<T>(0)); 333 }; 334 335 // TraceValue::TypeFor<T>::value returns the TRACE_VALUE_TYPE_XXX 336 // corresponding to initialization values of type T. 337 template <typename T, class = void> 338 struct TypeFor; 339 340 template <typename T> 341 struct TypeFor<T, 342 typename std::enable_if<HasHelperSupport< 343 typename InnerType<T>::type>::value>::type> { 344 using ValueType = typename InnerType<T>::type; 345 static const unsigned char value = Helper<ValueType>::kType; 346 }; 347 template <typename T> 348 struct TypeFor<T, 349 typename std::enable_if< 350 !HasHelperSupport<typename InnerType<T>::type>::value && 351 perfetto::internal::has_traced_value_support< 352 typename InnerType<T>::type>::value>::type> { 353 static const unsigned char value = TRACE_VALUE_TYPE_PROTO; 354 }; 355 356 // TraceValue::TypeCheck<T>::value is only defined iff T can be used to 357 // initialize a TraceValue instance. This is useful to restrict template 358 // instantiation to only the appropriate type (see TraceArguments 359 // constructors below). 360 template <typename T, 361 class = std::enable_if_t< 362 HasHelperSupport<typename InnerType<T>::type>::value || 363 perfetto::internal::has_traced_value_support< 364 typename InnerType<T>::type>::value>> 365 struct TypeCheck { 366 static const bool value = true; 367 }; 368 369 // There is no constructor to keep this structure POD intentionally. 370 // This avoids un-needed initialization when only 0 or 1 arguments are 371 // used to construct a TraceArguments instance. Use Init() instead to 372 // perform explicit initialization from a given C++ value. 373 374 // Initialize TraceValue instance from a C++ trace value. 375 // This relies on the proper specialization of TraceValue::Helper<> 376 // described below. Usage is simply: 377 // 378 // TraceValue v; 379 // v.Init(<value>); 380 // 381 // NOTE: For ConvertableToTraceFormat values, see the notes above. 382 template <class T> 383 typename std::enable_if< 384 HasHelperSupport<typename InnerType<T>::type>::value>::type 385 Init(T&& value) { 386 using ValueType = typename InnerType<T>::type; 387 Helper<ValueType>::SetValue(this, std::forward<T>(value)); 388 } 389 390 template <class T> 391 typename std::enable_if< 392 !HasHelperSupport<typename InnerType<T>::type>::value && 393 perfetto::internal::has_traced_value_support< 394 typename InnerType<T>::type>::value>::type 395 Init(T&& value) { 396 as_proto = new protozero::HeapBuffered< 397 perfetto::protos::pbzero::DebugAnnotation>(); 398 perfetto::WriteIntoTracedValue( 399 perfetto::internal::CreateTracedValueFromProto(as_proto->get()), 400 std::forward<T>(value)); 401 } 402 }; 403 404 // TraceValue::Helper for integers and enums. 405 template <typename T> 406 struct TraceValue::Helper< 407 T, 408 typename std::enable_if<std::is_integral<T>::value || 409 std::is_enum<T>::value>::type> { 410 static constexpr unsigned char kType = 411 std::is_signed<T>::value ? TRACE_VALUE_TYPE_INT : TRACE_VALUE_TYPE_UINT; 412 static inline void SetValue(TraceValue* v, T value) { 413 v->as_uint = static_cast<unsigned long long>(value); 414 } 415 }; 416 417 // TraceValue::Helper for floating-point types 418 template <typename T> 419 struct TraceValue:: 420 Helper<T, typename std::enable_if<std::is_floating_point<T>::value>::type> { 421 static constexpr unsigned char kType = TRACE_VALUE_TYPE_DOUBLE; 422 static inline void SetValue(TraceValue* v, T value) { v->as_double = value; } 423 }; 424 425 // TraceValue::Helper for bool. 426 template <> 427 struct TraceValue::Helper<bool> { 428 static constexpr unsigned char kType = TRACE_VALUE_TYPE_BOOL; 429 static inline void SetValue(TraceValue* v, bool value) { v->as_bool = value; } 430 }; 431 432 // TraceValue::Helper for generic pointer types. 433 template <> 434 struct TraceValue::Helper<const void*> { 435 static constexpr unsigned char kType = TRACE_VALUE_TYPE_POINTER; 436 static inline void SetValue(TraceValue* v, const void* value) { 437 v->as_pointer = value; 438 } 439 }; 440 441 template <> 442 struct TraceValue::Helper<void*> { 443 static constexpr unsigned char kType = TRACE_VALUE_TYPE_POINTER; 444 static inline void SetValue(TraceValue* v, void* value) { 445 v->as_pointer = value; 446 } 447 }; 448 449 // TraceValue::Helper for raw persistent C strings. 450 template <> 451 struct TraceValue::Helper<const char*> { 452 static constexpr unsigned char kType = TRACE_VALUE_TYPE_STRING; 453 static inline void SetValue(TraceValue* v, const char* value) { 454 v->as_string = value; 455 } 456 }; 457 458 // TraceValue::Helper for std::string values. 459 template <> 460 struct TraceValue::Helper<std::string> { 461 static constexpr unsigned char kType = TRACE_VALUE_TYPE_COPY_STRING; 462 static inline void SetValue(TraceValue* v, const std::string& value) { 463 v->as_string = value.c_str(); 464 } 465 }; 466 467 // Special case for scoped pointers to convertables to trace format. 468 // |CONVERTABLE_TYPE| must be a type whose pointers can be converted to a 469 // ConvertableToTraceFormat* pointer as well (e.g. a derived class). 470 // IMPORTANT: This takes an std::unique_ptr<CONVERTABLE_TYPE> value, and takes 471 // ownership of the pointed object! 472 template <typename CONVERTABLE_TYPE> 473 struct TraceValue::Helper<std::unique_ptr<CONVERTABLE_TYPE>, 474 typename std::enable_if<std::is_convertible< 475 CONVERTABLE_TYPE*, 476 ConvertableToTraceFormat*>::value>::type> { 477 static constexpr unsigned char kType = TRACE_VALUE_TYPE_CONVERTABLE; 478 static inline void SetValue(TraceValue* v, 479 std::unique_ptr<CONVERTABLE_TYPE> value) { 480 v->as_convertable = value.release(); 481 } 482 }; 483 484 // Specialization for time-based values like base::Time, which provide a 485 // a ToInternalValue() method. 486 template <typename T> 487 struct TraceValue::Helper< 488 T, 489 typename std::enable_if<std::is_same<T, base::Time>::value || 490 std::is_same<T, base::TimeTicks>::value || 491 std::is_same<T, base::ThreadTicks>::value>::type> { 492 static constexpr unsigned char kType = TRACE_VALUE_TYPE_INT; 493 static inline void SetValue(TraceValue* v, const T& value) { 494 v->as_int = value.ToInternalValue(); 495 } 496 }; 497 498 // Simple container for const char* that should be copied instead of retained. 499 // The goal is to indicate that the C string is copyable, unlike the default 500 // Init(const char*) implementation. Usage is: 501 // 502 // const char* str = ...; 503 // v.Init(TraceStringWithCopy(str)); 504 // 505 // Which will mark the string as TRACE_VALUE_TYPE_COPY_STRING, instead of 506 // TRACE_VALUE_TYPE_STRING. 507 // 508 class TraceStringWithCopy { 509 public: 510 explicit TraceStringWithCopy(const char* str) : str_(str) {} 511 const char* str() const { return str_; } 512 513 private: 514 const char* str_; 515 }; 516 517 template <> 518 struct TraceValue::Helper<TraceStringWithCopy> { 519 static constexpr unsigned char kType = TRACE_VALUE_TYPE_COPY_STRING; 520 static inline void SetValue(TraceValue* v, const TraceStringWithCopy& value) { 521 v->as_string = value.str(); 522 } 523 }; 524 525 class TraceArguments; 526 527 // A small class used to store a copy of all strings from a given 528 // TraceArguments instance (see below). When empty, this should only 529 // take the size of a pointer. Otherwise, this will point to a heap 530 // allocated block containing a size_t value followed by all characters 531 // in the storage area. For most cases, this is more efficient 532 // than using a std::unique_ptr<std::string> or an std::vector<char>. 533 class BASE_EXPORT StringStorage { 534 public: 535 constexpr StringStorage() = default; 536 537 explicit StringStorage(size_t alloc_size) { Reset(alloc_size); } 538 539 ~StringStorage() { 540 if (data_) 541 ::free(data_); 542 } 543 544 StringStorage(StringStorage&& other) noexcept : data_(other.data_) { 545 other.data_ = nullptr; 546 } 547 548 StringStorage& operator=(StringStorage&& other) noexcept { 549 if (this != &other) { 550 if (data_) 551 ::free(data_); 552 data_ = other.data_; 553 other.data_ = nullptr; 554 } 555 return *this; 556 } 557 558 // Reset storage area to new allocation size. Existing content might not 559 // be preserved. If |alloc_size| is 0, this will free the storage area 560 // as well. 561 void Reset(size_t alloc_size = 0); 562 563 // Accessors. 564 constexpr size_t size() const { return data_ ? data_->size : 0u; } 565 constexpr const char* data() const { return data_ ? data_->chars : nullptr; } 566 constexpr char* data() { return data_ ? data_->chars : nullptr; } 567 568 constexpr const char* begin() const { return data(); } 569 constexpr const char* end() const { return data() + size(); } 570 inline char* begin() { return data(); } 571 inline char* end() { return data() + size(); } 572 573 // True iff storage is empty. 574 constexpr bool empty() const { return size() == 0; } 575 576 // Returns true if |ptr| is inside the storage area, false otherwise. 577 // Used during unit-testing. 578 constexpr bool Contains(const void* ptr) const { 579 const char* char_ptr = static_cast<const char*>(ptr); 580 return (char_ptr >= begin() && char_ptr < end()); 581 } 582 583 // Returns true if all string pointers in |args| are contained in this 584 // storage area. 585 bool Contains(const TraceArguments& args) const; 586 587 // Return an estimate of the memory overhead of this instance. This doesn't 588 // count the size of |data_| itself. 589 constexpr size_t EstimateTraceMemoryOverhead() const { 590 return data_ ? sizeof(size_t) + data_->size : 0u; 591 } 592 593 private: 594 // Heap allocated data block (variable size), made of: 595 // 596 // - size: a size_t field, giving the size of the following |chars| array. 597 // - chars: an array of |size| characters, holding all zero-terminated 598 // strings referenced from a TraceArguments instance. 599 struct Data { 600 size_t size = 0; 601 char chars[1]; // really |size| character items in storage. 602 }; 603 604 // This is an owning pointer. Normally, using a std::unique_ptr<> would be 605 // enough, but the compiler will then complaing about inlined constructors 606 // and destructors being too complex (!), resulting in larger code for no 607 // good reason. 608 // This field is not a raw_ptr<> because it was filtered by the rewriter for: 609 // #constexpr-ctor-field-initializer 610 RAW_PTR_EXCLUSION Data* data_ = nullptr; 611 }; 612 613 // TraceArguments models an array of kMaxSize trace-related items, 614 // each one of them having: 615 // - a name, which is a constant char array literal. 616 // - a type, as described by TRACE_VALUE_TYPE_XXX macros. 617 // - a value, stored in a TraceValue union. 618 // 619 // IMPORTANT: For TRACE_VALUE_TYPE_CONVERTABLE, the value holds an owning 620 // pointer to an AsConvertableToTraceFormat instance, which will 621 // be destroyed with the array (or moved out of it when passed 622 // to a TraceEvent instance). 623 // 624 // For TRACE_VALUE_TYPE_COPY_STRING, the value holds a const char* pointer 625 // whose content will be copied when creating a TraceEvent instance. 626 // 627 // IMPORTANT: Most constructors and the destructor are all inlined 628 // intentionally, in order to let the compiler remove un-necessary operations 629 // and reduce machine code. 630 // 631 class BASE_EXPORT TraceArguments { 632 public: 633 // Maximum number of arguments held by this structure. 634 static constexpr size_t kMaxSize = 2; 635 636 // Default constructor, no arguments. 637 TraceArguments() : size_(0) {} 638 639 // Constructor for a single argument. 640 template <typename T, class = decltype(TraceValue::TypeCheck<T>::value)> 641 TraceArguments(const char* arg1_name, T&& arg1_value) : size_(1) { 642 types_[0] = TraceValue::TypeFor<T>::value; 643 names_[0] = arg1_name; 644 values_[0].Init(std::forward<T>(arg1_value)); 645 } 646 647 // Constructor for two arguments. 648 template <typename T1, 649 typename T2, 650 class = decltype(TraceValue::TypeCheck<T1>::value && 651 TraceValue::TypeCheck<T2>::value)> 652 TraceArguments(const char* arg1_name, 653 T1&& arg1_value, 654 const char* arg2_name, 655 T2&& arg2_value) 656 : size_(2) { 657 types_[0] = TraceValue::TypeFor<T1>::value; 658 types_[1] = TraceValue::TypeFor<T2>::value; 659 names_[0] = arg1_name; 660 names_[1] = arg2_name; 661 values_[0].Init(std::forward<T1>(arg1_value)); 662 values_[1].Init(std::forward<T2>(arg2_value)); 663 } 664 665 // Constructor used to convert a legacy set of arguments when there 666 // are no convertable values at all. 667 TraceArguments(int num_args, 668 const char* const* arg_names, 669 const unsigned char* arg_types, 670 const unsigned long long* arg_values); 671 672 // Constructor used to convert legacy set of arguments, where the 673 // convertable values are also provided by an array of CONVERTABLE_TYPE. 674 template <typename CONVERTABLE_TYPE> 675 TraceArguments(int num_args, 676 const char* const* arg_names, 677 const unsigned char* arg_types, 678 const unsigned long long* arg_values, 679 CONVERTABLE_TYPE* arg_convertables) { 680 static int max_args = static_cast<int>(kMaxSize); 681 if (num_args > max_args) 682 num_args = max_args; 683 size_ = static_cast<unsigned char>(num_args); 684 for (size_t n = 0; n < size_; ++n) { 685 types_[n] = arg_types[n]; 686 names_[n] = arg_names[n]; 687 if (arg_types[n] == TRACE_VALUE_TYPE_CONVERTABLE) { 688 values_[n].Init( 689 std::forward<CONVERTABLE_TYPE>(std::move(arg_convertables[n]))); 690 } else { 691 values_[n].as_uint = arg_values[n]; 692 } 693 } 694 } 695 696 // Destructor. NOTE: Intentionally inlined (see note above). 697 ~TraceArguments() { 698 for (size_t n = 0; n < size_; ++n) { 699 if (types_[n] == TRACE_VALUE_TYPE_CONVERTABLE) 700 delete values_[n].as_convertable; 701 if (types_[n] == TRACE_VALUE_TYPE_PROTO) 702 delete values_[n].as_proto; 703 } 704 } 705 706 // Disallow copy operations. 707 TraceArguments(const TraceArguments&) = delete; 708 TraceArguments& operator=(const TraceArguments&) = delete; 709 710 // Allow move operations. 711 TraceArguments(TraceArguments&& other) noexcept { 712 ::memcpy(this, &other, sizeof(*this)); 713 // All owning pointers were copied to |this|. Setting |other.size_| will 714 // mask the pointer values still in |other|. 715 other.size_ = 0; 716 } 717 718 TraceArguments& operator=(TraceArguments&&) noexcept; 719 720 // Accessors 721 size_t size() const { return size_; } 722 const unsigned char* types() const { return types_; } 723 const char* const* names() const { return names_; } 724 const TraceValue* values() const { return values_; } 725 726 // Reset to empty arguments list. 727 void Reset(); 728 729 // Use |storage| to copy all copyable strings. 730 // If |copy_all_strings| is false, then only the TRACE_VALUE_TYPE_COPY_STRING 731 // values will be copied into storage. If it is true, then argument names are 732 // also copied to storage, as well as the strings pointed to by 733 // |*extra_string1| and |*extra_string2|. 734 // NOTE: If there are no strings to copy, |*storage| is left untouched. 735 void CopyStringsTo(StringStorage* storage, 736 bool copy_all_strings, 737 const char** extra_string1, 738 const char** extra_string2); 739 740 // Append debug string representation to |*out|. 741 void AppendDebugString(std::string* out); 742 743 private: 744 unsigned char size_; 745 unsigned char types_[kMaxSize]; 746 const char* names_[kMaxSize]; 747 TraceValue values_[kMaxSize]; 748 }; 749 750 } // namespace trace_event 751 } // namespace base 752 753 #endif // BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_ 754