| Index: base/trace_event/trace_log.cc
|
| diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc
|
| index 872cd172b2b7310ef81b40befb90c06a3e7d5a90..a9f99d41f0dc97b37a1cc7364c30231451047088 100644
|
| --- a/base/trace_event/trace_log.cc
|
| +++ b/base/trace_event/trace_log.cc
|
| @@ -16,6 +16,7 @@
|
| #include "base/lazy_instance.h"
|
| #include "base/location.h"
|
| #include "base/macros.h"
|
| +#include "base/memory/ptr_util.h"
|
| #include "base/memory/ref_counted_memory.h"
|
| #include "base/memory/singleton.h"
|
| #include "base/process/process_metrics.h"
|
| @@ -102,6 +103,39 @@ const char* g_category_groups[MAX_CATEGORY_GROUPS] = {
|
|
|
| // The enabled flag is char instead of bool so that the API can be used from C.
|
| unsigned char g_category_group_enabled[MAX_CATEGORY_GROUPS] = {0};
|
| +
|
| +const char kEventNameWhitelist[] = "event_name_whitelist";
|
| +
|
| +class EventNameFilter : public TraceLog::TraceEventFilter {
|
| + public:
|
| + EventNameFilter(const base::DictionaryValue* filter_args) {
|
| + const base::ListValue* whitelist = nullptr;
|
| + if (filter_args->GetList(kEventNameWhitelist, &whitelist)) {
|
| + for (size_t i = 0; i < whitelist->GetSize(); ++i) {
|
| + std::string event_name;
|
| + if (!whitelist->GetString(i, &event_name))
|
| + continue;
|
| +
|
| + whitelist_.insert(event_name);
|
| + }
|
| + }
|
| + }
|
| +
|
| + bool FilterTraceEvent(const TraceEvent& trace_event) const override {
|
| + return ContainsKey(whitelist_, trace_event.name());
|
| + }
|
| +
|
| + private:
|
| + std::unordered_set<std::string> whitelist_;
|
| +};
|
| +
|
| +base::LazyInstance<
|
| + std::list<std::unique_ptr<TraceLog::TraceEventFilter>>>::Leaky
|
| + g_category_group_filter[MAX_CATEGORY_GROUPS] = {LAZY_INSTANCE_INITIALIZER};
|
| +
|
| +TraceLog::TraceEventFilterConstructorForTesting
|
| + g_trace_event_filter_constructor_for_testing = nullptr;
|
| +
|
| // Indexes here have to match the g_category_groups array indexes above.
|
| const int kCategoryAlreadyShutdown = 1;
|
| const int kCategoryCategoriesExhausted = 2;
|
| @@ -179,6 +213,22 @@ void MakeHandle(uint32_t chunk_seq,
|
| handle->event_index = static_cast<uint16_t>(event_index);
|
| }
|
|
|
| +uintptr_t GetCategoryIndex(const unsigned char* category_group_enabled) {
|
| + // Calculate the index of the category group by finding
|
| + // category_group_enabled in g_category_group_enabled array.
|
| + uintptr_t category_begin =
|
| + reinterpret_cast<uintptr_t>(g_category_group_enabled);
|
| + uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
|
| + DCHECK(category_ptr >= category_begin);
|
| + DCHECK(category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled +
|
| + MAX_CATEGORY_GROUPS))
|
| + << "out of bounds category pointer";
|
| + uintptr_t category_index =
|
| + (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]);
|
| +
|
| + return category_index;
|
| +}
|
| +
|
| } // namespace
|
|
|
| // A helper class that allows the lock to be acquired in the middle of the scope
|
| @@ -445,18 +495,13 @@ const unsigned char* TraceLog::GetCategoryGroupEnabled(
|
|
|
| const char* TraceLog::GetCategoryGroupName(
|
| const unsigned char* category_group_enabled) {
|
| - // Calculate the index of the category group by finding
|
| - // category_group_enabled in g_category_group_enabled array.
|
| - uintptr_t category_begin =
|
| - reinterpret_cast<uintptr_t>(g_category_group_enabled);
|
| - uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
|
| - DCHECK(category_ptr >= category_begin);
|
| - DCHECK(category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled +
|
| - MAX_CATEGORY_GROUPS))
|
| - << "out of bounds category pointer";
|
| - uintptr_t category_index =
|
| - (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]);
|
| - return g_category_groups[category_index];
|
| + return g_category_groups[GetCategoryIndex(category_group_enabled)];
|
| +}
|
| +
|
| +std::list<std::unique_ptr<TraceLog::TraceEventFilter>>* GetCategoryGroupFilter(
|
| + const unsigned char* category_group_enabled) {
|
| + return g_category_group_filter[GetCategoryIndex(category_group_enabled)]
|
| + .Pointer();
|
| }
|
|
|
| void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) {
|
| @@ -485,6 +530,31 @@ void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) {
|
| if (mode_ == RECORDING_MODE && !strcmp(category_group, "__metadata"))
|
| enabled_flag |= ENABLED_FOR_RECORDING;
|
|
|
| + // Having a filter is an exceptional case, so we avoid
|
| + // the LazyInstance creation in the common case.
|
| + if (!(g_category_group_filter[category_index] == nullptr))
|
| + g_category_group_filter[category_index].Get().clear();
|
| +
|
| + for (const auto& event_filter : trace_config_.event_filters()) {
|
| + if (event_filter.IsCategoryGroupEnabled(category_group)) {
|
| + std::unique_ptr<TraceEventFilter> new_filter;
|
| +
|
| + if (event_filter.predicate_name() == "event_whitelist_predicate") {
|
| + new_filter =
|
| + WrapUnique(new EventNameFilter(event_filter.filter_args()));
|
| + } else if (event_filter.predicate_name() == "testing_predicate") {
|
| + CHECK(g_trace_event_filter_constructor_for_testing);
|
| + new_filter = g_trace_event_filter_constructor_for_testing();
|
| + }
|
| +
|
| + if (new_filter) {
|
| + g_category_group_filter[category_index].Get().push_back(
|
| + std::move(new_filter));
|
| + enabled_flag |= ENABLED_FOR_FILTERING;
|
| + }
|
| + }
|
| + }
|
| +
|
| g_category_group_enabled[category_index] = enabled_flag;
|
| }
|
|
|
| @@ -1271,7 +1341,32 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
|
| #endif // OS_WIN
|
|
|
| std::string console_message;
|
| - if (*category_group_enabled & ENABLED_FOR_RECORDING) {
|
| + std::unique_ptr<TraceEvent> filtered_trace_event;
|
| + if (*category_group_enabled & ENABLED_FOR_FILTERING) {
|
| + std::unique_ptr<TraceEvent> new_trace_event(new TraceEvent);
|
| + new_trace_event->Initialize(thread_id, offset_event_timestamp, thread_now,
|
| + phase, category_group_enabled, name, scope, id,
|
| + bind_id, num_args, arg_names, arg_types,
|
| + arg_values, convertable_values, flags);
|
| +
|
| + auto filter_list = GetCategoryGroupFilter(category_group_enabled);
|
| + DCHECK(!filter_list->empty());
|
| +
|
| + bool should_add_event = false;
|
| + for (const auto& trace_event_filter : *filter_list) {
|
| + if (trace_event_filter->FilterTraceEvent(*new_trace_event))
|
| + should_add_event = true;
|
| + }
|
| +
|
| + if (should_add_event)
|
| + filtered_trace_event = std::move(new_trace_event);
|
| + }
|
| +
|
| + // Add the trace event if we're either *just* recording (and not filtering)
|
| + // or if we one of our filters indicates the event should be added.
|
| + if (((*category_group_enabled & ENABLED_FOR_RECORDING) &&
|
| + (*category_group_enabled & ENABLED_FOR_FILTERING) == 0) ||
|
| + filtered_trace_event) {
|
| OptionalAutoLock lock(&lock_);
|
|
|
| TraceEvent* trace_event = NULL;
|
| @@ -1283,21 +1378,14 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
|
| }
|
|
|
| if (trace_event) {
|
| - trace_event->Initialize(thread_id,
|
| - offset_event_timestamp,
|
| - thread_now,
|
| - phase,
|
| - category_group_enabled,
|
| - name,
|
| - scope,
|
| - id,
|
| - bind_id,
|
| - num_args,
|
| - arg_names,
|
| - arg_types,
|
| - arg_values,
|
| - convertable_values,
|
| - flags);
|
| + if (filtered_trace_event) {
|
| + trace_event->MoveFrom(std::move(filtered_trace_event));
|
| + } else {
|
| + trace_event->Initialize(thread_id, offset_event_timestamp, thread_now,
|
| + phase, category_group_enabled, name, scope, id,
|
| + bind_id, num_args, arg_names, arg_types,
|
| + arg_values, convertable_values, flags);
|
| + }
|
|
|
| #if defined(OS_ANDROID)
|
| trace_event->SendToATrace();
|
| @@ -1435,6 +1523,18 @@ std::string TraceLog::EventToConsoleMessage(unsigned char phase,
|
| return log.str();
|
| }
|
|
|
| +void TraceLog::EndFilteredEvent(const unsigned char* category_group_enabled,
|
| + const char* name,
|
| + TraceEventHandle handle) {
|
| + auto filter_list = GetCategoryGroupFilter(category_group_enabled);
|
| + DCHECK(!filter_list->empty());
|
| +
|
| + for (const auto& trace_event_filter : *filter_list) {
|
| + trace_event_filter->EndEvent(name,
|
| + GetCategoryGroupName(category_group_enabled));
|
| + }
|
| +}
|
| +
|
| void TraceLog::UpdateTraceEventDuration(
|
| const unsigned char* category_group_enabled,
|
| const char* name,
|
| @@ -1599,6 +1699,11 @@ void TraceLog::DeleteForTesting() {
|
| internal::DeleteTraceLogForTesting::Delete();
|
| }
|
|
|
| +void TraceLog::SetTraceEventFilterConstructorForTesting(
|
| + TraceEventFilterConstructorForTesting predicate) {
|
| + g_trace_event_filter_constructor_for_testing = predicate;
|
| +}
|
| +
|
| TraceEvent* TraceLog::GetEventByHandle(TraceEventHandle handle) {
|
| return GetEventByHandleInternal(handle, NULL);
|
| }
|
|
|