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); |
} |
} |
} |