chromium/base/trace_event/trace_arguments.h

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif

#ifndef BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_
#define BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_

#include <stdlib.h>
#include <string.h>

#include <algorithm>
#include <memory>
#include <string>
#include <utility>

#include "base/base_export.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/tracing_buildflags.h"
#include "third_party/perfetto/include/perfetto/protozero/scattered_heap_buffer.h"
#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
#include "third_party/perfetto/protos/perfetto/trace/track_event/debug_annotation.pbzero.h"

// Trace macro can have one or two optional arguments, each one of them
// identified by a name (a C string literal) and a value, which can be an
// integer, enum, floating point, boolean, string pointer or reference, or
// std::unique_ptr<ConvertableToTraceFormat> compatible values. Additionally,
// custom data types need to be supported, like time values or WTF::CString.
//
// TraceArguments is a helper class used to store 0 to 2 named arguments
// corresponding to an individual trace macro call. As efficiently as possible,
// and with the minimal amount of generated machine code (since this affects
// any TRACE macro call). Each argument has:
//
//  - A name (C string literal, e.g "dumps")
//  - An 8-bit type value, corresponding to the TRACE_VALUE_TYPE_XXX macros.
//  - A value, stored in a TraceValue union
//
// IMPORTANT: For a TRACE_VALUE_TYPE_CONVERTABLE types, the TraceArguments
// instance owns the pointed ConvertableToTraceFormat object, i.e. it will
// delete it automatically on destruction.
//
// TraceArguments instances should be built using one of specialized
// constructors declared below. One cannot modify an instance once it has
// been built, except for move operations, Reset() and destruction. Examples:
//
//    TraceArguments args;    // No arguments.
//    // args.size() == 0
//
//    TraceArguments("foo", 100);
//    // args.size() == 1
//    // args.types()[0] == TRACE_VALUE_TYPE_INT
//    // args.names()[0] == "foo"
//    // args.values()[0].as_int == 100
//
//    TraceArguments("bar", 1ULL);
//    // args.size() == 1
//    // args.types()[0] == TRACE_VALUE_TYPE_UINT
//    // args.names()[0] == "bar"
//    // args.values()[0].as_uint == 100
//
//    TraceArguments("foo", "Hello", "bar", "World");
//    // args.size() == 2
//    // args.types()[0] == TRACE_VALUE_TYPE_STRING
//    // args.types()[1] == TRACE_VALUE_TYPE_STRING
//    // args.names()[0] == "foo"
//    // args.names()[1] == "bar"
//    // args.values()[0].as_string == "Hello"
//    // args.values()[1].as_string == "World"
//
//    std::string some_string = ...;
//    TraceArguments("str1", some_string);
//    // args.size() == 1
//    // args.types()[0] == TRACE_VALUE_TYPE_COPY_STRING
//    // args.names()[0] == "str1"
//    // args.values()[0].as_string == some_string.c_str()
//
// Note that TRACE_VALUE_TYPE_COPY_STRING corresponds to string pointers
// that point to temporary values that may disappear soon. The
// TraceArguments::CopyStringTo() method can be used to copy their content
// into a StringStorage memory block, and update the |as_string| value pointers
// to it to avoid keeping any dangling pointers. This is used by TraceEvent
// to keep copies of such strings in the log after their initialization values
// have disappeared.
//
// The TraceStringWithCopy helper class can be used to initialize a value
// from a regular string pointer with TRACE_VALUE_TYPE_COPY_STRING too, as in:
//
//     const char str[] = "....";
//     TraceArguments("foo", str, "bar", TraceStringWithCopy(str));
//     // args.size() == 2
//     // args.types()[0] == TRACE_VALUE_TYPE_STRING
//     // args.types()[1] == TRACE_VALUE_TYPE_COPY_STRING
//     // args.names()[0] == "foo"
//     // args.names()[1] == "bar"
//     // args.values()[0].as_string == str
//     // args.values()[1].as_string == str
//
//     StringStorage storage;
//     args.CopyStringTo(&storage, false, nullptr, nullptr);
//     // args.size() == 2
//     // args.types()[0] == TRACE_VALUE_TYPE_STRING
//     // args.types()[1] == TRACE_VALUE_TYPE_COPY_STRING
//     // args.names()[0] == "foo"
//     // args.names()[1] == "bar"
//     // args.values()[0].as_string == str
//     // args.values()[1].as_string == Address inside |storage|.
//
// Initialization from a std::unique_ptr<ConvertableToTraceFormat>
// is supported but will move ownership of the pointer objects to the
// TraceArguments instance:
//
//     class MyConvertableType :
//         public base::trace_event::AsConvertableToTraceFormat {
//        ...
//     };
//
//     {
//       TraceArguments args("foo" , std::make_unique<MyConvertableType>(...));
//       // args.size() == 1
//       // args.values()[0].as_convertable == address of MyConvertable object.
//     } // Calls |args| destructor, which will delete the object too.
//
// Finally, it is possible to support initialization from custom values by
// specializing the TraceValue::Helper<> template struct as described below.
//
// This is how values of custom types like WTF::CString can be passed directly
// to trace macros.

namespace base {

class Time;
class TimeTicks;
class ThreadTicks;

namespace trace_event {

class TraceEventMemoryOverhead;

// For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
// class must implement this interface. Note that unlike other values,
// these objects will be owned by the TraceArguments instance that points
// to them.
class BASE_EXPORT ConvertableToTraceFormat
    : public perfetto::DebugAnnotation
{};

const int kTraceMaxNumArgs =;

// A union used to hold the values of individual trace arguments.
//
// This is a POD union for performance reason. Initialization from an
// explicit C++ trace argument should be performed with the Init()
// templated method described below.
//
// Initialization from custom types is possible by implementing a custom
// TraceValue::Helper<> instantiation as described below.
//
// IMPORTANT: Pointer storage inside a TraceUnion follows specific rules:
//
//   - |as_pointer| is for raw pointers that should be treated as a simple
//     address and will never be dereferenced. Associated with the
//     TRACE_VALUE_TYPE_POINTER type.
//
//   - |as_string| is for C-string pointers, associated with both
//     TRACE_VALUE_TYPE_STRING and TRACE_VALUE_TYPE_COPY_STRING. The former
//     indicates that the string pointer is persistent (e.g. a C string
//     literal), while the second indicates that the pointer belongs to a
//     temporary variable that may disappear soon. The TraceArguments class
//     provides a CopyStringTo() method to copy these strings into a
//     StringStorage instance, which is useful if the instance needs to
//     survive longer than the temporaries.
//
//   - |as_convertable| is equivalent to
//     std::unique_ptr<ConvertableToTraceFormat>, except that it is a pointer
//     to keep this union POD and avoid un-necessary declarations and potential
//     code generation. This means that its ownership is passed to the
//     TraceValue instance when Init(std::unique_ptr<ConvertableToTraceFormat>)
//     is called, and that it will be deleted by the containing TraceArguments
//     destructor, or Reset() method.
//
TraceValue;

// TraceValue::Helper for integers and enums.
Helper<T, std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<T>>>;

// TraceValue::Helper for floating-point types
Helper<T, std::enable_if_t<std::is_floating_point_v<T>>>;

// TraceValue::Helper for bool.
template <>
struct TraceValue::Helper<bool> {};

//  TraceValue::Helper for generic pointer types.
template <>
struct TraceValue::Helper<const void*> {};

template <>
struct TraceValue::Helper<void*> {};

// TraceValue::Helper for raw persistent C strings.
template <>
struct TraceValue::Helper<const char*> {};

// TraceValue::Helper for std::string values.
template <>
struct TraceValue::Helper<std::string> {};

// Special case for scoped pointers to convertables to trace format.
// |CONVERTABLE_TYPE| must be a type whose pointers can be converted to a
// ConvertableToTraceFormat* pointer as well (e.g. a derived class).
// IMPORTANT: This takes an std::unique_ptr<CONVERTABLE_TYPE> value, and takes
// ownership of the pointed object!
Helper<std::unique_ptr<CONVERTABLE_TYPE>, std::enable_if_t<std::is_convertible_v<CONVERTABLE_TYPE *, ConvertableToTraceFormat *>>>;

// Specialization for time-based values like base::Time, which provide a
// a ToInternalValue() method.
Helper<T, std::enable_if_t<std::is_same_v<T, base::Time> || std::is_same_v<T, base::TimeTicks> || std::is_same_v<T, base::ThreadTicks>>>;

// Simple container for const char* that should be copied instead of retained.
// The goal is to indicate that the C string is copyable, unlike the default
// Init(const char*) implementation. Usage is:
//
//    const char* str = ...;
//    v.Init(TraceStringWithCopy(str));
//
// Which will mark the string as TRACE_VALUE_TYPE_COPY_STRING, instead of
// TRACE_VALUE_TYPE_STRING.
//
class TraceStringWithCopy {};

template <>
struct TraceValue::Helper<TraceStringWithCopy> {};

class TraceArguments;

// A small class used to store a copy of all strings from a given
// TraceArguments instance (see below). When empty, this should only
// take the size of a pointer. Otherwise, this will point to a heap
// allocated block containing a size_t value followed by all characters
// in the storage area. For most cases, this is more efficient
// than using a std::unique_ptr<std::string> or an std::vector<char>.
class BASE_EXPORT StringStorage {};

// TraceArguments models an array of kMaxSize trace-related items,
// each one of them having:
//   - a name, which is a constant char array literal.
//   - a type, as described by TRACE_VALUE_TYPE_XXX macros.
//   - a value, stored in a TraceValue union.
//
// IMPORTANT: For TRACE_VALUE_TYPE_CONVERTABLE, the value holds an owning
//            pointer to an AsConvertableToTraceFormat instance, which will
//            be destroyed with the array (or moved out of it when passed
//            to a TraceEvent instance).
//
// For TRACE_VALUE_TYPE_COPY_STRING, the value holds a const char* pointer
// whose content will be copied when creating a TraceEvent instance.
//
// IMPORTANT: Most constructors and the destructor are all inlined
// intentionally, in order to let the compiler remove un-necessary operations
// and reduce machine code.
//
class BASE_EXPORT TraceArguments {};

}  // namespace trace_event
}  // namespace base

#endif  // BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_