Chromium Code Reviews| Index: base/trace_event/trace_log.cc |
| diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc |
| index 7b7022c42de32cad9560824d70de6382cb82f9d8..00ae9263f04350a816bcd0883e04a603bf1b7cf8 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,37 @@ 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}; |
| + |
| +class EventNameFilter : public TraceLog::TraceEventFilter { |
| + public: |
| + EventNameFilter(const base::DictionaryValue* filter_args) { |
| + const base::ListValue* whitelist = nullptr; |
| + if (filter_args->GetList("event_name_whitelist", &whitelist)) { |
|
shatch
2016/08/15 21:25:47
nit: maybe just define these at the top like you d
oystein (OOO til 10th of July)
2016/08/16 22:17:52
Done.
|
| + 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 +211,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 +493,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 +528,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 +1339,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 +1376,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 +1521,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 +1697,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); |
| } |