blob: c28776d4fcec29b626748a1e93114da740c0cbb0 [file] [log] [blame]
// Copyright 2017 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_TRACING_HELPER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_TRACING_HELPER_H_
#include <string>
#include <unordered_set>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
namespace scheduler {
// DISCLAIMER
// Using these constants in TRACE_EVENTs is discouraged nor should you pass any
// non-literal string as a category, unless familiar with tracing internals.
PLATFORM_EXPORT extern const char kTracingCategoryNameTopLevel[];
PLATFORM_EXPORT extern const char kTracingCategoryNameDefault[];
PLATFORM_EXPORT extern const char kTracingCategoryNameInfo[];
PLATFORM_EXPORT extern const char kTracingCategoryNameDebug[];
namespace internal {
PLATFORM_EXPORT void ValidateTracingCategory(const char* category);
} // namespace internal
PLATFORM_EXPORT void WarmupTracingCategories();
PLATFORM_EXPORT std::string PointerToString(const void* pointer);
PLATFORM_EXPORT double TimeDeltaToMilliseconds(const base::TimeDelta& value);
PLATFORM_EXPORT const char* YesNoStateToString(bool is_yes);
class TraceableVariable;
// Unfortunately, using |base::trace_event::TraceLog::EnabledStateObserver|
// wouldn't be helpful in our case because removing one takes linear time
// and tracers may be created and disposed frequently.
class PLATFORM_EXPORT TraceableVariableController {
public:
TraceableVariableController();
~TraceableVariableController();
// Not thread safe.
void RegisterTraceableVariable(TraceableVariable* traceable_variable);
void DeregisterTraceableVariable(TraceableVariable* traceable_variable);
void OnTraceLogEnabled();
private:
std::unordered_set<TraceableVariable*> traceable_variables_;
};
class TraceableVariable {
public:
TraceableVariable(TraceableVariableController* controller)
: controller_(controller) {
controller_->RegisterTraceableVariable(this);
}
virtual ~TraceableVariable() {
controller_->DeregisterTraceableVariable(this);
}
virtual void OnTraceLogEnabled() = 0;
private:
TraceableVariableController* const controller_; // Not owned.
};
// TRACE_EVENT macros define static variable to cache a pointer to the state
// of category. Hence, we need distinct version for each category in order to
// prevent unintended leak of state.
template <const char* category>
class StateTracer {
public:
StateTracer(const char* name, const void* object)
: name_(name), object_(object), slice_is_open_(false) {
internal::ValidateTracingCategory(category);
}
~StateTracer() {
if (slice_is_open_)
TRACE_EVENT_ASYNC_END0(category, name_, object_);
}
// String will be copied before leaving this function.
void TraceString(const String& state) {
TraceImpl(state.Utf8().data(), true);
}
// Trace compile-time defined const string, so no copy needed.
// Null may be passed to indicate the absence of state.
void TraceCompileTimeString(const char* state) { TraceImpl(state, false); }
protected:
bool is_enabled() const {
bool result = false;
TRACE_EVENT_CATEGORY_GROUP_ENABLED(category, &result); // Cached.
return result;
}
private:
void TraceImpl(const char* state, bool need_copy) {
if (slice_is_open_) {
TRACE_EVENT_ASYNC_END0(category, name_, object_);
slice_is_open_ = false;
}
if (!state || !is_enabled())
return;
// Trace viewer logic relies on subslice starting at the exact same time
// as the async event.
base::TimeTicks now = TRACE_TIME_TICKS_NOW();
TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(category, name_, object_, now);
if (need_copy) {
TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category, name_, object_,
TRACE_STR_COPY(state), now);
} else {
TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category, name_, object_,
state, now);
}
slice_is_open_ = true;
}
const char* const name_; // Not owned.
const void* const object_; // Not owned.
// We have to track whether slice is open to avoid confusion since assignment,
// "absent" state and OnTraceLogEnabled can happen anytime.
bool slice_is_open_;
DISALLOW_COPY_AND_ASSIGN(StateTracer);
};
// TODO(kraynov): Rename to something less generic and reflecting
// the enum nature of such variables.
template <typename T, const char* category>
class TraceableState : public TraceableVariable, private StateTracer<category> {
public:
// Converter must return compile-time defined const strings because tracing
// will not make a copy of them.
using ConverterFuncPtr = const char* (*)(T);
TraceableState(T initial_state,
const char* name,
const void* object,
TraceableVariableController* controller,
ConverterFuncPtr converter)
: TraceableVariable(controller),
StateTracer<category>(name, object),
converter_(converter),
state_(initial_state) {
Trace();
}
~TraceableState() override = default;
TraceableState& operator=(const T& value) {
Assign(value);
return *this;
}
TraceableState& operator=(const TraceableState& another) {
Assign(another.state_);
return *this;
}
operator T() const { return state_; }
const T& get() const { return state_; }
void OnTraceLogEnabled() final { Trace(); }
protected:
void Assign(T new_state) {
if (state_ != new_state) {
state_ = new_state;
Trace();
}
}
void (*mock_trace_for_test_)(const char*) = nullptr;
private:
void Trace() {
if (UNLIKELY(mock_trace_for_test_)) {
mock_trace_for_test_(converter_(state_));
return;
}
// Null state string means the absence of state.
const char* state_str = nullptr;
if (StateTracer<category>::is_enabled()) {
state_str = converter_(state_);
}
// We have to be explicit to deal with two-phase name lookup in templates:
// http://blog.llvm.org/2009/12/dreaded-two-phase-name-lookup.html
StateTracer<category>::TraceCompileTimeString(state_str);
}
const ConverterFuncPtr converter_;
T state_;
DISALLOW_COPY(TraceableState);
};
template <typename T, const char* category>
class TraceableCounter : public TraceableVariable {
public:
using ConverterFuncPtr = double (*)(const T&);
TraceableCounter(T initial_value,
const char* name,
const void* object,
TraceableVariableController* controller,
ConverterFuncPtr converter)
: TraceableVariable(controller),
name_(name),
object_(object),
converter_(converter),
value_(initial_value) {
internal::ValidateTracingCategory(category);
Trace();
}
TraceableCounter(T initial_value,
const char* name,
const void* object,
TraceableVariableController* controller)
: TraceableVariable(controller),
name_(name),
object_(object),
converter_([](const T& value) { return static_cast<double>(value); }),
value_(initial_value) {
internal::ValidateTracingCategory(category);
Trace();
}
TraceableCounter& operator=(const T& value) {
value_ = value;
Trace();
return *this;
}
TraceableCounter& operator=(const TraceableCounter& another) {
value_ = another.value_;
Trace();
return *this;
}
TraceableCounter& operator+=(const T& value) {
value_ += value;
Trace();
return *this;
}
TraceableCounter& operator-=(const T& value) {
value_ -= value;
Trace();
return *this;
}
const T& value() const { return value_; }
const T* operator->() const { return &value_; }
operator T() const { return value_; }
void OnTraceLogEnabled() final { Trace(); }
void Trace() const {
TRACE_COUNTER_ID1(category, name_, object_, converter_(value_));
}
private:
const char* const name_; // Not owned.
const void* const object_; // Not owned.
const ConverterFuncPtr converter_;
T value_;
DISALLOW_COPY(TraceableCounter);
};
// Add operators when it's needed.
template <typename T, const char* category>
constexpr T operator-(const TraceableCounter<T, category>& counter) {
return -counter.value();
}
template <typename T, const char* category>
constexpr T operator/(const TraceableCounter<T, category>& lhs, const T& rhs) {
return lhs.value() / rhs;
}
template <typename T, const char* category>
constexpr bool operator>(const TraceableCounter<T, category>& lhs,
const T& rhs) {
return lhs.value() > rhs;
}
template <typename T, const char* category>
constexpr bool operator<(const TraceableCounter<T, category>& lhs,
const T& rhs) {
return lhs.value() < rhs;
}
template <typename T, const char* category>
constexpr bool operator!=(const TraceableCounter<T, category>& lhs,
const T& rhs) {
return lhs.value() != rhs;
}
template <typename T, const char* category>
constexpr T operator++(TraceableCounter<T, category>& counter) {
counter = counter.value() + 1;
return counter.value();
}
template <typename T, const char* category>
constexpr T operator--(TraceableCounter<T, category>& counter) {
counter = counter.value() - 1;
return counter.value();
}
template <typename T, const char* category>
constexpr T operator++(TraceableCounter<T, category>& counter, int) {
T value = counter.value();
counter = value + 1;
return value;
}
template <typename T, const char* category>
constexpr T operator--(TraceableCounter<T, category>& counter, int) {
T value = counter.value();
counter = value - 1;
return value;
}
} // namespace scheduler
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_TRACING_HELPER_H_