| Index: base/trace_event/trace_log.cc
|
| diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc
|
| index a77197017f57bbadcec8ed3bc9581d05690038c2..f76393cf230a3e97772d3cee734ffac79b0ba5fc 100644
|
| --- a/base/trace_event/trace_log.cc
|
| +++ b/base/trace_event/trace_log.cc
|
| @@ -26,12 +26,12 @@
|
| #include "base/strings/string_tokenizer.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "base/sys_info.h"
|
| -#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
|
| #include "base/threading/platform_thread.h"
|
| #include "base/threading/thread_id_name_manager.h"
|
| #include "base/threading/thread_task_runner_handle.h"
|
| #include "base/threading/worker_pool.h"
|
| #include "base/time/time.h"
|
| +#include "base/trace_event/category_registry.h"
|
| #include "base/trace_event/heap_profiler.h"
|
| #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
|
| #include "base/trace_event/memory_dump_manager.h"
|
| @@ -84,23 +84,6 @@ const size_t kEchoToConsoleTraceEventBufferChunks = 256;
|
| const size_t kTraceEventBufferSizeInBytes = 100 * 1024;
|
| const int kThreadFlushTimeoutMs = 3000;
|
|
|
| -#define MAX_CATEGORY_GROUPS 200
|
| -
|
| -// Parallel arrays g_category_groups and g_category_group_enabled are separate
|
| -// so that a pointer to a member of g_category_group_enabled can be easily
|
| -// converted to an index into g_category_groups. This allows macros to deal
|
| -// only with char enabled pointers from g_category_group_enabled, and we can
|
| -// convert internally to determine the category name from the char enabled
|
| -// pointer.
|
| -const char* g_category_groups[MAX_CATEGORY_GROUPS] = {
|
| - "toplevel",
|
| - "tracing already shutdown",
|
| - "tracing categories exhausted; must increase MAX_CATEGORY_GROUPS",
|
| - "__metadata"};
|
| -
|
| -// 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";
|
|
|
| #define MAX_TRACE_EVENT_FILTERS 32
|
| @@ -109,9 +92,6 @@ const char kEventNameWhitelist[] = "event_name_whitelist";
|
| base::LazyInstance<std::vector<std::unique_ptr<TraceLog::TraceEventFilter>>>::
|
| Leaky g_category_group_filters = LAZY_INSTANCE_INITIALIZER;
|
|
|
| -// Stores a bitmap of filters enabled for each category group.
|
| -uint32_t g_category_group_filters_enabled[MAX_CATEGORY_GROUPS] = {0};
|
| -
|
| class EventNameFilter : public TraceLog::TraceEventFilter {
|
| public:
|
| EventNameFilter(const base::DictionaryValue* filter_args) {
|
| @@ -181,14 +161,6 @@ class HeapProfilerFilter : public TraceLog::TraceEventFilter {
|
| 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;
|
| -const int kCategoryMetadata = 3;
|
| -const int kNumBuiltinCategories = 4;
|
| -// Skip default categories.
|
| -base::subtle::AtomicWord g_category_index = kNumBuiltinCategories;
|
| -
|
| // The name of the current thread. This is used to decide if the current
|
| // thread name has changed. We combine all the seen thread names into the
|
| // output name for the thread.
|
| @@ -217,7 +189,7 @@ void InitializeMetadataEvent(TraceEvent* trace_event,
|
| TimeTicks(),
|
| ThreadTicks(),
|
| TRACE_EVENT_PHASE_METADATA,
|
| - &g_category_group_enabled[kCategoryMetadata],
|
| + CategoryRegistry::kCategoryMetadata->state_ptr(),
|
| metadata_name,
|
| trace_event_internal::kGlobalScope, // scope
|
| trace_event_internal::kNoId, // id
|
| @@ -259,27 +231,12 @@ 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;
|
| -}
|
| -
|
| template <typename Function>
|
| void ForEachCategoryGroupFilter(const unsigned char* category_group_enabled,
|
| Function filter_fn) {
|
| - uint32_t filter_bitmap = g_category_group_filters_enabled[GetCategoryIndex(
|
| - category_group_enabled)];
|
| + const TraceCategory* category =
|
| + CategoryRegistry::GetCategoryByStatePtr(category_group_enabled);
|
| + uint32_t filter_bitmap = category->enabled_filters();
|
| int index = 0;
|
| while (filter_bitmap) {
|
| if (filter_bitmap & 1 && g_category_group_filters.Get()[index])
|
| @@ -473,18 +430,8 @@ TraceLog::TraceLog()
|
| thread_shared_chunk_index_(0),
|
| generation_(0),
|
| use_worker_thread_(false) {
|
| - // Trace is enabled or disabled on one thread while other threads are
|
| - // accessing the enabled flag. We don't care whether edge-case events are
|
| - // traced or not, so we allow races on the enabled flag to keep the trace
|
| - // macros fast.
|
| - // TODO(jbates): ANNOTATE_BENIGN_RACE_SIZED crashes windows TSAN bots:
|
| - // ANNOTATE_BENIGN_RACE_SIZED(g_category_group_enabled,
|
| - // sizeof(g_category_group_enabled),
|
| - // "trace_event category enabled");
|
| - for (int i = 0; i < MAX_CATEGORY_GROUPS; ++i) {
|
| - ANNOTATE_BENIGN_RACE(&g_category_group_enabled[i],
|
| - "trace_event category enabled");
|
| - }
|
| + CategoryRegistry::Initialize();
|
| +
|
| #if defined(OS_NACL) // NaCl shouldn't expose the process id.
|
| SetProcessID(0);
|
| #else
|
| @@ -543,43 +490,52 @@ const unsigned char* TraceLog::GetCategoryGroupEnabled(
|
| const char* category_group) {
|
| TraceLog* tracelog = GetInstance();
|
| if (!tracelog) {
|
| - DCHECK(!g_category_group_enabled[kCategoryAlreadyShutdown]);
|
| - return &g_category_group_enabled[kCategoryAlreadyShutdown];
|
| + DCHECK(!CategoryRegistry::kCategoryAlreadyShutdown->is_enabled());
|
| + return CategoryRegistry::kCategoryAlreadyShutdown->state_ptr();
|
| }
|
| - return tracelog->GetCategoryGroupEnabledInternal(category_group);
|
| + TraceCategory* category = nullptr;
|
| + bool is_new_category =
|
| + CategoryRegistry::GetOrCreateCategoryByName(category_group, &category);
|
| + if (is_new_category)
|
| + tracelog->UpdateCategoryState(category);
|
| + DCHECK(category->state_ptr());
|
| + return category->state_ptr();
|
| }
|
|
|
| const char* TraceLog::GetCategoryGroupName(
|
| const unsigned char* category_group_enabled) {
|
| - return g_category_groups[GetCategoryIndex(category_group_enabled)];
|
| + return CategoryRegistry::GetCategoryByStatePtr(category_group_enabled)
|
| + ->name();
|
| }
|
|
|
| -void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) {
|
| - unsigned char enabled_flag = 0;
|
| - const char* category_group = g_category_groups[category_index];
|
| +void TraceLog::UpdateCategoryState(TraceCategory* category) {
|
| + DCHECK(category->is_valid());
|
| + unsigned char state_flags = 0;
|
| if (enabled_modes_ & RECORDING_MODE &&
|
| - trace_config_.IsCategoryGroupEnabled(category_group)) {
|
| - enabled_flag |= ENABLED_FOR_RECORDING;
|
| + trace_config_.IsCategoryGroupEnabled(category->name())) {
|
| + state_flags |= TraceCategory::ENABLED_FOR_RECORDING;
|
| + }
|
| +
|
| + // TODO(primiano): this is a temporary workaround for catapult:#2341,
|
| + // to guarantee that metadata events are always added even if the category
|
| + // filter is "-*". See crbug.com/618054 for more details and long-term fix.
|
| + if (enabled_modes_ & RECORDING_MODE &&
|
| + category == CategoryRegistry::kCategoryMetadata) {
|
| + state_flags |= TraceCategory::ENABLED_FOR_RECORDING;
|
| }
|
|
|
| #if defined(OS_WIN)
|
| if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled(
|
| - category_group)) {
|
| - enabled_flag |= ENABLED_FOR_ETW_EXPORT;
|
| + category->name())) {
|
| + state_flags |= TraceCategory::ENABLED_FOR_ETW_EXPORT;
|
| }
|
| #endif
|
|
|
| - // TODO(primiano): this is a temporary workaround for catapult:#2341,
|
| - // to guarantee that metadata events are always added even if the category
|
| - // filter is "-*". See crbug.com/618054 for more details and long-term fix.
|
| - if (enabled_modes_ & RECORDING_MODE && !strcmp(category_group, "__metadata"))
|
| - enabled_flag |= ENABLED_FOR_RECORDING;
|
| -
|
| uint32_t enabled_filters_bitmap = 0;
|
| int index = 0;
|
| for (const auto& event_filter : enabled_event_filters_) {
|
| - if (event_filter.IsCategoryGroupEnabled(category_group)) {
|
| - enabled_flag |= ENABLED_FOR_FILTERING;
|
| + if (event_filter.IsCategoryGroupEnabled(category->name())) {
|
| + state_flags |= TraceCategory::ENABLED_FOR_FILTERING;
|
| DCHECK(g_category_group_filters.Get()[index]);
|
| enabled_filters_bitmap |= 1 << index;
|
| }
|
| @@ -588,16 +544,15 @@ void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) {
|
| break;
|
| }
|
| }
|
| - g_category_group_filters_enabled[category_index] = enabled_filters_bitmap;
|
| -
|
| - g_category_group_enabled[category_index] = enabled_flag;
|
| + category->set_enabled_filters(enabled_filters_bitmap);
|
| + category->set_state(state_flags);
|
| }
|
|
|
| -void TraceLog::UpdateCategoryGroupEnabledFlags() {
|
| +void TraceLog::UpdateCategoryRegistry() {
|
| CreateFiltersForTraceConfig();
|
| - size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
|
| - for (size_t i = 0; i < category_index; i++)
|
| - UpdateCategoryGroupEnabledFlag(i);
|
| + for (TraceCategory& category : CategoryRegistry::GetAllCategories()) {
|
| + UpdateCategoryState(&category);
|
| + }
|
| }
|
|
|
| void TraceLog::CreateFiltersForTraceConfig() {
|
| @@ -662,64 +617,12 @@ void TraceLog::UpdateSyntheticDelaysFromTraceConfig() {
|
| }
|
| }
|
|
|
| -const unsigned char* TraceLog::GetCategoryGroupEnabledInternal(
|
| - const char* category_group) {
|
| - DCHECK(!strchr(category_group, '"'))
|
| - << "Category groups may not contain double quote";
|
| - // The g_category_groups is append only, avoid using a lock for the fast path.
|
| - size_t current_category_index = base::subtle::Acquire_Load(&g_category_index);
|
| -
|
| - // Search for pre-existing category group.
|
| - for (size_t i = 0; i < current_category_index; ++i) {
|
| - if (strcmp(g_category_groups[i], category_group) == 0) {
|
| - return &g_category_group_enabled[i];
|
| - }
|
| - }
|
| -
|
| - // This is the slow path: the lock is not held in the case above, so more
|
| - // than one thread could have reached here trying to add the same category.
|
| - // Only hold to lock when actually appending a new category, and
|
| - // check the categories groups again.
|
| - AutoLock lock(lock_);
|
| - size_t category_index = base::subtle::Acquire_Load(&g_category_index);
|
| - for (size_t i = 0; i < category_index; ++i) {
|
| - if (strcmp(g_category_groups[i], category_group) == 0) {
|
| - return &g_category_group_enabled[i];
|
| - }
|
| - }
|
| -
|
| - // Create a new category group.
|
| - DCHECK(category_index < MAX_CATEGORY_GROUPS)
|
| - << "must increase MAX_CATEGORY_GROUPS";
|
| - unsigned char* category_group_enabled = nullptr;
|
| - if (category_index < MAX_CATEGORY_GROUPS) {
|
| - // Don't hold on to the category_group pointer, so that we can create
|
| - // category groups with strings not known at compile time (this is
|
| - // required by SetWatchEvent).
|
| - const char* new_group = strdup(category_group);
|
| - ANNOTATE_LEAKING_OBJECT_PTR(new_group);
|
| - g_category_groups[category_index] = new_group;
|
| - DCHECK(!g_category_group_enabled[category_index]);
|
| - // Note that if both included and excluded patterns in the
|
| - // TraceConfig are empty, we exclude nothing,
|
| - // thereby enabling this category group.
|
| - UpdateCategoryGroupEnabledFlag(category_index);
|
| - category_group_enabled = &g_category_group_enabled[category_index];
|
| - // Update the max index now.
|
| - base::subtle::Release_Store(&g_category_index, category_index + 1);
|
| - } else {
|
| - category_group_enabled =
|
| - &g_category_group_enabled[kCategoryCategoriesExhausted];
|
| - }
|
| - return category_group_enabled;
|
| -}
|
| -
|
| void TraceLog::GetKnownCategoryGroups(
|
| std::vector<std::string>* category_groups) {
|
| - AutoLock lock(lock_);
|
| - size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
|
| - for (size_t i = kNumBuiltinCategories; i < category_index; i++)
|
| - category_groups->push_back(g_category_groups[i]);
|
| + for (const auto& category : CategoryRegistry::GetAllCategories()) {
|
| + if (!CategoryRegistry::IsBuiltinCategory(&category))
|
| + category_groups->push_back(category.name());
|
| + }
|
| }
|
|
|
| void TraceLog::SetEnabled(const TraceConfig& trace_config,
|
| @@ -783,7 +686,7 @@ void TraceLog::SetEnabled(const TraceConfig& trace_config,
|
| trace_config_.SetEventFilters(enabled_event_filters_);
|
|
|
| enabled_modes_ |= modes_to_enable;
|
| - UpdateCategoryGroupEnabledFlags();
|
| + UpdateCategoryRegistry();
|
|
|
| // Do not notify observers or create trace buffer if only enabled for
|
| // filtering or if recording was already enabled.
|
| @@ -797,7 +700,7 @@ void TraceLog::SetEnabled(const TraceConfig& trace_config,
|
|
|
| num_traces_recorded_++;
|
|
|
| - UpdateCategoryGroupEnabledFlags();
|
| + UpdateCategoryRegistry();
|
| UpdateSyntheticDelaysFromTraceConfig();
|
|
|
| dispatching_to_observer_list_ = true;
|
| @@ -885,7 +788,7 @@ void TraceLog::SetDisabledWhileLocked(uint8_t modes_to_disable) {
|
| trace_config_.Clear();
|
| }
|
|
|
| - UpdateCategoryGroupEnabledFlags();
|
| + UpdateCategoryRegistry();
|
|
|
| // Add metadata events and notify observers only if recording mode was
|
| // disabled now.
|
| @@ -1411,7 +1314,7 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
|
| #if defined(OS_WIN)
|
| // This is done sooner rather than later, to avoid creating the event and
|
| // acquiring the lock, which is not needed for ETW as it's already threadsafe.
|
| - if (*category_group_enabled & ENABLED_FOR_ETW_EXPORT)
|
| + if (*category_group_enabled & TraceCategory::ENABLED_FOR_ETW_EXPORT)
|
| TraceEventETWExport::AddEvent(phase, category_group_enabled, name, id,
|
| num_args, arg_names, arg_types, arg_values,
|
| convertable_values);
|
| @@ -1420,7 +1323,7 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
|
| std::string console_message;
|
| std::unique_ptr<TraceEvent> filtered_trace_event;
|
| bool disabled_by_filters = false;
|
| - if (*category_group_enabled & ENABLED_FOR_FILTERING) {
|
| + if (*category_group_enabled & TraceCategory::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,
|
| @@ -1440,7 +1343,7 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
|
|
|
| // If enabled for recording, the event should be added only if one of the
|
| // filters indicates or category is not enabled for filtering.
|
| - if ((*category_group_enabled & ENABLED_FOR_RECORDING) &&
|
| + if ((*category_group_enabled & TraceCategory::ENABLED_FOR_RECORDING) &&
|
| !disabled_by_filters) {
|
| OptionalAutoLock lock(&lock_);
|
|
|
| @@ -1586,12 +1489,12 @@ void TraceLog::UpdateTraceEventDuration(
|
|
|
| #if defined(OS_WIN)
|
| // Generate an ETW event that marks the end of a complete event.
|
| - if (category_group_enabled_local & ENABLED_FOR_ETW_EXPORT)
|
| + if (category_group_enabled_local & TraceCategory::ENABLED_FOR_ETW_EXPORT)
|
| TraceEventETWExport::AddCompleteEndEvent(name);
|
| #endif // OS_WIN
|
|
|
| std::string console_message;
|
| - if (category_group_enabled_local & ENABLED_FOR_RECORDING) {
|
| + if (category_group_enabled_local & TraceCategory::ENABLED_FOR_RECORDING) {
|
| OptionalAutoLock lock(&lock_);
|
|
|
| TraceEvent* trace_event = GetEventByHandleInternal(handle, &lock);
|
| @@ -1624,7 +1527,7 @@ void TraceLog::UpdateTraceEventDuration(
|
| if (!console_message.empty())
|
| LOG(ERROR) << console_message;
|
|
|
| - if (category_group_enabled_local & ENABLED_FOR_FILTERING)
|
| + if (category_group_enabled_local & TraceCategory::ENABLED_FOR_FILTERING)
|
| EndFilteredEvent(category_group_enabled, name, handle);
|
| }
|
|
|
| @@ -1699,6 +1602,7 @@ void TraceLog::AddMetadataEventsWhileLocked() {
|
|
|
| void TraceLog::DeleteForTesting() {
|
| internal::DeleteTraceLogForTesting::Delete();
|
| + CategoryRegistry::ResetForTesting();
|
| }
|
|
|
| void TraceLog::SetTraceEventFilterConstructorForTesting(
|
| @@ -1815,18 +1719,14 @@ TraceBuffer* TraceLog::CreateTraceBuffer() {
|
|
|
| #if defined(OS_WIN)
|
| void TraceLog::UpdateETWCategoryGroupEnabledFlags() {
|
| - AutoLock lock(lock_);
|
| - size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
|
| // Go through each category and set/clear the ETW bit depending on whether the
|
| // category is enabled.
|
| - for (size_t i = 0; i < category_index; i++) {
|
| - const char* category_group = g_category_groups[i];
|
| - DCHECK(category_group);
|
| + for (TraceCategory& category : CategoryRegistry::GetAllCategories()) {
|
| if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled(
|
| - category_group)) {
|
| - g_category_group_enabled[i] |= ENABLED_FOR_ETW_EXPORT;
|
| + category.name())) {
|
| + category.set_state_flag(TraceCategory::ENABLED_FOR_ETW_EXPORT);
|
| } else {
|
| - g_category_group_enabled[i] &= ~ENABLED_FOR_ETW_EXPORT;
|
| + category.clear_state_flag(TraceCategory::ENABLED_FOR_ETW_EXPORT);
|
| }
|
| }
|
| }
|
|
|