673 lines
25 KiB
C
673 lines
25 KiB
C
|
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
|
||
|
#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 "base/base_export.h"
|
||
|
#include "base/macros.h"
|
||
|
#include "base/trace_event/common/trace_event_common.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:
|
||
|
ConvertableToTraceFormat() = default;
|
||
|
virtual ~ConvertableToTraceFormat() = default;
|
||
|
|
||
|
// Append the class info to the provided |out| string. The appended
|
||
|
// data must be a valid JSON object. Strings must be properly quoted, and
|
||
|
// escaped. There is no processing applied to the content after it is
|
||
|
// appended.
|
||
|
virtual void AppendAsTraceFormat(std::string* out) const = 0;
|
||
|
|
||
|
// Append the class info directly into the Perfetto-defined proto
|
||
|
// format; this is attempted first and if this returns true,
|
||
|
// AppendAsTraceFormat is not called. The ProtoAppender interface
|
||
|
// acts as a bridge to avoid proto/Perfetto dependencies in base.
|
||
|
class BASE_EXPORT ProtoAppender {
|
||
|
public:
|
||
|
virtual ~ProtoAppender() = default;
|
||
|
|
||
|
virtual void AddBuffer(uint8_t* begin, uint8_t* end) = 0;
|
||
|
// Copy all of the previous buffers registered with AddBuffer
|
||
|
// into the proto, with the given |field_id|.
|
||
|
virtual size_t Finalize(uint32_t field_id) = 0;
|
||
|
};
|
||
|
virtual bool AppendToProto(ProtoAppender* appender);
|
||
|
|
||
|
virtual void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
|
||
|
|
||
|
private:
|
||
|
DISALLOW_COPY_AND_ASSIGN(ConvertableToTraceFormat);
|
||
|
};
|
||
|
|
||
|
const int kTraceMaxNumArgs = 2;
|
||
|
|
||
|
// 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.
|
||
|
//
|
||
|
union BASE_EXPORT TraceValue {
|
||
|
bool as_bool;
|
||
|
unsigned long long as_uint;
|
||
|
long long as_int;
|
||
|
double as_double;
|
||
|
const void* as_pointer;
|
||
|
const char* as_string;
|
||
|
ConvertableToTraceFormat* as_convertable;
|
||
|
|
||
|
// There is no constructor to keep this structure POD intentionally.
|
||
|
// This avoids un-needed initialization when only 0 or 1 arguments are
|
||
|
// used to construct a TraceArguments instance. Use Init() instead to
|
||
|
// perform explicit initialization from a given C++ value.
|
||
|
|
||
|
// Initialize TraceValue instance from a C++ trace value.
|
||
|
// This relies on the proper specialization of TraceValue::Helper<>
|
||
|
// described below. Usage is simply:
|
||
|
//
|
||
|
// TraceValue v;
|
||
|
// v.Init(<value>);
|
||
|
//
|
||
|
// NOTE: For ConvertableToTraceFormat values, see the note above and
|
||
|
// the one for TraceValue::Helper for CONVERTABLE_TYPE below.
|
||
|
template <typename T>
|
||
|
void Init(T&& value) {
|
||
|
using ValueType = typename InnerType<T>::type;
|
||
|
Helper<ValueType>::SetValue(this, std::forward<T>(value));
|
||
|
}
|
||
|
|
||
|
// Static method to create a new TraceValue instance from a given
|
||
|
// initialization value. Note that this deduces the TRACE_VALUE_TYPE_XXX
|
||
|
// type but doesn't return it, use ForType<T>::value for this.
|
||
|
//
|
||
|
// Usage example:
|
||
|
// auto v = TraceValue::Make(100);
|
||
|
// auto v2 = TraceValue::Make("Some text string");
|
||
|
//
|
||
|
// IMPORTANT: Experience shows that the compiler generates worse code when
|
||
|
// using this method rather than calling Init() directly on an existing
|
||
|
// TraceValue union :-(
|
||
|
//
|
||
|
template <typename T>
|
||
|
static TraceValue Make(T&& value) {
|
||
|
TraceValue ret;
|
||
|
ret.Init(std::forward<T>(value));
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
// Output current value as a JSON string. |type| must be a valid
|
||
|
// TRACE_VALUE_TYPE_XXX value.
|
||
|
void AppendAsJSON(unsigned char type, std::string* out) const;
|
||
|
|
||
|
// Output current value as a string. If the output string is to be used
|
||
|
// in a JSON format use AppendAsJSON instead. |type| must be valid
|
||
|
// TRACE_VALUE_TYPE_XXX value.
|
||
|
void AppendAsString(unsigned char type, std::string* out) const;
|
||
|
|
||
|
private:
|
||
|
void Append(unsigned char type, bool as_json, std::string* out) const;
|
||
|
|
||
|
// InnerType<T>::type removes reference, cv-qualifications and decays
|
||
|
// function and arrays into pointers. Only used internally.
|
||
|
template <typename T>
|
||
|
struct InnerType {
|
||
|
using type = typename std::remove_cv<typename std::remove_reference<
|
||
|
typename std::decay<T>::type>::type>::type;
|
||
|
};
|
||
|
|
||
|
public:
|
||
|
// TraceValue::Helper is used to provide information about initialization
|
||
|
// value types and an initialization function. It is a struct that should
|
||
|
// provide the following for supported initialization value types:
|
||
|
//
|
||
|
// - kType: is a static TRACE_VALUE_TYPE_XXX constant.
|
||
|
//
|
||
|
// - SetValue(TraceValue*, T): is a static inline method that sets
|
||
|
// TraceValue value from a given T value. Second parameter type
|
||
|
// can also be const T& or T&& to restrict uses.
|
||
|
//
|
||
|
// IMPORTANT: The type T must be InnerType<Q>, where Q is the real C++
|
||
|
// argument type. I.e. you should not have to deal with reference types
|
||
|
// in your specialization.
|
||
|
//
|
||
|
// Specializations are defined for integers, enums, floating point, pointers,
|
||
|
// constant C string literals and pointers, std::string, time values below.
|
||
|
//
|
||
|
// Specializations for custom types are possible provided that there exists
|
||
|
// a corresponding Helper specialization, for example:
|
||
|
//
|
||
|
// template <>
|
||
|
// struct base::trace_event::TraceValue::Helper<Foo> {
|
||
|
// static constexpr unsigned char kTypes = TRACE_VALUE_TYPE_COPY_STRING;
|
||
|
// static inline void SetValue(TraceValue* v, const Foo& value) {
|
||
|
// v->as_string = value.c_str();
|
||
|
// }
|
||
|
// };
|
||
|
//
|
||
|
// Will allow code like:
|
||
|
//
|
||
|
// Foo foo = ...;
|
||
|
// auto v = TraceValue::Make(foo);
|
||
|
//
|
||
|
// Or even:
|
||
|
// Foo foo = ...;
|
||
|
// TraceArguments args("foo_arg1", foo);
|
||
|
//
|
||
|
template <typename T, class = void>
|
||
|
struct Helper {};
|
||
|
|
||
|
// TraceValue::TypeFor<T>::value returns the TRACE_VALUE_TYPE_XXX
|
||
|
// corresponding to initialization values of type T.
|
||
|
template <typename T>
|
||
|
struct TypeFor {
|
||
|
using ValueType = typename InnerType<T>::type;
|
||
|
static const unsigned char value = Helper<ValueType>::kType;
|
||
|
};
|
||
|
|
||
|
// TraceValue::TypeCheck<T>::value is only defined iff T can be used to
|
||
|
// initialize a TraceValue instance. This is useful to restrict template
|
||
|
// instantiation to only the appropriate type (see TraceArguments
|
||
|
// constructors below).
|
||
|
template <typename T,
|
||
|
class = decltype(TraceValue::Helper<
|
||
|
typename TraceValue::InnerType<T>::type>::kType)>
|
||
|
struct TypeCheck {
|
||
|
static const bool value = true;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// TraceValue::Helper for integers and enums.
|
||
|
template <typename T>
|
||
|
struct TraceValue::Helper<
|
||
|
T,
|
||
|
typename std::enable_if<std::is_integral<T>::value ||
|
||
|
std::is_enum<T>::value>::type> {
|
||
|
static constexpr unsigned char kType =
|
||
|
std::is_signed<T>::value ? TRACE_VALUE_TYPE_INT : TRACE_VALUE_TYPE_UINT;
|
||
|
static inline void SetValue(TraceValue* v, T value) {
|
||
|
v->as_uint = static_cast<unsigned long long>(value);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// TraceValue::Helper for floating-point types
|
||
|
template <typename T>
|
||
|
struct TraceValue::
|
||
|
Helper<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
|
||
|
static constexpr unsigned char kType = TRACE_VALUE_TYPE_DOUBLE;
|
||
|
static inline void SetValue(TraceValue* v, T value) { v->as_double = value; }
|
||
|
};
|
||
|
|
||
|
// TraceValue::Helper for bool.
|
||
|
template <>
|
||
|
struct TraceValue::Helper<bool> {
|
||
|
static constexpr unsigned char kType = TRACE_VALUE_TYPE_BOOL;
|
||
|
static inline void SetValue(TraceValue* v, bool value) { v->as_bool = value; }
|
||
|
};
|
||
|
|
||
|
// TraceValue::Helper for generic pointer types.
|
||
|
template <typename T>
|
||
|
struct TraceValue::Helper<T*> {
|
||
|
static constexpr unsigned char kType = TRACE_VALUE_TYPE_POINTER;
|
||
|
static inline void SetValue(TraceValue* v,
|
||
|
const typename std::decay<T>::type* value) {
|
||
|
v->as_pointer = value;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// TraceValue::Helper for raw persistent C strings.
|
||
|
template <>
|
||
|
struct TraceValue::Helper<const char*> {
|
||
|
static constexpr unsigned char kType = TRACE_VALUE_TYPE_STRING;
|
||
|
static inline void SetValue(TraceValue* v, const char* value) {
|
||
|
v->as_string = value;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// TraceValue::Helper for std::string values.
|
||
|
template <>
|
||
|
struct TraceValue::Helper<std::string> {
|
||
|
static constexpr unsigned char kType = TRACE_VALUE_TYPE_COPY_STRING;
|
||
|
static inline void SetValue(TraceValue* v, const std::string& value) {
|
||
|
v->as_string = value.c_str();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// 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!
|
||
|
template <typename CONVERTABLE_TYPE>
|
||
|
struct TraceValue::Helper<std::unique_ptr<CONVERTABLE_TYPE>,
|
||
|
typename std::enable_if<std::is_convertible<
|
||
|
CONVERTABLE_TYPE*,
|
||
|
ConvertableToTraceFormat*>::value>::type> {
|
||
|
static constexpr unsigned char kType = TRACE_VALUE_TYPE_CONVERTABLE;
|
||
|
static inline void SetValue(TraceValue* v,
|
||
|
std::unique_ptr<CONVERTABLE_TYPE> value) {
|
||
|
v->as_convertable = value.release();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Specialization for time-based values like base::Time, which provide a
|
||
|
// a ToInternalValue() method.
|
||
|
template <typename T>
|
||
|
struct TraceValue::Helper<
|
||
|
T,
|
||
|
typename std::enable_if<std::is_same<T, base::Time>::value ||
|
||
|
std::is_same<T, base::TimeTicks>::value ||
|
||
|
std::is_same<T, base::ThreadTicks>::value>::type> {
|
||
|
static constexpr unsigned char kType = TRACE_VALUE_TYPE_INT;
|
||
|
static inline void SetValue(TraceValue* v, const T& value) {
|
||
|
v->as_int = value.ToInternalValue();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// 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 {
|
||
|
public:
|
||
|
explicit TraceStringWithCopy(const char* str) : str_(str) {}
|
||
|
const char* str() const { return str_; }
|
||
|
|
||
|
private:
|
||
|
const char* str_;
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct TraceValue::Helper<TraceStringWithCopy> {
|
||
|
static constexpr unsigned char kType = TRACE_VALUE_TYPE_COPY_STRING;
|
||
|
static inline void SetValue(TraceValue* v, const TraceStringWithCopy& value) {
|
||
|
v->as_string = value.str();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
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 {
|
||
|
public:
|
||
|
constexpr StringStorage() = default;
|
||
|
|
||
|
explicit StringStorage(size_t alloc_size) { Reset(alloc_size); }
|
||
|
|
||
|
~StringStorage() {
|
||
|
if (data_)
|
||
|
::free(data_);
|
||
|
}
|
||
|
|
||
|
StringStorage(StringStorage&& other) noexcept : data_(other.data_) {
|
||
|
other.data_ = nullptr;
|
||
|
}
|
||
|
|
||
|
StringStorage& operator=(StringStorage&& other) noexcept {
|
||
|
if (this != &other) {
|
||
|
if (data_)
|
||
|
::free(data_);
|
||
|
data_ = other.data_;
|
||
|
other.data_ = nullptr;
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
// Reset storage area to new allocation size. Existing content might not
|
||
|
// be preserved. If |alloc_size| is 0, this will free the storage area
|
||
|
// as well.
|
||
|
void Reset(size_t alloc_size = 0);
|
||
|
|
||
|
// Accessors.
|
||
|
constexpr size_t size() const { return data_ ? data_->size : 0u; }
|
||
|
constexpr const char* data() const { return data_ ? data_->chars : nullptr; }
|
||
|
constexpr char* data() { return data_ ? data_->chars : nullptr; }
|
||
|
|
||
|
constexpr const char* begin() const { return data(); }
|
||
|
constexpr const char* end() const { return data() + size(); }
|
||
|
inline char* begin() { return data(); }
|
||
|
inline char* end() { return data() + size(); }
|
||
|
|
||
|
// True iff storage is empty.
|
||
|
constexpr bool empty() const { return size() == 0; }
|
||
|
|
||
|
// Returns true if |ptr| is inside the storage area, false otherwise.
|
||
|
// Used during unit-testing.
|
||
|
constexpr bool Contains(const void* ptr) const {
|
||
|
const char* char_ptr = static_cast<const char*>(ptr);
|
||
|
return (char_ptr >= begin() && char_ptr < end());
|
||
|
}
|
||
|
|
||
|
// Returns true if all string pointers in |args| are contained in this
|
||
|
// storage area.
|
||
|
bool Contains(const TraceArguments& args) const;
|
||
|
|
||
|
// Return an estimate of the memory overhead of this instance. This doesn't
|
||
|
// count the size of |data_| itself.
|
||
|
constexpr size_t EstimateTraceMemoryOverhead() const {
|
||
|
return data_ ? sizeof(size_t) + data_->size : 0u;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
// Heap allocated data block (variable size), made of:
|
||
|
//
|
||
|
// - size: a size_t field, giving the size of the following |chars| array.
|
||
|
// - chars: an array of |size| characters, holding all zero-terminated
|
||
|
// strings referenced from a TraceArguments instance.
|
||
|
struct Data {
|
||
|
size_t size = 0;
|
||
|
char chars[1]; // really |size| character items in storage.
|
||
|
};
|
||
|
|
||
|
// This is an owning pointer. Normally, using a std::unique_ptr<> would be
|
||
|
// enough, but the compiler will then complaing about inlined constructors
|
||
|
// and destructors being too complex (!), resulting in larger code for no
|
||
|
// good reason.
|
||
|
Data* data_ = nullptr;
|
||
|
};
|
||
|
|
||
|
// 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 {
|
||
|
public:
|
||
|
// Maximum number of arguments held by this structure.
|
||
|
static constexpr size_t kMaxSize = 2;
|
||
|
|
||
|
// Default constructor, no arguments.
|
||
|
TraceArguments() : size_(0) {}
|
||
|
|
||
|
// Constructor for a single argument.
|
||
|
template <typename T, class = decltype(TraceValue::TypeCheck<T>::value)>
|
||
|
TraceArguments(const char* arg1_name, T&& arg1_value) : size_(1) {
|
||
|
types_[0] = TraceValue::TypeFor<T>::value;
|
||
|
names_[0] = arg1_name;
|
||
|
values_[0].Init(std::forward<T>(arg1_value));
|
||
|
}
|
||
|
|
||
|
// Constructor for two arguments.
|
||
|
template <typename T1,
|
||
|
typename T2,
|
||
|
class = decltype(TraceValue::TypeCheck<T1>::value &&
|
||
|
TraceValue::TypeCheck<T2>::value)>
|
||
|
TraceArguments(const char* arg1_name,
|
||
|
T1&& arg1_value,
|
||
|
const char* arg2_name,
|
||
|
T2&& arg2_value)
|
||
|
: size_(2) {
|
||
|
types_[0] = TraceValue::TypeFor<T1>::value;
|
||
|
types_[1] = TraceValue::TypeFor<T2>::value;
|
||
|
names_[0] = arg1_name;
|
||
|
names_[1] = arg2_name;
|
||
|
values_[0].Init(std::forward<T1>(arg1_value));
|
||
|
values_[1].Init(std::forward<T2>(arg2_value));
|
||
|
}
|
||
|
|
||
|
// Constructor used to convert a legacy set of arguments when there
|
||
|
// are no convertable values at all.
|
||
|
TraceArguments(int num_args,
|
||
|
const char* const* arg_names,
|
||
|
const unsigned char* arg_types,
|
||
|
const unsigned long long* arg_values);
|
||
|
|
||
|
// Constructor used to convert legacy set of arguments, where the
|
||
|
// convertable values are also provided by an array of CONVERTABLE_TYPE.
|
||
|
template <typename CONVERTABLE_TYPE>
|
||
|
TraceArguments(int num_args,
|
||
|
const char* const* arg_names,
|
||
|
const unsigned char* arg_types,
|
||
|
const unsigned long long* arg_values,
|
||
|
CONVERTABLE_TYPE* arg_convertables) {
|
||
|
static int max_args = static_cast<int>(kMaxSize);
|
||
|
if (num_args > max_args)
|
||
|
num_args = max_args;
|
||
|
size_ = static_cast<unsigned char>(num_args);
|
||
|
for (size_t n = 0; n < size_; ++n) {
|
||
|
types_[n] = arg_types[n];
|
||
|
names_[n] = arg_names[n];
|
||
|
if (arg_types[n] == TRACE_VALUE_TYPE_CONVERTABLE) {
|
||
|
values_[n].Init(
|
||
|
std::forward<CONVERTABLE_TYPE>(std::move(arg_convertables[n])));
|
||
|
} else {
|
||
|
values_[n].as_uint = arg_values[n];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Destructor. NOTE: Intentionally inlined (see note above).
|
||
|
~TraceArguments() {
|
||
|
for (size_t n = 0; n < size_; ++n) {
|
||
|
if (types_[n] == TRACE_VALUE_TYPE_CONVERTABLE)
|
||
|
delete values_[n].as_convertable;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Disallow copy operations.
|
||
|
TraceArguments(const TraceArguments&) = delete;
|
||
|
TraceArguments& operator=(const TraceArguments&) = delete;
|
||
|
|
||
|
// Allow move operations.
|
||
|
TraceArguments(TraceArguments&& other) noexcept {
|
||
|
::memcpy(this, &other, sizeof(*this));
|
||
|
// All owning pointers were copied to |this|. Setting |other.size_| will
|
||
|
// mask the pointer values still in |other|.
|
||
|
other.size_ = 0;
|
||
|
}
|
||
|
|
||
|
TraceArguments& operator=(TraceArguments&&) noexcept;
|
||
|
|
||
|
// Accessors
|
||
|
size_t size() const { return size_; }
|
||
|
const unsigned char* types() const { return types_; }
|
||
|
const char* const* names() const { return names_; }
|
||
|
const TraceValue* values() const { return values_; }
|
||
|
|
||
|
// Reset to empty arguments list.
|
||
|
void Reset();
|
||
|
|
||
|
// Use |storage| to copy all copyable strings.
|
||
|
// If |copy_all_strings| is false, then only the TRACE_VALUE_TYPE_COPY_STRING
|
||
|
// values will be copied into storage. If it is true, then argument names are
|
||
|
// also copied to storage, as well as the strings pointed to by
|
||
|
// |*extra_string1| and |*extra_string2|.
|
||
|
// NOTE: If there are no strings to copy, |*storage| is left untouched.
|
||
|
void CopyStringsTo(StringStorage* storage,
|
||
|
bool copy_all_strings,
|
||
|
const char** extra_string1,
|
||
|
const char** extra_string2);
|
||
|
|
||
|
// Append debug string representation to |*out|.
|
||
|
void AppendDebugString(std::string* out);
|
||
|
|
||
|
private:
|
||
|
unsigned char size_;
|
||
|
unsigned char types_[kMaxSize];
|
||
|
const char* names_[kMaxSize];
|
||
|
TraceValue values_[kMaxSize];
|
||
|
};
|
||
|
|
||
|
} // namespace trace_event
|
||
|
} // namespace base
|
||
|
|
||
|
#endif // BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_
|