summaryrefslogtreecommitdiff
path: root/base/trace_event
diff options
context:
space:
mode:
Diffstat (limited to 'base/trace_event')
-rw-r--r--base/trace_event/category_registry.cc156
-rw-r--r--base/trace_event/category_registry.h93
-rw-r--r--base/trace_event/common/trace_event_common.h163
-rw-r--r--base/trace_event/etw_manifest/etw_manifest.gyp41
-rw-r--r--base/trace_event/event_name_filter.cc26
-rw-r--r--base/trace_event/event_name_filter.h46
-rw-r--r--base/trace_event/event_name_filter_unittest.cc41
-rw-r--r--base/trace_event/heap_profiler_allocation_context_tracker.cc58
-rw-r--r--base/trace_event/heap_profiler_allocation_context_tracker.h27
-rw-r--r--base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc97
-rw-r--r--base/trace_event/heap_profiler_allocation_register.cc8
-rw-r--r--base/trace_event/heap_profiler_allocation_register.h32
-rw-r--r--base/trace_event/heap_profiler_event_filter.cc67
-rw-r--r--base/trace_event/heap_profiler_event_filter.h40
-rw-r--r--base/trace_event/heap_profiler_heap_dump_writer.cc3
-rw-r--r--base/trace_event/heap_profiler_stack_frame_deduplicator.cc20
-rw-r--r--base/trace_event/heap_profiler_stack_frame_deduplicator.h2
-rw-r--r--base/trace_event/heap_profiler_type_name_deduplicator.cc28
-rw-r--r--base/trace_event/malloc_dump_provider.cc178
-rw-r--r--base/trace_event/malloc_dump_provider.h2
-rw-r--r--base/trace_event/memory_allocator_dump.h6
-rw-r--r--base/trace_event/memory_dump_manager.cc314
-rw-r--r--base/trace_event/memory_dump_manager.h65
-rw-r--r--base/trace_event/memory_dump_manager_unittest.cc200
-rw-r--r--base/trace_event/memory_dump_provider.h20
-rw-r--r--base/trace_event/memory_dump_request_args.cc17
-rw-r--r--base/trace_event/memory_dump_request_args.h18
-rw-r--r--base/trace_event/memory_dump_scheduler.cc304
-rw-r--r--base/trace_event/memory_dump_scheduler.h141
-rw-r--r--base/trace_event/memory_dump_session_state.cc15
-rw-r--r--base/trace_event/memory_dump_session_state.h22
-rw-r--r--base/trace_event/memory_infra_background_whitelist.cc71
-rw-r--r--base/trace_event/memory_usage_estimator.cc14
-rw-r--r--base/trace_event/memory_usage_estimator.h549
-rw-r--r--base/trace_event/memory_usage_estimator_unittest.cc244
-rw-r--r--base/trace_event/process_memory_dump.cc24
-rw-r--r--base/trace_event/process_memory_dump.h1
-rw-r--r--base/trace_event/trace_buffer.cc13
-rw-r--r--base/trace_event/trace_category.h109
-rw-r--r--base/trace_event/trace_config.cc249
-rw-r--r--base/trace_event/trace_config.h63
-rw-r--r--base/trace_event/trace_config_memory_test_util.h181
-rw-r--r--base/trace_event/trace_config_unittest.cc178
-rw-r--r--base/trace_event/trace_event.gypi107
-rw-r--r--base/trace_event/trace_event.h407
-rw-r--r--base/trace_event/trace_event_argument.cc36
-rw-r--r--base/trace_event/trace_event_argument_unittest.cc10
-rw-r--r--base/trace_event/trace_event_filter.cc21
-rw-r--r--base/trace_event/trace_event_filter.h51
-rw-r--r--base/trace_event/trace_event_filter_test_utils.cc61
-rw-r--r--base/trace_event/trace_event_filter_test_utils.h53
-rw-r--r--base/trace_event/trace_event_impl.cc68
-rw-r--r--base/trace_event/trace_event_impl.h5
-rw-r--r--base/trace_event/trace_event_memory_overhead.cc20
-rw-r--r--base/trace_event/trace_event_synthetic_delay.h3
-rw-r--r--base/trace_event/trace_event_unittest.cc770
-rw-r--r--base/trace_event/trace_log.cc750
-rw-r--r--base/trace_event/trace_log.h140
-rw-r--r--base/trace_event/trace_log_constants.cc3
-rw-r--r--base/trace_event/trace_sampling_thread.cc107
-rw-r--r--base/trace_event/trace_sampling_thread.h54
61 files changed, 2052 insertions, 4560 deletions
diff --git a/base/trace_event/category_registry.cc b/base/trace_event/category_registry.cc
deleted file mode 100644
index e7c14606d6..0000000000
--- a/base/trace_event/category_registry.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2016 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.
-
-#include "base/trace_event/category_registry.h"
-
-#include <string.h>
-
-#include <type_traits>
-
-#include "base/atomicops.h"
-#include "base/debug/leak_annotations.h"
-#include "base/logging.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "base/trace_event/trace_category.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-constexpr size_t kMaxCategories = 200;
-const int kNumBuiltinCategories = 4;
-
-// |g_categories| might end up causing creating dynamic initializers if not POD.
-static_assert(std::is_pod<TraceCategory>::value, "TraceCategory must be POD");
-
-// These entries must be kept consistent with the kCategory* consts below.
-TraceCategory g_categories[kMaxCategories] = {
- {0, 0, "tracing categories exhausted; must increase kMaxCategories"},
- {0, 0, "tracing already shutdown"}, // See kCategoryAlreadyShutdown below.
- {0, 0, "__metadata"}, // See kCategoryMetadata below.
- {0, 0, "toplevel"}, // Warmup the toplevel category.
-};
-
-base::subtle::AtomicWord g_category_index = kNumBuiltinCategories;
-
-bool IsValidCategoryPtr(const TraceCategory* category) {
- // If any of these are hit, something has cached a corrupt category pointer.
- uintptr_t ptr = reinterpret_cast<uintptr_t>(category);
- return ptr % sizeof(void*) == 0 &&
- ptr >= reinterpret_cast<uintptr_t>(&g_categories[0]) &&
- ptr <= reinterpret_cast<uintptr_t>(&g_categories[kMaxCategories - 1]);
-}
-
-} // namespace
-
-// static
-TraceCategory* const CategoryRegistry::kCategoryExhausted = &g_categories[0];
-TraceCategory* const CategoryRegistry::kCategoryAlreadyShutdown =
- &g_categories[1];
-TraceCategory* const CategoryRegistry::kCategoryMetadata = &g_categories[2];
-
-// static
-void CategoryRegistry::Initialize() {
- // 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.
- for (size_t i = 0; i < kMaxCategories; ++i) {
- ANNOTATE_BENIGN_RACE(g_categories[i].state_ptr(),
- "trace_event category enabled");
- // If this DCHECK is hit in a test it means that ResetForTesting() is not
- // called and the categories state leaks between test fixtures.
- DCHECK(!g_categories[i].is_enabled());
- }
-}
-
-// static
-void CategoryRegistry::ResetForTesting() {
- // reset_for_testing clears up only the enabled state and filters. The
- // categories themselves cannot be cleared up because the static pointers
- // injected by the macros still point to them and cannot be reset.
- for (size_t i = 0; i < kMaxCategories; ++i)
- g_categories[i].reset_for_testing();
-}
-
-// static
-TraceCategory* CategoryRegistry::GetCategoryByName(const char* category_name) {
- DCHECK(!strchr(category_name, '"'))
- << "Category names may not contain double quote";
-
- // The g_categories is append only, avoid using a lock for the fast path.
- size_t category_index = base::subtle::Acquire_Load(&g_category_index);
-
- // Search for pre-existing category group.
- for (size_t i = 0; i < category_index; ++i) {
- if (strcmp(g_categories[i].name(), category_name) == 0) {
- return &g_categories[i];
- }
- }
- return nullptr;
-}
-
-bool CategoryRegistry::GetOrCreateCategoryLocked(
- const char* category_name,
- CategoryInitializerFn category_initializer_fn,
- TraceCategory** category) {
- // This is the slow path: the lock is not held in the fastpath
- // (GetCategoryByName), so more than one thread could have reached here trying
- // to add the same category.
- *category = GetCategoryByName(category_name);
- if (*category)
- return false;
-
- // Create a new category.
- size_t category_index = base::subtle::Acquire_Load(&g_category_index);
- if (category_index >= kMaxCategories) {
- NOTREACHED() << "must increase kMaxCategories";
- *category = kCategoryExhausted;
- return false;
- }
-
- // TODO(primiano): this strdup should be removed. The only documented reason
- // for it was TraceWatchEvent, which is gone. However, something might have
- // ended up relying on this. Needs some auditing before removal.
- const char* category_name_copy = strdup(category_name);
- ANNOTATE_LEAKING_OBJECT_PTR(category_name_copy);
-
- *category = &g_categories[category_index];
- DCHECK(!(*category)->is_valid());
- DCHECK(!(*category)->is_enabled());
- (*category)->set_name(category_name_copy);
- category_initializer_fn(*category);
-
- // Update the max index now.
- base::subtle::Release_Store(&g_category_index, category_index + 1);
- return true;
-}
-
-// static
-const TraceCategory* CategoryRegistry::GetCategoryByStatePtr(
- const uint8_t* category_state) {
- const TraceCategory* category = TraceCategory::FromStatePtr(category_state);
- DCHECK(IsValidCategoryPtr(category));
- return category;
-}
-
-// static
-bool CategoryRegistry::IsBuiltinCategory(const TraceCategory* category) {
- DCHECK(IsValidCategoryPtr(category));
- return category < &g_categories[kNumBuiltinCategories];
-}
-
-// static
-CategoryRegistry::Range CategoryRegistry::GetAllCategories() {
- // The |g_categories| array is append only. We have to only guarantee to
- // not return an index to a category which is being initialized by
- // GetOrCreateCategoryByName().
- size_t category_index = base::subtle::Acquire_Load(&g_category_index);
- return CategoryRegistry::Range(&g_categories[0],
- &g_categories[category_index]);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/category_registry.h b/base/trace_event/category_registry.h
deleted file mode 100644
index 9c08efa3e1..0000000000
--- a/base/trace_event/category_registry.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2016 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 BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_
-#define BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/base_export.h"
-#include "base/logging.h"
-
-namespace base {
-namespace trace_event {
-
-struct TraceCategory;
-class TraceCategoryTest;
-class TraceLog;
-
-// Allows fast and thread-safe acces to the state of all tracing categories.
-// All the methods in this class can be concurrently called on multiple threads,
-// unless otherwise noted (e.g., GetOrCreateCategoryLocked).
-// The reason why this is a fully static class with global state is to allow to
-// statically define known categories as global linker-initialized structs,
-// without requiring static initializers.
-class BASE_EXPORT CategoryRegistry {
- public:
- // Allows for-each iterations over a slice of the categories array.
- class Range {
- public:
- Range(TraceCategory* begin, TraceCategory* end) : begin_(begin), end_(end) {
- DCHECK_LE(begin, end);
- }
- TraceCategory* begin() const { return begin_; }
- TraceCategory* end() const { return end_; }
-
- private:
- TraceCategory* const begin_;
- TraceCategory* const end_;
- };
-
- // Known categories.
- static TraceCategory* const kCategoryExhausted;
- static TraceCategory* const kCategoryMetadata;
- static TraceCategory* const kCategoryAlreadyShutdown;
-
- // Returns a category entry from the Category.state_ptr() pointer.
- // TODO(primiano): trace macros should just keep a pointer to the entire
- // TraceCategory, not just the enabled state pointer. That would remove the
- // need for this function and make everything cleaner at no extra cost (as
- // long as the |state_| is the first field of the struct, which can be
- // guaranteed via static_assert, see TraceCategory ctor).
- static const TraceCategory* GetCategoryByStatePtr(
- const uint8_t* category_state);
-
- // Returns a category from its name or nullptr if not found.
- // The output |category| argument is an undefinitely lived pointer to the
- // TraceCategory owned by the registry. TRACE_EVENTx macros will cache this
- // pointer and use it for checks in their fast-paths.
- static TraceCategory* GetCategoryByName(const char* category_name);
-
- static bool IsBuiltinCategory(const TraceCategory*);
-
- private:
- friend class TraceCategoryTest;
- friend class TraceLog;
- using CategoryInitializerFn = void (*)(TraceCategory*);
-
- // Only for debugging/testing purposes, is a no-op on release builds.
- static void Initialize();
-
- // Resets the state of all categories, to clear up the state between tests.
- static void ResetForTesting();
-
- // Used to get/create a category in the slow-path. If the category exists
- // already, this has the same effect of GetCategoryByName and returns false.
- // If not, a new category is created and the CategoryInitializerFn is invoked
- // before retuning true. The caller must guarantee serialization: either call
- // this method from a single thread or hold a lock when calling this.
- static bool GetOrCreateCategoryLocked(const char* category_name,
- CategoryInitializerFn,
- TraceCategory**);
-
- // Allows to iterate over the valid categories in a for-each loop.
- // This includes builtin categories such as __metadata.
- static Range GetAllCategories();
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_
diff --git a/base/trace_event/common/trace_event_common.h b/base/trace_event/common/trace_event_common.h
index bb6fa1b82b..0a04d62710 100644
--- a/base/trace_event/common/trace_event_common.h
+++ b/base/trace_event/common/trace_event_common.h
@@ -223,6 +223,49 @@
flow_flags, arg1_name, arg1_val, \
arg2_name, arg2_val)
+// UNSHIPPED_TRACE_EVENT* are like TRACE_EVENT* except that they are not
+// included in official builds.
+
+#if OFFICIAL_BUILD
+#undef TRACING_IS_OFFICIAL_BUILD
+#define TRACING_IS_OFFICIAL_BUILD 1
+#elif !defined(TRACING_IS_OFFICIAL_BUILD)
+#define TRACING_IS_OFFICIAL_BUILD 0
+#endif
+
+#if TRACING_IS_OFFICIAL_BUILD
+#define UNSHIPPED_TRACE_EVENT0(category_group, name) (void)0
+#define UNSHIPPED_TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+ (void)0
+#define UNSHIPPED_TRACE_EVENT2(category_group, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT0(category_group, name, scope) (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, \
+ arg1_val) \
+ (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, \
+ arg1_val, arg2_name, arg2_val) \
+ (void)0
+#else
+#define UNSHIPPED_TRACE_EVENT0(category_group, name) \
+ TRACE_EVENT0(category_group, name)
+#define UNSHIPPED_TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+ TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
+#define UNSHIPPED_TRACE_EVENT2(category_group, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)
+#define UNSHIPPED_TRACE_EVENT_INSTANT0(category_group, name, scope) \
+ TRACE_EVENT_INSTANT0(category_group, name, scope)
+#define UNSHIPPED_TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, \
+ arg1_val) \
+ TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, arg1_val)
+#define UNSHIPPED_TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, \
+ arg1_val, arg2_name, arg2_val) \
+ TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, arg1_val, \
+ arg2_name, arg2_val)
+#endif
+
// Records a single event called "name" immediately, with 0, 1 or 2
// associated arguments. If the category is not enabled, then this
// does nothing.
@@ -254,10 +297,20 @@
#define TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(category_group, name, scope, \
timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \
- TRACE_EVENT_PHASE_INSTANT, category_group, name, timestamp, \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_INSTANT, category_group, name, 0, 0, timestamp, \
TRACE_EVENT_FLAG_NONE | scope)
+// Syntactic sugars for the sampling tracing in the main thread.
+#define TRACE_EVENT_SCOPED_SAMPLING_STATE(category, name) \
+ TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(0, category, name)
+#define TRACE_EVENT_GET_SAMPLING_STATE() \
+ TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(0)
+#define TRACE_EVENT_SET_SAMPLING_STATE(category, name) \
+ TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(0, category, name)
+#define TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(categoryAndName) \
+ TRACE_EVENT_SET_NONCONST_SAMPLING_STATE_FOR_BUCKET(0, categoryAndName)
+
// Records a single BEGIN event called "name" immediately, with 0, 1 or 2
// associated arguments. If the category is not enabled, then this
// does nothing.
@@ -342,15 +395,10 @@
TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
arg2_name, arg2_val)
-#define TRACE_EVENT_MARK_WITH_TIMESTAMP0(category_group, name, timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \
- TRACE_EVENT_PHASE_MARK, category_group, name, timestamp, \
- TRACE_EVENT_FLAG_NONE)
-
#define TRACE_EVENT_MARK_WITH_TIMESTAMP1(category_group, name, timestamp, \
arg1_name, arg1_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \
- TRACE_EVENT_PHASE_MARK, category_group, name, timestamp, \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_MARK, category_group, name, 0, 0, timestamp, \
TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
#define TRACE_EVENT_COPY_MARK(category_group, name) \
@@ -358,8 +406,8 @@
TRACE_EVENT_FLAG_COPY)
#define TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(category_group, name, timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \
- TRACE_EVENT_PHASE_MARK, category_group, name, timestamp, \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_MARK, category_group, name, 0, 0, timestamp, \
TRACE_EVENT_FLAG_COPY)
// Similar to TRACE_EVENT_ENDx but with a custom |at| timestamp provided.
@@ -496,12 +544,6 @@
TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
-#define TRACE_EVENT_SAMPLE_WITH_ID1(category_group, name, id, arg1_name, \
- arg1_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_SAMPLE, category_group, \
- name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \
- arg1_val)
-
// ASYNC_STEP_* APIs should be only used by legacy code. New code should
// consider using NESTABLE_ASYNC_* APIs to describe substeps within an async
// event.
@@ -570,13 +612,6 @@
TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
arg1_name, arg1_val)
-#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP2(category_group, name, id, \
- timestamp, arg1_name, \
- arg1_val, arg2_name, arg2_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
- TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
- TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
- arg1_name, arg1_val, arg2_name, arg2_val)
#define TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, id, \
timestamp) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
@@ -666,13 +701,6 @@
TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \
TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
arg1_name, arg1_val)
-#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP2(category_group, name, id, \
- timestamp, arg1_name, arg1_val, \
- arg2_name, arg2_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
- TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \
- TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
- arg1_name, arg1_val, arg2_name, arg2_val)
// NESTABLE_ASYNC_* APIs are used to describe an async operation, which can
// be nested within a NESTABLE_ASYNC event and/or have inner NESTABLE_ASYNC
@@ -732,19 +760,16 @@
TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
-// with none, one or two associated argument. If the category is not enabled,
-// then this does nothing.
-#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT0(category_group, name, id) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, \
- category_group, name, id, \
- TRACE_EVENT_FLAG_NONE)
-
+// with one associated argument. If the category is not enabled, then this
+// does nothing.
#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT1(category_group, name, id, \
arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, \
category_group, name, id, \
TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
-
+// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
+// with 2 associated arguments. If the category is not enabled, then this
+// does nothing.
#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT2( \
category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
@@ -919,58 +944,48 @@
#define TRACE_EVENT_CLOCK_SYNC_ISSUER(sync_id, issue_ts, issue_end_ts) \
INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \
TRACE_EVENT_PHASE_CLOCK_SYNC, "__metadata", "clock_sync", \
- issue_end_ts, TRACE_EVENT_FLAG_NONE, \
- "sync_id", sync_id, "issue_ts", issue_ts)
+ issue_end_ts.ToInternalValue(), TRACE_EVENT_FLAG_NONE, \
+ "sync_id", sync_id, "issue_ts", issue_ts.ToInternalValue())
// Macros to track the life time and value of arbitrary client objects.
// See also TraceTrackableObject.
#define TRACE_EVENT_OBJECT_CREATED_WITH_ID(category_group, name, id) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
- TRACE_EVENT_PHASE_CREATE_OBJECT, category_group, name, id, \
- TRACE_EVENT_FLAG_NONE)
+ TRACE_EVENT_PHASE_CREATE_OBJECT, category_group, name, \
+ TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE)
#define TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(category_group, name, id, \
snapshot) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, category_group, name, \
- id, TRACE_EVENT_FLAG_NONE, "snapshot", snapshot)
+ TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE, "snapshot", snapshot)
-#define TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID_AND_TIMESTAMP( \
- category_group, name, id, timestamp, snapshot) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
- TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, category_group, name, \
- id, TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
- "snapshot", snapshot)
+#define TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID_AND_TIMESTAMP( \
+ category_group, name, id, timestamp, snapshot) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, category_group, name, \
+ TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, \
+ TRACE_EVENT_FLAG_NONE, "snapshot", snapshot)
#define TRACE_EVENT_OBJECT_DELETED_WITH_ID(category_group, name, id) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
- TRACE_EVENT_PHASE_DELETE_OBJECT, category_group, name, id, \
- TRACE_EVENT_FLAG_NONE)
+ TRACE_EVENT_PHASE_DELETE_OBJECT, category_group, name, \
+ TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE)
// Records entering and leaving trace event contexts. |category_group| and
// |name| specify the context category and type. |context| is a
// snapshotted context object id.
-#define TRACE_EVENT_ENTER_CONTEXT(category_group, name, context) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
- TRACE_EVENT_PHASE_ENTER_CONTEXT, category_group, name, context, \
- TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_LEAVE_CONTEXT(category_group, name, context) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
- TRACE_EVENT_PHASE_LEAVE_CONTEXT, category_group, name, context, \
- TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ENTER_CONTEXT(category_group, name, context) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
+ TRACE_EVENT_PHASE_ENTER_CONTEXT, category_group, name, \
+ TRACE_ID_DONT_MANGLE(context), TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_LEAVE_CONTEXT(category_group, name, context) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
+ TRACE_EVENT_PHASE_LEAVE_CONTEXT, category_group, name, \
+ TRACE_ID_DONT_MANGLE(context), TRACE_EVENT_FLAG_NONE)
#define TRACE_EVENT_SCOPED_CONTEXT(category_group, name, context) \
- INTERNAL_TRACE_EVENT_SCOPED_CONTEXT(category_group, name, context)
-
-// Macro to specify that two trace IDs are identical. For example,
-// TRACE_LINK_IDS(
-// "category", "name",
-// TRACE_ID_WITH_SCOPE("net::URLRequest", 0x1000),
-// TRACE_ID_WITH_SCOPE("blink::ResourceFetcher::FetchRequest", 0x2000))
-// tells the trace consumer that events with ID ("net::URLRequest", 0x1000) from
-// the current process have the same ID as events with ID
-// ("blink::ResourceFetcher::FetchRequest", 0x2000).
-#define TRACE_LINK_IDS(category_group, name, id, linked_id) \
- INTERNAL_TRACE_EVENT_ADD_LINK_IDS(category_group, name, id, linked_id);
+ INTERNAL_TRACE_EVENT_SCOPED_CONTEXT(category_group, name, \
+ TRACE_ID_DONT_MANGLE(context))
// Macro to efficiently determine if a given category group is enabled.
#define TRACE_EVENT_CATEGORY_GROUP_ENABLED(category_group, ret) \
@@ -1037,13 +1052,11 @@
#define TRACE_EVENT_PHASE_CLOCK_SYNC ('c')
#define TRACE_EVENT_PHASE_ENTER_CONTEXT ('(')
#define TRACE_EVENT_PHASE_LEAVE_CONTEXT (')')
-#define TRACE_EVENT_PHASE_LINK_IDS ('=')
// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
#define TRACE_EVENT_FLAG_NONE (static_cast<unsigned int>(0))
#define TRACE_EVENT_FLAG_COPY (static_cast<unsigned int>(1 << 0))
#define TRACE_EVENT_FLAG_HAS_ID (static_cast<unsigned int>(1 << 1))
-// TODO(crbug.com/639003): Free this bit after ID mangling is deprecated.
#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast<unsigned int>(1 << 2))
#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast<unsigned int>(1 << 3))
#define TRACE_EVENT_FLAG_SCOPE_EXTRA (static_cast<unsigned int>(1 << 4))
@@ -1054,8 +1067,6 @@
#define TRACE_EVENT_FLAG_FLOW_OUT (static_cast<unsigned int>(1 << 9))
#define TRACE_EVENT_FLAG_HAS_CONTEXT_ID (static_cast<unsigned int>(1 << 10))
#define TRACE_EVENT_FLAG_HAS_PROCESS_ID (static_cast<unsigned int>(1 << 11))
-#define TRACE_EVENT_FLAG_HAS_LOCAL_ID (static_cast<unsigned int>(1 << 12))
-#define TRACE_EVENT_FLAG_HAS_GLOBAL_ID (static_cast<unsigned int>(1 << 13))
#define TRACE_EVENT_FLAG_SCOPE_MASK \
(static_cast<unsigned int>(TRACE_EVENT_FLAG_SCOPE_OFFSET | \
diff --git a/base/trace_event/etw_manifest/etw_manifest.gyp b/base/trace_event/etw_manifest/etw_manifest.gyp
new file mode 100644
index 0000000000..b2f0eb8ea1
--- /dev/null
+++ b/base/trace_event/etw_manifest/etw_manifest.gyp
@@ -0,0 +1,41 @@
+# Copyright 2015 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.
+{
+ 'targets': [
+ {
+ # GN version: //base/trace_event/etw_manifest/BUILD.gn
+ 'target_name': 'etw_manifest',
+ 'type': 'none',
+ 'toolsets': ['host', 'target'],
+ 'hard_dependency': 1,
+ 'conditions': [
+ ['OS=="win"', {
+ 'sources': [
+ 'chrome_events_win.man',
+ ],
+ 'variables': {
+ 'man_output_dir': '<(SHARED_INTERMEDIATE_DIR)/base/trace_event/etw_manifest',
+ },
+ 'rules': [{
+ # Rule to run the message compiler.
+ 'rule_name': 'message_compiler',
+ 'extension': 'man',
+ 'outputs': [
+ '<(man_output_dir)/chrome_events_win.h',
+ '<(man_output_dir)/chrome_events_win.rc',
+ ],
+ 'action': [
+ 'mc.exe',
+ '-h', '<(man_output_dir)',
+ '-r', '<(man_output_dir)/.',
+ '-um',
+ '<(RULE_INPUT_PATH)',
+ ],
+ 'message': 'Running message compiler on <(RULE_INPUT_PATH)',
+ }],
+ }],
+ ],
+ }
+ ]
+}
diff --git a/base/trace_event/event_name_filter.cc b/base/trace_event/event_name_filter.cc
deleted file mode 100644
index 8d0058c147..0000000000
--- a/base/trace_event/event_name_filter.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2016 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.
-
-#include "base/trace_event/event_name_filter.h"
-
-#include "base/trace_event/trace_event_impl.h"
-
-namespace base {
-namespace trace_event {
-
-// static
-const char EventNameFilter::kName[] = "event_whitelist_predicate";
-
-EventNameFilter::EventNameFilter(
- std::unique_ptr<EventNamesWhitelist> event_names_whitelist)
- : event_names_whitelist_(std::move(event_names_whitelist)) {}
-
-EventNameFilter::~EventNameFilter() {}
-
-bool EventNameFilter::FilterTraceEvent(const TraceEvent& trace_event) const {
- return event_names_whitelist_->count(trace_event.name()) != 0;
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/event_name_filter.h b/base/trace_event/event_name_filter.h
deleted file mode 100644
index 19333b3e03..0000000000
--- a/base/trace_event/event_name_filter.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2016 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 BASE_TRACE_EVENT_EVENT_NAME_FILTER_H_
-#define BASE_TRACE_EVENT_EVENT_NAME_FILTER_H_
-
-#include <memory>
-#include <string>
-#include <unordered_set>
-
-#include "base/base_export.h"
-#include "base/macros.h"
-#include "base/trace_event/trace_event_filter.h"
-
-namespace base {
-namespace trace_event {
-
-class TraceEvent;
-
-// Filters trace events by checking the full name against a whitelist.
-// The current implementation is quite simple and dumb and just uses a
-// hashtable which requires char* to std::string conversion. It could be smarter
-// and use a bloom filter trie. However, today this is used too rarely to
-// justify that cost.
-class BASE_EXPORT EventNameFilter : public TraceEventFilter {
- public:
- using EventNamesWhitelist = std::unordered_set<std::string>;
- static const char kName[];
-
- EventNameFilter(std::unique_ptr<EventNamesWhitelist>);
- ~EventNameFilter() override;
-
- // TraceEventFilter implementation.
- bool FilterTraceEvent(const TraceEvent&) const override;
-
- private:
- std::unique_ptr<const EventNamesWhitelist> event_names_whitelist_;
-
- DISALLOW_COPY_AND_ASSIGN(EventNameFilter);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_EVENT_NAME_FILTER_H_
diff --git a/base/trace_event/event_name_filter_unittest.cc b/base/trace_event/event_name_filter_unittest.cc
deleted file mode 100644
index 0bc2a4dafc..0000000000
--- a/base/trace_event/event_name_filter_unittest.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 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.
-
-#include "base/trace_event/event_name_filter.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/trace_event/trace_event_impl.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace trace_event {
-
-const TraceEvent& MakeTraceEvent(const char* name) {
- static TraceEvent event;
- event.Reset();
- event.Initialize(0, TimeTicks(), ThreadTicks(), 'b', nullptr, name, "", 0, 0,
- 0, nullptr, nullptr, nullptr, nullptr, 0);
- return event;
-}
-
-TEST(TraceEventNameFilterTest, Whitelist) {
- auto empty_whitelist = MakeUnique<EventNameFilter::EventNamesWhitelist>();
- auto filter = MakeUnique<EventNameFilter>(std::move(empty_whitelist));
-
- // No events should be filtered if the whitelist is empty.
- EXPECT_FALSE(filter->FilterTraceEvent(MakeTraceEvent("foo")));
-
- auto whitelist = MakeUnique<EventNameFilter::EventNamesWhitelist>();
- whitelist->insert("foo");
- whitelist->insert("bar");
- filter = MakeUnique<EventNameFilter>(std::move(whitelist));
- EXPECT_TRUE(filter->FilterTraceEvent(MakeTraceEvent("foo")));
- EXPECT_FALSE(filter->FilterTraceEvent(MakeTraceEvent("fooz")));
- EXPECT_FALSE(filter->FilterTraceEvent(MakeTraceEvent("afoo")));
- EXPECT_TRUE(filter->FilterTraceEvent(MakeTraceEvent("bar")));
- EXPECT_FALSE(filter->FilterTraceEvent(MakeTraceEvent("foobar")));
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.cc b/base/trace_event/heap_profiler_allocation_context_tracker.cc
index b47dc16edd..31f311a918 100644
--- a/base/trace_event/heap_profiler_allocation_context_tracker.cc
+++ b/base/trace_event/heap_profiler_allocation_context_tracker.cc
@@ -29,6 +29,7 @@ const size_t kMaxStackDepth = 128u;
const size_t kMaxTaskDepth = 16u;
AllocationContextTracker* const kInitializingSentinel =
reinterpret_cast<AllocationContextTracker*>(-1);
+const char kTracingOverhead[] = "tracing_overhead";
ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER;
@@ -107,17 +108,17 @@ void AllocationContextTracker::SetCaptureMode(CaptureMode mode) {
}
void AllocationContextTracker::PushPseudoStackFrame(
- AllocationContextTracker::PseudoStackFrame stack_frame) {
+ const char* trace_event_name) {
// Impose a limit on the height to verify that every push is popped, because
// in practice the pseudo stack never grows higher than ~20 frames.
if (pseudo_stack_.size() < kMaxStackDepth)
- pseudo_stack_.push_back(stack_frame);
+ pseudo_stack_.push_back(trace_event_name);
else
NOTREACHED();
}
void AllocationContextTracker::PopPseudoStackFrame(
- AllocationContextTracker::PseudoStackFrame stack_frame) {
+ const char* trace_event_name) {
// Guard for stack underflow. If tracing was started with a TRACE_EVENT in
// scope, the frame was never pushed, so it is possible that pop is called
// on an empty stack.
@@ -127,10 +128,8 @@ void AllocationContextTracker::PopPseudoStackFrame(
// Assert that pushes and pops are nested correctly. This DCHECK can be
// hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call
// without a corresponding TRACE_EVENT_BEGIN).
- DCHECK(stack_frame == pseudo_stack_.back())
- << "Encountered an unmatched TRACE_EVENT_END: "
- << stack_frame.trace_event_name
- << " vs event in stack: " << pseudo_stack_.back().trace_event_name;
+ DCHECK_EQ(trace_event_name, pseudo_stack_.back())
+ << "Encountered an unmatched TRACE_EVENT_END";
pseudo_stack_.pop_back();
}
@@ -156,15 +155,21 @@ void AllocationContextTracker::PopCurrentTaskContext(const char* context) {
}
// static
-bool AllocationContextTracker::GetContextSnapshot(AllocationContext* ctx) {
- if (ignore_scope_depth_)
- return false;
+AllocationContext AllocationContextTracker::GetContextSnapshot() {
+ AllocationContext ctx;
+
+ if (ignore_scope_depth_) {
+ ctx.backtrace.frames[0] = StackFrame::FromTraceEventName(kTracingOverhead);
+ ctx.type_name = kTracingOverhead;
+ ctx.backtrace.frame_count = 1;
+ return ctx;
+ }
CaptureMode mode = static_cast<CaptureMode>(
subtle::NoBarrier_Load(&capture_mode_));
- auto* backtrace = std::begin(ctx->backtrace.frames);
- auto* backtrace_end = std::end(ctx->backtrace.frames);
+ auto* backtrace = std::begin(ctx.backtrace.frames);
+ auto* backtrace_end = std::end(ctx.backtrace.frames);
if (!thread_name_) {
// Ignore the string allocation made by GetAndLeakThreadName to avoid
@@ -188,12 +193,11 @@ bool AllocationContextTracker::GetContextSnapshot(AllocationContext* ctx) {
}
case CaptureMode::PSEUDO_STACK:
{
- for (const PseudoStackFrame& stack_frame : pseudo_stack_) {
+ for (const char* event_name: pseudo_stack_) {
if (backtrace == backtrace_end) {
break;
}
- *backtrace++ =
- StackFrame::FromTraceEventName(stack_frame.trace_event_name);
+ *backtrace++ = StackFrame::FromTraceEventName(event_name);
}
break;
}
@@ -218,32 +222,24 @@ bool AllocationContextTracker::GetContextSnapshot(AllocationContext* ctx) {
// Copy frames backwards
size_t backtrace_capacity = backtrace_end - backtrace;
- int32_t top_frame_index = (backtrace_capacity >= frame_count)
- ? 0
- : frame_count - backtrace_capacity;
- for (int32_t i = frame_count - 1; i >= top_frame_index; --i) {
- const void* frame = frames[i];
+ size_t top_frame_index = (backtrace_capacity >= frame_count) ?
+ 0 :
+ frame_count - backtrace_capacity;
+ for (size_t i = frame_count; i > top_frame_index;) {
+ const void* frame = frames[--i];
*backtrace++ = StackFrame::FromProgramCounter(frame);
}
break;
}
}
- ctx->backtrace.frame_count = backtrace - std::begin(ctx->backtrace.frames);
+ ctx.backtrace.frame_count = backtrace - std::begin(ctx.backtrace.frames);
// TODO(ssid): Fix crbug.com/594803 to add file name as 3rd dimension
// (component name) in the heap profiler and not piggy back on the type name.
- if (!task_contexts_.empty()) {
- ctx->type_name = task_contexts_.back();
- } else if (!pseudo_stack_.empty()) {
- // If task context was unavailable, then the category names are taken from
- // trace events.
- ctx->type_name = pseudo_stack_.back().trace_event_category;
- } else {
- ctx->type_name = nullptr;
- }
+ ctx.type_name = task_contexts_.empty() ? nullptr : task_contexts_.back();
- return true;
+ return ctx;
}
} // namespace trace_event
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.h b/base/trace_event/heap_profiler_allocation_context_tracker.h
index 4f2a8c9502..454200c474 100644
--- a/base/trace_event/heap_profiler_allocation_context_tracker.h
+++ b/base/trace_event/heap_profiler_allocation_context_tracker.h
@@ -10,6 +10,7 @@
#include "base/atomicops.h"
#include "base/base_export.h"
#include "base/debug/stack_trace.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/trace_event/heap_profiler_allocation_context.h"
@@ -29,17 +30,6 @@ class BASE_EXPORT AllocationContextTracker {
NATIVE_STACK // GetContextSnapshot() returns native (real) stack trace
};
- // Stack frame constructed from trace events in codebase.
- struct BASE_EXPORT PseudoStackFrame {
- const char* trace_event_category;
- const char* trace_event_name;
-
- bool operator==(const PseudoStackFrame& other) const {
- return trace_event_category == other.trace_event_category &&
- trace_event_name == other.trace_event_name;
- }
- };
-
// Globally sets capturing mode.
// TODO(primiano): How to guard against *_STACK -> DISABLED -> *_STACK?
static void SetCaptureMode(CaptureMode mode);
@@ -70,8 +60,8 @@ class BASE_EXPORT AllocationContextTracker {
static void SetCurrentThreadName(const char* name);
// Starts and ends a new ignore scope between which the allocations are
- // ignored by the heap profiler. GetContextSnapshot() returns false when
- // allocations are ignored.
+ // ignored in the heap profiler. A dummy context that short circuits to
+ // "tracing_overhead" is returned for these allocations.
void begin_ignore_scope() { ignore_scope_depth_++; }
void end_ignore_scope() {
if (ignore_scope_depth_)
@@ -79,19 +69,18 @@ class BASE_EXPORT AllocationContextTracker {
}
// Pushes a frame onto the thread-local pseudo stack.
- void PushPseudoStackFrame(PseudoStackFrame stack_frame);
+ void PushPseudoStackFrame(const char* trace_event_name);
// Pops a frame from the thread-local pseudo stack.
- void PopPseudoStackFrame(PseudoStackFrame stack_frame);
+ void PopPseudoStackFrame(const char* trace_event_name);
// Push and pop current task's context. A stack is used to support nested
// tasks and the top of the stack will be used in allocation context.
void PushCurrentTaskContext(const char* context);
void PopCurrentTaskContext(const char* context);
- // Fills a snapshot of the current thread-local context. Doesn't fill and
- // returns false if allocations are being ignored.
- bool GetContextSnapshot(AllocationContext* snapshot);
+ // Returns a snapshot of the current thread-local context.
+ AllocationContext GetContextSnapshot();
~AllocationContextTracker();
@@ -101,7 +90,7 @@ class BASE_EXPORT AllocationContextTracker {
static subtle::Atomic32 capture_mode_;
// The pseudo stack where frames are |TRACE_EVENT| names.
- std::vector<PseudoStackFrame> pseudo_stack_;
+ std::vector<const char*> pseudo_stack_;
// The thread name is used as the first entry in the pseudo stack.
const char* thread_name_;
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc b/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
index 577f50043d..3064a6a711 100644
--- a/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
+++ b/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
@@ -11,7 +11,6 @@
#include "base/trace_event/heap_profiler.h"
#include "base/trace_event/heap_profiler_allocation_context.h"
#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
-#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_event.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -27,25 +26,13 @@ const char kEclair[] = "Eclair";
const char kFroyo[] = "Froyo";
const char kGingerbread[] = "Gingerbread";
-const char kFilteringTraceConfig[] =
- "{"
- " \"event_filters\": ["
- " {"
- " \"excluded_categories\": [],"
- " \"filter_args\": {},"
- " \"filter_predicate\": \"heap_profiler_predicate\","
- " \"included_categories\": [\"*\"]"
- " }"
- " ]"
- "}";
-
// Asserts that the fixed-size array |expected_backtrace| matches the backtrace
// in |AllocationContextTracker::GetContextSnapshot|.
template <size_t N>
void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) {
- AllocationContext ctx;
- ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx));
+ AllocationContext ctx =
+ AllocationContextTracker::GetInstanceForCurrentThread()
+ ->GetContextSnapshot();
auto* actual = std::begin(ctx.backtrace.frames);
auto* actual_bottom = actual + ctx.backtrace.frame_count;
@@ -65,9 +52,9 @@ void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) {
void AssertBacktraceContainsOnlyThreadName() {
StackFrame t = StackFrame::FromThreadName(kThreadName);
- AllocationContext ctx;
- ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx));
+ AllocationContext ctx =
+ AllocationContextTracker::GetInstanceForCurrentThread()
+ ->GetContextSnapshot();
ASSERT_EQ(1u, ctx.backtrace.frame_count);
ASSERT_EQ(t, ctx.backtrace.frames[0]);
@@ -76,19 +63,17 @@ void AssertBacktraceContainsOnlyThreadName() {
class AllocationContextTrackerTest : public testing::Test {
public:
void SetUp() override {
+ TraceConfig config("");
+ TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE);
AllocationContextTracker::SetCaptureMode(
AllocationContextTracker::CaptureMode::PSEUDO_STACK);
- // Enabling memory-infra category sets default memory dump config which
- // includes filters for capturing pseudo stack.
- TraceConfig config(kFilteringTraceConfig);
- TraceLog::GetInstance()->SetEnabled(config, TraceLog::FILTERING_MODE);
AllocationContextTracker::SetCurrentThreadName(kThreadName);
}
void TearDown() override {
AllocationContextTracker::SetCaptureMode(
AllocationContextTracker::CaptureMode::DISABLED);
- TraceLog::GetInstance()->SetDisabled(TraceLog::FILTERING_MODE);
+ TraceLog::GetInstance()->SetDisabled();
}
};
@@ -121,12 +106,6 @@ TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) {
AssertBacktraceEquals(frame_ce);
}
- {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("Testing"), kCupcake);
- StackFrame frame_cc[] = {t, c, c};
- AssertBacktraceEquals(frame_cc);
- }
-
AssertBacktraceEquals(frame_c);
}
@@ -243,9 +222,9 @@ TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) {
{
TRACE_EVENT0("Testing", kGingerbread);
- AllocationContext ctx;
- ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx));
+ AllocationContext ctx =
+ AllocationContextTracker::GetInstanceForCurrentThread()
+ ->GetContextSnapshot();
// The pseudo stack relies on pointer equality, not deep string comparisons.
ASSERT_EQ(t, ctx.backtrace.frames[0]);
@@ -254,54 +233,38 @@ TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) {
}
{
- AllocationContext ctx;
- ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx));
+ AllocationContext ctx =
+ AllocationContextTracker::GetInstanceForCurrentThread()
+ ->GetContextSnapshot();
ASSERT_EQ(t, ctx.backtrace.frames[0]);
ASSERT_EQ(c, ctx.backtrace.frames[1]);
ASSERT_EQ(f, ctx.backtrace.frames[11]);
}
}
-TEST_F(AllocationContextTrackerTest, TrackCategoryName) {
+TEST_F(AllocationContextTrackerTest, TrackTaskContext) {
const char kContext1[] = "context1";
const char kContext2[] = "context2";
{
// The context from the scoped task event should be used as type name.
TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event1(kContext1);
- AllocationContext ctx1;
- ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx1));
+ AllocationContext ctx1 =
+ AllocationContextTracker::GetInstanceForCurrentThread()
+ ->GetContextSnapshot();
ASSERT_EQ(kContext1, ctx1.type_name);
// In case of nested events, the last event's context should be used.
TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event2(kContext2);
- AllocationContext ctx2;
- ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx2));
+ AllocationContext ctx2 =
+ AllocationContextTracker::GetInstanceForCurrentThread()
+ ->GetContextSnapshot();
ASSERT_EQ(kContext2, ctx2.type_name);
}
- {
- // Type should be category name of the last seen trace event.
- TRACE_EVENT0("Testing", kCupcake);
- AllocationContext ctx1;
- ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx1));
- ASSERT_EQ("Testing", std::string(ctx1.type_name));
-
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("Testing"), kCupcake);
- AllocationContext ctx2;
- ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx2));
- ASSERT_EQ(TRACE_DISABLED_BY_DEFAULT("Testing"),
- std::string(ctx2.type_name));
- }
-
// Type should be nullptr without task event.
- AllocationContext ctx;
- ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx));
+ AllocationContext ctx =
+ AllocationContextTracker::GetInstanceForCurrentThread()
+ ->GetContextSnapshot();
ASSERT_FALSE(ctx.type_name);
}
@@ -309,9 +272,13 @@ TEST_F(AllocationContextTrackerTest, IgnoreAllocationTest) {
TRACE_EVENT0("Testing", kCupcake);
TRACE_EVENT0("Testing", kDonut);
HEAP_PROFILER_SCOPED_IGNORE;
- AllocationContext ctx;
- ASSERT_FALSE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx));
+ AllocationContext ctx =
+ AllocationContextTracker::GetInstanceForCurrentThread()
+ ->GetContextSnapshot();
+ const StringPiece kTracingOverhead("tracing_overhead");
+ ASSERT_EQ(kTracingOverhead,
+ static_cast<const char*>(ctx.backtrace.frames[0].value));
+ ASSERT_EQ(1u, ctx.backtrace.frame_count);
}
} // namespace trace_event
diff --git a/base/trace_event/heap_profiler_allocation_register.cc b/base/trace_event/heap_profiler_allocation_register.cc
index 63d40611a6..2c2cd378bb 100644
--- a/base/trace_event/heap_profiler_allocation_register.cc
+++ b/base/trace_event/heap_profiler_allocation_register.cc
@@ -60,12 +60,12 @@ size_t AllocationRegister::AddressHasher::operator () (
// The multiplicative hashing scheme from [Knuth 1998]. The value of |a| has
// been chosen carefully based on measurements with real-word data (addresses
// recorded from a Chrome trace run). It is the first prime after 2^17. For
- // |shift|, 15 yield good results for both 2^18 and 2^19 bucket sizes.
- // Microbenchmarks show that this simple scheme outperforms fancy hashes like
- // Murmur3 by 20 to 40 percent.
+ // |shift|, 13, 14 and 15 yield good results. These values are tuned to 2^18
+ // buckets. Microbenchmarks show that this simple scheme outperforms fancy
+ // hashes like Murmur3 by 20 to 40 percent.
const uintptr_t key = reinterpret_cast<uintptr_t>(address);
const uintptr_t a = 131101;
- const uintptr_t shift = 15;
+ const uintptr_t shift = 14;
const uintptr_t h = (key * a) >> shift;
return h;
}
diff --git a/base/trace_event/heap_profiler_allocation_register.h b/base/trace_event/heap_profiler_allocation_register.h
index d6a02faeae..86e2721c56 100644
--- a/base/trace_event/heap_profiler_allocation_register.h
+++ b/base/trace_event/heap_profiler_allocation_register.h
@@ -16,7 +16,6 @@
#include "base/process/process_metrics.h"
#include "base/template_util.h"
#include "base/trace_event/heap_profiler_allocation_context.h"
-#include "build/build_config.h"
namespace base {
namespace trace_event {
@@ -46,7 +45,8 @@ class FixedHashMap {
using KVPair = std::pair<const Key, Value>;
// For implementation simplicity API uses integer index instead
- // of iterators. Most operations (except Find) on KVIndex are O(1).
+ // of iterators. Most operations (except FindValidIndex) on KVIndex
+ // are O(1).
using KVIndex = size_t;
static const KVIndex kInvalidKVIndex = static_cast<KVIndex>(-1);
@@ -199,9 +199,7 @@ class FixedHashMap {
// the simplest solution is to just allocate a humongous chunk of address
// space.
- CHECK_LT(next_unused_cell_, num_cells_ + 1)
- << "Allocation Register hash table has too little capacity. Increase "
- "the capacity to run heap profiler in large sessions.";
+ DCHECK_LT(next_unused_cell_, num_cells_ + 1);
return &cells_[idx];
}
@@ -302,25 +300,15 @@ class BASE_EXPORT AllocationRegister {
private:
friend AllocationRegisterTest;
-// Expect lower number of allocations from mobile platforms. Load factor
-// (capacity / bucket count) is kept less than 10 for optimal hashing. The
-// number of buckets should be changed together with AddressHasher.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+ // Expect max 1.5M allocations. Number of buckets is 2^18 for optimal
+ // hashing and should be changed together with AddressHasher.
static const size_t kAllocationBuckets = 1 << 18;
static const size_t kAllocationCapacity = 1500000;
-#else
- static const size_t kAllocationBuckets = 1 << 19;
- static const size_t kAllocationCapacity = 5000000;
-#endif
-
- // 2^16 works well with BacktraceHasher. When increasing this number make
- // sure BacktraceHasher still produces low number of collisions.
- static const size_t kBacktraceBuckets = 1 << 16;
-#if defined(OS_ANDROID)
- static const size_t kBacktraceCapacity = 32000; // 22K was observed
-#else
- static const size_t kBacktraceCapacity = 55000; // 45K was observed on Linux
-#endif
+
+ // Expect max 2^15 unique backtraces. Can be changed to 2^16 without
+ // needing to tweak BacktraceHasher implementation.
+ static const size_t kBacktraceBuckets = 1 << 15;
+ static const size_t kBacktraceCapacity = kBacktraceBuckets;
struct BacktraceHasher {
size_t operator () (const Backtrace& backtrace) const;
diff --git a/base/trace_event/heap_profiler_event_filter.cc b/base/trace_event/heap_profiler_event_filter.cc
deleted file mode 100644
index 6c91c91b13..0000000000
--- a/base/trace_event/heap_profiler_event_filter.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2016 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.
-
-#include "base/trace_event/heap_profiler_event_filter.h"
-
-#include "base/trace_event/category_registry.h"
-#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
-#include "base/trace_event/trace_category.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_impl.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-inline bool IsPseudoStackEnabled() {
- return AllocationContextTracker::capture_mode() ==
- AllocationContextTracker::CaptureMode::PSEUDO_STACK;
-}
-
-inline AllocationContextTracker* GetThreadLocalTracker() {
- return AllocationContextTracker::GetInstanceForCurrentThread();
-}
-
-} // namespace
-
-// static
-const char HeapProfilerEventFilter::kName[] = "heap_profiler_predicate";
-
-HeapProfilerEventFilter::HeapProfilerEventFilter() {}
-HeapProfilerEventFilter::~HeapProfilerEventFilter() {}
-
-bool HeapProfilerEventFilter::FilterTraceEvent(
- const TraceEvent& trace_event) const {
- if (!IsPseudoStackEnabled())
- return true;
-
- // TODO(primiano): Add support for events with copied name crbug.com/581079.
- if (trace_event.flags() & TRACE_EVENT_FLAG_COPY)
- return true;
-
- const auto* category = CategoryRegistry::GetCategoryByStatePtr(
- trace_event.category_group_enabled());
- AllocationContextTracker::PseudoStackFrame frame = {category->name(),
- trace_event.name()};
- if (trace_event.phase() == TRACE_EVENT_PHASE_BEGIN ||
- trace_event.phase() == TRACE_EVENT_PHASE_COMPLETE) {
- GetThreadLocalTracker()->PushPseudoStackFrame(frame);
- } else if (trace_event.phase() == TRACE_EVENT_PHASE_END) {
- // The pop for |TRACE_EVENT_PHASE_COMPLETE| events is in |EndEvent|.
- GetThreadLocalTracker()->PopPseudoStackFrame(frame);
- }
- // Do not filter-out any events and always return true. TraceLog adds the
- // event only if it is enabled for recording.
- return true;
-}
-
-void HeapProfilerEventFilter::EndEvent(const char* category_name,
- const char* event_name) const {
- if (IsPseudoStackEnabled())
- GetThreadLocalTracker()->PopPseudoStackFrame({category_name, event_name});
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/heap_profiler_event_filter.h b/base/trace_event/heap_profiler_event_filter.h
deleted file mode 100644
index 47368a1b07..0000000000
--- a/base/trace_event/heap_profiler_event_filter.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2016 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 BASE_TRACE_EVENT_HEAP_PROFILER_EVENT_FILTER_H_
-#define BASE_TRACE_EVENT_HEAP_PROFILER_EVENT_FILTER_H_
-
-#include "base/base_export.h"
-#include "base/macros.h"
-#include "base/trace_event/trace_event_filter.h"
-
-namespace base {
-namespace trace_event {
-
-class TraceEvent;
-
-// This filter unconditionally accepts all events and pushes/pops them from the
-// thread-local AllocationContextTracker instance as they are seen.
-// This is used to cheaply construct the heap profiler pseudo stack without
-// having to actually record all events.
-class BASE_EXPORT HeapProfilerEventFilter : public TraceEventFilter {
- public:
- static const char kName[];
-
- HeapProfilerEventFilter();
- ~HeapProfilerEventFilter() override;
-
- // TraceEventFilter implementation.
- bool FilterTraceEvent(const TraceEvent& trace_event) const override;
- void EndEvent(const char* category_name,
- const char* event_name) const override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(HeapProfilerEventFilter);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_HEAP_PROFILER_EVENT_FILTER_H_
diff --git a/base/trace_event/heap_profiler_heap_dump_writer.cc b/base/trace_event/heap_profiler_heap_dump_writer.cc
index 8043fff995..1bf06dbd97 100644
--- a/base/trace_event/heap_profiler_heap_dump_writer.cc
+++ b/base/trace_event/heap_profiler_heap_dump_writer.cc
@@ -314,7 +314,8 @@ std::unique_ptr<TracedValue> ExportHeapDump(
internal::HeapDumpWriter writer(
session_state.stack_frame_deduplicator(),
session_state.type_name_deduplicator(),
- session_state.heap_profiler_breakdown_threshold_bytes());
+ session_state.memory_dump_config().heap_profiler_options
+ .breakdown_threshold_bytes);
return Serialize(writer.Summarize(metrics_by_context));
}
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator.cc b/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
index fc5da0d1dd..49a235051c 100644
--- a/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
+++ b/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
@@ -11,7 +11,6 @@
#include <utility>
#include "base/strings/stringprintf.h"
-#include "base/trace_event/memory_usage_estimator.h"
#include "base/trace_event/trace_event_argument.h"
#include "base/trace_event/trace_event_memory_overhead.h"
@@ -24,10 +23,6 @@ StackFrameDeduplicator::FrameNode::FrameNode(StackFrame frame,
StackFrameDeduplicator::FrameNode::FrameNode(const FrameNode& other) = default;
StackFrameDeduplicator::FrameNode::~FrameNode() {}
-size_t StackFrameDeduplicator::FrameNode::EstimateMemoryUsage() const {
- return base::trace_event::EstimateMemoryUsage(children);
-}
-
StackFrameDeduplicator::StackFrameDeduplicator() {}
StackFrameDeduplicator::~StackFrameDeduplicator() {}
@@ -121,10 +116,19 @@ void StackFrameDeduplicator::AppendAsTraceFormat(std::string* out) const {
void StackFrameDeduplicator::EstimateTraceMemoryOverhead(
TraceEventMemoryOverhead* overhead) {
- size_t memory_usage =
- EstimateMemoryUsage(frames_) + EstimateMemoryUsage(roots_);
+ // The sizes here are only estimates; they fail to take into account the
+ // overhead of the tree nodes for the map, but as an estimate this should be
+ // fine.
+ size_t maps_size = roots_.size() * sizeof(std::pair<StackFrame, int>);
+ size_t frames_allocated = frames_.capacity() * sizeof(FrameNode);
+ size_t frames_resident = frames_.size() * sizeof(FrameNode);
+
+ for (const FrameNode& node : frames_)
+ maps_size += node.children.size() * sizeof(std::pair<StackFrame, int>);
+
overhead->Add("StackFrameDeduplicator",
- sizeof(StackFrameDeduplicator) + memory_usage);
+ sizeof(StackFrameDeduplicator) + maps_size + frames_allocated,
+ sizeof(StackFrameDeduplicator) + maps_size + frames_resident);
}
} // namespace trace_event
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator.h b/base/trace_event/heap_profiler_stack_frame_deduplicator.h
index 66d430f2ee..4932534e1d 100644
--- a/base/trace_event/heap_profiler_stack_frame_deduplicator.h
+++ b/base/trace_event/heap_profiler_stack_frame_deduplicator.h
@@ -34,8 +34,6 @@ class BASE_EXPORT StackFrameDeduplicator : public ConvertableToTraceFormat {
FrameNode(const FrameNode& other);
~FrameNode();
- size_t EstimateMemoryUsage() const;
-
StackFrame frame;
// The index of the parent stack frame in |frames_|, or -1 if there is no
diff --git a/base/trace_event/heap_profiler_type_name_deduplicator.cc b/base/trace_event/heap_profiler_type_name_deduplicator.cc
index a6dab51ad2..055f86abf0 100644
--- a/base/trace_event/heap_profiler_type_name_deduplicator.cc
+++ b/base/trace_event/heap_profiler_type_name_deduplicator.cc
@@ -10,10 +10,7 @@
#include <utility>
#include "base/json/string_escape.h"
-#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
-#include "base/trace_event/memory_usage_estimator.h"
-#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_memory_overhead.h"
namespace base {
@@ -21,24 +18,16 @@ namespace trace_event {
namespace {
-// If |type_name| is file name then extract directory name. Or if |type_name| is
-// category name, then disambiguate multple categories and remove
-// "disabled-by-default" prefix if present.
-StringPiece ExtractCategoryFromTypeName(const char* type_name) {
+// Extract directory name if |type_name| was file name. Otherwise, return
+// |type_name|.
+StringPiece ExtractDirNameFromFileName(const char* type_name) {
StringPiece result(type_name);
size_t last_seperator = result.find_last_of("\\/");
// If |type_name| was a not a file path, the seperator will not be found, so
// the whole type name is returned.
- if (last_seperator == StringPiece::npos) {
- // Use the first the category name if it has ",".
- size_t first_comma_position = result.find(',');
- if (first_comma_position != StringPiece::npos)
- result = result.substr(0, first_comma_position);
- if (result.starts_with(TRACE_DISABLED_BY_DEFAULT("")))
- result.remove_prefix(sizeof(TRACE_DISABLED_BY_DEFAULT("")) - 1);
+ if (last_seperator == StringPiece::npos)
return result;
- }
// Remove the file name from the path.
result.remove_suffix(result.length() - last_seperator);
@@ -93,7 +82,7 @@ void TypeNameDeduplicator::AppendAsTraceFormat(std::string* out) const {
// TODO(ssid): crbug.com/594803 the type name is misused for file name in
// some cases.
- StringPiece type_info = ExtractCategoryFromTypeName(it->first);
+ StringPiece type_info = ExtractDirNameFromFileName(it->first);
// |EscapeJSONString| appends, it does not overwrite |buffer|.
bool put_in_quotes = true;
@@ -106,9 +95,12 @@ void TypeNameDeduplicator::AppendAsTraceFormat(std::string* out) const {
void TypeNameDeduplicator::EstimateTraceMemoryOverhead(
TraceEventMemoryOverhead* overhead) {
- size_t memory_usage = EstimateMemoryUsage(type_ids_);
+ // The size here is only an estimate; it fails to take into account the size
+ // of the tree nodes for the map, but as an estimate this should be fine.
+ size_t map_size = type_ids_.size() * sizeof(std::pair<const char*, int>);
+
overhead->Add("TypeNameDeduplicator",
- sizeof(TypeNameDeduplicator) + memory_usage);
+ sizeof(TypeNameDeduplicator) + map_size);
}
} // namespace trace_event
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc
index 3565b8b95b..c3d3258651 100644
--- a/base/trace_event/malloc_dump_provider.cc
+++ b/base/trace_event/malloc_dump_provider.cc
@@ -9,7 +9,6 @@
#include "base/allocator/allocator_extension.h"
#include "base/allocator/allocator_shim.h"
#include "base/allocator/features.h"
-#include "base/debug/profiler.h"
#include "base/trace_event/heap_profiler_allocation_context.h"
#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
#include "base/trace_event/heap_profiler_allocation_register.h"
@@ -23,32 +22,26 @@
#else
#include <malloc.h>
#endif
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
namespace base {
namespace trace_event {
-namespace {
#if BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM)
+namespace {
using allocator::AllocatorDispatch;
-void* HookAlloc(const AllocatorDispatch* self, size_t size, void* context) {
+void* HookAlloc(const AllocatorDispatch* self, size_t size) {
const AllocatorDispatch* const next = self->next;
- void* ptr = next->alloc_function(next, size, context);
+ void* ptr = next->alloc_function(next, size);
if (ptr)
MallocDumpProvider::GetInstance()->InsertAllocation(ptr, size);
return ptr;
}
-void* HookZeroInitAlloc(const AllocatorDispatch* self,
- size_t n,
- size_t size,
- void* context) {
+void* HookZeroInitAlloc(const AllocatorDispatch* self, size_t n, size_t size) {
const AllocatorDispatch* const next = self->next;
- void* ptr = next->alloc_zero_initialized_function(next, n, size, context);
+ void* ptr = next->alloc_zero_initialized_function(next, n, size);
if (ptr)
MallocDumpProvider::GetInstance()->InsertAllocation(ptr, n * size);
return ptr;
@@ -56,127 +49,41 @@ void* HookZeroInitAlloc(const AllocatorDispatch* self,
void* HookllocAligned(const AllocatorDispatch* self,
size_t alignment,
- size_t size,
- void* context) {
+ size_t size) {
const AllocatorDispatch* const next = self->next;
- void* ptr = next->alloc_aligned_function(next, alignment, size, context);
+ void* ptr = next->alloc_aligned_function(next, alignment, size);
if (ptr)
MallocDumpProvider::GetInstance()->InsertAllocation(ptr, size);
return ptr;
}
-void* HookRealloc(const AllocatorDispatch* self,
- void* address,
- size_t size,
- void* context) {
+void* HookRealloc(const AllocatorDispatch* self, void* address, size_t size) {
const AllocatorDispatch* const next = self->next;
- void* ptr = next->realloc_function(next, address, size, context);
+ void* ptr = next->realloc_function(next, address, size);
MallocDumpProvider::GetInstance()->RemoveAllocation(address);
if (size > 0) // realloc(size == 0) means free().
MallocDumpProvider::GetInstance()->InsertAllocation(ptr, size);
return ptr;
}
-void HookFree(const AllocatorDispatch* self, void* address, void* context) {
+void HookFree(const AllocatorDispatch* self, void* address) {
if (address)
MallocDumpProvider::GetInstance()->RemoveAllocation(address);
const AllocatorDispatch* const next = self->next;
- next->free_function(next, address, context);
-}
-
-size_t HookGetSizeEstimate(const AllocatorDispatch* self,
- void* address,
- void* context) {
- const AllocatorDispatch* const next = self->next;
- return next->get_size_estimate_function(next, address, context);
-}
-
-unsigned HookBatchMalloc(const AllocatorDispatch* self,
- size_t size,
- void** results,
- unsigned num_requested,
- void* context) {
- const AllocatorDispatch* const next = self->next;
- unsigned count =
- next->batch_malloc_function(next, size, results, num_requested, context);
- for (unsigned i = 0; i < count; ++i) {
- MallocDumpProvider::GetInstance()->InsertAllocation(results[i], size);
- }
- return count;
-}
-
-void HookBatchFree(const AllocatorDispatch* self,
- void** to_be_freed,
- unsigned num_to_be_freed,
- void* context) {
- const AllocatorDispatch* const next = self->next;
- for (unsigned i = 0; i < num_to_be_freed; ++i) {
- MallocDumpProvider::GetInstance()->RemoveAllocation(to_be_freed[i]);
- }
- next->batch_free_function(next, to_be_freed, num_to_be_freed, context);
-}
-
-void HookFreeDefiniteSize(const AllocatorDispatch* self,
- void* ptr,
- size_t size,
- void* context) {
- if (ptr)
- MallocDumpProvider::GetInstance()->RemoveAllocation(ptr);
- const AllocatorDispatch* const next = self->next;
- next->free_definite_size_function(next, ptr, size, context);
+ next->free_function(next, address);
}
AllocatorDispatch g_allocator_hooks = {
- &HookAlloc, /* alloc_function */
- &HookZeroInitAlloc, /* alloc_zero_initialized_function */
- &HookllocAligned, /* alloc_aligned_function */
- &HookRealloc, /* realloc_function */
- &HookFree, /* free_function */
- &HookGetSizeEstimate, /* get_size_estimate_function */
- &HookBatchMalloc, /* batch_malloc_function */
- &HookBatchFree, /* batch_free_function */
- &HookFreeDefiniteSize, /* free_definite_size_function */
- nullptr, /* next */
+ &HookAlloc, /* alloc_function */
+ &HookZeroInitAlloc, /* alloc_zero_initialized_function */
+ &HookllocAligned, /* alloc_aligned_function */
+ &HookRealloc, /* realloc_function */
+ &HookFree, /* free_function */
+ nullptr, /* next */
};
-#endif // BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM)
-#if defined(OS_WIN)
-// A structure containing some information about a given heap.
-struct WinHeapInfo {
- size_t committed_size;
- size_t uncommitted_size;
- size_t allocated_size;
- size_t block_count;
-};
-
-// NOTE: crbug.com/665516
-// Unfortunately, there is no safe way to collect information from secondary
-// heaps due to limitations and racy nature of this piece of WinAPI.
-void WinHeapMemoryDumpImpl(WinHeapInfo* crt_heap_info) {
-#if defined(SYZYASAN)
- if (base::debug::IsBinaryInstrumented())
- return;
-#endif
-
- // Iterate through whichever heap our CRT is using.
- HANDLE crt_heap = reinterpret_cast<HANDLE>(_get_heap_handle());
- ::HeapLock(crt_heap);
- PROCESS_HEAP_ENTRY heap_entry;
- heap_entry.lpData = nullptr;
- // Walk over all the entries in the main heap.
- while (::HeapWalk(crt_heap, &heap_entry) != FALSE) {
- if ((heap_entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {
- crt_heap_info->allocated_size += heap_entry.cbData;
- crt_heap_info->block_count++;
- } else if ((heap_entry.wFlags & PROCESS_HEAP_REGION) != 0) {
- crt_heap_info->committed_size += heap_entry.Region.dwCommittedSize;
- crt_heap_info->uncommitted_size += heap_entry.Region.dwUnCommittedSize;
- }
- }
- CHECK(::HeapUnlock(crt_heap) == TRUE);
-}
-#endif // defined(OS_WIN)
} // namespace
+#endif // BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM)
// static
const char MallocDumpProvider::kAllocatedObjects[] = "malloc/allocated_objects";
@@ -199,7 +106,6 @@ bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
size_t total_virtual_size = 0;
size_t resident_size = 0;
size_t allocated_objects_size = 0;
- size_t allocated_objects_count = 0;
#if defined(USE_TCMALLOC)
bool res =
allocator::GetNumericProperty("generic.heap_size", &total_virtual_size);
@@ -211,35 +117,18 @@ bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
&allocated_objects_size);
DCHECK(res);
#elif defined(OS_MACOSX) || defined(OS_IOS)
- malloc_statistics_t stats = {0};
+ malloc_statistics_t stats;
+ memset(&stats, 0, sizeof(stats));
malloc_zone_statistics(nullptr, &stats);
total_virtual_size = stats.size_allocated;
allocated_objects_size = stats.size_in_use;
- // Resident size is approximated pretty well by stats.max_size_in_use.
- // However, on macOS, freed blocks are both resident and reusable, which is
- // semantically equivalent to deallocated. The implementation of libmalloc
- // will also only hold a fixed number of freed regions before actually
- // starting to deallocate them, so stats.max_size_in_use is also not
- // representative of the peak size. As a result, stats.max_size_in_use is
- // typically somewhere between actually resident [non-reusable] pages, and
- // peak size. This is not very useful, so we just use stats.size_in_use for
- // resident_size, even though it's an underestimate and fails to account for
- // fragmentation. See
- // https://bugs.chromium.org/p/chromium/issues/detail?id=695263#c1.
- resident_size = stats.size_in_use;
-#elif defined(OS_WIN)
- WinHeapInfo main_heap_info = {};
- WinHeapMemoryDumpImpl(&main_heap_info);
- total_virtual_size =
- main_heap_info.committed_size + main_heap_info.uncommitted_size;
- // Resident size is approximated with committed heap size. Note that it is
- // possible to do this with better accuracy on windows by intersecting the
- // working set with the virtual memory ranges occuipied by the heap. It's not
- // clear that this is worth it, as it's fairly expensive to do.
- resident_size = main_heap_info.committed_size;
- allocated_objects_size = main_heap_info.allocated_size;
- allocated_objects_count = main_heap_info.block_count;
+ // The resident size is approximated to the max size in use, which would count
+ // the total size of all regions other than the free bytes at the end of each
+ // region. In each allocation region the allocations are rounded off to a
+ // fixed quantum, so the excess region will not be resident.
+ // See crrev.com/1531463004 for detailed explanation.
+ resident_size = stats.max_size_in_use;
#else
struct mallinfo info = mallinfo();
DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
@@ -249,8 +138,6 @@ bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
// |arena| + |hblkhd|. For more details see link: http://goo.gl/fMR8lF.
total_virtual_size = info.arena + info.hblkhd;
resident_size = info.uordblks;
-
- // Total allocated space is given by |uordblks|.
allocated_objects_size = info.uordblks;
#endif
@@ -260,17 +147,13 @@ bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
outer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
MemoryAllocatorDump::kUnitsBytes, resident_size);
+ // Total allocated space is given by |uordblks|.
MemoryAllocatorDump* inner_dump = pmd->CreateAllocatorDump(kAllocatedObjects);
inner_dump->AddScalar(MemoryAllocatorDump::kNameSize,
MemoryAllocatorDump::kUnitsBytes,
allocated_objects_size);
- if (allocated_objects_count != 0) {
- inner_dump->AddScalar(MemoryAllocatorDump::kNameObjectCount,
- MemoryAllocatorDump::kUnitsObjects,
- allocated_objects_count);
- }
- if (resident_size > allocated_objects_size) {
+ if (resident_size - allocated_objects_size > 0) {
// Explicitly specify why is extra memory resident. In tcmalloc it accounts
// for free lists and caches. In mac and ios it accounts for the
// fragmentation and metadata.
@@ -350,10 +233,7 @@ void MallocDumpProvider::InsertAllocation(void* address, size_t size) {
auto* tracker = AllocationContextTracker::GetInstanceForCurrentThread();
if (!tracker)
return;
-
- AllocationContext context;
- if (!tracker->GetContextSnapshot(&context))
- return;
+ AllocationContext context = tracker->GetContextSnapshot();
AutoLock lock(allocation_register_lock_);
if (!allocation_register_)
diff --git a/base/trace_event/malloc_dump_provider.h b/base/trace_event/malloc_dump_provider.h
index 384033c9b8..4746cf5896 100644
--- a/base/trace_event/malloc_dump_provider.h
+++ b/base/trace_event/malloc_dump_provider.h
@@ -15,7 +15,7 @@
#include "base/trace_event/memory_dump_provider.h"
#include "build/build_config.h"
-#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_WIN) || \
+#if defined(OS_LINUX) || defined(OS_ANDROID) || \
(defined(OS_MACOSX) && !defined(OS_IOS))
#define MALLOC_MEMORY_TRACING_SUPPORTED
#endif
diff --git a/base/trace_event/memory_allocator_dump.h b/base/trace_event/memory_allocator_dump.h
index c781f071bb..7d1023606b 100644
--- a/base/trace_event/memory_allocator_dump.h
+++ b/base/trace_event/memory_allocator_dump.h
@@ -19,6 +19,7 @@
namespace base {
namespace trace_event {
+class MemoryDumpManager;
class ProcessMemoryDump;
class TracedValue;
@@ -69,6 +70,11 @@ class BASE_EXPORT MemoryAllocatorDump {
// Called at trace generation time to populate the TracedValue.
void AsValueInto(TracedValue* value) const;
+ // Get the ProcessMemoryDump instance that owns this.
+ ProcessMemoryDump* process_memory_dump() const {
+ return process_memory_dump_;
+ }
+
// Use enum Flags to set values.
void set_flags(int flags) { flags_ |= flags; }
void clear_flags(int flags) { flags_ &= ~flags; }
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 5a54a773c5..eed070a782 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -7,26 +7,21 @@
#include <algorithm>
#include <utility>
-#include "base/allocator/features.h"
#include "base/atomic_sequence_num.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
-#include "base/debug/alias.h"
#include "base/debug/debugging_flags.h"
#include "base/debug/stack_trace.h"
-#include "base/debug/thread_heap_usage_tracker.h"
#include "base/memory/ptr_util.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/heap_profiler.h"
#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
-#include "base/trace_event/heap_profiler_event_filter.h"
#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
#include "base/trace_event/malloc_dump_provider.h"
#include "base/trace_event/memory_dump_provider.h"
-#include "base/trace_event/memory_dump_scheduler.h"
#include "base/trace_event/memory_dump_session_state.h"
#include "base/trace_event/memory_infra_background_whitelist.h"
#include "base/trace_event/process_memory_dump.h"
@@ -38,6 +33,10 @@
#include "base/trace_event/java_heap_dump_provider_android.h"
#endif
+#if defined(OS_WIN)
+#include "base/trace_event/winheap_dump_provider_win.h"
+#endif
+
namespace base {
namespace trace_event {
@@ -50,31 +49,6 @@ const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
StaticAtomicSequenceNumber g_next_guid;
MemoryDumpManager* g_instance_for_testing = nullptr;
-// The list of names of dump providers that are blacklisted from strict thread
-// affinity check on unregistration. These providers could potentially cause
-// crashes on build bots if they do not unregister on right thread.
-// TODO(ssid): Fix all the dump providers to unregister if needed and clear the
-// blacklist, crbug.com/643438.
-const char* const kStrictThreadCheckBlacklist[] = {
- "ClientDiscardableSharedMemoryManager",
- "ContextProviderCommandBuffer",
- "DiscardableSharedMemoryManager",
- "FontCaches",
- "GpuMemoryBufferVideoFramePool",
- "IndexedDBBackingStore",
- "Sql",
- "ThreadLocalEventBuffer",
- "TraceLog",
- "URLRequestContext",
- "VpxVideoDecoder",
- "cc::SoftwareImageDecodeCache",
- "cc::StagingBufferPool",
- "gpu::BufferManager",
- "gpu::MappedMemoryManager",
- "gpu::RenderbufferManager",
- "BlacklistTestDumpProvider" // for testing
-};
-
// Callback wrapper to hook upon the completion of RequestGlobalDump() and
// inject trace markers.
void OnGlobalDumpDone(MemoryDumpCallback wrapped_callback,
@@ -136,6 +110,8 @@ const uint64_t MemoryDumpManager::kInvalidTracingProcessId = 0;
const char* const MemoryDumpManager::kSystemAllocatorPoolName =
#if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
MallocDumpProvider::kAllocatedObjects;
+#elif defined(OS_WIN)
+ WinHeapDumpProvider::kAllocatedObjects;
#else
nullptr;
#endif
@@ -166,9 +142,6 @@ MemoryDumpManager::MemoryDumpManager()
// At this point the command line may not be initialized but we try to
// enable the heap profiler to capture allocations as soon as possible.
EnableHeapProfilingIfNeeded();
-
- strict_thread_check_blacklist_.insert(std::begin(kStrictThreadCheckBlacklist),
- std::end(kStrictThreadCheckBlacklist));
}
MemoryDumpManager::~MemoryDumpManager() {
@@ -189,20 +162,18 @@ void MemoryDumpManager::EnableHeapProfilingIfNeeded() {
if (profiling_mode == "") {
AllocationContextTracker::SetCaptureMode(
AllocationContextTracker::CaptureMode::PSEUDO_STACK);
+ }
+ else if (profiling_mode == switches::kEnableHeapProfilingModeNative) {
#if HAVE_TRACE_STACK_FRAME_POINTERS && \
(BUILDFLAG(ENABLE_PROFILING) || !defined(NDEBUG))
- } else if (profiling_mode == switches::kEnableHeapProfilingModeNative) {
// We need frame pointers for native tracing to work, and they are
// enabled in profiling and debug builds.
AllocationContextTracker::SetCaptureMode(
AllocationContextTracker::CaptureMode::NATIVE_STACK);
-#endif
-#if BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER)
- } else if (profiling_mode == switches::kEnableHeapProfilingTaskProfiler) {
- // Enable heap tracking, which in turn enables capture of heap usage
- // tracking in tracked_objects.cc.
- if (!base::debug::ThreadHeapUsageTracker::IsHeapTrackingEnabled())
- base::debug::ThreadHeapUsageTracker::EnableHeapTracking();
+#else
+ CHECK(false) << "'" << profiling_mode << "' mode for "
+ << switches::kEnableHeapProfiling << " flag is not supported "
+ << "for this platform / build type.";
#endif
} else {
CHECK(false) << "Invalid mode '" << profiling_mode << "' for "
@@ -235,33 +206,14 @@ void MemoryDumpManager::Initialize(MemoryDumpManagerDelegate* delegate,
nullptr);
#endif
- TRACE_EVENT_WARMUP_CATEGORY(kTraceCategory);
-
- // TODO(ssid): This should be done in EnableHeapProfiling so that we capture
- // more allocations (crbug.com/625170).
- if (AllocationContextTracker::capture_mode() ==
- AllocationContextTracker::CaptureMode::PSEUDO_STACK &&
- !(TraceLog::GetInstance()->enabled_modes() & TraceLog::FILTERING_MODE)) {
- // Create trace config with heap profiling filter.
- TraceConfig::EventFilterConfig heap_profiler_filter_config(
- HeapProfilerEventFilter::kName);
- heap_profiler_filter_config.AddIncludedCategory("*");
- heap_profiler_filter_config.AddIncludedCategory(
- MemoryDumpManager::kTraceCategory);
- TraceConfig::EventFilters filters;
- filters.push_back(heap_profiler_filter_config);
- TraceConfig filtering_trace_config;
- filtering_trace_config.SetEventFilters(filters);
-
- TraceLog::GetInstance()->SetEnabled(filtering_trace_config,
- TraceLog::FILTERING_MODE);
- }
+#if defined(OS_WIN)
+ RegisterDumpProvider(WinHeapDumpProvider::GetInstance(), "WinHeap", nullptr);
+#endif
// If tracing was enabled before initializing MemoryDumpManager, we missed the
// OnTraceLogEnabled() event. Synthetize it so we can late-join the party.
- // IsEnabled is called before adding observer to avoid calling
- // OnTraceLogEnabled twice.
bool is_tracing_already_enabled = TraceLog::GetInstance()->IsEnabled();
+ TRACE_EVENT0(kTraceCategory, "init"); // Add to trace-viewer category list.
TraceLog::GetInstance()->AddEnabledStateObserver(this);
if (is_tracing_already_enabled)
OnTraceLogEnabled();
@@ -310,11 +262,6 @@ void MemoryDumpManager::RegisterDumpProviderInternal(
new MemoryDumpProviderInfo(mdp, name, std::move(task_runner), options,
whitelisted_for_background_mode);
- if (options.is_fast_polling_supported) {
- DCHECK(!mdpinfo->task_runner) << "MemoryDumpProviders capable of fast "
- "polling must NOT be thread bound.";
- }
-
{
AutoLock lock(lock_);
bool already_registered = !dump_providers_.insert(mdpinfo).second;
@@ -322,15 +269,6 @@ void MemoryDumpManager::RegisterDumpProviderInternal(
// path for RenderThreadImpl::Init().
if (already_registered)
return;
-
- // The list of polling MDPs is populated OnTraceLogEnabled(). This code
- // deals with the case of a MDP capable of fast polling that is registered
- // after the OnTraceLogEnabled()
- if (options.is_fast_polling_supported && dump_thread_) {
- dump_thread_->task_runner()->PostTask(
- FROM_HERE, Bind(&MemoryDumpManager::RegisterPollingMDPOnDumpThread,
- Unretained(this), mdpinfo));
- }
}
if (heap_profiling_enabled_)
@@ -369,18 +307,9 @@ void MemoryDumpManager::UnregisterDumpProviderInternal(
// - At the end of this function, if no dump is in progress.
// - Either in SetupNextMemoryDump() or InvokeOnMemoryDump() when MDPInfo is
// removed from |pending_dump_providers|.
- // - When the provider is removed from |dump_providers_for_polling_|.
DCHECK(!(*mdp_iter)->owned_dump_provider);
(*mdp_iter)->owned_dump_provider = std::move(owned_mdp);
- } else if (strict_thread_check_blacklist_.count((*mdp_iter)->name) == 0 ||
- subtle::NoBarrier_Load(&memory_tracing_enabled_)) {
- // If dump provider's name is on |strict_thread_check_blacklist_|, then the
- // DCHECK is fired only when tracing is enabled. Otherwise the DCHECK is
- // fired even when tracing is not enabled (stricter).
- // TODO(ssid): Remove this condition after removing all the dump providers
- // in the blacklist and the buildbots are no longer flakily hitting the
- // DCHECK, crbug.com/643438.
-
+ } else if (subtle::NoBarrier_Load(&memory_tracing_enabled_)) {
// If you hit this DCHECK, your dump provider has a bug.
// Unregistration of a MemoryDumpProvider is safe only if:
// - The MDP has specified a sequenced task runner affinity AND the
@@ -396,13 +325,6 @@ void MemoryDumpManager::UnregisterDumpProviderInternal(
<< "unregister itself in a racy way. Please file a crbug.";
}
- if ((*mdp_iter)->options.is_fast_polling_supported && dump_thread_) {
- DCHECK(take_mdp_ownership_and_delete_async);
- dump_thread_->task_runner()->PostTask(
- FROM_HERE, Bind(&MemoryDumpManager::UnregisterPollingMDPOnDumpThread,
- Unretained(this), *mdp_iter));
- }
-
// The MDPInfo instance can still be referenced by the
// |ProcessMemoryDumpAsyncState.pending_dump_providers|. For this reason
// the MDPInfo is flagged as disabled. It will cause InvokeOnMemoryDump()
@@ -412,28 +334,6 @@ void MemoryDumpManager::UnregisterDumpProviderInternal(
dump_providers_.erase(mdp_iter);
}
-void MemoryDumpManager::RegisterPollingMDPOnDumpThread(
- scoped_refptr<MemoryDumpManager::MemoryDumpProviderInfo> mdpinfo) {
- AutoLock lock(lock_);
- dump_providers_for_polling_.insert(mdpinfo);
-
- // Notify ready for polling when first polling supported provider is
- // registered. This handles the case where OnTraceLogEnabled() did not notify
- // ready since no polling supported mdp has yet been registered.
- if (dump_providers_for_polling_.size() == 1)
- dump_scheduler_->NotifyPollingSupported();
-}
-
-void MemoryDumpManager::UnregisterPollingMDPOnDumpThread(
- scoped_refptr<MemoryDumpManager::MemoryDumpProviderInfo> mdpinfo) {
- mdpinfo->dump_provider->SuspendFastMemoryPolling();
-
- AutoLock lock(lock_);
- dump_providers_for_polling_.erase(mdpinfo);
- DCHECK(!dump_providers_for_polling_.empty())
- << "All polling MDPs cannot be unregistered.";
-}
-
void MemoryDumpManager::RequestGlobalDump(
MemoryDumpType dump_type,
MemoryDumpLevelOfDetail level_of_detail,
@@ -513,10 +413,8 @@ void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args,
// with disallowed modes. If |session_state_| is null then tracing is
// disabled.
CHECK(!session_state_ ||
- session_state_->IsDumpModeAllowed(args.level_of_detail));
-
- if (dump_scheduler_)
- dump_scheduler_->NotifyDumpTriggered();
+ session_state_->memory_dump_config().allowed_dump_modes.count(
+ args.level_of_detail));
}
TRACE_EVENT_WITH_FLOW0(kTraceCategory, "MemoryDumpManager::CreateProcessDump",
@@ -672,16 +570,6 @@ void MemoryDumpManager::InvokeOnMemoryDump(
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
"dump_provider.name", mdpinfo->name);
- // A stack allocated string with dump provider name is useful to debug
- // crashes while invoking dump after a |dump_provider| is not unregistered
- // in safe way.
- // TODO(ssid): Remove this after fixing crbug.com/643438.
- char provider_name_for_debugging[16];
- strncpy(provider_name_for_debugging, mdpinfo->name,
- sizeof(provider_name_for_debugging) - 1);
- provider_name_for_debugging[sizeof(provider_name_for_debugging) - 1] = '\0';
- base::debug::Alias(provider_name_for_debugging);
-
// Pid of the target process being dumped. Often kNullProcessId (= current
// process), non-zero when the coordinator process creates dumps on behalf
// of child processes (see crbug.com/461788).
@@ -699,28 +587,6 @@ void MemoryDumpManager::InvokeOnMemoryDump(
SetupNextMemoryDump(std::move(pmd_async_state));
}
-bool MemoryDumpManager::PollFastMemoryTotal(uint64_t* memory_total) {
-#if DCHECK_IS_ON()
- {
- AutoLock lock(lock_);
- if (dump_thread_)
- DCHECK(dump_thread_->task_runner()->BelongsToCurrentThread());
- }
-#endif
- if (dump_providers_for_polling_.empty())
- return false;
-
- *memory_total = 0;
- // Note that we call PollFastMemoryTotal() even if the dump provider is
- // disabled (unregistered). This is to avoid taking lock while polling.
- for (const auto& mdpinfo : dump_providers_for_polling_) {
- uint64_t value = 0;
- mdpinfo->dump_provider->PollFastMemoryTotal(&value);
- *memory_total += value;
- }
- return true;
-}
-
// static
void MemoryDumpManager::FinalizeDumpAndAddToTrace(
std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
@@ -797,15 +663,11 @@ void MemoryDumpManager::OnTraceLogEnabled() {
return;
}
- const TraceConfig& trace_config =
+ const TraceConfig trace_config =
TraceLog::GetInstance()->GetCurrentTraceConfig();
- const TraceConfig::MemoryDumpConfig& memory_dump_config =
- trace_config.memory_dump_config();
scoped_refptr<MemoryDumpSessionState> session_state =
new MemoryDumpSessionState;
- session_state->SetAllowedDumpModes(memory_dump_config.allowed_dump_modes);
- session_state->set_heap_profiler_breakdown_threshold_bytes(
- memory_dump_config.heap_profiler_options.breakdown_threshold_bytes);
+ session_state->SetMemoryDumpConfig(trace_config.memory_dump_config());
if (heap_profiling_enabled_) {
// If heap profiling is enabled, the stack frame deduplicator and type name
// deduplicator will be in use. Add a metadata events to write the frames
@@ -819,26 +681,14 @@ void MemoryDumpManager::OnTraceLogEnabled() {
TRACE_EVENT_API_ADD_METADATA_EVENT(
TraceLog::GetCategoryGroupEnabled("__metadata"), "stackFrames",
"stackFrames",
- MakeUnique<SessionStateConvertableProxy<StackFrameDeduplicator>>(
- session_state, &MemoryDumpSessionState::stack_frame_deduplicator));
+ WrapUnique(new SessionStateConvertableProxy<StackFrameDeduplicator>(
+ session_state, &MemoryDumpSessionState::stack_frame_deduplicator)));
TRACE_EVENT_API_ADD_METADATA_EVENT(
TraceLog::GetCategoryGroupEnabled("__metadata"), "typeNames",
"typeNames",
- MakeUnique<SessionStateConvertableProxy<TypeNameDeduplicator>>(
- session_state, &MemoryDumpSessionState::type_name_deduplicator));
- }
-
- std::unique_ptr<MemoryDumpScheduler> dump_scheduler(
- new MemoryDumpScheduler(this, dump_thread->task_runner()));
- DCHECK_LE(memory_dump_config.triggers.size(), 3u);
- for (const auto& trigger : memory_dump_config.triggers) {
- if (!session_state->IsDumpModeAllowed(trigger.level_of_detail)) {
- NOTREACHED();
- continue;
- }
- dump_scheduler->AddTrigger(trigger.trigger_type, trigger.level_of_detail,
- trigger.min_time_between_dumps_ms);
+ WrapUnique(new SessionStateConvertableProxy<TypeNameDeduplicator>(
+ session_state, &MemoryDumpSessionState::type_name_deduplicator)));
}
{
@@ -849,65 +699,48 @@ void MemoryDumpManager::OnTraceLogEnabled() {
DCHECK(!dump_thread_);
dump_thread_ = std::move(dump_thread);
- dump_scheduler_ = std::move(dump_scheduler);
subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
- dump_providers_for_polling_.clear();
- for (const auto& mdpinfo : dump_providers_) {
- if (mdpinfo->options.is_fast_polling_supported)
- dump_providers_for_polling_.insert(mdpinfo);
+ // TODO(primiano): This is a temporary hack to disable periodic memory dumps
+ // when running memory benchmarks until telemetry uses TraceConfig to
+ // enable/disable periodic dumps. See crbug.com/529184 .
+ if (!is_coordinator_ ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ "enable-memory-benchmarking")) {
+ return;
}
- // Notify polling supported only if some polling supported provider was
- // registered, else RegisterPollingMDPOnDumpThread() will notify when first
- // polling MDP registers.
- if (!dump_providers_for_polling_.empty())
- dump_scheduler_->NotifyPollingSupported();
-
- // Only coordinator process triggers periodic global memory dumps.
- if (is_coordinator_)
- dump_scheduler_->NotifyPeriodicTriggerSupported();
}
+ // Enable periodic dumps if necessary.
+ periodic_dump_timer_.Start(trace_config.memory_dump_config().triggers);
}
void MemoryDumpManager::OnTraceLogDisabled() {
// There might be a memory dump in progress while this happens. Therefore,
// ensure that the MDM state which depends on the tracing enabled / disabled
// state is always accessed by the dumping methods holding the |lock_|.
- if (!subtle::NoBarrier_Load(&memory_tracing_enabled_))
- return;
subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
std::unique_ptr<Thread> dump_thread;
- std::unique_ptr<MemoryDumpScheduler> scheduler;
{
AutoLock lock(lock_);
dump_thread = std::move(dump_thread_);
session_state_ = nullptr;
- scheduler = std::move(dump_scheduler_);
}
- scheduler->DisableAllTriggers();
// Thread stops are blocking and must be performed outside of the |lock_|
// or will deadlock (e.g., if SetupNextMemoryDump() tries to acquire it).
+ periodic_dump_timer_.Stop();
if (dump_thread)
dump_thread->Stop();
-
- // |dump_providers_for_polling_| must be cleared only after the dump thread is
- // stopped (polling tasks are done).
- {
- AutoLock lock(lock_);
- for (const auto& mdpinfo : dump_providers_for_polling_)
- mdpinfo->dump_provider->SuspendFastMemoryPolling();
- dump_providers_for_polling_.clear();
- }
}
bool MemoryDumpManager::IsDumpModeAllowed(MemoryDumpLevelOfDetail dump_mode) {
AutoLock lock(lock_);
if (!session_state_)
return false;
- return session_state_->IsDumpModeAllowed(dump_mode);
+ return session_state_->memory_dump_config().allowed_dump_modes.count(
+ dump_mode) != 0;
}
uint64_t MemoryDumpManager::GetTracingProcessId() const {
@@ -973,5 +806,78 @@ ProcessMemoryDump* MemoryDumpManager::ProcessMemoryDumpAsyncState::
return iter->second.get();
}
+MemoryDumpManager::PeriodicGlobalDumpTimer::PeriodicGlobalDumpTimer() {}
+
+MemoryDumpManager::PeriodicGlobalDumpTimer::~PeriodicGlobalDumpTimer() {
+ Stop();
+}
+
+void MemoryDumpManager::PeriodicGlobalDumpTimer::Start(
+ const std::vector<TraceConfig::MemoryDumpConfig::Trigger>& triggers_list) {
+ if (triggers_list.empty())
+ return;
+
+ // At the moment the periodic support is limited to at most one periodic
+ // trigger per dump mode. All intervals should be an integer multiple of the
+ // smallest interval specified.
+ periodic_dumps_count_ = 0;
+ uint32_t min_timer_period_ms = std::numeric_limits<uint32_t>::max();
+ uint32_t light_dump_period_ms = 0;
+ uint32_t heavy_dump_period_ms = 0;
+ DCHECK_LE(triggers_list.size(), 3u);
+ auto* mdm = MemoryDumpManager::GetInstance();
+ for (const TraceConfig::MemoryDumpConfig::Trigger& config : triggers_list) {
+ DCHECK_NE(0u, config.periodic_interval_ms);
+ switch (config.level_of_detail) {
+ case MemoryDumpLevelOfDetail::BACKGROUND:
+ DCHECK(mdm->IsDumpModeAllowed(MemoryDumpLevelOfDetail::BACKGROUND));
+ break;
+ case MemoryDumpLevelOfDetail::LIGHT:
+ DCHECK_EQ(0u, light_dump_period_ms);
+ DCHECK(mdm->IsDumpModeAllowed(MemoryDumpLevelOfDetail::LIGHT));
+ light_dump_period_ms = config.periodic_interval_ms;
+ break;
+ case MemoryDumpLevelOfDetail::DETAILED:
+ DCHECK_EQ(0u, heavy_dump_period_ms);
+ DCHECK(mdm->IsDumpModeAllowed(MemoryDumpLevelOfDetail::DETAILED));
+ heavy_dump_period_ms = config.periodic_interval_ms;
+ break;
+ }
+ min_timer_period_ms =
+ std::min(min_timer_period_ms, config.periodic_interval_ms);
+ }
+
+ DCHECK_EQ(0u, light_dump_period_ms % min_timer_period_ms);
+ light_dump_rate_ = light_dump_period_ms / min_timer_period_ms;
+ DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms);
+ heavy_dump_rate_ = heavy_dump_period_ms / min_timer_period_ms;
+
+ timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(min_timer_period_ms),
+ base::Bind(&PeriodicGlobalDumpTimer::RequestPeriodicGlobalDump,
+ base::Unretained(this)));
+}
+
+void MemoryDumpManager::PeriodicGlobalDumpTimer::Stop() {
+ if (IsRunning()) {
+ timer_.Stop();
+ }
+}
+
+bool MemoryDumpManager::PeriodicGlobalDumpTimer::IsRunning() {
+ return timer_.IsRunning();
+}
+
+void MemoryDumpManager::PeriodicGlobalDumpTimer::RequestPeriodicGlobalDump() {
+ MemoryDumpLevelOfDetail level_of_detail = MemoryDumpLevelOfDetail::BACKGROUND;
+ if (light_dump_rate_ > 0 && periodic_dumps_count_ % light_dump_rate_ == 0)
+ level_of_detail = MemoryDumpLevelOfDetail::LIGHT;
+ if (heavy_dump_rate_ > 0 && periodic_dumps_count_ % heavy_dump_rate_ == 0)
+ level_of_detail = MemoryDumpLevelOfDetail::DETAILED;
+ ++periodic_dumps_count_;
+
+ MemoryDumpManager::GetInstance()->RequestGlobalDump(
+ MemoryDumpType::PERIODIC_INTERVAL, level_of_detail);
+}
+
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index 92cc2f401b..06b772c6e4 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -18,6 +18,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "base/synchronization/lock.h"
+#include "base/timer/timer.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_event.h"
@@ -32,7 +33,6 @@ namespace trace_event {
class MemoryDumpManagerDelegate;
class MemoryDumpProvider;
class MemoryDumpSessionState;
-class MemoryDumpScheduler;
// This is the interface exposed to the rest of the codebase to deal with
// memory tracing. The main entry point for clients is represented by
@@ -94,8 +94,7 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
// This method takes ownership of the dump provider and guarantees that:
// - The |mdp| will be deleted at some point in the near future.
// - Its deletion will not happen concurrently with the OnMemoryDump() call.
- // Note that OnMemoryDump() and PollFastMemoryTotal() calls can still happen
- // after this method returns.
+ // Note that OnMemoryDump() calls can still happen after this method returns.
void UnregisterAndDeleteDumpProviderSoon(
std::unique_ptr<MemoryDumpProvider> mdp);
@@ -117,9 +116,6 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
void OnTraceLogEnabled() override;
void OnTraceLogDisabled() override;
- // Enable heap profiling if kEnableHeapProfiling is specified.
- void EnableHeapProfilingIfNeeded();
-
// Returns true if the dump mode is allowed for current tracing session.
bool IsDumpModeAllowed(MemoryDumpLevelOfDetail dump_mode);
@@ -155,7 +151,6 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
friend struct DefaultSingletonTraits<MemoryDumpManager>;
friend class MemoryDumpManagerDelegate;
friend class MemoryDumpManagerTest;
- friend class MemoryDumpScheduler;
// Descriptor used to hold information about registered MDPs.
// Some important considerations about lifetime of this object:
@@ -278,6 +273,31 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState);
};
+ // Sets up periodic memory dump timers to start global dump requests based on
+ // the dump triggers from trace config.
+ class BASE_EXPORT PeriodicGlobalDumpTimer {
+ public:
+ PeriodicGlobalDumpTimer();
+ ~PeriodicGlobalDumpTimer();
+
+ void Start(const std::vector<TraceConfig::MemoryDumpConfig::Trigger>&
+ triggers_list);
+ void Stop();
+
+ bool IsRunning();
+
+ private:
+ // Periodically called by the timer.
+ void RequestPeriodicGlobalDump();
+
+ RepeatingTimer timer_;
+ uint32_t periodic_dumps_count_;
+ uint32_t light_dump_rate_;
+ uint32_t heavy_dump_rate_;
+
+ DISALLOW_COPY_AND_ASSIGN(PeriodicGlobalDumpTimer);
+ };
+
static const int kMaxConsecutiveFailuresCount;
static const char* const kSystemAllocatorPoolName;
@@ -288,6 +308,9 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
static void FinalizeDumpAndAddToTrace(
std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
+ // Enable heap profiling if kEnableHeapProfiling is specified.
+ void EnableHeapProfilingIfNeeded();
+
// Internal, used only by MemoryDumpManagerDelegate.
// Creates a memory dump for the current process and appends it to the trace.
// |callback| will be invoked asynchronously upon completion on the same
@@ -306,14 +329,6 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
// runner.
void InvokeOnMemoryDump(ProcessMemoryDumpAsyncState* owned_pmd_async_state);
- // Records a quick total memory usage in |memory_total|. This is used to track
- // and detect peaks in the memory usage of the process without having to
- // record all data from dump providers. This value is approximate to trade-off
- // speed, and not consistent with the rest of the memory-infra metrics. Must
- // be called on the dump thread.
- // Returns true if |memory_total| was updated by polling at least 1 MDP.
- bool PollFastMemoryTotal(uint64_t* memory_total);
-
// Helper for RegierDumpProvider* functions.
void RegisterDumpProviderInternal(
MemoryDumpProvider* mdp,
@@ -325,29 +340,13 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
void UnregisterDumpProviderInternal(MemoryDumpProvider* mdp,
bool take_mdp_ownership_and_delete_async);
- // Adds / removes provider that supports polling to
- // |dump_providers_for_polling_|.
- void RegisterPollingMDPOnDumpThread(
- scoped_refptr<MemoryDumpProviderInfo> mdpinfo);
- void UnregisterPollingMDPOnDumpThread(
- scoped_refptr<MemoryDumpProviderInfo> mdpinfo);
-
// An ordererd set of registered MemoryDumpProviderInfo(s), sorted by task
// runner affinity (MDPs belonging to the same task runners are adjacent).
MemoryDumpProviderInfo::OrderedSet dump_providers_;
- // A copy of mdpinfo list that support polling. It must be accessed only on
- // the dump thread if dump thread exists.
- MemoryDumpProviderInfo::OrderedSet dump_providers_for_polling_;
-
// Shared among all the PMDs to keep state scoped to the tracing session.
scoped_refptr<MemoryDumpSessionState> session_state_;
- // The list of names of dump providers that are blacklisted from strict thread
- // affinity check on unregistration.
- std::unordered_set<StringPiece, StringPieceHash>
- strict_thread_check_blacklist_;
-
MemoryDumpManagerDelegate* delegate_; // Not owned.
// When true, this instance is in charge of coordinating periodic dumps.
@@ -361,8 +360,8 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
// dump_providers_enabled_ list) when tracing is not enabled.
subtle::AtomicWord memory_tracing_enabled_;
- // For triggering memory dumps.
- std::unique_ptr<MemoryDumpScheduler> dump_scheduler_;
+ // For time-triggered periodic dumps.
+ PeriodicGlobalDumpTimer periodic_dump_timer_;
// Thread used for MemoryDumpProviders which don't specify a task runner
// affinity.
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index 51d41943fb..d14093cbcc 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -16,16 +16,13 @@
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
-#include "base/test/sequenced_worker_pool_owner.h"
#include "base/test/test_io_thread.h"
#include "base/test/trace_event_analyzer.h"
#include "base/threading/platform_thread.h"
-#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/memory_dump_provider.h"
-#include "base/trace_event/memory_dump_scheduler.h"
#include "base/trace_event/memory_infra_background_whitelist.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_buffer.h"
@@ -73,10 +70,8 @@ void RegisterDumpProvider(
mdm->set_dumper_registrations_ignored_for_testing(true);
}
-void RegisterDumpProvider(
- MemoryDumpProvider* mdp,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- RegisterDumpProvider(mdp, task_runner, MemoryDumpProvider::Options());
+void RegisterDumpProvider(MemoryDumpProvider* mdp) {
+ RegisterDumpProvider(mdp, nullptr, MemoryDumpProvider::Options());
}
void RegisterDumpProviderWithSequencedTaskRunner(
@@ -99,20 +94,6 @@ void OnTraceDataCollected(Closure quit_closure,
quit_closure.Run();
}
-// Posts |task| to |task_runner| and blocks until it is executed.
-void PostTaskAndWait(const tracked_objects::Location& from_here,
- SequencedTaskRunner* task_runner,
- const base::Closure& task) {
- base::WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
- WaitableEvent::InitialState::NOT_SIGNALED);
- task_runner->PostTask(from_here, task);
- task_runner->PostTask(
- FROM_HERE, base::Bind(&WaitableEvent::Signal, base::Unretained(&event)));
- // The SequencedTaskRunner guarantees that |event| will only be signaled after
- // |task| is executed.
- event.Wait();
-}
-
} // namespace
// Testing MemoryDumpManagerDelegate which, by default, short-circuits dump
@@ -143,8 +124,6 @@ class MockMemoryDumpProvider : public MemoryDumpProvider {
MOCK_METHOD0(Destructor, void());
MOCK_METHOD2(OnMemoryDump,
bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd));
- MOCK_METHOD1(PollFastMemoryTotal, void(uint64_t* memory_total));
- MOCK_METHOD0(SuspendFastMemoryPolling, void());
MockMemoryDumpProvider() : enable_mock_destructor(false) {
ON_CALL(*this, OnMemoryDump(_, _))
@@ -156,10 +135,6 @@ class MockMemoryDumpProvider : public MemoryDumpProvider {
EXPECT_TRUE(pmd->session_state().get() != nullptr);
return true;
}));
-
- ON_CALL(*this, PollFastMemoryTotal(_))
- .WillByDefault(
- Invoke([](uint64_t* memory_total) -> void { NOTREACHED(); }));
}
~MockMemoryDumpProvider() override {
if (enable_mock_destructor)
@@ -172,7 +147,8 @@ class MockMemoryDumpProvider : public MemoryDumpProvider {
class TestSequencedTaskRunner : public SequencedTaskRunner {
public:
TestSequencedTaskRunner()
- : worker_pool_(2 /* max_threads */, "Test Task Runner"),
+ : worker_pool_(
+ new SequencedWorkerPool(2 /* max_threads */, "Test Task Runner")),
enabled_(true),
num_of_post_tasks_(0) {}
@@ -190,21 +166,19 @@ class TestSequencedTaskRunner : public SequencedTaskRunner {
const Closure& task,
TimeDelta delay) override {
num_of_post_tasks_++;
- if (enabled_) {
- return worker_pool_.pool()->PostSequencedWorkerTask(token_, from_here,
- task);
- }
+ if (enabled_)
+ return worker_pool_->PostSequencedWorkerTask(token_, from_here, task);
return false;
}
bool RunsTasksOnCurrentThread() const override {
- return worker_pool_.pool()->RunsTasksOnCurrentThread();
+ return worker_pool_->IsRunningSequenceOnCurrentThread(token_);
}
private:
~TestSequencedTaskRunner() override {}
- SequencedWorkerPoolOwner worker_pool_;
+ scoped_refptr<SequencedWorkerPool> worker_pool_;
const SequencedWorkerPool::SequenceToken token_;
bool enabled_;
unsigned num_of_post_tasks_;
@@ -241,10 +215,6 @@ class MemoryDumpManagerTest : public testing::Test {
task_runner->PostTask(FROM_HERE, closure);
}
- void PollFastMemoryTotal(uint64_t* memory_total) {
- mdm_->PollFastMemoryTotal(memory_total);
- }
-
protected:
void InitializeMemoryDumpManager(bool is_coordinator) {
mdm_->set_dumper_registrations_ignored_for_testing(true);
@@ -274,7 +244,7 @@ class MemoryDumpManagerTest : public testing::Test {
void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
bool IsPeriodicDumpingEnabled() const {
- return mdm_->dump_scheduler_->IsPeriodicTimerRunningForTesting();
+ return mdm_->periodic_dump_timer_.IsRunning();
}
int GetMaxConsecutiveFailuresCount() const {
@@ -298,7 +268,7 @@ class MemoryDumpManagerTest : public testing::Test {
TEST_F(MemoryDumpManagerTest, SingleDumper) {
InitializeMemoryDumpManager(false /* is_coordinator */);
MockMemoryDumpProvider mdp;
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
+ RegisterDumpProvider(&mdp);
// Check that the dumper is not called if the memory category is not enabled.
EnableTracingWithLegacyCategories("foobar-but-not-memory");
@@ -339,7 +309,7 @@ TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) {
InitializeMemoryDumpManager(false /* is_coordinator */);
MockMemoryDumpProvider mdp;
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
+ RegisterDumpProvider(&mdp);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp, OnMemoryDump(IsDetailedDump(), _)).WillOnce(Return(true));
@@ -350,7 +320,7 @@ TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) {
// Check that requesting dumps with low level of detail actually propagates to
// OnMemoryDump() call on dump providers.
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
+ RegisterDumpProvider(&mdp);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp, OnMemoryDump(IsLightDump(), _)).WillOnce(Return(true));
@@ -365,8 +335,8 @@ TEST_F(MemoryDumpManagerTest, SharedSessionState) {
InitializeMemoryDumpManager(false /* is_coordinator */);
MockMemoryDumpProvider mdp1;
MockMemoryDumpProvider mdp2;
- RegisterDumpProvider(&mdp1, nullptr);
- RegisterDumpProvider(&mdp2, nullptr);
+ RegisterDumpProvider(&mdp1);
+ RegisterDumpProvider(&mdp2);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
const MemoryDumpSessionState* session_state =
@@ -402,7 +372,7 @@ TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
MockMemoryDumpProvider mdp2;
// Enable only mdp1.
- RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
+ RegisterDumpProvider(&mdp1);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
@@ -413,7 +383,7 @@ TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
// Invert: enable mdp1 and disable mdp2.
mdm_->UnregisterDumpProvider(&mdp1);
- RegisterDumpProvider(&mdp2, nullptr);
+ RegisterDumpProvider(&mdp2);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
@@ -423,7 +393,7 @@ TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
DisableTracing();
// Enable both mdp1 and mdp2.
- RegisterDumpProvider(&mdp1, nullptr);
+ RegisterDumpProvider(&mdp1);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
@@ -439,7 +409,7 @@ TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
InitializeMemoryDumpManager(false /* is_coordinator */);
MockMemoryDumpProvider mdp;
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
+ RegisterDumpProvider(&mdp);
{
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
@@ -461,7 +431,7 @@ TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
DisableTracing();
}
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
+ RegisterDumpProvider(&mdp);
mdm_->UnregisterDumpProvider(&mdp);
{
@@ -473,9 +443,9 @@ TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
DisableTracing();
}
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
+ RegisterDumpProvider(&mdp);
mdm_->UnregisterDumpProvider(&mdp);
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
+ RegisterDumpProvider(&mdp);
{
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
@@ -597,8 +567,8 @@ TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
MockMemoryDumpProvider mdp1;
MockMemoryDumpProvider mdp2;
- RegisterDumpProvider(&mdp1, nullptr);
- RegisterDumpProvider(&mdp2, nullptr);
+ RegisterDumpProvider(&mdp1);
+ RegisterDumpProvider(&mdp2);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
const int kNumDumps = 2 * GetMaxConsecutiveFailuresCount();
@@ -631,7 +601,7 @@ TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
MockMemoryDumpProvider mdp1;
MockMemoryDumpProvider mdp2;
- RegisterDumpProvider(&mdp1, nullptr);
+ RegisterDumpProvider(&mdp1);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
@@ -641,7 +611,7 @@ TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
.WillOnce(Return(true))
.WillOnce(
Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
- RegisterDumpProvider(&mdp2, nullptr);
+ RegisterDumpProvider(&mdp2);
return true;
}))
.WillRepeatedly(Return(true));
@@ -717,16 +687,13 @@ TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {
// unregister the other one.
for (const std::unique_ptr<MockMemoryDumpProvider>& mdp : mdps) {
int other_idx = (mdps.front() == mdp);
- // TestIOThread's task runner must be obtained from the main thread but can
- // then be used from other threads.
- scoped_refptr<SingleThreadTaskRunner> other_runner =
- threads[other_idx]->task_runner();
+ TestIOThread* other_thread = threads[other_idx].get();
MockMemoryDumpProvider* other_mdp = mdps[other_idx].get();
- auto on_dump = [this, other_runner, other_mdp, &on_memory_dump_call_count](
+ auto on_dump = [this, other_thread, other_mdp, &on_memory_dump_call_count](
const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
- PostTaskAndWait(FROM_HERE, other_runner.get(),
- base::Bind(&MemoryDumpManager::UnregisterDumpProvider,
- base::Unretained(&*mdm_), other_mdp));
+ other_thread->PostTaskAndWait(
+ FROM_HERE, base::Bind(&MemoryDumpManager::UnregisterDumpProvider,
+ base::Unretained(&*mdm_), other_mdp));
on_memory_dump_call_count++;
return true;
};
@@ -749,75 +716,6 @@ TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {
DisableTracing();
}
-TEST_F(MemoryDumpManagerTest, TestPollingOnDumpThread) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- std::unique_ptr<MockMemoryDumpProvider> mdp1(new MockMemoryDumpProvider());
- std::unique_ptr<MockMemoryDumpProvider> mdp2(new MockMemoryDumpProvider());
- mdp1->enable_mock_destructor = true;
- mdp2->enable_mock_destructor = true;
-
- EXPECT_CALL(*mdp1, SuspendFastMemoryPolling()).Times(1);
- EXPECT_CALL(*mdp2, SuspendFastMemoryPolling()).Times(1);
- EXPECT_CALL(*mdp1, Destructor());
- EXPECT_CALL(*mdp2, Destructor());
-
- MemoryDumpProvider::Options options;
- options.is_fast_polling_supported = true;
- RegisterDumpProvider(mdp1.get(), nullptr, options);
-
- RunLoop run_loop;
- scoped_refptr<SingleThreadTaskRunner> test_task_runner =
- ThreadTaskRunnerHandle::Get();
- auto quit_closure = run_loop.QuitClosure();
-
- const int kPollsToQuit = 10;
- int call_count = 0;
- MemoryDumpManager* mdm = mdm_.get();
- const auto poll_function1 = [&call_count, &test_task_runner, quit_closure,
- &mdp2, mdm, &options, kPollsToQuit,
- this](uint64_t* total) -> void {
- ++call_count;
- if (call_count == 1)
- RegisterDumpProvider(mdp2.get(), nullptr, options, kMDPName);
- else if (call_count == 4)
- mdm->UnregisterAndDeleteDumpProviderSoon(std::move(mdp2));
- else if (call_count == kPollsToQuit)
- test_task_runner->PostTask(FROM_HERE, quit_closure);
-
- // Record increase of 1 GiB of memory at each call.
- *total = static_cast<uint64_t>(call_count) * 1024 * 1024 * 1024;
- };
- EXPECT_CALL(*mdp1, PollFastMemoryTotal(_))
- .Times(testing::AtLeast(kPollsToQuit))
- .WillRepeatedly(Invoke(poll_function1));
-
- // Depending on the order of PostTask calls the mdp2 might be registered after
- // all polls or in between polls.
- EXPECT_CALL(*mdp2, PollFastMemoryTotal(_))
- .Times(Between(0, kPollsToQuit - 1))
- .WillRepeatedly(Return());
-
- MemoryDumpScheduler::SetPollingIntervalForTesting(1);
- EnableTracingWithTraceConfig(
- TraceConfigMemoryTestUtil::GetTraceConfig_PeakDetectionTrigger(3));
-
- int last_poll_to_request_dump = -2;
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _))
- .Times(testing::AtLeast(2))
- .WillRepeatedly(Invoke([&last_poll_to_request_dump, &call_count](
- const MemoryDumpRequestArgs& args,
- const MemoryDumpCallback& callback) -> void {
- // Minimum number of polls between dumps must be 3 (polling interval is
- // 1ms).
- EXPECT_GE(call_count - last_poll_to_request_dump, 3);
- last_poll_to_request_dump = call_count;
- }));
-
- run_loop.Run();
- DisableTracing();
- mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdp1));
-}
-
// If a thread (with a dump provider living on it) is torn down during a dump
// its dump provider should be skipped but the dump itself should succeed.
TEST_F(MemoryDumpManagerTest, TearDownThreadWhileDumping) {
@@ -840,14 +738,9 @@ TEST_F(MemoryDumpManagerTest, TearDownThreadWhileDumping) {
for (const std::unique_ptr<MockMemoryDumpProvider>& mdp : mdps) {
int other_idx = (mdps.front() == mdp);
TestIOThread* other_thread = threads[other_idx].get();
- // TestIOThread isn't thread-safe and must be stopped on the |main_runner|.
- scoped_refptr<SequencedTaskRunner> main_runner =
- SequencedTaskRunnerHandle::Get();
- auto on_dump = [other_thread, main_runner, &on_memory_dump_call_count](
+ auto on_dump = [other_thread, &on_memory_dump_call_count](
const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
- PostTaskAndWait(
- FROM_HERE, main_runner.get(),
- base::Bind(&TestIOThread::Stop, base::Unretained(other_thread)));
+ other_thread->Stop();
on_memory_dump_call_count++;
return true;
};
@@ -875,7 +768,7 @@ TEST_F(MemoryDumpManagerTest, TearDownThreadWhileDumping) {
TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) {
InitializeMemoryDumpManager(false /* is_coordinator */);
MockMemoryDumpProvider mdp1;
- RegisterDumpProvider(&mdp1, nullptr);
+ RegisterDumpProvider(&mdp1);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
@@ -890,7 +783,7 @@ TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) {
// began, it will still late-join the party (real use case: startup tracing).
TEST_F(MemoryDumpManagerTest, InitializedAfterStartOfTracing) {
MockMemoryDumpProvider mdp;
- RegisterDumpProvider(&mdp, nullptr);
+ RegisterDumpProvider(&mdp);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
// First check that a RequestGlobalDump() issued before the MemoryDumpManager
@@ -1073,7 +966,7 @@ TEST_F(MemoryDumpManagerTest, DisableTracingRightBeforeStartOfDump) {
// Create both same-thread MDP and another MDP with dedicated thread
MockMemoryDumpProvider mdp1;
- RegisterDumpProvider(&mdp1, nullptr);
+ RegisterDumpProvider(&mdp1);
MockMemoryDumpProvider mdp2;
RegisterDumpProvider(&mdp2, mdp_thread->task_runner(), kDefaultOptions);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
@@ -1192,8 +1085,8 @@ TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoonDuringDump) {
const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
thread_ref = PlatformThread::CurrentRef();
TestIOThread thread_for_unregistration(TestIOThread::kAutoStart);
- PostTaskAndWait(
- FROM_HERE, thread_for_unregistration.task_runner().get(),
+ thread_for_unregistration.PostTaskAndWait(
+ FROM_HERE,
base::Bind(
&MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon,
base::Unretained(MemoryDumpManager::GetInstance()),
@@ -1223,7 +1116,7 @@ TEST_F(MemoryDumpManagerTest, TestWhitelistingMDP) {
InitializeMemoryDumpManager(false /* is_coordinator */);
SetDumpProviderWhitelistForTesting(kTestMDPWhitelist);
std::unique_ptr<MockMemoryDumpProvider> mdp1(new MockMemoryDumpProvider);
- RegisterDumpProvider(mdp1.get(), nullptr);
+ RegisterDumpProvider(mdp1.get());
std::unique_ptr<MockMemoryDumpProvider> mdp2(new MockMemoryDumpProvider);
RegisterDumpProvider(mdp2.get(), nullptr, kDefaultOptions,
kWhitelistedMDPName);
@@ -1274,22 +1167,5 @@ TEST_F(MemoryDumpManagerTest, TestBackgroundTracingSetup) {
DisableTracing();
}
-TEST_F(MemoryDumpManagerTest, TestBlacklistedUnsafeUnregistration) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- MockMemoryDumpProvider mdp1;
- RegisterDumpProvider(&mdp1, nullptr, kDefaultOptions,
- "BlacklistTestDumpProvider");
- // Not calling UnregisterAndDeleteDumpProviderSoon() should not crash.
- mdm_->UnregisterDumpProvider(&mdp1);
-
- Thread thread("test thread");
- thread.Start();
- RegisterDumpProvider(&mdp1, thread.task_runner(), kDefaultOptions,
- "BlacklistTestDumpProvider");
- // Unregistering on wrong thread should not crash.
- mdm_->UnregisterDumpProvider(&mdp1);
- thread.Stop();
-}
-
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/memory_dump_provider.h b/base/trace_event/memory_dump_provider.h
index 76c2969e96..2c502861d8 100644
--- a/base/trace_event/memory_dump_provider.h
+++ b/base/trace_event/memory_dump_provider.h
@@ -22,8 +22,7 @@ class BASE_EXPORT MemoryDumpProvider {
struct Options {
Options()
: target_pid(kNullProcessId),
- dumps_on_single_thread_task_runner(false),
- is_fast_polling_supported(false) {}
+ dumps_on_single_thread_task_runner(false) {}
// If the dump provider generates dumps on behalf of another process,
// |target_pid| contains the pid of that process.
@@ -35,11 +34,6 @@ class BASE_EXPORT MemoryDumpProvider {
// a SingleThreadTaskRunner, which is usually the case. It is faster to run
// all providers that run on the same thread together without thread hops.
bool dumps_on_single_thread_task_runner;
-
- // Set to true if the dump provider implementation supports high frequency
- // polling. Only providers running without task runner affinity are
- // supported.
- bool is_fast_polling_supported;
};
virtual ~MemoryDumpProvider() {}
@@ -58,18 +52,6 @@ class BASE_EXPORT MemoryDumpProvider {
// collecting extensive allocation data, if supported.
virtual void OnHeapProfilingEnabled(bool) {}
- // Quickly record the total memory usage in |memory_total|. This method will
- // be called only when the dump provider registration has
- // |is_fast_polling_supported| set to true. This method is used for polling at
- // high frequency for detecting peaks. See comment on
- // |is_fast_polling_supported| option if you need to override this method.
- virtual void PollFastMemoryTotal(uint64_t* /* memory_total */) {}
-
- // Indicates that fast memory polling is not going to be used in the near
- // future and the MDP can tear down any resource kept around for fast memory
- // polling.
- virtual void SuspendFastMemoryPolling() {}
-
protected:
MemoryDumpProvider() {}
diff --git a/base/trace_event/memory_dump_request_args.cc b/base/trace_event/memory_dump_request_args.cc
index bf72bef5e4..e6c5b87b22 100644
--- a/base/trace_event/memory_dump_request_args.cc
+++ b/base/trace_event/memory_dump_request_args.cc
@@ -12,28 +12,19 @@ namespace trace_event {
// static
const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type) {
switch (dump_type) {
+ case MemoryDumpType::TASK_BEGIN:
+ return "task_begin";
+ case MemoryDumpType::TASK_END:
+ return "task_end";
case MemoryDumpType::PERIODIC_INTERVAL:
return "periodic_interval";
case MemoryDumpType::EXPLICITLY_TRIGGERED:
return "explicitly_triggered";
- case MemoryDumpType::PEAK_MEMORY_USAGE:
- return "peak_memory_usage";
}
NOTREACHED();
return "unknown";
}
-MemoryDumpType StringToMemoryDumpType(const std::string& str) {
- if (str == "periodic_interval")
- return MemoryDumpType::PERIODIC_INTERVAL;
- if (str == "explicitly_triggered")
- return MemoryDumpType::EXPLICITLY_TRIGGERED;
- if (str == "peak_memory_usage")
- return MemoryDumpType::PEAK_MEMORY_USAGE;
- NOTREACHED();
- return MemoryDumpType::LAST;
-}
-
const char* MemoryDumpLevelOfDetailToString(
const MemoryDumpLevelOfDetail& level_of_detail) {
switch (level_of_detail) {
diff --git a/base/trace_event/memory_dump_request_args.h b/base/trace_event/memory_dump_request_args.h
index 90a866fa7a..f3ff9d8e3b 100644
--- a/base/trace_event/memory_dump_request_args.h
+++ b/base/trace_event/memory_dump_request_args.h
@@ -18,19 +18,16 @@ namespace base {
namespace trace_event {
// Captures the reason why a memory dump is being requested. This is to allow
-// selective enabling of dumps, filtering and post-processing. Important: this
-// must be kept consistent with
-// services/resource_coordinator/public/cpp/memory/memory_infra_traits.cc.
+// selective enabling of dumps, filtering and post-processing.
enum class MemoryDumpType {
- PERIODIC_INTERVAL, // Dumping memory at periodic intervals.
+ TASK_BEGIN, // Dumping memory at the beginning of a message-loop task.
+ TASK_END, // Dumping memory at the ending of a message-loop task.
+ PERIODIC_INTERVAL, // Dumping memory at periodic intervals.
EXPLICITLY_TRIGGERED, // Non maskable dump request.
- PEAK_MEMORY_USAGE, // Dumping memory at detected peak total memory usage.
- LAST = PEAK_MEMORY_USAGE // For IPC macros.
+ LAST = EXPLICITLY_TRIGGERED // For IPC macros.
};
// Tells the MemoryDumpProvider(s) how much detailed their dumps should be.
-// Important: this must be kept consistent with
-// services/resource_Coordinator/public/cpp/memory/memory_infra_traits.cc.
enum class MemoryDumpLevelOfDetail : uint32_t {
FIRST,
@@ -53,8 +50,7 @@ enum class MemoryDumpLevelOfDetail : uint32_t {
};
// Initial request arguments for a global memory dump. (see
-// MemoryDumpManager::RequestGlobalMemoryDump()). Important: this must be kept
-// consistent with services/memory_infra/public/cpp/memory_infra_traits.cc.
+// MemoryDumpManager::RequestGlobalMemoryDump()).
struct BASE_EXPORT MemoryDumpRequestArgs {
// Globally unique identifier. In multi-process dumps, all processes issue a
// local dump with the same guid. This allows the trace importers to
@@ -76,8 +72,6 @@ using MemoryDumpCallback = Callback<void(uint64_t dump_guid, bool success)>;
BASE_EXPORT const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type);
-BASE_EXPORT MemoryDumpType StringToMemoryDumpType(const std::string& str);
-
BASE_EXPORT const char* MemoryDumpLevelOfDetailToString(
const MemoryDumpLevelOfDetail& level_of_detail);
diff --git a/base/trace_event/memory_dump_scheduler.cc b/base/trace_event/memory_dump_scheduler.cc
deleted file mode 100644
index eaa8d63661..0000000000
--- a/base/trace_event/memory_dump_scheduler.cc
+++ /dev/null
@@ -1,304 +0,0 @@
-// 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.
-
-#include "base/trace_event/memory_dump_scheduler.h"
-
-#include "base/process/process_metrics.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "build/build_config.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-// Threshold on increase in memory from last dump beyond which a new dump must
-// be triggered.
-int64_t kDefaultMemoryIncreaseThreshold = 50 * 1024 * 1024; // 50MiB
-const uint32_t kMemoryTotalsPollingInterval = 25;
-uint32_t g_polling_interval_ms_for_testing = 0;
-} // namespace
-
-MemoryDumpScheduler::MemoryDumpScheduler(
- MemoryDumpManager* mdm,
- scoped_refptr<SingleThreadTaskRunner> polling_task_runner)
- : mdm_(mdm), polling_state_(polling_task_runner) {}
-
-MemoryDumpScheduler::~MemoryDumpScheduler() {}
-
-void MemoryDumpScheduler::AddTrigger(MemoryDumpType trigger_type,
- MemoryDumpLevelOfDetail level_of_detail,
- uint32_t min_time_between_dumps_ms) {
- if (trigger_type == MemoryDumpType::PEAK_MEMORY_USAGE) {
- DCHECK(!periodic_state_.is_configured);
- DCHECK_EQ(PollingTriggerState::DISABLED, polling_state_.current_state);
- DCHECK_NE(0u, min_time_between_dumps_ms);
-
- polling_state_.level_of_detail = level_of_detail;
- polling_state_.min_polls_between_dumps =
- (min_time_between_dumps_ms + polling_state_.polling_interval_ms - 1) /
- polling_state_.polling_interval_ms;
- polling_state_.current_state = PollingTriggerState::CONFIGURED;
- } else if (trigger_type == MemoryDumpType::PERIODIC_INTERVAL) {
- DCHECK_EQ(PollingTriggerState::DISABLED, polling_state_.current_state);
- periodic_state_.is_configured = true;
- DCHECK_NE(0u, min_time_between_dumps_ms);
- switch (level_of_detail) {
- case MemoryDumpLevelOfDetail::BACKGROUND:
- break;
- case MemoryDumpLevelOfDetail::LIGHT:
- DCHECK_EQ(0u, periodic_state_.light_dump_period_ms);
- periodic_state_.light_dump_period_ms = min_time_between_dumps_ms;
- break;
- case MemoryDumpLevelOfDetail::DETAILED:
- DCHECK_EQ(0u, periodic_state_.heavy_dump_period_ms);
- periodic_state_.heavy_dump_period_ms = min_time_between_dumps_ms;
- break;
- }
-
- periodic_state_.min_timer_period_ms = std::min(
- periodic_state_.min_timer_period_ms, min_time_between_dumps_ms);
- DCHECK_EQ(0u, periodic_state_.light_dump_period_ms %
- periodic_state_.min_timer_period_ms);
- DCHECK_EQ(0u, periodic_state_.heavy_dump_period_ms %
- periodic_state_.min_timer_period_ms);
- }
-}
-
-void MemoryDumpScheduler::NotifyPeriodicTriggerSupported() {
- if (!periodic_state_.is_configured || periodic_state_.timer.IsRunning())
- return;
- periodic_state_.light_dumps_rate = periodic_state_.light_dump_period_ms /
- periodic_state_.min_timer_period_ms;
- periodic_state_.heavy_dumps_rate = periodic_state_.heavy_dump_period_ms /
- periodic_state_.min_timer_period_ms;
-
- periodic_state_.dump_count = 0;
- periodic_state_.timer.Start(
- FROM_HERE,
- TimeDelta::FromMilliseconds(periodic_state_.min_timer_period_ms),
- Bind(&MemoryDumpScheduler::RequestPeriodicGlobalDump, Unretained(this)));
-}
-
-void MemoryDumpScheduler::NotifyPollingSupported() {
- if (polling_state_.current_state != PollingTriggerState::CONFIGURED)
- return;
-
- polling_state_.current_state = PollingTriggerState::ENABLED;
- polling_state_.ResetTotals();
-
- polling_state_.polling_task_runner->PostTask(
- FROM_HERE,
- Bind(&MemoryDumpScheduler::PollMemoryOnPollingThread, Unretained(this)));
-}
-
-void MemoryDumpScheduler::NotifyDumpTriggered() {
- if (polling_state_.polling_task_runner &&
- polling_state_.polling_task_runner->RunsTasksOnCurrentThread()) {
- polling_state_.polling_task_runner->PostTask(
- FROM_HERE,
- Bind(&MemoryDumpScheduler::NotifyDumpTriggered, Unretained(this)));
- return;
- }
- if (polling_state_.current_state != PollingTriggerState::ENABLED)
- return;
-
- polling_state_.ResetTotals();
-}
-
-void MemoryDumpScheduler::DisableAllTriggers() {
- if (periodic_state_.timer.IsRunning())
- periodic_state_.timer.Stop();
- DisablePolling();
-}
-
-void MemoryDumpScheduler::DisablePolling() {
- if (polling_state_.polling_task_runner->RunsTasksOnCurrentThread()) {
- if (polling_state_.polling_task_runner->PostTask(
- FROM_HERE,
- Bind(&MemoryDumpScheduler::DisablePolling, Unretained(this))))
- return;
- }
- polling_state_.current_state = PollingTriggerState::DISABLED;
- polling_state_.polling_task_runner = nullptr;
-}
-
-// static
-void MemoryDumpScheduler::SetPollingIntervalForTesting(uint32_t interval) {
- g_polling_interval_ms_for_testing = interval;
-}
-
-bool MemoryDumpScheduler::IsPeriodicTimerRunningForTesting() {
- return periodic_state_.timer.IsRunning();
-}
-
-void MemoryDumpScheduler::RequestPeriodicGlobalDump() {
- MemoryDumpLevelOfDetail level_of_detail = MemoryDumpLevelOfDetail::BACKGROUND;
- if (periodic_state_.light_dumps_rate > 0 &&
- periodic_state_.dump_count % periodic_state_.light_dumps_rate == 0)
- level_of_detail = MemoryDumpLevelOfDetail::LIGHT;
- if (periodic_state_.heavy_dumps_rate > 0 &&
- periodic_state_.dump_count % periodic_state_.heavy_dumps_rate == 0)
- level_of_detail = MemoryDumpLevelOfDetail::DETAILED;
- ++periodic_state_.dump_count;
-
- mdm_->RequestGlobalDump(MemoryDumpType::PERIODIC_INTERVAL, level_of_detail);
-}
-
-void MemoryDumpScheduler::PollMemoryOnPollingThread() {
- if (polling_state_.current_state != PollingTriggerState::ENABLED)
- return;
-
- uint64_t polled_memory = 0;
- bool res = mdm_->PollFastMemoryTotal(&polled_memory);
- DCHECK(res);
- if (polling_state_.level_of_detail == MemoryDumpLevelOfDetail::DETAILED) {
- TRACE_COUNTER1(MemoryDumpManager::kTraceCategory, "PolledMemoryMB",
- polled_memory / 1024 / 1024);
- }
-
- if (ShouldTriggerDump(polled_memory)) {
- TRACE_EVENT_INSTANT1(MemoryDumpManager::kTraceCategory,
- "Peak memory dump Triggered",
- TRACE_EVENT_SCOPE_PROCESS, "total_usage_MB",
- polled_memory / 1024 / 1024);
-
- mdm_->RequestGlobalDump(MemoryDumpType::PEAK_MEMORY_USAGE,
- polling_state_.level_of_detail);
- }
-
- // TODO(ssid): Use RequestSchedulerCallback, crbug.com/607533.
- ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE,
- Bind(&MemoryDumpScheduler::PollMemoryOnPollingThread, Unretained(this)),
- TimeDelta::FromMilliseconds(polling_state_.polling_interval_ms));
-}
-
-bool MemoryDumpScheduler::ShouldTriggerDump(uint64_t current_memory_total) {
- // This function tries to detect peak memory usage as discussed in
- // https://goo.gl/0kOU4A.
-
- if (current_memory_total == 0)
- return false;
-
- bool should_dump = false;
- ++polling_state_.num_polls_from_last_dump;
- if (polling_state_.last_dump_memory_total == 0) {
- // If it's first sample then trigger memory dump.
- should_dump = true;
- } else if (polling_state_.min_polls_between_dumps >
- polling_state_.num_polls_from_last_dump) {
- return false;
- }
-
- int64_t increase_from_last_dump =
- current_memory_total - polling_state_.last_dump_memory_total;
- should_dump |=
- increase_from_last_dump > polling_state_.memory_increase_threshold;
- should_dump |= IsCurrentSamplePeak(current_memory_total);
- if (should_dump)
- polling_state_.ResetTotals();
- return should_dump;
-}
-
-bool MemoryDumpScheduler::IsCurrentSamplePeak(
- uint64_t current_memory_total_bytes) {
- uint64_t current_memory_total_kb = current_memory_total_bytes / 1024;
- polling_state_.last_memory_totals_kb_index =
- (polling_state_.last_memory_totals_kb_index + 1) %
- PollingTriggerState::kMaxNumMemorySamples;
- uint64_t mean = 0;
- for (uint32_t i = 0; i < PollingTriggerState::kMaxNumMemorySamples; ++i) {
- if (polling_state_.last_memory_totals_kb[i] == 0) {
- // Not enough samples to detect peaks.
- polling_state_
- .last_memory_totals_kb[polling_state_.last_memory_totals_kb_index] =
- current_memory_total_kb;
- return false;
- }
- mean += polling_state_.last_memory_totals_kb[i];
- }
- mean = mean / PollingTriggerState::kMaxNumMemorySamples;
- uint64_t variance = 0;
- for (uint32_t i = 0; i < PollingTriggerState::kMaxNumMemorySamples; ++i) {
- variance += (polling_state_.last_memory_totals_kb[i] - mean) *
- (polling_state_.last_memory_totals_kb[i] - mean);
- }
- variance = variance / PollingTriggerState::kMaxNumMemorySamples;
-
- polling_state_
- .last_memory_totals_kb[polling_state_.last_memory_totals_kb_index] =
- current_memory_total_kb;
-
- // If stddev is less than 0.2% then we consider that the process is inactive.
- bool is_stddev_low = variance < mean / 500 * mean / 500;
- if (is_stddev_low)
- return false;
-
- // (mean + 3.69 * stddev) corresponds to a value that is higher than current
- // sample with 99.99% probability.
- return (current_memory_total_kb - mean) * (current_memory_total_kb - mean) >
- (3.69 * 3.69 * variance);
-}
-
-MemoryDumpScheduler::PeriodicTriggerState::PeriodicTriggerState()
- : is_configured(false),
- dump_count(0),
- min_timer_period_ms(std::numeric_limits<uint32_t>::max()),
- light_dumps_rate(0),
- heavy_dumps_rate(0),
- light_dump_period_ms(0),
- heavy_dump_period_ms(0) {}
-
-MemoryDumpScheduler::PeriodicTriggerState::~PeriodicTriggerState() {
- DCHECK(!timer.IsRunning());
-}
-
-MemoryDumpScheduler::PollingTriggerState::PollingTriggerState(
- scoped_refptr<SingleThreadTaskRunner> polling_task_runner)
- : current_state(DISABLED),
- level_of_detail(MemoryDumpLevelOfDetail::FIRST),
- polling_task_runner(polling_task_runner),
- polling_interval_ms(g_polling_interval_ms_for_testing
- ? g_polling_interval_ms_for_testing
- : kMemoryTotalsPollingInterval),
- min_polls_between_dumps(0),
- num_polls_from_last_dump(-1),
- last_dump_memory_total(0),
- memory_increase_threshold(0),
- last_memory_totals_kb_index(0) {}
-
-MemoryDumpScheduler::PollingTriggerState::~PollingTriggerState() {
- DCHECK(!polling_task_runner);
-}
-
-void MemoryDumpScheduler::PollingTriggerState::ResetTotals() {
- if (!memory_increase_threshold) {
- memory_increase_threshold = kDefaultMemoryIncreaseThreshold;
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
- defined(OS_ANDROID)
- // Set threshold to 1% of total system memory.
- SystemMemoryInfoKB meminfo;
- bool res = GetSystemMemoryInfo(&meminfo);
- if (res)
- memory_increase_threshold = (meminfo.total / 100) * 1024;
-#endif
- }
-
- // Update the |last_dump_memory_total|'s value from the totals if it's not
- // first poll.
- if (num_polls_from_last_dump >= 0 &&
- last_memory_totals_kb[last_memory_totals_kb_index]) {
- last_dump_memory_total =
- last_memory_totals_kb[last_memory_totals_kb_index] * 1024;
- }
- num_polls_from_last_dump = 0;
- for (uint32_t i = 0; i < kMaxNumMemorySamples; ++i)
- last_memory_totals_kb[i] = 0;
- last_memory_totals_kb_index = 0;
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_dump_scheduler.h b/base/trace_event/memory_dump_scheduler.h
deleted file mode 100644
index fd21fce834..0000000000
--- a/base/trace_event/memory_dump_scheduler.h
+++ /dev/null
@@ -1,141 +0,0 @@
-// 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 BASE_TRACE_EVENT_MEMORY_DUMP_SCHEDULER_H
-#define BASE_TRACE_EVENT_MEMORY_DUMP_SCHEDULER_H
-
-#include "base/base_export.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/timer/timer.h"
-#include "base/trace_event/memory_dump_request_args.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-
-namespace trace_event {
-
-class MemoryDumpManager;
-
-// Schedules global dump requests based on the triggers added.
-class BASE_EXPORT MemoryDumpScheduler {
- public:
- MemoryDumpScheduler(
- MemoryDumpManager* mdm_,
- scoped_refptr<SingleThreadTaskRunner> polling_task_runner);
- ~MemoryDumpScheduler();
-
- // Adds triggers for scheduling global dumps. Both periodic and peak triggers
- // cannot be added together. At the moment the periodic support is limited to
- // at most one periodic trigger per dump mode and peak triggers are limited to
- // at most one. All intervals should be an integeral multiple of the smallest
- // interval specified.
- void AddTrigger(MemoryDumpType trigger_type,
- MemoryDumpLevelOfDetail level_of_detail,
- uint32_t min_time_between_dumps_ms);
-
- // Starts periodic dumps.
- void NotifyPeriodicTriggerSupported();
-
- // Starts polling memory total.
- void NotifyPollingSupported();
-
- // Resets time for triggering dump to account for minimum time between the
- // dumps.
- void NotifyDumpTriggered();
-
- // Disables all triggers.
- void DisableAllTriggers();
-
- private:
- friend class MemoryDumpManagerTest;
- FRIEND_TEST_ALL_PREFIXES(MemoryDumpManagerTest, TestPollingOnDumpThread);
-
- // Helper class to schdule periodic memory dumps.
- struct PeriodicTriggerState {
- PeriodicTriggerState();
- ~PeriodicTriggerState();
-
- bool is_configured;
-
- RepeatingTimer timer;
- uint32_t dump_count;
- uint32_t min_timer_period_ms;
- uint32_t light_dumps_rate;
- uint32_t heavy_dumps_rate;
-
- uint32_t light_dump_period_ms;
- uint32_t heavy_dump_period_ms;
-
- DISALLOW_COPY_AND_ASSIGN(PeriodicTriggerState);
- };
-
- struct PollingTriggerState {
- enum State {
- CONFIGURED, // Polling trigger was added.
- ENABLED, // Polling is running.
- DISABLED // Polling is disabled.
- };
-
- static const uint32_t kMaxNumMemorySamples = 50;
-
- explicit PollingTriggerState(
- scoped_refptr<SingleThreadTaskRunner> polling_task_runner);
- ~PollingTriggerState();
-
- // Helper to clear the tracked memory totals and poll count from last dump.
- void ResetTotals();
-
- State current_state;
- MemoryDumpLevelOfDetail level_of_detail;
-
- scoped_refptr<SingleThreadTaskRunner> polling_task_runner;
- uint32_t polling_interval_ms;
-
- // Minimum numer of polls after the last dump at which next dump can be
- // triggered.
- int min_polls_between_dumps;
- int num_polls_from_last_dump;
-
- uint64_t last_dump_memory_total;
- int64_t memory_increase_threshold;
- uint64_t last_memory_totals_kb[kMaxNumMemorySamples];
- uint32_t last_memory_totals_kb_index;
-
- DISALLOW_COPY_AND_ASSIGN(PollingTriggerState);
- };
-
- // Helper to set polling disabled on the polling thread.
- void DisablePolling();
-
- // Periodically called by the timer.
- void RequestPeriodicGlobalDump();
-
- // Called for polling memory usage and trigger dumps if peak is detected.
- void PollMemoryOnPollingThread();
-
- // Returns true if peak memory value is detected.
- bool ShouldTriggerDump(uint64_t current_memory_total);
-
- // Helper to detect peaks in memory usage.
- bool IsCurrentSamplePeak(uint64_t current_memory_total);
-
- // Must be set before enabling tracing.
- static void SetPollingIntervalForTesting(uint32_t interval);
-
- // True if periodic dumping is enabled.
- bool IsPeriodicTimerRunningForTesting();
-
- MemoryDumpManager* mdm_;
-
- PeriodicTriggerState periodic_state_;
- PollingTriggerState polling_state_;
-
- DISALLOW_COPY_AND_ASSIGN(MemoryDumpScheduler);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_MEMORY_DUMP_SCHEDULER_H
diff --git a/base/trace_event/memory_dump_session_state.cc b/base/trace_event/memory_dump_session_state.cc
index d26b82a5b7..b3d9a8ccfc 100644
--- a/base/trace_event/memory_dump_session_state.cc
+++ b/base/trace_event/memory_dump_session_state.cc
@@ -7,8 +7,8 @@
namespace base {
namespace trace_event {
-MemoryDumpSessionState::MemoryDumpSessionState()
- : heap_profiler_breakdown_threshold_bytes_(0) {}
+MemoryDumpSessionState::MemoryDumpSessionState() {}
+
MemoryDumpSessionState::~MemoryDumpSessionState() {}
void MemoryDumpSessionState::SetStackFrameDeduplicator(
@@ -23,14 +23,9 @@ void MemoryDumpSessionState::SetTypeNameDeduplicator(
type_name_deduplicator_ = std::move(type_name_deduplicator);
}
-void MemoryDumpSessionState::SetAllowedDumpModes(
- std::set<MemoryDumpLevelOfDetail> allowed_dump_modes) {
- allowed_dump_modes_ = allowed_dump_modes;
-}
-
-bool MemoryDumpSessionState::IsDumpModeAllowed(
- MemoryDumpLevelOfDetail dump_mode) const {
- return allowed_dump_modes_.count(dump_mode) != 0;
+void MemoryDumpSessionState::SetMemoryDumpConfig(
+ const TraceConfig::MemoryDumpConfig& config) {
+ memory_dump_config_ = config;
}
} // namespace trace_event
diff --git a/base/trace_event/memory_dump_session_state.h b/base/trace_event/memory_dump_session_state.h
index 46092cb483..f199ec1a2f 100644
--- a/base/trace_event/memory_dump_session_state.h
+++ b/base/trace_event/memory_dump_session_state.h
@@ -6,12 +6,11 @@
#define BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
#include <memory>
-#include <set>
#include "base/base_export.h"
#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
-#include "base/trace_event/memory_dump_request_args.h"
+#include "base/trace_event/trace_config.h"
namespace base {
namespace trace_event {
@@ -41,18 +40,11 @@ class BASE_EXPORT MemoryDumpSessionState
void SetTypeNameDeduplicator(
std::unique_ptr<TypeNameDeduplicator> type_name_deduplicator);
- void SetAllowedDumpModes(
- std::set<MemoryDumpLevelOfDetail> allowed_dump_modes);
-
- bool IsDumpModeAllowed(MemoryDumpLevelOfDetail dump_mode) const;
-
- void set_heap_profiler_breakdown_threshold_bytes(uint32_t value) {
- heap_profiler_breakdown_threshold_bytes_ = value;
+ const TraceConfig::MemoryDumpConfig& memory_dump_config() const {
+ return memory_dump_config_;
}
- uint32_t heap_profiler_breakdown_threshold_bytes() const {
- return heap_profiler_breakdown_threshold_bytes_;
- }
+ void SetMemoryDumpConfig(const TraceConfig::MemoryDumpConfig& config);
private:
friend class RefCountedThreadSafe<MemoryDumpSessionState>;
@@ -66,9 +58,9 @@ class BASE_EXPORT MemoryDumpSessionState
// trace is finalized.
std::unique_ptr<TypeNameDeduplicator> type_name_deduplicator_;
- std::set<MemoryDumpLevelOfDetail> allowed_dump_modes_;
-
- uint32_t heap_profiler_breakdown_threshold_bytes_;
+ // The memory dump config, copied at the time when the tracing session was
+ // started.
+ TraceConfig::MemoryDumpConfig memory_dump_config_;
};
} // namespace trace_event
diff --git a/base/trace_event/memory_infra_background_whitelist.cc b/base/trace_event/memory_infra_background_whitelist.cc
index ae74322040..aed187fa1d 100644
--- a/base/trace_event/memory_infra_background_whitelist.cc
+++ b/base/trace_event/memory_infra_background_whitelist.cc
@@ -17,26 +17,20 @@ namespace {
// providers can be added here only if the background mode dump has very
// less performance and memory overhead.
const char* const kDumpProviderWhitelist[] = {
- "android::ResourceManagerImpl",
"BlinkGC",
- "ClientDiscardableSharedMemoryManager",
+ "ChildDiscardableSharedMemoryManager",
"DOMStorage",
- "DiscardableSharedMemoryManager",
+ "HostDiscardableSharedMemoryManager",
"IndexedDBBackingStore",
"JavaHeap",
- "LevelDB",
"LeveldbValueStore",
"Malloc",
- "MemoryCache",
"PartitionAlloc",
"ProcessMemoryMetrics",
"Skia",
"Sql",
- "URLRequestContext",
"V8Isolate",
"WinHeap",
- "SyncDirectory",
- "TabRestoreServiceHelper",
nullptr // End of list marker.
};
@@ -52,7 +46,6 @@ const char* const kAllocatorDumpNameWhitelist[] = {
"java_heap",
"java_heap/allocated_objects",
"leveldb/index_db/0x?",
- "leveldb/leveldb_proto/0x?",
"leveldb/value_store/Extensions.Database.Open.Settings/0x?",
"leveldb/value_store/Extensions.Database.Open.Rules/0x?",
"leveldb/value_store/Extensions.Database.Open.State/0x?",
@@ -62,33 +55,14 @@ const char* const kAllocatorDumpNameWhitelist[] = {
"malloc",
"malloc/allocated_objects",
"malloc/metadata_fragmentation_caches",
- "net/http_network_session_0x?",
- "net/http_network_session_0x?/quic_stream_factory",
- "net/http_network_session_0x?/socket_pool",
- "net/http_network_session_0x?/spdy_session_pool",
- "net/http_network_session_0x?/stream_factory",
- "net/sdch_manager_0x?",
- "net/ssl_session_cache",
- "net/url_request_context_0x?",
- "net/url_request_context_0x?/http_cache",
- "net/url_request_context_0x?/http_network_session",
- "net/url_request_context_0x?/sdch_manager",
- "web_cache/Image_resources",
- "web_cache/CSS stylesheet_resources",
- "web_cache/Script_resources",
- "web_cache/XSL stylesheet_resources",
- "web_cache/Font_resources",
- "web_cache/Other_resources",
"partition_alloc/allocated_objects",
"partition_alloc/partitions",
- "partition_alloc/partitions/array_buffer",
"partition_alloc/partitions/buffer",
"partition_alloc/partitions/fast_malloc",
"partition_alloc/partitions/layout",
"skia/sk_glyph_cache",
"skia/sk_resource_cache",
"sqlite",
- "ui/resource_manager_0x?",
"v8/isolate_0x?/heap_spaces",
"v8/isolate_0x?/heap_spaces/code_space",
"v8/isolate_0x?/heap_spaces/large_object_space",
@@ -100,47 +74,6 @@ const char* const kAllocatorDumpNameWhitelist[] = {
"v8/isolate_0x?/zapped_for_debug",
"winheap",
"winheap/allocated_objects",
- "sync/0x?/kernel",
- "sync/0x?/store",
- "sync/0x?/model_type/APP",
- "sync/0x?/model_type/APP_LIST",
- "sync/0x?/model_type/APP_NOTIFICATION",
- "sync/0x?/model_type/APP_SETTING",
- "sync/0x?/model_type/ARC_PACKAGE",
- "sync/0x?/model_type/ARTICLE",
- "sync/0x?/model_type/AUTOFILL",
- "sync/0x?/model_type/AUTOFILL_PROFILE",
- "sync/0x?/model_type/AUTOFILL_WALLET",
- "sync/0x?/model_type/BOOKMARK",
- "sync/0x?/model_type/DEVICE_INFO",
- "sync/0x?/model_type/DICTIONARY",
- "sync/0x?/model_type/EXPERIMENTS",
- "sync/0x?/model_type/EXTENSION",
- "sync/0x?/model_type/EXTENSION_SETTING",
- "sync/0x?/model_type/FAVICON_IMAGE",
- "sync/0x?/model_type/FAVICON_TRACKING",
- "sync/0x?/model_type/HISTORY_DELETE_DIRECTIVE",
- "sync/0x?/model_type/MANAGED_USER",
- "sync/0x?/model_type/MANAGED_USER_SETTING",
- "sync/0x?/model_type/MANAGED_USER_SHARED_SETTING",
- "sync/0x?/model_type/MANAGED_USER_WHITELIST",
- "sync/0x?/model_type/NIGORI",
- "sync/0x?/model_type/PASSWORD",
- "sync/0x?/model_type/PREFERENCE",
- "sync/0x?/model_type/PRINTER",
- "sync/0x?/model_type/PRIORITY_PREFERENCE",
- "sync/0x?/model_type/READING_LIST",
- "sync/0x?/model_type/SEARCH_ENGINE",
- "sync/0x?/model_type/SESSION",
- "sync/0x?/model_type/SYNCED_NOTIFICATION",
- "sync/0x?/model_type/SYNCED_NOTIFICATION_APP_INFO",
- "sync/0x?/model_type/THEME",
- "sync/0x?/model_type/TYPED_URL",
- "sync/0x?/model_type/WALLET_METADATA",
- "sync/0x?/model_type/WIFI_CREDENTIAL",
- "tab_restore/service_helper_0x?/entries",
- "tab_restore/service_helper_0x?/entries/tab_0x?",
- "tab_restore/service_helper_0x?/entries/window_0x?",
nullptr // End of list marker.
};
diff --git a/base/trace_event/memory_usage_estimator.cc b/base/trace_event/memory_usage_estimator.cc
deleted file mode 100644
index c769d5b6f1..0000000000
--- a/base/trace_event/memory_usage_estimator.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2016 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.
-
-#include "base/trace_event/memory_usage_estimator.h"
-
-namespace base {
-namespace trace_event {
-
-template size_t EstimateMemoryUsage(const std::string&);
-template size_t EstimateMemoryUsage(const string16&);
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_usage_estimator.h b/base/trace_event/memory_usage_estimator.h
deleted file mode 100644
index db4ea6956c..0000000000
--- a/base/trace_event/memory_usage_estimator.h
+++ /dev/null
@@ -1,549 +0,0 @@
-// Copyright 2016 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 BASE_TRACE_EVENT_MEMORY_USAGE_ESTIMATOR_H_
-#define BASE_TRACE_EVENT_MEMORY_USAGE_ESTIMATOR_H_
-
-#include <stdint.h>
-
-#include <array>
-#include <deque>
-#include <list>
-#include <map>
-#include <memory>
-#include <queue>
-#include <set>
-#include <stack>
-#include <string>
-#include <type_traits>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-#include "base/base_export.h"
-#include "base/containers/linked_list.h"
-#include "base/strings/string16.h"
-#include "base/template_util.h"
-
-// Composable memory usage estimators.
-//
-// This file defines set of EstimateMemoryUsage(object) functions that return
-// approximate memory usage of their argument.
-//
-// The ultimate goal is to make memory usage estimation for a class simply a
-// matter of aggregating EstimateMemoryUsage() results over all fields.
-//
-// That is achieved via composability: if EstimateMemoryUsage() is defined
-// for T then EstimateMemoryUsage() is also defined for any combination of
-// containers holding T (e.g. std::map<int, std::vector<T>>).
-//
-// There are two ways of defining EstimateMemoryUsage() for a type:
-//
-// 1. As a global function 'size_t EstimateMemoryUsage(T)' in
-// in base::trace_event namespace.
-//
-// 2. As 'size_t T::EstimateMemoryUsage() const' method. In this case
-// EstimateMemoryUsage(T) function in base::trace_event namespace is
-// provided automatically.
-//
-// Here is an example implementation:
-//
-// size_t foo::bar::MyClass::EstimateMemoryUsage() const {
-// return base::trace_event::EstimateMemoryUsage(name_) +
-// base::trace_event::EstimateMemoryUsage(id_) +
-// base::trace_event::EstimateMemoryUsage(items_);
-// }
-//
-// The approach is simple: first call EstimateMemoryUsage() on all members,
-// then recursively fix compilation errors that are caused by types not
-// implementing EstimateMemoryUsage().
-
-namespace base {
-namespace trace_event {
-
-// Declarations
-
-// If T declares 'EstimateMemoryUsage() const' member function, then
-// global function EstimateMemoryUsage(T) is available, and just calls
-// the member function.
-template <class T>
-auto EstimateMemoryUsage(const T& object)
- -> decltype(object.EstimateMemoryUsage());
-
-// String
-
-template <class C, class T, class A>
-size_t EstimateMemoryUsage(const std::basic_string<C, T, A>& string);
-
-// Arrays
-
-template <class T, size_t N>
-size_t EstimateMemoryUsage(const std::array<T, N>& array);
-
-template <class T, size_t N>
-size_t EstimateMemoryUsage(T (&array)[N]);
-
-template <class T>
-size_t EstimateMemoryUsage(const T* array, size_t array_length);
-
-// std::unique_ptr
-
-template <class T, class D>
-size_t EstimateMemoryUsage(const std::unique_ptr<T, D>& ptr);
-
-template <class T, class D>
-size_t EstimateMemoryUsage(const std::unique_ptr<T[], D>& array,
- size_t array_length);
-
-// std::shared_ptr
-
-template <class T>
-size_t EstimateMemoryUsage(const std::shared_ptr<T>& ptr);
-
-// Containers
-
-template <class F, class S>
-size_t EstimateMemoryUsage(const std::pair<F, S>& pair);
-
-template <class T, class A>
-size_t EstimateMemoryUsage(const std::vector<T, A>& vector);
-
-template <class T, class A>
-size_t EstimateMemoryUsage(const std::list<T, A>& list);
-
-template <class T>
-size_t EstimateMemoryUsage(const base::LinkedList<T>& list);
-
-template <class T, class C, class A>
-size_t EstimateMemoryUsage(const std::set<T, C, A>& set);
-
-template <class T, class C, class A>
-size_t EstimateMemoryUsage(const std::multiset<T, C, A>& set);
-
-template <class K, class V, class C, class A>
-size_t EstimateMemoryUsage(const std::map<K, V, C, A>& map);
-
-template <class K, class V, class C, class A>
-size_t EstimateMemoryUsage(const std::multimap<K, V, C, A>& map);
-
-template <class T, class H, class KE, class A>
-size_t EstimateMemoryUsage(const std::unordered_set<T, H, KE, A>& set);
-
-template <class T, class H, class KE, class A>
-size_t EstimateMemoryUsage(const std::unordered_multiset<T, H, KE, A>& set);
-
-template <class K, class V, class H, class KE, class A>
-size_t EstimateMemoryUsage(const std::unordered_map<K, V, H, KE, A>& map);
-
-template <class K, class V, class H, class KE, class A>
-size_t EstimateMemoryUsage(const std::unordered_multimap<K, V, H, KE, A>& map);
-
-template <class T, class A>
-size_t EstimateMemoryUsage(const std::deque<T, A>& deque);
-
-template <class T, class C>
-size_t EstimateMemoryUsage(const std::queue<T, C>& queue);
-
-template <class T, class C>
-size_t EstimateMemoryUsage(const std::priority_queue<T, C>& queue);
-
-template <class T, class C>
-size_t EstimateMemoryUsage(const std::stack<T, C>& stack);
-
-// TODO(dskiba):
-// std::forward_list
-
-// Definitions
-
-namespace internal {
-
-// HasEMU<T>::value is true iff EstimateMemoryUsage(T) is available.
-// (This is the default version, which is false.)
-template <class T, class X = void>
-struct HasEMU : std::false_type {};
-
-// This HasEMU specialization is only picked up if there exists function
-// EstimateMemoryUsage(const T&) that returns size_t. Simpler ways to
-// achieve this don't work on MSVC.
-template <class T>
-struct HasEMU<
- T,
- typename std::enable_if<std::is_same<
- size_t,
- decltype(EstimateMemoryUsage(std::declval<const T&>()))>::value>::type>
- : std::true_type {};
-
-// EMUCaller<T> does three things:
-// 1. Defines Call() method that calls EstimateMemoryUsage(T) if it's
-// available.
-// 2. If EstimateMemoryUsage(T) is not available, but T has trivial dtor
-// (i.e. it's POD, integer, pointer, enum, etc.) then it defines Call()
-// method that returns 0. This is useful for containers, which allocate
-// memory regardless of T (also for cases like std::map<int, MyClass>).
-// 3. Finally, if EstimateMemoryUsage(T) is not available, then it triggers
-// a static_assert with a helpful message. That cuts numbers of errors
-// considerably - if you just call EstimateMemoryUsage(T) but it's not
-// available for T, then compiler will helpfully list *all* possible
-// variants of it, with an explanation for each.
-template <class T, class X = void>
-struct EMUCaller {
- // std::is_same<> below makes static_assert depend on T, in order to
- // prevent it from asserting regardless instantiation.
- static_assert(std::is_same<T, std::false_type>::value,
- "Neither global function 'size_t EstimateMemoryUsage(T)' "
- "nor member function 'size_t T::EstimateMemoryUsage() const' "
- "is defined for the type.");
-
- static size_t Call(const T&) { return 0; }
-};
-
-template <class T>
-struct EMUCaller<T, typename std::enable_if<HasEMU<T>::value>::type> {
- static size_t Call(const T& value) { return EstimateMemoryUsage(value); }
-};
-
-template <class T>
-struct EMUCaller<
- T,
- typename std::enable_if<!HasEMU<T>::value &&
- is_trivially_destructible<T>::value>::type> {
- static size_t Call(const T&) { return 0; }
-};
-
-// Returns reference to the underlying container of a container adapter.
-// Works for std::stack, std::queue and std::priority_queue.
-template <class A>
-const typename A::container_type& GetUnderlyingContainer(const A& adapter) {
- struct ExposedAdapter : A {
- using A::c;
- };
- return adapter.*&ExposedAdapter::c;
-}
-
-} // namespace internal
-
-// Proxy that deducts T and calls EMUCaller<T>.
-// To be used by EstimateMemoryUsage() implementations for containers.
-template <class T>
-size_t EstimateItemMemoryUsage(const T& value) {
- return internal::EMUCaller<T>::Call(value);
-}
-
-template <class I>
-size_t EstimateIterableMemoryUsage(const I& iterable) {
- size_t memory_usage = 0;
- for (const auto& item : iterable) {
- memory_usage += EstimateItemMemoryUsage(item);
- }
- return memory_usage;
-}
-
-// Global EstimateMemoryUsage(T) that just calls T::EstimateMemoryUsage().
-template <class T>
-auto EstimateMemoryUsage(const T& object)
- -> decltype(object.EstimateMemoryUsage()) {
- static_assert(
- std::is_same<decltype(object.EstimateMemoryUsage()), size_t>::value,
- "'T::EstimateMemoryUsage() const' must return size_t.");
- return object.EstimateMemoryUsage();
-}
-
-// String
-
-template <class C, class T, class A>
-size_t EstimateMemoryUsage(const std::basic_string<C, T, A>& string) {
- using string_type = std::basic_string<C, T, A>;
- using value_type = typename string_type::value_type;
- // C++11 doesn't leave much room for implementors - std::string can
- // use short string optimization, but that's about it. We detect SSO
- // by checking that c_str() points inside |string|.
- const uint8_t* cstr = reinterpret_cast<const uint8_t*>(string.c_str());
- const uint8_t* inline_cstr = reinterpret_cast<const uint8_t*>(&string);
- if (cstr >= inline_cstr && cstr < inline_cstr + sizeof(string)) {
- // SSO string
- return 0;
- }
- return (string.capacity() + 1) * sizeof(value_type);
-}
-
-// Use explicit instantiations from the .cc file (reduces bloat).
-extern template BASE_EXPORT size_t EstimateMemoryUsage(const std::string&);
-extern template BASE_EXPORT size_t EstimateMemoryUsage(const string16&);
-
-// Arrays
-
-template <class T, size_t N>
-size_t EstimateMemoryUsage(const std::array<T, N>& array) {
- return EstimateIterableMemoryUsage(array);
-}
-
-template <class T, size_t N>
-size_t EstimateMemoryUsage(T (&array)[N]) {
- return EstimateIterableMemoryUsage(array);
-}
-
-template <class T>
-size_t EstimateMemoryUsage(const T* array, size_t array_length) {
- size_t memory_usage = sizeof(T) * array_length;
- for (size_t i = 0; i != array_length; ++i) {
- memory_usage += EstimateItemMemoryUsage(array[i]);
- }
- return memory_usage;
-}
-
-// std::unique_ptr
-
-template <class T, class D>
-size_t EstimateMemoryUsage(const std::unique_ptr<T, D>& ptr) {
- return ptr ? (sizeof(T) + EstimateItemMemoryUsage(*ptr)) : 0;
-}
-
-template <class T, class D>
-size_t EstimateMemoryUsage(const std::unique_ptr<T[], D>& array,
- size_t array_length) {
- return EstimateMemoryUsage(array.get(), array_length);
-}
-
-// std::shared_ptr
-
-template <class T>
-size_t EstimateMemoryUsage(const std::shared_ptr<T>& ptr) {
- auto use_count = ptr.use_count();
- if (use_count == 0) {
- return 0;
- }
- // Model shared_ptr after libc++,
- // see __shared_ptr_pointer from include/memory
- struct SharedPointer {
- void* vtbl;
- long shared_owners;
- long shared_weak_owners;
- T* value;
- };
- // If object of size S shared N > S times we prefer to (potentially)
- // overestimate than to return 0.
- return sizeof(SharedPointer) +
- (EstimateItemMemoryUsage(*ptr) + (use_count - 1)) / use_count;
-}
-
-// std::pair
-
-template <class F, class S>
-size_t EstimateMemoryUsage(const std::pair<F, S>& pair) {
- return EstimateItemMemoryUsage(pair.first) +
- EstimateItemMemoryUsage(pair.second);
-}
-
-// std::vector
-
-template <class T, class A>
-size_t EstimateMemoryUsage(const std::vector<T, A>& vector) {
- return sizeof(T) * vector.capacity() + EstimateIterableMemoryUsage(vector);
-}
-
-// std::list
-
-template <class T, class A>
-size_t EstimateMemoryUsage(const std::list<T, A>& list) {
- using value_type = typename std::list<T, A>::value_type;
- struct Node {
- Node* prev;
- Node* next;
- value_type value;
- };
- return sizeof(Node) * list.size() +
- EstimateIterableMemoryUsage(list);
-}
-
-template <class T>
-size_t EstimateMemoryUsage(const base::LinkedList<T>& list) {
- size_t memory_usage = 0u;
- for (base::LinkNode<T>* node = list.head(); node != list.end();
- node = node->next()) {
- // Since we increment by calling node = node->next() we know that node
- // isn't nullptr.
- memory_usage += EstimateMemoryUsage(*node->value()) + sizeof(T);
- }
- return memory_usage;
-}
-
-// Tree containers
-
-template <class V>
-size_t EstimateTreeMemoryUsage(size_t size) {
- // Tree containers are modeled after libc++
- // (__tree_node from include/__tree)
- struct Node {
- Node* left;
- Node* right;
- Node* parent;
- bool is_black;
- V value;
- };
- return sizeof(Node) * size;
-}
-
-template <class T, class C, class A>
-size_t EstimateMemoryUsage(const std::set<T, C, A>& set) {
- using value_type = typename std::set<T, C, A>::value_type;
- return EstimateTreeMemoryUsage<value_type>(set.size()) +
- EstimateIterableMemoryUsage(set);
-}
-
-template <class T, class C, class A>
-size_t EstimateMemoryUsage(const std::multiset<T, C, A>& set) {
- using value_type = typename std::multiset<T, C, A>::value_type;
- return EstimateTreeMemoryUsage<value_type>(set.size()) +
- EstimateIterableMemoryUsage(set);
-}
-
-template <class K, class V, class C, class A>
-size_t EstimateMemoryUsage(const std::map<K, V, C, A>& map) {
- using value_type = typename std::map<K, V, C, A>::value_type;
- return EstimateTreeMemoryUsage<value_type>(map.size()) +
- EstimateIterableMemoryUsage(map);
-}
-
-template <class K, class V, class C, class A>
-size_t EstimateMemoryUsage(const std::multimap<K, V, C, A>& map) {
- using value_type = typename std::multimap<K, V, C, A>::value_type;
- return EstimateTreeMemoryUsage<value_type>(map.size()) +
- EstimateIterableMemoryUsage(map);
-}
-
-// HashMap containers
-
-namespace internal {
-
-// While hashtable containers model doesn't depend on STL implementation, one
-// detail still crept in: bucket_count. It's used in size estimation, but its
-// value after inserting N items is not predictable.
-// This function is specialized by unittests to return constant value, thus
-// excluding bucket_count from testing.
-template <class V>
-size_t HashMapBucketCountForTesting(size_t bucket_count) {
- return bucket_count;
-}
-
-} // namespace internal
-
-template <class V>
-size_t EstimateHashMapMemoryUsage(size_t bucket_count, size_t size) {
- // Hashtable containers are modeled after libc++
- // (__hash_node from include/__hash_table)
- struct Node {
- void* next;
- size_t hash;
- V value;
- };
- using Bucket = void*;
- bucket_count = internal::HashMapBucketCountForTesting<V>(bucket_count);
- return sizeof(Bucket) * bucket_count + sizeof(Node) * size;
-}
-
-template <class K, class H, class KE, class A>
-size_t EstimateMemoryUsage(const std::unordered_set<K, H, KE, A>& set) {
- using value_type = typename std::unordered_set<K, H, KE, A>::value_type;
- return EstimateHashMapMemoryUsage<value_type>(set.bucket_count(),
- set.size()) +
- EstimateIterableMemoryUsage(set);
-}
-
-template <class K, class H, class KE, class A>
-size_t EstimateMemoryUsage(const std::unordered_multiset<K, H, KE, A>& set) {
- using value_type = typename std::unordered_multiset<K, H, KE, A>::value_type;
- return EstimateHashMapMemoryUsage<value_type>(set.bucket_count(),
- set.size()) +
- EstimateIterableMemoryUsage(set);
-}
-
-template <class K, class V, class H, class KE, class A>
-size_t EstimateMemoryUsage(const std::unordered_map<K, V, H, KE, A>& map) {
- using value_type = typename std::unordered_map<K, V, H, KE, A>::value_type;
- return EstimateHashMapMemoryUsage<value_type>(map.bucket_count(),
- map.size()) +
- EstimateIterableMemoryUsage(map);
-}
-
-template <class K, class V, class H, class KE, class A>
-size_t EstimateMemoryUsage(const std::unordered_multimap<K, V, H, KE, A>& map) {
- using value_type =
- typename std::unordered_multimap<K, V, H, KE, A>::value_type;
- return EstimateHashMapMemoryUsage<value_type>(map.bucket_count(),
- map.size()) +
- EstimateIterableMemoryUsage(map);
-}
-
-// std::deque
-
-template <class T, class A>
-size_t EstimateMemoryUsage(const std::deque<T, A>& deque) {
-// Since std::deque implementations are wildly different
-// (see crbug.com/674287), we can't have one "good enough"
-// way to estimate.
-
-// kBlockSize - minimum size of a block, in bytes
-// kMinBlockLength - number of elements in a block
-// if sizeof(T) > kBlockSize
-#if defined(_LIBCPP_VERSION)
- size_t kBlockSize = 4096;
- size_t kMinBlockLength = 16;
-#elif defined(__GLIBCXX__)
- size_t kBlockSize = 512;
- size_t kMinBlockLength = 1;
-#elif defined(_MSC_VER)
- size_t kBlockSize = 16;
- size_t kMinBlockLength = 1;
-#else
- size_t kBlockSize = 0;
- size_t kMinBlockLength = 1;
-#endif
-
- size_t block_length =
- (sizeof(T) > kBlockSize) ? kMinBlockLength : kBlockSize / sizeof(T);
-
- size_t blocks = (deque.size() + block_length - 1) / block_length;
-
-#if defined(__GLIBCXX__)
- // libstdc++: deque always has at least one block
- if (!blocks)
- blocks = 1;
-#endif
-
-#if defined(_LIBCPP_VERSION)
- // libc++: deque keeps at most two blocks when it shrinks,
- // so even if the size is zero, deque might be holding up
- // to 4096 * 2 bytes. One way to know whether deque has
- // ever allocated (and hence has 1 or 2 blocks) is to check
- // iterator's pointer. Non-zero value means that deque has
- // at least one block.
- if (!blocks && deque.begin().operator->())
- blocks = 1;
-#endif
-
- return (blocks * block_length * sizeof(T)) +
- EstimateIterableMemoryUsage(deque);
-}
-
-// Container adapters
-
-template <class T, class C>
-size_t EstimateMemoryUsage(const std::queue<T, C>& queue) {
- return EstimateMemoryUsage(internal::GetUnderlyingContainer(queue));
-}
-
-template <class T, class C>
-size_t EstimateMemoryUsage(const std::priority_queue<T, C>& queue) {
- return EstimateMemoryUsage(internal::GetUnderlyingContainer(queue));
-}
-
-template <class T, class C>
-size_t EstimateMemoryUsage(const std::stack<T, C>& stack) {
- return EstimateMemoryUsage(internal::GetUnderlyingContainer(stack));
-}
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_MEMORY_USAGE_ESTIMATOR_H_
diff --git a/base/trace_event/memory_usage_estimator_unittest.cc b/base/trace_event/memory_usage_estimator_unittest.cc
deleted file mode 100644
index 80237c0192..0000000000
--- a/base/trace_event/memory_usage_estimator_unittest.cc
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright 2016 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.
-
-#include "base/trace_event/memory_usage_estimator.h"
-
-#include <stdlib.h>
-
-#include "base/memory/ptr_util.h"
-#include "base/strings/string16.h"
-#include "build/build_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(ARCH_CPU_64_BITS)
-#define EXPECT_EQ_32_64(_, e, a) EXPECT_EQ(e, a)
-#else
-#define EXPECT_EQ_32_64(e, _, a) EXPECT_EQ(e, a)
-#endif
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-// Test class with predictable memory usage.
-class Data {
- public:
- explicit Data(size_t size = 17): size_(size) {
- }
-
- size_t size() const { return size_; }
-
- size_t EstimateMemoryUsage() const {
- return size_;
- }
-
- bool operator < (const Data& other) const {
- return size_ < other.size_;
- }
- bool operator == (const Data& other) const {
- return size_ == other.size_;
- }
-
- struct Hasher {
- size_t operator () (const Data& data) const {
- return data.size();
- }
- };
-
- private:
- size_t size_;
-};
-
-} // namespace
-
-namespace internal {
-
-// This kills variance of bucket_count across STL implementations.
-template <>
-size_t HashMapBucketCountForTesting<Data>(size_t) {
- return 10;
-}
-template <>
-size_t HashMapBucketCountForTesting<std::pair<const Data, short>>(size_t) {
- return 10;
-}
-
-} // namespace internal
-
-TEST(EstimateMemoryUsageTest, String) {
- std::string string(777, 'a');
- EXPECT_EQ(string.capacity() + 1, EstimateMemoryUsage(string));
-}
-
-TEST(EstimateMemoryUsageTest, String16) {
- string16 string(777, 'a');
- EXPECT_EQ(sizeof(char16) * (string.capacity() + 1),
- EstimateMemoryUsage(string));
-}
-
-TEST(EstimateMemoryUsageTest, Arrays) {
- // std::array
- {
- std::array<Data, 10> array;
- EXPECT_EQ(170u, EstimateMemoryUsage(array));
- }
-
- // T[N]
- {
- Data array[10];
- EXPECT_EQ(170u, EstimateMemoryUsage(array));
- }
-
- // C array
- {
- struct Item {
- char payload[10];
- };
- Item* array = new Item[7];
- EXPECT_EQ(70u, EstimateMemoryUsage(array, 7));
- delete[] array;
- }
-}
-
-TEST(EstimateMemoryUsageTest, UniquePtr) {
- // Empty
- {
- std::unique_ptr<Data> ptr;
- EXPECT_EQ(0u, EstimateMemoryUsage(ptr));
- }
-
- // Not empty
- {
- std::unique_ptr<Data> ptr(new Data());
- EXPECT_EQ_32_64(21u, 25u, EstimateMemoryUsage(ptr));
- }
-
- // With a pointer
- {
- std::unique_ptr<Data*> ptr(new Data*());
- EXPECT_EQ(sizeof(void*), EstimateMemoryUsage(ptr));
- }
-
- // With an array
- {
- struct Item {
- uint32_t payload[10];
- };
- std::unique_ptr<Item[]> ptr(new Item[7]);
- EXPECT_EQ(280u, EstimateMemoryUsage(ptr, 7));
- }
-}
-
-TEST(EstimateMemoryUsageTest, Vector) {
- std::vector<Data> vector;
- vector.reserve(1000);
-
- // For an empty vector we should return memory usage of its buffer
- size_t capacity = vector.capacity();
- size_t expected_size = capacity * sizeof(Data);
- EXPECT_EQ(expected_size, EstimateMemoryUsage(vector));
-
- // If vector is not empty, its size should also include memory usages
- // of all elements.
- for (size_t i = 0; i != capacity / 2; ++i) {
- vector.push_back(Data(i));
- expected_size += EstimateMemoryUsage(vector.back());
- }
- EXPECT_EQ(expected_size, EstimateMemoryUsage(vector));
-}
-
-TEST(EstimateMemoryUsageTest, List) {
- struct POD {
- short data;
- };
- std::list<POD> list;
- for (int i = 0; i != 1000; ++i) {
- list.push_back(POD());
- }
- EXPECT_EQ_32_64(12000u, 24000u, EstimateMemoryUsage(list));
-}
-
-TEST(EstimateMemoryUsageTest, Set) {
- std::set<std::pair<int, Data>> set;
- for (int i = 0; i != 1000; ++i) {
- set.insert({i, Data(i)});
- }
- EXPECT_EQ_32_64(523500u, 547500u, EstimateMemoryUsage(set));
-}
-
-TEST(EstimateMemoryUsageTest, MultiSet) {
- std::multiset<bool> set;
- for (int i = 0; i != 1000; ++i) {
- set.insert((i & 1) != 0);
- }
- EXPECT_EQ_32_64(16000u, 32000u, EstimateMemoryUsage(set));
-}
-
-TEST(EstimateMemoryUsageTest, Map) {
- std::map<Data, int> map;
- for (int i = 0; i != 1000; ++i) {
- map.insert({Data(i), i});
- }
- EXPECT_EQ_32_64(523500u, 547500u, EstimateMemoryUsage(map));
-}
-
-TEST(EstimateMemoryUsageTest, MultiMap) {
- std::multimap<char, Data> map;
- for (int i = 0; i != 1000; ++i) {
- map.insert({static_cast<char>(i), Data(i)});
- }
- EXPECT_EQ_32_64(523500u, 547500u, EstimateMemoryUsage(map));
-}
-
-TEST(EstimateMemoryUsageTest, UnorderedSet) {
- std::unordered_set<Data, Data::Hasher> set;
- for (int i = 0; i != 1000; ++i) {
- set.insert(Data(i));
- }
- EXPECT_EQ_32_64(511540u, 523580u, EstimateMemoryUsage(set));
-}
-
-TEST(EstimateMemoryUsageTest, UnorderedMultiSet) {
- std::unordered_multiset<Data, Data::Hasher> set;
- for (int i = 0; i != 500; ++i) {
- set.insert(Data(i));
- set.insert(Data(i));
- }
- EXPECT_EQ_32_64(261540u, 273580u, EstimateMemoryUsage(set));
-}
-
-TEST(EstimateMemoryUsageTest, UnorderedMap) {
- std::unordered_map<Data, short, Data::Hasher> map;
- for (int i = 0; i != 1000; ++i) {
- map.insert({Data(i), static_cast<short>(i)});
- }
- EXPECT_EQ_32_64(515540u, 531580u, EstimateMemoryUsage(map));
-}
-
-TEST(EstimateMemoryUsageTest, UnorderedMultiMap) {
- std::unordered_multimap<Data, short, Data::Hasher> map;
- for (int i = 0; i != 1000; ++i) {
- map.insert({Data(i), static_cast<short>(i)});
- }
- EXPECT_EQ_32_64(515540u, 531580u, EstimateMemoryUsage(map));
-}
-
-TEST(EstimateMemoryUsageTest, Deque) {
- std::deque<Data> deque;
-
- // Pick a large value so that platform-specific accounting
- // for deque's blocks is small compared to usage of all items.
- constexpr size_t kDataSize = 100000;
- for (int i = 0; i != 1500; ++i) {
- deque.push_back(Data(kDataSize));
- }
-
- // Compare against a reasonable minimum (i.e. no overhead).
- size_t min_expected_usage = deque.size() * (sizeof(Data) + kDataSize);
- EXPECT_LE(min_expected_usage, EstimateMemoryUsage(deque));
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index 63d1340e42..826989237b 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -18,7 +18,7 @@
#include "build/build_config.h"
#if defined(OS_IOS)
-#include <mach/vm_page_size.h>
+#include <sys/sysctl.h>
#endif
#if defined(OS_POSIX)
@@ -57,13 +57,19 @@ bool ProcessMemoryDump::is_black_hole_non_fatal_for_testing_ = false;
size_t ProcessMemoryDump::GetSystemPageSize() {
#if defined(OS_IOS)
// On iOS, getpagesize() returns the user page sizes, but for allocating
- // arrays for mincore(), kernel page sizes is needed. Use vm_kernel_page_size
- // as recommended by Apple, https://forums.developer.apple.com/thread/47532/.
- // Refer to http://crbug.com/542671 and Apple rdar://23651782
- return vm_kernel_page_size;
-#else
- return base::GetPageSize();
+ // arrays for mincore(), kernel page sizes is needed. sysctlbyname() should
+ // be used for this. Refer to crbug.com/542671 and Apple rdar://23651782
+ int pagesize;
+ size_t pagesize_len;
+ int status = sysctlbyname("vm.pagesize", NULL, &pagesize_len, nullptr, 0);
+ if (!status && pagesize_len == sizeof(pagesize)) {
+ if (!sysctlbyname("vm.pagesize", &pagesize, &pagesize_len, nullptr, 0))
+ return pagesize;
+ }
+ LOG(ERROR) << "sysctlbyname(\"vm.pagesize\") failed.";
+ // Falls back to getpagesize() although it may be wrong in certain cases.
#endif // defined(OS_IOS)
+ return base::GetPageSize();
}
// static
@@ -158,14 +164,14 @@ ProcessMemoryDump::~ProcessMemoryDump() {}
MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
const std::string& absolute_name) {
return AddAllocatorDumpInternal(
- MakeUnique<MemoryAllocatorDump>(absolute_name, this));
+ WrapUnique(new MemoryAllocatorDump(absolute_name, this)));
}
MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
const std::string& absolute_name,
const MemoryAllocatorDumpGuid& guid) {
return AddAllocatorDumpInternal(
- MakeUnique<MemoryAllocatorDump>(absolute_name, this, guid));
+ WrapUnique(new MemoryAllocatorDump(absolute_name, this, guid)));
}
MemoryAllocatorDump* ProcessMemoryDump::AddAllocatorDumpInternal(
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
index 6f8d167273..d020c7d652 100644
--- a/base/trace_event/process_memory_dump.h
+++ b/base/trace_event/process_memory_dump.h
@@ -31,6 +31,7 @@
namespace base {
namespace trace_event {
+class MemoryDumpManager;
class MemoryDumpSessionState;
class TracedValue;
diff --git a/base/trace_event/trace_buffer.cc b/base/trace_event/trace_buffer.cc
index e26e9fd28f..d40f4302fe 100644
--- a/base/trace_event/trace_buffer.cc
+++ b/base/trace_event/trace_buffer.cc
@@ -168,8 +168,7 @@ class TraceBufferVector : public TraceBuffer {
// have to add the metadata events and flush thread-local buffers even if
// the buffer is full.
*index = chunks_.size();
- // Put nullptr in the slot of a in-flight chunk.
- chunks_.push_back(nullptr);
+ chunks_.push_back(NULL); // Put NULL in the slot of a in-flight chunk.
++in_flight_chunk_count_;
// + 1 because zero chunk_seq is not allowed.
return std::unique_ptr<TraceBufferChunk>(
@@ -182,7 +181,7 @@ class TraceBufferVector : public TraceBuffer {
DCHECK_LT(index, chunks_.size());
DCHECK(!chunks_[index]);
--in_flight_chunk_count_;
- chunks_[index] = std::move(chunk);
+ chunks_[index] = chunk.release();
}
bool IsFull() const override { return chunks_.size() >= max_chunks_; }
@@ -199,7 +198,7 @@ class TraceBufferVector : public TraceBuffer {
TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
if (handle.chunk_index >= chunks_.size())
return NULL;
- TraceBufferChunk* chunk = chunks_[handle.chunk_index].get();
+ TraceBufferChunk* chunk = chunks_[handle.chunk_index];
if (!chunk || chunk->seq() != handle.chunk_seq)
return NULL;
return chunk->GetEventAt(handle.event_index);
@@ -208,7 +207,7 @@ class TraceBufferVector : public TraceBuffer {
const TraceBufferChunk* NextChunk() override {
while (current_iteration_index_ < chunks_.size()) {
// Skip in-flight chunks.
- const TraceBufferChunk* chunk = chunks_[current_iteration_index_++].get();
+ const TraceBufferChunk* chunk = chunks_[current_iteration_index_++];
if (chunk)
return chunk;
}
@@ -224,7 +223,7 @@ class TraceBufferVector : public TraceBuffer {
overhead->Add("TraceBufferVector", chunks_ptr_vector_allocated_size,
chunks_ptr_vector_resident_size);
for (size_t i = 0; i < chunks_.size(); ++i) {
- TraceBufferChunk* chunk = chunks_[i].get();
+ TraceBufferChunk* chunk = chunks_[i];
// Skip the in-flight (nullptr) chunks. They will be accounted by the
// per-thread-local dumpers, see ThreadLocalEventBuffer::OnMemoryDump.
if (chunk)
@@ -236,7 +235,7 @@ class TraceBufferVector : public TraceBuffer {
size_t in_flight_chunk_count_;
size_t current_iteration_index_;
size_t max_chunks_;
- std::vector<std::unique_ptr<TraceBufferChunk>> chunks_;
+ ScopedVector<TraceBufferChunk> chunks_;
DISALLOW_COPY_AND_ASSIGN(TraceBufferVector);
};
diff --git a/base/trace_event/trace_category.h b/base/trace_event/trace_category.h
deleted file mode 100644
index 5a7915ac03..0000000000
--- a/base/trace_event/trace_category.h
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2016 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 BASE_TRACE_EVENT_TRACE_CATEGORY_H_
-#define BASE_TRACE_EVENT_TRACE_CATEGORY_H_
-
-#include <stdint.h>
-
-namespace base {
-namespace trace_event {
-
-// Captures the state of an invidivual trace category. Nothing except tracing
-// internals (e.g., TraceLog) is supposed to have non-const Category pointers.
-struct TraceCategory {
- // The TRACE_EVENT macros should only use this value as a bool.
- // These enum values are effectively a public API and third_party projects
- // depend on their value. Hence, never remove or recycle existing bits, unless
- // you are sure that all the third-party projects that depend on this have
- // been updated.
- enum StateFlags : uint8_t {
- ENABLED_FOR_RECORDING = 1 << 0,
-
- // Not used anymore.
- DEPRECATED_ENABLED_FOR_MONITORING = 1 << 1,
- DEPRECATED_ENABLED_FOR_EVENT_CALLBACK = 1 << 2,
-
- ENABLED_FOR_ETW_EXPORT = 1 << 3,
- ENABLED_FOR_FILTERING = 1 << 4
- };
-
- static const TraceCategory* FromStatePtr(const uint8_t* state_ptr) {
- static_assert(
- offsetof(TraceCategory, state_) == 0,
- "|state_| must be the first field of the TraceCategory class.");
- return reinterpret_cast<const TraceCategory*>(state_ptr);
- }
-
- bool is_valid() const { return name_ != nullptr; }
- void set_name(const char* name) { name_ = name; }
- const char* name() const {
- DCHECK(is_valid());
- return name_;
- }
-
- // TODO(primiano): This is an intermediate solution to deal with the fact that
- // today TRACE_EVENT* macros cache the state ptr. They should just cache the
- // full TraceCategory ptr, which is immutable, and use these helper function
- // here. This will get rid of the need of this awkward ptr getter completely.
- const uint8_t* state_ptr() const {
- return const_cast<const uint8_t*>(&state_);
- }
-
- uint8_t state() const {
- return *const_cast<volatile const uint8_t*>(&state_);
- }
-
- bool is_enabled() const { return state() != 0; }
-
- void set_state(uint8_t state) {
- *const_cast<volatile uint8_t*>(&state_) = state;
- }
-
- void clear_state_flag(StateFlags flag) { set_state(state() & (~flag)); }
- void set_state_flag(StateFlags flag) { set_state(state() | flag); }
-
- uint32_t enabled_filters() const {
- return *const_cast<volatile const uint32_t*>(&enabled_filters_);
- }
-
- bool is_filter_enabled(size_t index) const {
- DCHECK(index < sizeof(enabled_filters_) * 8);
- return (enabled_filters() & (1 << index)) != 0;
- }
-
- void set_enabled_filters(uint32_t enabled_filters) {
- *const_cast<volatile uint32_t*>(&enabled_filters_) = enabled_filters;
- }
-
- void reset_for_testing() {
- set_state(0);
- set_enabled_filters(0);
- }
-
- // These fields should not be accessed directly, not even by tracing code.
- // The only reason why these are not private is because it makes it impossible
- // to have a global array of TraceCategory in category_registry.cc without
- // creating initializers. See discussion on goo.gl/qhZN94 and
- // crbug.com/{660967,660828}.
-
- // The enabled state. TRACE_EVENT* macros will capture events if any of the
- // flags here are set. Since TRACE_EVENTx macros are used in a lot of
- // fast-paths, accesses to this field are non-barriered and racy by design.
- // This field is mutated when starting/stopping tracing and we don't care
- // about missing some events.
- uint8_t state_;
-
- // When ENABLED_FOR_FILTERING is set, this contains a bitmap to the
- // coressponding filter (see event_filters.h).
- uint32_t enabled_filters_;
-
- // TraceCategory group names are long lived static strings.
- const char* name_;
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_TRACE_CATEGORY_H_
diff --git a/base/trace_event/trace_config.cc b/base/trace_event/trace_config.cc
index 36de107bf8..b343ea00bc 100644
--- a/base/trace_event/trace_config.cc
+++ b/base/trace_event/trace_config.cc
@@ -30,11 +30,13 @@ const char kRecordUntilFull[] = "record-until-full";
const char kRecordContinuously[] = "record-continuously";
const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
const char kTraceToConsole[] = "trace-to-console";
+const char kEnableSampling[] = "enable-sampling";
const char kEnableSystrace[] = "enable-systrace";
const char kEnableArgumentFilter[] = "enable-argument-filter";
// String parameters that can be used to parse the trace config string.
const char kRecordModeParam[] = "record_mode";
+const char kEnableSamplingParam[] = "enable_sampling";
const char kEnableSystraceParam[] = "enable_systrace";
const char kEnableArgumentFilterParam[] = "enable_argument_filter";
const char kIncludedCategoriesParam[] = "included_categories";
@@ -48,32 +50,24 @@ const char kSyntheticDelayCategoryFilterPrefix[] = "DELAY(";
const char kMemoryDumpConfigParam[] = "memory_dump_config";
const char kAllowedDumpModesParam[] = "allowed_dump_modes";
const char kTriggersParam[] = "triggers";
-const char kTriggerModeParam[] = "mode";
-const char kMinTimeBetweenDumps[] = "min_time_between_dumps_ms";
-const char kTriggerTypeParam[] = "type";
-const char kPeriodicIntervalLegacyParam[] = "periodic_interval_ms";
+const char kPeriodicIntervalParam[] = "periodic_interval_ms";
+const char kModeParam[] = "mode";
const char kHeapProfilerOptions[] = "heap_profiler_options";
const char kBreakdownThresholdBytes[] = "breakdown_threshold_bytes";
-// String parameters used to parse category event filters.
-const char kEventFiltersParam[] = "event_filters";
-const char kFilterPredicateParam[] = "filter_predicate";
-const char kFilterArgsParam[] = "filter_args";
-
// Default configuration of memory dumps.
const TraceConfig::MemoryDumpConfig::Trigger kDefaultHeavyMemoryDumpTrigger = {
- 2000, // min_time_between_dumps_ms
- MemoryDumpLevelOfDetail::DETAILED, MemoryDumpType::PERIODIC_INTERVAL};
+ 2000, // periodic_interval_ms
+ MemoryDumpLevelOfDetail::DETAILED};
const TraceConfig::MemoryDumpConfig::Trigger kDefaultLightMemoryDumpTrigger = {
- 250, // min_time_between_dumps_ms
- MemoryDumpLevelOfDetail::LIGHT, MemoryDumpType::PERIODIC_INTERVAL};
+ 250, // periodic_interval_ms
+ MemoryDumpLevelOfDetail::LIGHT};
class ConvertableTraceConfigToTraceFormat
: public base::trace_event::ConvertableToTraceFormat {
public:
explicit ConvertableTraceConfigToTraceFormat(const TraceConfig& trace_config)
: trace_config_(trace_config) {}
-
~ConvertableTraceConfigToTraceFormat() override {}
void AppendAsTraceFormat(std::string* out) const override {
@@ -121,94 +115,6 @@ void TraceConfig::MemoryDumpConfig::Clear() {
heap_profiler_options.Clear();
}
-void TraceConfig::MemoryDumpConfig::Merge(
- const TraceConfig::MemoryDumpConfig& config) {
- triggers.insert(triggers.end(), config.triggers.begin(),
- config.triggers.end());
- allowed_dump_modes.insert(config.allowed_dump_modes.begin(),
- config.allowed_dump_modes.end());
- heap_profiler_options.breakdown_threshold_bytes =
- std::min(heap_profiler_options.breakdown_threshold_bytes,
- config.heap_profiler_options.breakdown_threshold_bytes);
-}
-
-TraceConfig::EventFilterConfig::EventFilterConfig(
- const std::string& predicate_name)
- : predicate_name_(predicate_name) {}
-
-TraceConfig::EventFilterConfig::~EventFilterConfig() {}
-
-TraceConfig::EventFilterConfig::EventFilterConfig(const EventFilterConfig& tc) {
- *this = tc;
-}
-
-TraceConfig::EventFilterConfig& TraceConfig::EventFilterConfig::operator=(
- const TraceConfig::EventFilterConfig& rhs) {
- if (this == &rhs)
- return *this;
-
- predicate_name_ = rhs.predicate_name_;
- included_categories_ = rhs.included_categories_;
- excluded_categories_ = rhs.excluded_categories_;
- if (rhs.args_)
- args_ = rhs.args_->CreateDeepCopy();
-
- return *this;
-}
-
-void TraceConfig::EventFilterConfig::AddIncludedCategory(
- const std::string& category) {
- included_categories_.push_back(category);
-}
-
-void TraceConfig::EventFilterConfig::AddExcludedCategory(
- const std::string& category) {
- excluded_categories_.push_back(category);
-}
-
-void TraceConfig::EventFilterConfig::SetArgs(
- std::unique_ptr<base::DictionaryValue> args) {
- args_ = std::move(args);
-}
-
-bool TraceConfig::EventFilterConfig::GetArgAsSet(
- const char* key,
- std::unordered_set<std::string>* out_set) const {
- const ListValue* list = nullptr;
- if (!args_->GetList(key, &list))
- return false;
- for (size_t i = 0; i < list->GetSize(); ++i) {
- std::string value;
- if (list->GetString(i, &value))
- out_set->insert(value);
- }
- return true;
-}
-
-bool TraceConfig::EventFilterConfig::IsCategoryGroupEnabled(
- const char* category_group_name) const {
- CStringTokenizer category_group_tokens(
- category_group_name, category_group_name + strlen(category_group_name),
- ",");
- while (category_group_tokens.GetNext()) {
- std::string category_group_token = category_group_tokens.token();
-
- for (const auto& excluded_category : excluded_categories_) {
- if (base::MatchPattern(category_group_token, excluded_category)) {
- return false;
- }
- }
-
- for (const auto& included_category : included_categories_) {
- if (base::MatchPattern(category_group_token, included_category)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
TraceConfig::TraceConfig() {
InitializeDefault();
}
@@ -253,14 +159,14 @@ TraceConfig::TraceConfig(StringPiece config_string) {
TraceConfig::TraceConfig(const TraceConfig& tc)
: record_mode_(tc.record_mode_),
+ enable_sampling_(tc.enable_sampling_),
enable_systrace_(tc.enable_systrace_),
enable_argument_filter_(tc.enable_argument_filter_),
memory_dump_config_(tc.memory_dump_config_),
included_categories_(tc.included_categories_),
disabled_categories_(tc.disabled_categories_),
excluded_categories_(tc.excluded_categories_),
- synthetic_delays_(tc.synthetic_delays_),
- event_filters_(tc.event_filters_) {}
+ synthetic_delays_(tc.synthetic_delays_) {}
TraceConfig::~TraceConfig() {
}
@@ -270,6 +176,7 @@ TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
return *this;
record_mode_ = rhs.record_mode_;
+ enable_sampling_ = rhs.enable_sampling_;
enable_systrace_ = rhs.enable_systrace_;
enable_argument_filter_ = rhs.enable_argument_filter_;
memory_dump_config_ = rhs.memory_dump_config_;
@@ -277,7 +184,6 @@ TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
disabled_categories_ = rhs.disabled_categories_;
excluded_categories_ = rhs.excluded_categories_;
synthetic_delays_ = rhs.synthetic_delays_;
- event_filters_ = rhs.event_filters_;
return *this;
}
@@ -294,7 +200,7 @@ std::string TraceConfig::ToString() const {
std::unique_ptr<ConvertableToTraceFormat>
TraceConfig::AsConvertableToTraceFormat() const {
- return MakeUnique<ConvertableTraceConfigToTraceFormat>(*this);
+ return WrapUnique(new ConvertableTraceConfigToTraceFormat(*this));
}
std::string TraceConfig::ToCategoryFilterString() const {
@@ -365,6 +271,7 @@ bool TraceConfig::IsCategoryGroupEnabled(
void TraceConfig::Merge(const TraceConfig& config) {
if (record_mode_ != config.record_mode_
+ || enable_sampling_ != config.enable_sampling_
|| enable_systrace_ != config.enable_systrace_
|| enable_argument_filter_ != config.enable_argument_filter_) {
DLOG(ERROR) << "Attempting to merge trace config with a different "
@@ -382,7 +289,9 @@ void TraceConfig::Merge(const TraceConfig& config) {
included_categories_.clear();
}
- memory_dump_config_.Merge(config.memory_dump_config_);
+ memory_dump_config_.triggers.insert(memory_dump_config_.triggers.end(),
+ config.memory_dump_config_.triggers.begin(),
+ config.memory_dump_config_.triggers.end());
disabled_categories_.insert(disabled_categories_.end(),
config.disabled_categories_.begin(),
@@ -393,12 +302,11 @@ void TraceConfig::Merge(const TraceConfig& config) {
synthetic_delays_.insert(synthetic_delays_.end(),
config.synthetic_delays_.begin(),
config.synthetic_delays_.end());
- event_filters_.insert(event_filters_.end(), config.event_filters().begin(),
- config.event_filters().end());
}
void TraceConfig::Clear() {
record_mode_ = RECORD_UNTIL_FULL;
+ enable_sampling_ = false;
enable_systrace_ = false;
enable_argument_filter_ = false;
included_categories_.clear();
@@ -406,11 +314,11 @@ void TraceConfig::Clear() {
excluded_categories_.clear();
synthetic_delays_.clear();
memory_dump_config_.Clear();
- event_filters_.clear();
}
void TraceConfig::InitializeDefault() {
record_mode_ = RECORD_UNTIL_FULL;
+ enable_sampling_ = false;
enable_systrace_ = false;
enable_argument_filter_ = false;
}
@@ -431,6 +339,7 @@ void TraceConfig::InitializeFromConfigDict(const DictionaryValue& dict) {
}
bool val;
+ enable_sampling_ = dict.GetBoolean(kEnableSamplingParam, &val) ? val : false;
enable_systrace_ = dict.GetBoolean(kEnableSystraceParam, &val) ? val : false;
enable_argument_filter_ =
dict.GetBoolean(kEnableArgumentFilterParam, &val) ? val : false;
@@ -443,10 +352,6 @@ void TraceConfig::InitializeFromConfigDict(const DictionaryValue& dict) {
if (dict.GetList(kSyntheticDelaysParam, &category_list))
SetSyntheticDelaysFromList(*category_list);
- const base::ListValue* category_event_filters = nullptr;
- if (dict.GetList(kEventFiltersParam, &category_event_filters))
- SetEventFiltersFromConfigList(*category_event_filters);
-
if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
// If dump triggers not set, the client is using the legacy with just
// category enabled. So, use the default periodic dump config.
@@ -501,6 +406,7 @@ void TraceConfig::InitializeFromStrings(StringPiece category_filter_string,
}
record_mode_ = RECORD_UNTIL_FULL;
+ enable_sampling_ = false;
enable_systrace_ = false;
enable_argument_filter_ = false;
if (!trace_options_string.empty()) {
@@ -515,6 +421,8 @@ void TraceConfig::InitializeFromStrings(StringPiece category_filter_string,
record_mode_ = ECHO_TO_CONSOLE;
} else if (token == kRecordAsMuchAsPossible) {
record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
+ } else if (token == kEnableSampling) {
+ enable_sampling_ = true;
} else if (token == kEnableSystrace) {
enable_systrace_ = true;
} else if (token == kEnableArgumentFilter) {
@@ -608,26 +516,17 @@ void TraceConfig::SetMemoryDumpConfigFromConfigDict(
if (!trigger_list->GetDictionary(i, &trigger))
continue;
- MemoryDumpConfig::Trigger dump_config;
int interval = 0;
- if (!trigger->GetInteger(kMinTimeBetweenDumps, &interval)) {
- // If "min_time_between_dumps_ms" param was not given, then the trace
- // config uses old format where only periodic dumps are supported.
- trigger->GetInteger(kPeriodicIntervalLegacyParam, &interval);
- dump_config.trigger_type = MemoryDumpType::PERIODIC_INTERVAL;
- } else {
- std::string trigger_type_str;
- trigger->GetString(kTriggerTypeParam, &trigger_type_str);
- dump_config.trigger_type = StringToMemoryDumpType(trigger_type_str);
- }
- DCHECK_GT(interval, 0);
- dump_config.min_time_between_dumps_ms = static_cast<uint32_t>(interval);
+ if (!trigger->GetInteger(kPeriodicIntervalParam, &interval))
+ continue;
+ DCHECK_GT(interval, 0);
+ MemoryDumpConfig::Trigger dump_config;
+ dump_config.periodic_interval_ms = static_cast<uint32_t>(interval);
std::string level_of_detail_str;
- trigger->GetString(kTriggerModeParam, &level_of_detail_str);
+ trigger->GetString(kModeParam, &level_of_detail_str);
dump_config.level_of_detail =
StringToMemoryDumpLevelOfDetail(level_of_detail_str);
-
memory_dump_config_.triggers.push_back(dump_config);
}
}
@@ -656,50 +555,6 @@ void TraceConfig::SetDefaultMemoryDumpConfig() {
memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
}
-void TraceConfig::SetEventFiltersFromConfigList(
- const base::ListValue& category_event_filters) {
- event_filters_.clear();
-
- for (size_t event_filter_index = 0;
- event_filter_index < category_event_filters.GetSize();
- ++event_filter_index) {
- const base::DictionaryValue* event_filter = nullptr;
- if (!category_event_filters.GetDictionary(event_filter_index,
- &event_filter))
- continue;
-
- std::string predicate_name;
- CHECK(event_filter->GetString(kFilterPredicateParam, &predicate_name))
- << "Invalid predicate name in category event filter.";
-
- EventFilterConfig new_config(predicate_name);
- const base::ListValue* included_list = nullptr;
- CHECK(event_filter->GetList(kIncludedCategoriesParam, &included_list))
- << "Missing included_categories in category event filter.";
-
- for (size_t i = 0; i < included_list->GetSize(); ++i) {
- std::string category;
- if (included_list->GetString(i, &category))
- new_config.AddIncludedCategory(category);
- }
-
- const base::ListValue* excluded_list = nullptr;
- if (event_filter->GetList(kExcludedCategoriesParam, &excluded_list)) {
- for (size_t i = 0; i < excluded_list->GetSize(); ++i) {
- std::string category;
- if (excluded_list->GetString(i, &category))
- new_config.AddExcludedCategory(category);
- }
- }
-
- const base::DictionaryValue* args_dict = nullptr;
- if (event_filter->GetDictionary(kFilterArgsParam, &args_dict))
- new_config.SetArgs(args_dict->CreateDeepCopy());
-
- event_filters_.push_back(new_config);
- }
-}
-
std::unique_ptr<DictionaryValue> TraceConfig::ToDict() const {
auto dict = MakeUnique<DictionaryValue>();
switch (record_mode_) {
@@ -719,6 +574,7 @@ std::unique_ptr<DictionaryValue> TraceConfig::ToDict() const {
NOTREACHED();
}
+ dict->SetBoolean(kEnableSamplingParam, enable_sampling_);
dict->SetBoolean(kEnableSystraceParam, enable_systrace_);
dict->SetBoolean(kEnableArgumentFilterParam, enable_argument_filter_);
@@ -730,41 +586,6 @@ std::unique_ptr<DictionaryValue> TraceConfig::ToDict() const {
AddCategoryToDict(dict.get(), kExcludedCategoriesParam, excluded_categories_);
AddCategoryToDict(dict.get(), kSyntheticDelaysParam, synthetic_delays_);
- if (!event_filters_.empty()) {
- std::unique_ptr<base::ListValue> filter_list(new base::ListValue());
- for (const EventFilterConfig& filter : event_filters_) {
- std::unique_ptr<base::DictionaryValue> filter_dict(
- new base::DictionaryValue());
- filter_dict->SetString(kFilterPredicateParam, filter.predicate_name());
-
- std::unique_ptr<base::ListValue> included_categories_list(
- new base::ListValue());
- for (const std::string& included_category : filter.included_categories())
- included_categories_list->AppendString(included_category);
-
- filter_dict->Set(kIncludedCategoriesParam,
- std::move(included_categories_list));
-
- if (!filter.excluded_categories().empty()) {
- std::unique_ptr<base::ListValue> excluded_categories_list(
- new base::ListValue());
- for (const std::string& excluded_category :
- filter.excluded_categories())
- excluded_categories_list->AppendString(excluded_category);
-
- filter_dict->Set(kExcludedCategoriesParam,
- std::move(excluded_categories_list));
- }
-
- if (filter.filter_args())
- filter_dict->Set(kFilterArgsParam,
- filter.filter_args()->CreateDeepCopy());
-
- filter_list->Append(std::move(filter_dict));
- }
- dict->Set(kEventFiltersParam, std::move(filter_list));
- }
-
if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
auto allowed_modes = MakeUnique<ListValue>();
for (auto dump_mode : memory_dump_config_.allowed_dump_modes)
@@ -776,14 +597,10 @@ std::unique_ptr<DictionaryValue> TraceConfig::ToDict() const {
auto triggers_list = MakeUnique<ListValue>();
for (const auto& config : memory_dump_config_.triggers) {
auto trigger_dict = MakeUnique<DictionaryValue>();
- trigger_dict->SetString(kTriggerTypeParam,
- MemoryDumpTypeToString(config.trigger_type));
- trigger_dict->SetInteger(
- kMinTimeBetweenDumps,
- static_cast<int>(config.min_time_between_dumps_ms));
+ trigger_dict->SetInteger(kPeriodicIntervalParam,
+ static_cast<int>(config.periodic_interval_ms));
trigger_dict->SetString(
- kTriggerModeParam,
- MemoryDumpLevelOfDetailToString(config.level_of_detail));
+ kModeParam, MemoryDumpLevelOfDetailToString(config.level_of_detail));
triggers_list->Append(std::move(trigger_dict));
}
@@ -822,6 +639,8 @@ std::string TraceConfig::ToTraceOptionsString() const {
default:
NOTREACHED();
}
+ if (enable_sampling_)
+ ret = ret + "," + kEnableSampling;
if (enable_systrace_)
ret = ret + "," + kEnableSystrace;
if (enable_argument_filter_)
diff --git a/base/trace_event/trace_config.h b/base/trace_event/trace_config.h
index 717c261316..91d6f1f3bd 100644
--- a/base/trace_event/trace_config.h
+++ b/base/trace_event/trace_config.h
@@ -7,10 +7,8 @@
#include <stdint.h>
-#include <memory>
#include <set>
#include <string>
-#include <unordered_set>
#include <vector>
#include "base/base_export.h"
@@ -53,9 +51,8 @@ class BASE_EXPORT TraceConfig {
// Specifies the triggers in the memory dump config.
struct Trigger {
- uint32_t min_time_between_dumps_ms;
+ uint32_t periodic_interval_ms;
MemoryDumpLevelOfDetail level_of_detail;
- MemoryDumpType trigger_type;
};
// Specifies the configuration options for the heap profiler.
@@ -74,8 +71,6 @@ class BASE_EXPORT TraceConfig {
// Reset the values in the config.
void Clear();
- void Merge(const MemoryDumpConfig& config);
-
// Set of memory dump modes allowed for the tracing session. The explicitly
// triggered dumps will be successful only if the dump mode is allowed in
// the config.
@@ -85,39 +80,6 @@ class BASE_EXPORT TraceConfig {
HeapProfiler heap_profiler_options;
};
- class BASE_EXPORT EventFilterConfig {
- public:
- EventFilterConfig(const std::string& predicate_name);
- EventFilterConfig(const EventFilterConfig& tc);
-
- ~EventFilterConfig();
-
- EventFilterConfig& operator=(const EventFilterConfig& rhs);
-
- void AddIncludedCategory(const std::string& category);
- void AddExcludedCategory(const std::string& category);
- void SetArgs(std::unique_ptr<base::DictionaryValue> args);
- bool GetArgAsSet(const char* key, std::unordered_set<std::string>*) const;
-
- bool IsCategoryGroupEnabled(const char* category_group_name) const;
-
- const std::string& predicate_name() const { return predicate_name_; }
- base::DictionaryValue* filter_args() const { return args_.get(); }
- const StringList& included_categories() const {
- return included_categories_;
- }
- const StringList& excluded_categories() const {
- return excluded_categories_;
- }
-
- private:
- std::string predicate_name_;
- StringList included_categories_;
- StringList excluded_categories_;
- std::unique_ptr<base::DictionaryValue> args_;
- };
- typedef std::vector<EventFilterConfig> EventFilters;
-
TraceConfig();
// Create TraceConfig object from category filter and trace options strings.
@@ -131,22 +93,22 @@ class BASE_EXPORT TraceConfig {
//
// |trace_options_string| is a comma-delimited list of trace options.
// Possible options are: "record-until-full", "record-continuously",
- // "record-as-much-as-possible", "trace-to-console", "enable-systrace" and
- // "enable-argument-filter".
+ // "record-as-much-as-possible", "trace-to-console", "enable-sampling",
+ // "enable-systrace" and "enable-argument-filter".
// The first 4 options are trace recoding modes and hence
// mutually exclusive. If more than one trace recording modes appear in the
// options_string, the last one takes precedence. If none of the trace
// recording mode is specified, recording mode is RECORD_UNTIL_FULL.
//
// The trace option will first be reset to the default option
- // (record_mode set to RECORD_UNTIL_FULL, enable_systrace and
- // enable_argument_filter set to false) before options parsed from
+ // (record_mode set to RECORD_UNTIL_FULL, enable_sampling, enable_systrace,
+ // and enable_argument_filter set to false) before options parsed from
// |trace_options_string| are applied on it. If |trace_options_string| is
// invalid, the final state of trace options is undefined.
//
// Example: TraceConfig("test_MyTest*", "record-until-full");
// Example: TraceConfig("test_MyTest*,test_OtherStuff",
- // "record-continuously");
+ // "record-continuously, enable-sampling");
// Example: TraceConfig("-excluded_category1,-excluded_category2",
// "record-until-full, trace-to-console");
// would set ECHO_TO_CONSOLE as the recording mode.
@@ -176,6 +138,7 @@ class BASE_EXPORT TraceConfig {
// Example:
// {
// "record_mode": "record-continuously",
+ // "enable_sampling": true,
// "enable_systrace": true,
// "enable_argument_filter": true,
// "included_categories": ["included",
@@ -211,10 +174,12 @@ class BASE_EXPORT TraceConfig {
const StringList& GetSyntheticDelayValues() const;
TraceRecordMode GetTraceRecordMode() const { return record_mode_; }
+ bool IsSamplingEnabled() const { return enable_sampling_; }
bool IsSystraceEnabled() const { return enable_systrace_; }
bool IsArgumentFilterEnabled() const { return enable_argument_filter_; }
void SetTraceRecordMode(TraceRecordMode mode) { record_mode_ = mode; }
+ void EnableSampling() { enable_sampling_ = true; }
void EnableSystrace() { enable_systrace_ = true; }
void EnableArgumentFilter() { enable_argument_filter_ = true; }
@@ -231,7 +196,7 @@ class BASE_EXPORT TraceConfig {
// Returns true if at least one category in the list is enabled by this
// trace config. This is used to determine if the category filters are
// enabled in the TRACE_* macros.
- bool IsCategoryGroupEnabled(const char* category_group_name) const;
+ bool IsCategoryGroupEnabled(const char* category_group) const;
// Merges config with the current TraceConfig
void Merge(const TraceConfig& config);
@@ -245,11 +210,6 @@ class BASE_EXPORT TraceConfig {
return memory_dump_config_;
}
- const EventFilters& event_filters() const { return event_filters_; }
- void SetEventFilters(const EventFilters& filter_configs) {
- event_filters_ = filter_configs;
- }
-
private:
FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromValidLegacyFormat);
FRIEND_TEST_ALL_PREFIXES(TraceConfigTest,
@@ -290,7 +250,6 @@ class BASE_EXPORT TraceConfig {
const DictionaryValue& memory_dump_config);
void SetDefaultMemoryDumpConfig();
- void SetEventFiltersFromConfigList(const base::ListValue& event_filters);
std::unique_ptr<DictionaryValue> ToDict() const;
std::string ToTraceOptionsString() const;
@@ -312,6 +271,7 @@ class BASE_EXPORT TraceConfig {
bool HasIncludedPatterns() const;
TraceRecordMode record_mode_;
+ bool enable_sampling_ : 1;
bool enable_systrace_ : 1;
bool enable_argument_filter_ : 1;
@@ -321,7 +281,6 @@ class BASE_EXPORT TraceConfig {
StringList disabled_categories_;
StringList excluded_categories_;
StringList synthetic_delays_;
- EventFilters event_filters_;
};
} // namespace trace_event
diff --git a/base/trace_event/trace_config_memory_test_util.h b/base/trace_event/trace_config_memory_test_util.h
index 744e8a8acc..6b47f8dc55 100644
--- a/base/trace_event/trace_config_memory_test_util.h
+++ b/base/trace_event/trace_config_memory_test_util.h
@@ -13,144 +13,87 @@ namespace trace_event {
class TraceConfigMemoryTestUtil {
public:
- static std::string GetTraceConfig_LegacyPeriodicTriggers(int light_period,
- int heavy_period) {
- return StringPrintf(
- "{"
- "\"enable_argument_filter\":false,"
- "\"enable_systrace\":false,"
- "\"included_categories\":["
- "\"%s\""
- "],"
- "\"memory_dump_config\":{"
- "\"allowed_dump_modes\":[\"background\",\"light\",\"detailed\"],"
- "\"heap_profiler_options\":{"
- "\"breakdown_threshold_bytes\":2048"
- "},"
- "\"triggers\":["
- "{"
- "\"mode\":\"light\","
- "\"periodic_interval_ms\":%d"
- "},"
- "{"
- "\"mode\":\"detailed\","
- "\"periodic_interval_ms\":%d"
- "}"
- "]"
- "},"
- "\"record_mode\":\"record-until-full\""
- "}",
- MemoryDumpManager::kTraceCategory, light_period, heavy_period);
- ;
- }
-
static std::string GetTraceConfig_PeriodicTriggers(int light_period,
int heavy_period) {
return StringPrintf(
"{"
- "\"enable_argument_filter\":false,"
- "\"enable_systrace\":false,"
- "\"included_categories\":["
- "\"%s\""
- "],"
- "\"memory_dump_config\":{"
- "\"allowed_dump_modes\":[\"background\",\"light\",\"detailed\"],"
- "\"heap_profiler_options\":{"
- "\"breakdown_threshold_bytes\":2048"
- "},"
- "\"triggers\":["
- "{"
- "\"min_time_between_dumps_ms\":%d,"
- "\"mode\":\"light\","
- "\"type\":\"periodic_interval\""
- "},"
- "{"
- "\"min_time_between_dumps_ms\":%d,"
- "\"mode\":\"detailed\","
- "\"type\":\"periodic_interval\""
- "}"
- "]"
- "},"
- "\"record_mode\":\"record-until-full\""
- "}",
- MemoryDumpManager::kTraceCategory, light_period, heavy_period);
+ "\"enable_argument_filter\":false,"
+ "\"enable_sampling\":false,"
+ "\"enable_systrace\":false,"
+ "\"included_categories\":["
+ "\"%s\""
+ "],"
+ "\"memory_dump_config\":{"
+ "\"allowed_dump_modes\":[\"background\",\"light\",\"detailed\"],"
+ "\"heap_profiler_options\":{"
+ "\"breakdown_threshold_bytes\":2048"
+ "},"
+ "\"triggers\":["
+ "{"
+ "\"mode\":\"light\","
+ "\"periodic_interval_ms\":%d"
+ "},"
+ "{"
+ "\"mode\":\"detailed\","
+ "\"periodic_interval_ms\":%d"
+ "}"
+ "]"
+ "},"
+ "\"record_mode\":\"record-until-full\""
+ "}", MemoryDumpManager::kTraceCategory, light_period, heavy_period);
}
static std::string GetTraceConfig_EmptyTriggers() {
return StringPrintf(
"{"
- "\"enable_argument_filter\":false,"
- "\"enable_systrace\":false,"
- "\"included_categories\":["
- "\"%s\""
- "],"
- "\"memory_dump_config\":{"
- "\"allowed_dump_modes\":[\"background\",\"light\",\"detailed\"],"
- "\"triggers\":["
- "]"
- "},"
- "\"record_mode\":\"record-until-full\""
- "}",
- MemoryDumpManager::kTraceCategory);
+ "\"enable_argument_filter\":false,"
+ "\"enable_sampling\":false,"
+ "\"enable_systrace\":false,"
+ "\"included_categories\":["
+ "\"%s\""
+ "],"
+ "\"memory_dump_config\":{"
+ "\"allowed_dump_modes\":[\"background\",\"light\",\"detailed\"],"
+ "\"triggers\":["
+ "]"
+ "},"
+ "\"record_mode\":\"record-until-full\""
+ "}", MemoryDumpManager::kTraceCategory);
}
static std::string GetTraceConfig_NoTriggers() {
return StringPrintf(
"{"
- "\"enable_argument_filter\":false,"
- "\"enable_systrace\":false,"
- "\"included_categories\":["
- "\"%s\""
- "],"
- "\"record_mode\":\"record-until-full\""
- "}",
- MemoryDumpManager::kTraceCategory);
+ "\"enable_argument_filter\":false,"
+ "\"enable_sampling\":false,"
+ "\"enable_systrace\":false,"
+ "\"included_categories\":["
+ "\"%s\""
+ "],"
+ "\"record_mode\":\"record-until-full\""
+ "}", MemoryDumpManager::kTraceCategory);
}
static std::string GetTraceConfig_BackgroundTrigger(int period_ms) {
return StringPrintf(
"{"
- "\"enable_argument_filter\":false,"
- "\"enable_systrace\":false,"
- "\"included_categories\":["
- "\"%s\""
- "],"
- "\"memory_dump_config\":{"
- "\"allowed_dump_modes\":[\"background\"],"
- "\"triggers\":["
- "{"
- "\"min_time_between_dumps_ms\":%d,"
- "\"mode\":\"background\","
- "\"type\":\"periodic_interval\""
- "}"
- "]"
- "},"
- "\"record_mode\":\"record-until-full\""
- "}",
- MemoryDumpManager::kTraceCategory, period_ms);
- }
-
- static std::string GetTraceConfig_PeakDetectionTrigger(int heavy_period) {
- return StringPrintf(
- "{"
- "\"enable_argument_filter\":false,"
- "\"enable_systrace\":false,"
- "\"included_categories\":["
- "\"%s\""
- "],"
- "\"memory_dump_config\":{"
- "\"allowed_dump_modes\":[\"background\",\"light\",\"detailed\"],"
- "\"triggers\":["
- "{"
- "\"min_time_between_dumps_ms\":%d,"
- "\"mode\":\"detailed\","
- "\"type\":\"peak_memory_usage\""
- "}"
- "]"
- "},"
- "\"record_mode\":\"record-until-full\""
- "}",
- MemoryDumpManager::kTraceCategory, heavy_period);
+ "\"enable_argument_filter\":false,"
+ "\"enable_sampling\":false,"
+ "\"enable_systrace\":false,"
+ "\"included_categories\":["
+ "\"%s\""
+ "],"
+ "\"memory_dump_config\":{"
+ "\"allowed_dump_modes\":[\"background\"],"
+ "\"triggers\":["
+ "{"
+ "\"mode\":\"background\","
+ "\"periodic_interval_ms\":%d"
+ "}"
+ "]"
+ "},"
+ "\"record_mode\":\"record-until-full\""
+ "}", MemoryDumpManager::kTraceCategory, period_ms);
}
};
diff --git a/base/trace_event/trace_config_unittest.cc b/base/trace_event/trace_config_unittest.cc
index 74aa7bdc63..4b46b2fefd 100644
--- a/base/trace_event/trace_config_unittest.cc
+++ b/base/trace_event/trace_config_unittest.cc
@@ -5,7 +5,6 @@
#include <stddef.h>
#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
#include "base/macros.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_config.h"
@@ -20,52 +19,38 @@ namespace {
const char kDefaultTraceConfigString[] =
"{"
"\"enable_argument_filter\":false,"
+ "\"enable_sampling\":false,"
"\"enable_systrace\":false,"
"\"record_mode\":\"record-until-full\""
"}";
const char kCustomTraceConfigString[] =
- "{"
+ "{"
"\"enable_argument_filter\":true,"
+ "\"enable_sampling\":true,"
"\"enable_systrace\":true,"
- "\"event_filters\":["
- "{"
- "\"excluded_categories\":[\"unfiltered_cat\"],"
- "\"filter_args\":{\"event_name_whitelist\":[\"a snake\",\"a dog\"]},"
- "\"filter_predicate\":\"event_whitelist_predicate\","
- "\"included_categories\":[\"*\"]"
- "}"
- "],"
"\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
- "\"included_categories\":["
- "\"included\","
- "\"inc_pattern*\","
- "\"disabled-by-default-cc\","
- "\"disabled-by-default-memory-infra\"],"
+ "\"included_categories\":[\"included\","
+ "\"inc_pattern*\","
+ "\"disabled-by-default-cc\","
+ "\"disabled-by-default-memory-infra\"],"
"\"memory_dump_config\":{"
- "\"allowed_dump_modes\":[\"background\",\"light\",\"detailed\"],"
- "\"heap_profiler_options\":{"
- "\"breakdown_threshold_bytes\":10240"
- "},"
- "\"triggers\":["
- "{"
- "\"min_time_between_dumps_ms\":50,"
- "\"mode\":\"light\","
- "\"type\":\"periodic_interval\""
- "},"
- "{"
- "\"min_time_between_dumps_ms\":1000,"
- "\"mode\":\"detailed\","
- "\"type\":\"peak_memory_usage\""
- "}"
- "]"
+ "\"allowed_dump_modes\":[\"background\",\"light\",\"detailed\"],"
+ "\"heap_profiler_options\":{"
+ "\"breakdown_threshold_bytes\":10240"
+ "},"
+ "\"triggers\":["
+ "{\"mode\":\"light\",\"periodic_interval_ms\":50},"
+ "{\"mode\":\"detailed\",\"periodic_interval_ms\":1000}"
+ "]"
"},"
"\"record_mode\":\"record-continuously\","
"\"synthetic_delays\":[\"test.Delay1;16\",\"test.Delay2;32\"]"
- "}";
+ "}";
void CheckDefaultTraceConfigBehavior(const TraceConfig& tc) {
EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+ EXPECT_FALSE(tc.IsSamplingEnabled());
EXPECT_FALSE(tc.IsSystraceEnabled());
EXPECT_FALSE(tc.IsArgumentFilterEnabled());
@@ -87,31 +72,44 @@ TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
// From trace options strings
TraceConfig config("", "record-until-full");
EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_FALSE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
config = TraceConfig("", "record-continuously");
EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_FALSE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str());
config = TraceConfig("", "trace-to-console");
EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_FALSE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str());
config = TraceConfig("", "record-as-much-as-possible");
EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_FALSE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("record-as-much-as-possible",
config.ToTraceOptionsString().c_str());
+ config = TraceConfig("", "record-until-full, enable-sampling");
+ EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+ EXPECT_TRUE(config.IsSamplingEnabled());
+ EXPECT_FALSE(config.IsSystraceEnabled());
+ EXPECT_FALSE(config.IsArgumentFilterEnabled());
+ EXPECT_STREQ("record-until-full,enable-sampling",
+ config.ToTraceOptionsString().c_str());
+
config = TraceConfig("", "enable-systrace, record-continuously");
EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_TRUE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("record-continuously,enable-systrace",
@@ -119,6 +117,7 @@ TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
config = TraceConfig("", "enable-argument-filter,record-as-much-as-possible");
EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_FALSE(config.IsSystraceEnabled());
EXPECT_TRUE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("record-as-much-as-possible,enable-argument-filter",
@@ -126,17 +125,19 @@ TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
config = TraceConfig(
"",
- "enable-systrace,trace-to-console,enable-argument-filter");
+ "enable-systrace,trace-to-console,enable-sampling,enable-argument-filter");
EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+ EXPECT_TRUE(config.IsSamplingEnabled());
EXPECT_TRUE(config.IsSystraceEnabled());
EXPECT_TRUE(config.IsArgumentFilterEnabled());
EXPECT_STREQ(
- "trace-to-console,enable-systrace,enable-argument-filter",
+ "trace-to-console,enable-sampling,enable-systrace,enable-argument-filter",
config.ToTraceOptionsString().c_str());
config = TraceConfig(
"", "record-continuously, record-until-full, trace-to-console");
EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_FALSE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str());
@@ -144,24 +145,28 @@ TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
// From TraceRecordMode
config = TraceConfig("", RECORD_UNTIL_FULL);
EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_FALSE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
config = TraceConfig("", RECORD_CONTINUOUSLY);
EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_FALSE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str());
config = TraceConfig("", ECHO_TO_CONSOLE);
EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_FALSE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str());
config = TraceConfig("", RECORD_AS_MUCH_AS_POSSIBLE);
EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_FALSE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("record-as-much-as-possible",
@@ -193,30 +198,33 @@ TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
// From both trace options and category filter strings
config = TraceConfig("", "");
EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_FALSE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("", config.ToCategoryFilterString().c_str());
EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*",
- "enable-systrace, trace-to-console");
+ "enable-systrace, trace-to-console, enable-sampling");
EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+ EXPECT_TRUE(config.IsSamplingEnabled());
EXPECT_TRUE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
config.ToCategoryFilterString().c_str());
- EXPECT_STREQ("trace-to-console,enable-systrace",
+ EXPECT_STREQ("trace-to-console,enable-sampling,enable-systrace",
config.ToTraceOptionsString().c_str());
// From both trace options and category filter strings with spaces.
config = TraceConfig(" included , -excluded, inc_pattern*, ,-exc_pattern* ",
- "enable-systrace, ,trace-to-console ");
+ "enable-systrace, ,trace-to-console, enable-sampling ");
EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+ EXPECT_TRUE(config.IsSamplingEnabled());
EXPECT_TRUE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
config.ToCategoryFilterString().c_str());
- EXPECT_STREQ("trace-to-console,enable-systrace",
+ EXPECT_STREQ("trace-to-console,enable-sampling,enable-systrace",
config.ToTraceOptionsString().c_str());
// From category filter string and TraceRecordMode
@@ -224,6 +232,7 @@ TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
RECORD_CONTINUOUSLY);
EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
EXPECT_FALSE(config.IsSystraceEnabled());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
config.ToCategoryFilterString().c_str());
@@ -233,6 +242,7 @@ TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
TEST(TraceConfigTest, TraceConfigFromInvalidLegacyStrings) {
TraceConfig config("", "foo-bar-baz");
EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_FALSE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("", config.ToCategoryFilterString().c_str());
@@ -240,6 +250,7 @@ TEST(TraceConfigTest, TraceConfigFromInvalidLegacyStrings) {
config = TraceConfig("arbitrary-category", "foo-bar-baz, enable-systrace");
EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+ EXPECT_FALSE(config.IsSamplingEnabled());
EXPECT_TRUE(config.IsSystraceEnabled());
EXPECT_FALSE(config.IsArgumentFilterEnabled());
EXPECT_STREQ("arbitrary-category", config.ToCategoryFilterString().c_str());
@@ -319,7 +330,6 @@ TEST(TraceConfigTest, DisabledByDefaultCategoryFilterString) {
EXPECT_FALSE(tc.IsCategoryGroupEnabled("bar"));
EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-bar"));
- EXPECT_TRUE(tc.event_filters().empty());
// Enabling only the disabled-by-default-* category means the default ones
// are also enabled.
tc = TraceConfig("disabled-by-default-foo", "");
@@ -336,6 +346,7 @@ TEST(TraceConfigTest, TraceConfigFromDict) {
TraceConfig tc(dict);
EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+ EXPECT_FALSE(tc.IsSamplingEnabled());
EXPECT_FALSE(tc.IsSystraceEnabled());
EXPECT_FALSE(tc.IsArgumentFilterEnabled());
EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
@@ -349,6 +360,7 @@ TEST(TraceConfigTest, TraceConfigFromDict) {
TraceConfig default_tc(*default_dict);
EXPECT_STREQ(kDefaultTraceConfigString, default_tc.ToString().c_str());
EXPECT_EQ(RECORD_UNTIL_FULL, default_tc.GetTraceRecordMode());
+ EXPECT_FALSE(default_tc.IsSamplingEnabled());
EXPECT_FALSE(default_tc.IsSystraceEnabled());
EXPECT_FALSE(default_tc.IsArgumentFilterEnabled());
EXPECT_STREQ("", default_tc.ToCategoryFilterString().c_str());
@@ -362,6 +374,7 @@ TEST(TraceConfigTest, TraceConfigFromDict) {
TraceConfig custom_tc(*custom_dict);
EXPECT_STREQ(kCustomTraceConfigString, custom_tc.ToString().c_str());
EXPECT_EQ(RECORD_CONTINUOUSLY, custom_tc.GetTraceRecordMode());
+ EXPECT_TRUE(custom_tc.IsSamplingEnabled());
EXPECT_TRUE(custom_tc.IsSystraceEnabled());
EXPECT_TRUE(custom_tc.IsArgumentFilterEnabled());
EXPECT_STREQ("included,inc_pattern*,"
@@ -374,28 +387,22 @@ TEST(TraceConfigTest, TraceConfigFromDict) {
TEST(TraceConfigTest, TraceConfigFromValidString) {
// Using some non-empty config string.
const char config_string[] =
- "{"
+ "{"
"\"enable_argument_filter\":true,"
+ "\"enable_sampling\":true,"
"\"enable_systrace\":true,"
- "\"event_filters\":["
- "{"
- "\"excluded_categories\":[\"unfiltered_cat\"],"
- "\"filter_args\":{\"event_name_whitelist\":[\"a snake\",\"a dog\"]},"
- "\"filter_predicate\":\"event_whitelist_predicate\","
- "\"included_categories\":[\"*\"]"
- "}"
- "],"
"\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
"\"included_categories\":[\"included\","
- "\"inc_pattern*\","
- "\"disabled-by-default-cc\"],"
+ "\"inc_pattern*\","
+ "\"disabled-by-default-cc\"],"
"\"record_mode\":\"record-continuously\","
"\"synthetic_delays\":[\"test.Delay1;16\",\"test.Delay2;32\"]"
- "}";
+ "}";
TraceConfig tc(config_string);
EXPECT_STREQ(config_string, tc.ToString().c_str());
EXPECT_EQ(RECORD_CONTINUOUSLY, tc.GetTraceRecordMode());
+ EXPECT_TRUE(tc.IsSamplingEnabled());
EXPECT_TRUE(tc.IsSystraceEnabled());
EXPECT_TRUE(tc.IsArgumentFilterEnabled());
EXPECT_STREQ("included,inc_pattern*,disabled-by-default-cc,-excluded,"
@@ -427,26 +434,6 @@ TEST(TraceConfigTest, TraceConfigFromValidString) {
EXPECT_STREQ("test.Delay1;16", tc.GetSyntheticDelayValues()[0].c_str());
EXPECT_STREQ("test.Delay2;32", tc.GetSyntheticDelayValues()[1].c_str());
- EXPECT_EQ(tc.event_filters().size(), 1u);
- const TraceConfig::EventFilterConfig& event_filter = tc.event_filters()[0];
- EXPECT_STREQ("event_whitelist_predicate",
- event_filter.predicate_name().c_str());
- EXPECT_EQ(1u, event_filter.included_categories().size());
- EXPECT_STREQ("*", event_filter.included_categories()[0].c_str());
- EXPECT_EQ(1u, event_filter.excluded_categories().size());
- EXPECT_STREQ("unfiltered_cat", event_filter.excluded_categories()[0].c_str());
- EXPECT_TRUE(event_filter.filter_args());
-
- std::string json_out;
- base::JSONWriter::Write(*event_filter.filter_args(), &json_out);
- EXPECT_STREQ(json_out.c_str(),
- "{\"event_name_whitelist\":[\"a snake\",\"a dog\"]}");
- std::unordered_set<std::string> filter_values;
- EXPECT_TRUE(event_filter.GetArgAsSet("event_name_whitelist", &filter_values));
- EXPECT_EQ(2u, filter_values.size());
- EXPECT_EQ(1u, filter_values.count("a snake"));
- EXPECT_EQ(1u, filter_values.count("a dog"));
-
const char config_string_2[] = "{\"included_categories\":[\"*\"]}";
TraceConfig tc2(config_string_2);
EXPECT_TRUE(tc2.IsCategoryEnabled("non-disabled-by-default-pattern"));
@@ -459,6 +446,7 @@ TEST(TraceConfigTest, TraceConfigFromValidString) {
EXPECT_STREQ(tc.ToString().c_str(),
"{"
"\"enable_argument_filter\":false,"
+ "\"enable_sampling\":false,"
"\"enable_systrace\":false,"
"\"record_mode\":\"record-until-full\""
"}");
@@ -470,6 +458,7 @@ TEST(TraceConfigTest, TraceConfigFromInvalidString) {
TraceConfig tc("");
EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+ EXPECT_FALSE(tc.IsSamplingEnabled());
EXPECT_FALSE(tc.IsSystraceEnabled());
EXPECT_FALSE(tc.IsArgumentFilterEnabled());
EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
@@ -478,6 +467,7 @@ TEST(TraceConfigTest, TraceConfigFromInvalidString) {
tc = TraceConfig("This is an invalid config string.");
EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+ EXPECT_FALSE(tc.IsSamplingEnabled());
EXPECT_FALSE(tc.IsSystraceEnabled());
EXPECT_FALSE(tc.IsArgumentFilterEnabled());
EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
@@ -486,6 +476,7 @@ TEST(TraceConfigTest, TraceConfigFromInvalidString) {
tc = TraceConfig("[\"This\", \"is\", \"not\", \"a\", \"dictionary\"]");
EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+ EXPECT_FALSE(tc.IsSamplingEnabled());
EXPECT_FALSE(tc.IsSystraceEnabled());
EXPECT_FALSE(tc.IsArgumentFilterEnabled());
EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
@@ -494,6 +485,7 @@ TEST(TraceConfigTest, TraceConfigFromInvalidString) {
tc = TraceConfig("{\"record_mode\": invalid-value-needs-double-quote}");
EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+ EXPECT_FALSE(tc.IsSamplingEnabled());
EXPECT_FALSE(tc.IsSystraceEnabled());
EXPECT_FALSE(tc.IsArgumentFilterEnabled());
EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
@@ -503,6 +495,7 @@ TEST(TraceConfigTest, TraceConfigFromInvalidString) {
// initialize TraceConfig with best effort.
tc = TraceConfig("{}");
EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+ EXPECT_FALSE(tc.IsSamplingEnabled());
EXPECT_FALSE(tc.IsSystraceEnabled());
EXPECT_FALSE(tc.IsArgumentFilterEnabled());
EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
@@ -510,6 +503,7 @@ TEST(TraceConfigTest, TraceConfigFromInvalidString) {
tc = TraceConfig("{\"arbitrary-key\":\"arbitrary-value\"}");
EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+ EXPECT_FALSE(tc.IsSamplingEnabled());
EXPECT_FALSE(tc.IsSystraceEnabled());
EXPECT_FALSE(tc.IsArgumentFilterEnabled());
EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
@@ -517,6 +511,7 @@ TEST(TraceConfigTest, TraceConfigFromInvalidString) {
const char invalid_config_string[] =
"{"
+ "\"enable_sampling\":\"true\","
"\"enable_systrace\":1,"
"\"excluded_categories\":[\"excluded\"],"
"\"included_categories\":\"not a list\","
@@ -527,6 +522,7 @@ TEST(TraceConfigTest, TraceConfigFromInvalidString) {
"}";
tc = TraceConfig(invalid_config_string);
EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+ EXPECT_FALSE(tc.IsSamplingEnabled());
EXPECT_FALSE(tc.IsSystraceEnabled());
EXPECT_FALSE(tc.IsArgumentFilterEnabled());
EXPECT_STREQ("-excluded,DELAY(test.Delay1;16),DELAY(test.Delay2;32)",
@@ -551,6 +547,7 @@ TEST(TraceConfigTest, MergingTraceConfigs) {
tc.Merge(tc2);
EXPECT_STREQ("{"
"\"enable_argument_filter\":false,"
+ "\"enable_sampling\":false,"
"\"enable_systrace\":false,"
"\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
"\"record_mode\":\"record-until-full\""
@@ -617,11 +614,15 @@ TEST(TraceConfigTest, IsEmptyOrContainsLeadingOrTrailingWhitespace) {
TEST(TraceConfigTest, SetTraceOptionValues) {
TraceConfig tc;
EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+ EXPECT_FALSE(tc.IsSamplingEnabled());
EXPECT_FALSE(tc.IsSystraceEnabled());
tc.SetTraceRecordMode(RECORD_AS_MUCH_AS_POSSIBLE);
EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, tc.GetTraceRecordMode());
+ tc.EnableSampling();
+ EXPECT_TRUE(tc.IsSamplingEnabled());
+
tc.EnableSystrace();
EXPECT_TRUE(tc.IsSystraceEnabled());
}
@@ -631,47 +632,30 @@ TEST(TraceConfigTest, TraceConfigFromMemoryConfigString) {
TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(200, 2000);
TraceConfig tc1(tc_str1);
EXPECT_EQ(tc_str1, tc1.ToString());
- TraceConfig tc2(
- TraceConfigMemoryTestUtil::GetTraceConfig_LegacyPeriodicTriggers(200,
- 2000));
- EXPECT_EQ(tc_str1, tc2.ToString());
-
EXPECT_TRUE(tc1.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
ASSERT_EQ(2u, tc1.memory_dump_config_.triggers.size());
- EXPECT_EQ(200u,
- tc1.memory_dump_config_.triggers[0].min_time_between_dumps_ms);
+ EXPECT_EQ(200u, tc1.memory_dump_config_.triggers[0].periodic_interval_ms);
EXPECT_EQ(MemoryDumpLevelOfDetail::LIGHT,
tc1.memory_dump_config_.triggers[0].level_of_detail);
- EXPECT_EQ(2000u,
- tc1.memory_dump_config_.triggers[1].min_time_between_dumps_ms);
+ EXPECT_EQ(2000u, tc1.memory_dump_config_.triggers[1].periodic_interval_ms);
EXPECT_EQ(MemoryDumpLevelOfDetail::DETAILED,
tc1.memory_dump_config_.triggers[1].level_of_detail);
EXPECT_EQ(
2048u,
tc1.memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes);
- std::string tc_str3 =
+ std::string tc_str2 =
TraceConfigMemoryTestUtil::GetTraceConfig_BackgroundTrigger(
1 /* period_ms */);
- TraceConfig tc3(tc_str3);
- EXPECT_EQ(tc_str3, tc3.ToString());
- EXPECT_TRUE(tc3.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
- ASSERT_EQ(1u, tc3.memory_dump_config_.triggers.size());
- EXPECT_EQ(1u, tc3.memory_dump_config_.triggers[0].min_time_between_dumps_ms);
+ TraceConfig tc2(tc_str2);
+ EXPECT_EQ(tc_str2, tc2.ToString());
+ EXPECT_TRUE(tc2.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
+ ASSERT_EQ(1u, tc2.memory_dump_config_.triggers.size());
+ EXPECT_EQ(1u, tc2.memory_dump_config_.triggers[0].periodic_interval_ms);
EXPECT_EQ(MemoryDumpLevelOfDetail::BACKGROUND,
- tc3.memory_dump_config_.triggers[0].level_of_detail);
-
- std::string tc_str4 =
- TraceConfigMemoryTestUtil::GetTraceConfig_PeakDetectionTrigger(
- 1 /*heavy_period */);
- TraceConfig tc4(tc_str4);
- EXPECT_EQ(tc_str4, tc4.ToString());
- ASSERT_EQ(1u, tc4.memory_dump_config_.triggers.size());
- EXPECT_EQ(1u, tc4.memory_dump_config_.triggers[0].min_time_between_dumps_ms);
- EXPECT_EQ(MemoryDumpLevelOfDetail::DETAILED,
- tc4.memory_dump_config_.triggers[0].level_of_detail);
+ tc2.memory_dump_config_.triggers[0].level_of_detail);
}
TEST(TraceConfigTest, EmptyMemoryDumpConfigTest) {
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi
new file mode 100644
index 0000000000..f915780de5
--- /dev/null
+++ b/base/trace_event/trace_event.gypi
@@ -0,0 +1,107 @@
+# Copyright 2015 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.
+{
+ 'variables': {
+ 'trace_event_sources' : [
+ 'trace_event/blame_context.cc',
+ 'trace_event/blame_context.h',
+ 'trace_event/common/trace_event_common.h',
+ 'trace_event/heap_profiler.h',
+ 'trace_event/heap_profiler_allocation_context.cc',
+ 'trace_event/heap_profiler_allocation_context.h',
+ 'trace_event/heap_profiler_allocation_context_tracker.cc',
+ 'trace_event/heap_profiler_allocation_context_tracker.h',
+ 'trace_event/heap_profiler_allocation_register.cc',
+ 'trace_event/heap_profiler_allocation_register_posix.cc',
+ 'trace_event/heap_profiler_allocation_register_win.cc',
+ 'trace_event/heap_profiler_allocation_register.h',
+ 'trace_event/heap_profiler_heap_dump_writer.cc',
+ 'trace_event/heap_profiler_heap_dump_writer.h',
+ 'trace_event/heap_profiler_stack_frame_deduplicator.cc',
+ 'trace_event/heap_profiler_stack_frame_deduplicator.h',
+ 'trace_event/heap_profiler_type_name_deduplicator.cc',
+ 'trace_event/heap_profiler_type_name_deduplicator.h',
+ 'trace_event/java_heap_dump_provider_android.cc',
+ 'trace_event/java_heap_dump_provider_android.h',
+ 'trace_event/memory_allocator_dump.cc',
+ 'trace_event/memory_allocator_dump.h',
+ 'trace_event/memory_allocator_dump_guid.cc',
+ 'trace_event/memory_allocator_dump_guid.h',
+ 'trace_event/memory_dump_manager.cc',
+ 'trace_event/memory_dump_manager.h',
+ 'trace_event/memory_dump_provider.h',
+ 'trace_event/memory_dump_request_args.cc',
+ 'trace_event/memory_dump_request_args.h',
+ 'trace_event/memory_dump_session_state.cc',
+ 'trace_event/memory_dump_session_state.h',
+ 'trace_event/memory_infra_background_whitelist.cc',
+ 'trace_event/memory_infra_background_whitelist.h',
+ 'trace_event/process_memory_dump.cc',
+ 'trace_event/process_memory_dump.h',
+ 'trace_event/process_memory_maps.cc',
+ 'trace_event/process_memory_maps.h',
+ 'trace_event/process_memory_totals.cc',
+ 'trace_event/process_memory_totals.h',
+ 'trace_event/trace_buffer.cc',
+ 'trace_event/trace_buffer.h',
+ 'trace_event/trace_config.cc',
+ 'trace_event/trace_config.h',
+ 'trace_event/trace_event.h',
+ 'trace_event/trace_event_android.cc',
+ 'trace_event/trace_event_argument.cc',
+ 'trace_event/trace_event_argument.h',
+ 'trace_event/trace_event_etw_export_win.cc',
+ 'trace_event/trace_event_etw_export_win.h',
+ 'trace_event/trace_event_impl.cc',
+ 'trace_event/trace_event_impl.h',
+ 'trace_event/trace_event_memory_overhead.cc',
+ 'trace_event/trace_event_memory_overhead.h',
+ 'trace_event/trace_event_synthetic_delay.cc',
+ 'trace_event/trace_event_synthetic_delay.h',
+ 'trace_event/trace_event_system_stats_monitor.cc',
+ 'trace_event/trace_event_system_stats_monitor.h',
+ 'trace_event/trace_log.cc',
+ 'trace_event/trace_log.h',
+ 'trace_event/trace_log_constants.cc',
+ 'trace_event/trace_sampling_thread.cc',
+ 'trace_event/trace_sampling_thread.h',
+ 'trace_event/tracing_agent.cc',
+ 'trace_event/tracing_agent.h',
+ 'trace_event/winheap_dump_provider_win.cc',
+ 'trace_event/winheap_dump_provider_win.h',
+ ],
+ 'trace_event_test_sources' : [
+ 'trace_event/blame_context_unittest.cc',
+ 'trace_event/heap_profiler_allocation_context_tracker_unittest.cc',
+ 'trace_event/heap_profiler_allocation_register_unittest.cc',
+ 'trace_event/heap_profiler_heap_dump_writer_unittest.cc',
+ 'trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc',
+ 'trace_event/heap_profiler_type_name_deduplicator_unittest.cc',
+ 'trace_event/java_heap_dump_provider_android_unittest.cc',
+ 'trace_event/memory_allocator_dump_unittest.cc',
+ 'trace_event/memory_dump_manager_unittest.cc',
+ 'trace_event/process_memory_dump_unittest.cc',
+ 'trace_event/trace_config_memory_test_util.h',
+ 'trace_event/trace_config_unittest.cc',
+ 'trace_event/trace_event_argument_unittest.cc',
+ 'trace_event/trace_event_synthetic_delay_unittest.cc',
+ 'trace_event/trace_event_system_stats_monitor_unittest.cc',
+ 'trace_event/trace_event_unittest.cc',
+ 'trace_event/winheap_dump_provider_win_unittest.cc',
+ ],
+ 'conditions': [
+ ['OS == "linux" or OS=="android" or OS=="mac" or OS=="ios"', {
+ 'trace_event_sources': [
+ 'trace_event/malloc_dump_provider.cc',
+ 'trace_event/malloc_dump_provider.h',
+ ],
+ }],
+ ['OS == "android"', {
+ 'trace_event_test_sources' : [
+ 'trace_event/trace_event_android_unittest.cc',
+ ],
+ }],
+ ],
+ },
+}
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index 51e6927cbd..a075898269 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -19,7 +19,6 @@
#include "base/time/time.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/heap_profiler.h"
-#include "base/trace_event/trace_category.h"
#include "base/trace_event/trace_event_system_stats_monitor.h"
#include "base/trace_event/trace_log.h"
#include "build/build_config.h"
@@ -29,52 +28,55 @@
#define TRACE_STR_COPY(str) \
trace_event_internal::TraceStringWithCopy(str)
-// DEPRECATED: do not use: Consider using TRACE_ID_{GLOBAL, LOCAL} macros,
-// instead. By default, uint64_t ID argument values are not mangled with the
-// Process ID in TRACE_EVENT_ASYNC macros. Use this macro to force Process ID
-// mangling.
+// By default, uint64_t ID argument values are not mangled with the Process ID
+// in TRACE_EVENT_ASYNC macros. Use this macro to force Process ID mangling.
#define TRACE_ID_MANGLE(id) \
trace_event_internal::TraceID::ForceMangle(id)
-// DEPRECATED: do not use: Consider using TRACE_ID_{GLOBAL, LOCAL} macros,
-// instead. By default, pointers are mangled with the Process ID in
-// TRACE_EVENT_ASYNC macros. Use this macro to prevent Process ID mangling.
+// By default, pointers are mangled with the Process ID in TRACE_EVENT_ASYNC
+// macros. Use this macro to prevent Process ID mangling.
#define TRACE_ID_DONT_MANGLE(id) \
trace_event_internal::TraceID::DontMangle(id)
// By default, trace IDs are eventually converted to a single 64-bit number. Use
-// this macro to add a scope string. For example,
+// this macro to add a scope string.
+#define TRACE_ID_WITH_SCOPE(scope, id) \
+ trace_event_internal::TraceID::WithScope(scope, id)
+
+// Sets the current sample state to the given category and name (both must be
+// constant strings). These states are intended for a sampling profiler.
+// Implementation note: we store category and name together because we don't
+// want the inconsistency/expense of storing two pointers.
+// |thread_bucket| is [0..2] and is used to statically isolate samples in one
+// thread from others.
+#define TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET( \
+ bucket_number, category, name) \
+ trace_event_internal:: \
+ TraceEventSamplingStateScope<bucket_number>::Set(category "\0" name)
+
+// Returns a current sampling state of the given bucket.
+#define TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(bucket_number) \
+ trace_event_internal::TraceEventSamplingStateScope<bucket_number>::Current()
+
+// Creates a scope of a sampling state of the given bucket.
//
-// TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
-// "network", "ResourceLoad",
-// TRACE_ID_WITH_SCOPE("BlinkResourceID", resourceID));
-//
-// Also, it is possible to prepend the ID with another number, like the process
-// ID. This is useful in creatin IDs that are unique among all processes. To do
-// that, pass two numbers after the scope string instead of one. For example,
-//
-// TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
-// "network", "ResourceLoad",
-// TRACE_ID_WITH_SCOPE("BlinkResourceID", pid, resourceID));
-#define TRACE_ID_WITH_SCOPE(scope, ...) \
- trace_event_internal::TraceID::WithScope(scope, ##__VA_ARGS__)
-
-#define TRACE_ID_GLOBAL(id) trace_event_internal::TraceID::GlobalId(id)
-#define TRACE_ID_LOCAL(id) trace_event_internal::TraceID::LocalId(id)
+// { // The sampling state is set within this scope.
+// TRACE_EVENT_SAMPLING_STATE_SCOPE_FOR_BUCKET(0, "category", "name");
+// ...;
+// }
+#define TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET( \
+ bucket_number, category, name) \
+ trace_event_internal::TraceEventSamplingStateScope<bucket_number> \
+ traceEventSamplingScope(category "\0" name);
#define TRACE_EVENT_API_CURRENT_THREAD_ID \
static_cast<int>(base::PlatformThread::CurrentId())
#define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
UNLIKELY(*INTERNAL_TRACE_EVENT_UID(category_group_enabled) & \
- (base::trace_event::TraceCategory::ENABLED_FOR_RECORDING | \
- base::trace_event::TraceCategory::ENABLED_FOR_ETW_EXPORT))
-
-#define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED() \
- UNLIKELY(*INTERNAL_TRACE_EVENT_UID(category_group_enabled) & \
- (base::trace_event::TraceCategory::ENABLED_FOR_RECORDING | \
- base::trace_event::TraceCategory::ENABLED_FOR_ETW_EXPORT | \
- base::trace_event::TraceCategory::ENABLED_FOR_FILTERING))
+ (base::trace_event::TraceLog::ENABLED_FOR_RECORDING | \
+ base::trace_event::TraceLog::ENABLED_FOR_EVENT_CALLBACK | \
+ base::trace_event::TraceLog::ENABLED_FOR_ETW_EXPORT))
////////////////////////////////////////////////////////////////////////////////
// Implementation specific tracing API definitions.
@@ -202,6 +204,13 @@
// Defines visibility for classes in trace_event.h
#define TRACE_EVENT_API_CLASS_EXPORT BASE_EXPORT
+// The thread buckets for the sampling profiler.
+TRACE_EVENT_API_CLASS_EXPORT extern \
+ TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3];
+
+#define TRACE_EVENT_API_THREAD_BUCKET(thread_bucket) \
+ g_trace_state[thread_bucket]
+
////////////////////////////////////////////////////////////////////////////////
// Implementation detail: trace event macros create temporary variables
@@ -240,69 +249,69 @@
// Implementation detail: internal macro to create static category and add
// event if the category is enabled.
-#define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...) \
- do { \
- INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
- if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) { \
- trace_event_internal::AddTraceEvent( \
- phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
- trace_event_internal::kGlobalScope, trace_event_internal::kNoId, \
- flags, trace_event_internal::kNoId, ##__VA_ARGS__); \
- } \
- } while (0)
+#define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...) \
+ do { \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+ if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+ trace_event_internal::AddTraceEvent( \
+ phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+ trace_event_internal::kGlobalScope, trace_event_internal::kNoId, \
+ flags, trace_event_internal::kNoId, ##__VA_ARGS__); \
+ } \
+ } while (0)
// Implementation detail: internal macro to create static category and add begin
// event if the category is enabled. Also adds the end event when the scope
// ends.
-#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, ...) \
- INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
- trace_event_internal::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \
- if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) { \
- base::trace_event::TraceEventHandle h = \
- trace_event_internal::AddTraceEvent( \
- TRACE_EVENT_PHASE_COMPLETE, \
- INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
- trace_event_internal::kGlobalScope, trace_event_internal::kNoId, \
- TRACE_EVENT_FLAG_NONE, trace_event_internal::kNoId, \
- ##__VA_ARGS__); \
- INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \
- INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \
- }
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, ...) \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+ trace_event_internal::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \
+ if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+ base::trace_event::TraceEventHandle h = \
+ trace_event_internal::AddTraceEvent( \
+ TRACE_EVENT_PHASE_COMPLETE, \
+ INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+ trace_event_internal::kGlobalScope, trace_event_internal::kNoId, \
+ TRACE_EVENT_FLAG_NONE, trace_event_internal::kNoId, \
+ ##__VA_ARGS__); \
+ INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \
+ INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \
+ }
-#define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, \
- bind_id, flow_flags, ...) \
- INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
- trace_event_internal::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \
- if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) { \
- trace_event_internal::TraceID trace_event_bind_id((bind_id)); \
- unsigned int trace_event_flags = \
- flow_flags | trace_event_bind_id.id_flags(); \
- base::trace_event::TraceEventHandle h = \
- trace_event_internal::AddTraceEvent( \
- TRACE_EVENT_PHASE_COMPLETE, \
- INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW( \
+ category_group, name, bind_id, flow_flags, ...) \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+ trace_event_internal::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \
+ if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+ unsigned int trace_event_flags = flow_flags; \
+ trace_event_internal::TraceID trace_event_bind_id(bind_id, \
+ &trace_event_flags); \
+ base::trace_event::TraceEventHandle h = \
+ trace_event_internal::AddTraceEvent( \
+ TRACE_EVENT_PHASE_COMPLETE, \
+ INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
trace_event_internal::kGlobalScope, trace_event_internal::kNoId, \
trace_event_flags, trace_event_bind_id.raw_id(), ##__VA_ARGS__); \
- INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \
- INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \
+ INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \
+ INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \
}
// Implementation detail: internal macro to create static category and add
// event if the category is enabled.
#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category_group, name, id, \
- flags, ...) \
- do { \
- INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
- if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) { \
- trace_event_internal::TraceID trace_event_trace_id((id)); \
- unsigned int trace_event_flags = \
- flags | trace_event_trace_id.id_flags(); \
- trace_event_internal::AddTraceEvent( \
- phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
- trace_event_trace_id.scope(), trace_event_trace_id.raw_id(), \
- trace_event_flags, trace_event_internal::kNoId, ##__VA_ARGS__); \
- } \
- } while (0)
+ flags, ...) \
+ do { \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+ if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+ unsigned int trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
+ trace_event_internal::TraceID trace_event_trace_id( \
+ id, &trace_event_flags); \
+ trace_event_internal::AddTraceEvent( \
+ phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
+ name, trace_event_trace_id.scope(), trace_event_trace_id.raw_id(), \
+ trace_event_flags, trace_event_internal::kNoId, ##__VA_ARGS__); \
+ } \
+ } while (0)
// Implementation detail: internal macro to create static category and add
// event if the category is enabled.
@@ -310,11 +319,12 @@
timestamp, flags, ...) \
do { \
INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
- if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) { \
+ if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \
phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
trace_event_internal::kGlobalScope, trace_event_internal::kNoId, \
- TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, \
+ base::TimeTicks::FromInternalValue(timestamp), \
flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
trace_event_internal::kNoId, ##__VA_ARGS__); \
} \
@@ -322,50 +332,33 @@
// Implementation detail: internal macro to create static category and add
// event if the category is enabled.
-#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
- phase, category_group, name, id, thread_id, timestamp, flags, ...) \
- do { \
- INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
- if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) { \
- trace_event_internal::TraceID trace_event_trace_id((id)); \
- unsigned int trace_event_flags = \
- flags | trace_event_trace_id.id_flags(); \
- trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \
- phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
- trace_event_trace_id.scope(), trace_event_trace_id.raw_id(), \
- thread_id, timestamp, \
- trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
- trace_event_internal::kNoId, ##__VA_ARGS__); \
- } \
- } while (0)
-
-// The linked ID will not be mangled.
-#define INTERNAL_TRACE_EVENT_ADD_LINK_IDS(category_group, name, id1, id2) \
- do { \
- INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
- if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) { \
- trace_event_internal::TraceID source_id((id1)); \
- unsigned int source_flags = source_id.id_flags(); \
- trace_event_internal::TraceID target_id((id2)); \
- trace_event_internal::AddTraceEvent( \
- TRACE_EVENT_PHASE_LINK_IDS, \
- INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
- source_id.scope(), source_id.raw_id(), source_flags, \
- trace_event_internal::kNoId, "linked_id", \
- target_id.AsConvertableToTraceFormat()); \
- } \
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ phase, category_group, name, id, thread_id, timestamp, flags, ...) \
+ do { \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+ if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+ unsigned int trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
+ trace_event_internal::TraceID trace_event_trace_id(id, \
+ &trace_event_flags); \
+ trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \
+ phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+ trace_event_trace_id.scope(), trace_event_trace_id.raw_id(), \
+ thread_id, base::TimeTicks::FromInternalValue(timestamp), \
+ trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
+ trace_event_internal::kNoId, ##__VA_ARGS__); \
+ } \
} while (0)
// Implementation detail: internal macro to create static category and add
// metadata event if the category is enabled.
-#define INTERNAL_TRACE_EVENT_METADATA_ADD(category_group, name, ...) \
- do { \
- INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
- if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) { \
- TRACE_EVENT_API_ADD_METADATA_EVENT( \
- INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
- ##__VA_ARGS__); \
- } \
+#define INTERNAL_TRACE_EVENT_METADATA_ADD(category_group, name, ...) \
+ do { \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+ if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+ TRACE_EVENT_API_ADD_METADATA_EVENT( \
+ INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+ ##__VA_ARGS__); \
+ } \
} while (0)
// Implementation detail: internal macro to enter and leave a
@@ -388,7 +381,7 @@
void operator=(const INTERNAL_TRACE_EVENT_UID(ScopedContext)&) {}; \
}; \
INTERNAL_TRACE_EVENT_UID(ScopedContext) \
- INTERNAL_TRACE_EVENT_UID(scoped_context)(context);
+ INTERNAL_TRACE_EVENT_UID(scoped_context)(context.raw_id());
// Implementation detail: internal macro to trace a task execution with the
// location where it was posted from.
@@ -410,64 +403,19 @@ const unsigned long long kNoId = 0;
// TraceID encapsulates an ID that can either be an integer or pointer. Pointers
// are by default mangled with the Process ID so that they are unlikely to
// collide when the same pointer is used on different processes.
-class BASE_EXPORT TraceID {
+class TraceID {
public:
- // Can be combined with WithScope.
- class LocalId {
- public:
- explicit LocalId(unsigned long long raw_id) : raw_id_(raw_id) {}
- unsigned long long raw_id() const { return raw_id_; }
- private:
- unsigned long long raw_id_;
- };
-
- // Can be combined with WithScope.
- class GlobalId {
- public:
- explicit GlobalId(unsigned long long raw_id) : raw_id_(raw_id) {}
- unsigned long long raw_id() const { return raw_id_; }
- private:
- unsigned long long raw_id_;
- };
-
class WithScope {
public:
WithScope(const char* scope, unsigned long long raw_id)
: scope_(scope), raw_id_(raw_id) {}
- WithScope(const char* scope, LocalId local_id)
- : scope_(scope), raw_id_(local_id.raw_id()) {
- id_flags_ = TRACE_EVENT_FLAG_HAS_LOCAL_ID;
- }
- WithScope(const char* scope, GlobalId global_id)
- : scope_(scope), raw_id_(global_id.raw_id()) {
- id_flags_ = TRACE_EVENT_FLAG_HAS_GLOBAL_ID;
- }
- WithScope(const char* scope,
- unsigned long long prefix,
- unsigned long long raw_id)
- : scope_(scope), has_prefix_(true), prefix_(prefix), raw_id_(raw_id) {}
- WithScope(const char* scope, unsigned long long prefix, GlobalId global_id)
- : scope_(scope),
- has_prefix_(true),
- prefix_(prefix),
- raw_id_(global_id.raw_id()) {
- id_flags_ = TRACE_EVENT_FLAG_HAS_GLOBAL_ID;
- }
unsigned long long raw_id() const { return raw_id_; }
const char* scope() const { return scope_; }
- bool has_prefix() const { return has_prefix_; }
- unsigned long long prefix() const { return prefix_; }
- unsigned int id_flags() const { return id_flags_; }
-
private:
const char* scope_ = nullptr;
- bool has_prefix_ = false;
- unsigned long long prefix_;
unsigned long long raw_id_;
- unsigned int id_flags_ = TRACE_EVENT_FLAG_HAS_ID;
};
- // DEPRECATED: consider using LocalId or GlobalId, instead.
class DontMangle {
public:
explicit DontMangle(const void* raw_id)
@@ -488,12 +436,15 @@ class BASE_EXPORT TraceID {
: raw_id_(static_cast<unsigned long long>(raw_id)) {}
explicit DontMangle(signed char raw_id)
: raw_id_(static_cast<unsigned long long>(raw_id)) {}
+ explicit DontMangle(WithScope scoped_id)
+ : scope_(scoped_id.scope()), raw_id_(scoped_id.raw_id()) {}
+ const char* scope() const { return scope_; }
unsigned long long raw_id() const { return raw_id_; }
private:
+ const char* scope_ = nullptr;
unsigned long long raw_id_;
};
- // DEPRECATED: consider using LocalId or GlobalId, instead.
class ForceMangle {
public:
explicit ForceMangle(unsigned long long raw_id) : raw_id_(raw_id) {}
@@ -515,58 +466,50 @@ class BASE_EXPORT TraceID {
private:
unsigned long long raw_id_;
};
-
- TraceID(const void* raw_id) : raw_id_(static_cast<unsigned long long>(
- reinterpret_cast<uintptr_t>(raw_id))) {
- id_flags_ = TRACE_EVENT_FLAG_HAS_ID | TRACE_EVENT_FLAG_MANGLE_ID;
+ TraceID(const void* raw_id, unsigned int* flags)
+ : raw_id_(static_cast<unsigned long long>(
+ reinterpret_cast<uintptr_t>(raw_id))) {
+ *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
+ }
+ TraceID(ForceMangle raw_id, unsigned int* flags) : raw_id_(raw_id.raw_id()) {
+ *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
+ }
+ TraceID(DontMangle maybe_scoped_id, unsigned int* /*flags*/)
+ : scope_(maybe_scoped_id.scope()), raw_id_(maybe_scoped_id.raw_id()) {}
+ TraceID(unsigned long long raw_id, unsigned int* flags) : raw_id_(raw_id) {
+ (void)flags;
}
- TraceID(ForceMangle raw_id) : raw_id_(raw_id.raw_id()) {
- id_flags_ = TRACE_EVENT_FLAG_HAS_ID | TRACE_EVENT_FLAG_MANGLE_ID;
+ TraceID(unsigned long raw_id, unsigned int* flags) : raw_id_(raw_id) {
+ (void)flags;
}
- TraceID(DontMangle raw_id) : raw_id_(raw_id.raw_id()) {}
- TraceID(unsigned long long raw_id) : raw_id_(raw_id) {}
- TraceID(unsigned long raw_id) : raw_id_(raw_id) {}
- TraceID(unsigned int raw_id) : raw_id_(raw_id) {}
- TraceID(unsigned short raw_id) : raw_id_(raw_id) {}
- TraceID(unsigned char raw_id) : raw_id_(raw_id) {}
- TraceID(long long raw_id)
- : raw_id_(static_cast<unsigned long long>(raw_id)) {}
- TraceID(long raw_id)
- : raw_id_(static_cast<unsigned long long>(raw_id)) {}
- TraceID(int raw_id)
- : raw_id_(static_cast<unsigned long long>(raw_id)) {}
- TraceID(short raw_id)
- : raw_id_(static_cast<unsigned long long>(raw_id)) {}
- TraceID(signed char raw_id)
- : raw_id_(static_cast<unsigned long long>(raw_id)) {}
- TraceID(LocalId raw_id) : raw_id_(raw_id.raw_id()) {
- id_flags_ = TRACE_EVENT_FLAG_HAS_LOCAL_ID;
+ TraceID(unsigned int raw_id, unsigned int* flags) : raw_id_(raw_id) {
+ (void)flags;
}
- TraceID(GlobalId raw_id) : raw_id_(raw_id.raw_id()) {
- id_flags_ = TRACE_EVENT_FLAG_HAS_GLOBAL_ID;
+ TraceID(unsigned short raw_id, unsigned int* flags) : raw_id_(raw_id) {
+ (void)flags;
}
- TraceID(WithScope scoped_id)
- : scope_(scoped_id.scope()),
- has_prefix_(scoped_id.has_prefix()),
- prefix_(scoped_id.prefix()),
- raw_id_(scoped_id.raw_id()),
- id_flags_(scoped_id.id_flags()) {}
+ TraceID(unsigned char raw_id, unsigned int* flags) : raw_id_(raw_id) {
+ (void)flags;
+ }
+ TraceID(long long raw_id, unsigned int* flags)
+ : raw_id_(static_cast<unsigned long long>(raw_id)) { (void)flags; }
+ TraceID(long raw_id, unsigned int* flags)
+ : raw_id_(static_cast<unsigned long long>(raw_id)) { (void)flags; }
+ TraceID(int raw_id, unsigned int* flags)
+ : raw_id_(static_cast<unsigned long long>(raw_id)) { (void)flags; }
+ TraceID(short raw_id, unsigned int* flags)
+ : raw_id_(static_cast<unsigned long long>(raw_id)) { (void)flags; }
+ TraceID(signed char raw_id, unsigned int* flags)
+ : raw_id_(static_cast<unsigned long long>(raw_id)) { (void)flags; }
+ TraceID(WithScope scoped_id, unsigned int* /*flags*/)
+ : scope_(scoped_id.scope()), raw_id_(scoped_id.raw_id()) {}
unsigned long long raw_id() const { return raw_id_; }
const char* scope() const { return scope_; }
- bool has_prefix() const { return has_prefix_; }
- unsigned long long prefix() const { return prefix_; }
- unsigned int id_flags() const { return id_flags_; }
-
- std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
- AsConvertableToTraceFormat() const;
private:
const char* scope_ = nullptr;
- bool has_prefix_ = false;
- unsigned long long prefix_;
unsigned long long raw_id_;
- unsigned int id_flags_ = TRACE_EVENT_FLAG_HAS_ID;
};
// Simple union to store various types as unsigned long long.
@@ -1030,10 +973,9 @@ class TRACE_EVENT_API_CLASS_EXPORT ScopedTracer {
ScopedTracer() : p_data_(NULL) {}
~ScopedTracer() {
- if (p_data_ && *data_.category_group_enabled) {
+ if (p_data_ && *data_.category_group_enabled)
TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
data_.category_group_enabled, data_.name, data_.event_handle);
- }
}
void Initialize(const unsigned char* category_group_enabled,
@@ -1081,6 +1023,37 @@ class TRACE_EVENT_API_CLASS_EXPORT ScopedTraceBinaryEfficient {
trace_event_internal::ScopedTraceBinaryEfficient \
INTERNAL_TRACE_EVENT_UID(scoped_trace)(category_group, name);
+// TraceEventSamplingStateScope records the current sampling state
+// and sets a new sampling state. When the scope exists, it restores
+// the sampling state having recorded.
+template<size_t BucketNumber>
+class TraceEventSamplingStateScope {
+ public:
+ TraceEventSamplingStateScope(const char* category_and_name) {
+ previous_state_ = TraceEventSamplingStateScope<BucketNumber>::Current();
+ TraceEventSamplingStateScope<BucketNumber>::Set(category_and_name);
+ }
+
+ ~TraceEventSamplingStateScope() {
+ TraceEventSamplingStateScope<BucketNumber>::Set(previous_state_);
+ }
+
+ static inline const char* Current() {
+ return reinterpret_cast<const char*>(TRACE_EVENT_API_ATOMIC_LOAD(
+ g_trace_state[BucketNumber]));
+ }
+
+ static inline void Set(const char* category_and_name) {
+ TRACE_EVENT_API_ATOMIC_STORE(
+ g_trace_state[BucketNumber],
+ reinterpret_cast<TRACE_EVENT_API_ATOMIC_WORD>(
+ const_cast<char*>(category_and_name)));
+ }
+
+ private:
+ const char* previous_state_;
+};
+
} // namespace trace_event_internal
namespace base {
diff --git a/base/trace_event/trace_event_argument.cc b/base/trace_event/trace_event_argument.cc
index db702b6231..336d964bff 100644
--- a/base/trace_event/trace_event_argument.cc
+++ b/base/trace_event/trace_event_argument.cc
@@ -244,36 +244,36 @@ void TracedValue::SetBaseValueWithCopiedName(base::StringPiece name,
const base::Value& value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
switch (value.GetType()) {
- case base::Value::Type::NONE:
- case base::Value::Type::BINARY:
+ case base::Value::TYPE_NULL:
+ case base::Value::TYPE_BINARY:
NOTREACHED();
break;
- case base::Value::Type::BOOLEAN: {
+ case base::Value::TYPE_BOOLEAN: {
bool bool_value;
value.GetAsBoolean(&bool_value);
SetBooleanWithCopiedName(name, bool_value);
} break;
- case base::Value::Type::INTEGER: {
+ case base::Value::TYPE_INTEGER: {
int int_value;
value.GetAsInteger(&int_value);
SetIntegerWithCopiedName(name, int_value);
} break;
- case base::Value::Type::DOUBLE: {
+ case base::Value::TYPE_DOUBLE: {
double double_value;
value.GetAsDouble(&double_value);
SetDoubleWithCopiedName(name, double_value);
} break;
- case base::Value::Type::STRING: {
- const Value* string_value;
+ case base::Value::TYPE_STRING: {
+ const StringValue* string_value;
value.GetAsString(&string_value);
SetStringWithCopiedName(name, string_value->GetString());
} break;
- case base::Value::Type::DICTIONARY: {
+ case base::Value::TYPE_DICTIONARY: {
const DictionaryValue* dict_value;
value.GetAsDictionary(&dict_value);
BeginDictionaryWithCopiedName(name);
@@ -284,7 +284,7 @@ void TracedValue::SetBaseValueWithCopiedName(base::StringPiece name,
EndDictionary();
} break;
- case base::Value::Type::LIST: {
+ case base::Value::TYPE_LIST: {
const ListValue* list_value;
value.GetAsList(&list_value);
BeginArrayWithCopiedName(name);
@@ -298,36 +298,36 @@ void TracedValue::SetBaseValueWithCopiedName(base::StringPiece name,
void TracedValue::AppendBaseValue(const base::Value& value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
switch (value.GetType()) {
- case base::Value::Type::NONE:
- case base::Value::Type::BINARY:
+ case base::Value::TYPE_NULL:
+ case base::Value::TYPE_BINARY:
NOTREACHED();
break;
- case base::Value::Type::BOOLEAN: {
+ case base::Value::TYPE_BOOLEAN: {
bool bool_value;
value.GetAsBoolean(&bool_value);
AppendBoolean(bool_value);
} break;
- case base::Value::Type::INTEGER: {
+ case base::Value::TYPE_INTEGER: {
int int_value;
value.GetAsInteger(&int_value);
AppendInteger(int_value);
} break;
- case base::Value::Type::DOUBLE: {
+ case base::Value::TYPE_DOUBLE: {
double double_value;
value.GetAsDouble(&double_value);
AppendDouble(double_value);
} break;
- case base::Value::Type::STRING: {
- const Value* string_value;
+ case base::Value::TYPE_STRING: {
+ const StringValue* string_value;
value.GetAsString(&string_value);
AppendString(string_value->GetString());
} break;
- case base::Value::Type::DICTIONARY: {
+ case base::Value::TYPE_DICTIONARY: {
const DictionaryValue* dict_value;
value.GetAsDictionary(&dict_value);
BeginDictionary();
@@ -338,7 +338,7 @@ void TracedValue::AppendBaseValue(const base::Value& value) {
EndDictionary();
} break;
- case base::Value::Type::LIST: {
+ case base::Value::TYPE_LIST: {
const ListValue* list_value;
value.GetAsList(&list_value);
BeginArray();
diff --git a/base/trace_event/trace_event_argument_unittest.cc b/base/trace_event/trace_event_argument_unittest.cc
index aef8441c8e..61395f4d55 100644
--- a/base/trace_event/trace_event_argument_unittest.cc
+++ b/base/trace_event/trace_event_argument_unittest.cc
@@ -97,9 +97,9 @@ TEST(TraceEventArgumentTest, LongStrings) {
}
TEST(TraceEventArgumentTest, PassBaseValue) {
- Value int_value(42);
- Value bool_value(true);
- Value double_value(42.0f);
+ FundamentalValue int_value(42);
+ FundamentalValue bool_value(true);
+ FundamentalValue double_value(42.0f);
auto dict_value = WrapUnique(new DictionaryValue);
dict_value->SetBoolean("bool", true);
@@ -131,10 +131,10 @@ TEST(TraceEventArgumentTest, PassBaseValue) {
}
TEST(TraceEventArgumentTest, PassTracedValue) {
- auto dict_value = MakeUnique<TracedValue>();
+ auto dict_value = WrapUnique(new TracedValue());
dict_value->SetInteger("a", 1);
- auto nested_dict_value = MakeUnique<TracedValue>();
+ auto nested_dict_value = WrapUnique(new TracedValue());
nested_dict_value->SetInteger("b", 2);
nested_dict_value->BeginArray("c");
nested_dict_value->AppendString("foo");
diff --git a/base/trace_event/trace_event_filter.cc b/base/trace_event/trace_event_filter.cc
deleted file mode 100644
index d50c5fe251..0000000000
--- a/base/trace_event/trace_event_filter.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 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.
-
-#include "base/compiler_specific.h"
-#include "base/trace_event/trace_event_filter.h"
-
-namespace base {
-namespace trace_event {
-
-TraceEventFilter::TraceEventFilter() {}
-TraceEventFilter::~TraceEventFilter() {}
-
-void TraceEventFilter::EndEvent(const char* category_name,
- const char* event_name) const {
- ALLOW_UNUSED_PARAM(category_name);
- ALLOW_UNUSED_PARAM(event_name);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/trace_event_filter.h b/base/trace_event/trace_event_filter.h
deleted file mode 100644
index 48c6711432..0000000000
--- a/base/trace_event/trace_event_filter.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2016 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 BASE_TRACE_EVENT_TRACE_EVENT_FILTER_H_
-#define BASE_TRACE_EVENT_TRACE_EVENT_FILTER_H_
-
-#include <memory>
-
-#include "base/base_export.h"
-#include "base/macros.h"
-
-namespace base {
-namespace trace_event {
-
-class TraceEvent;
-
-// TraceEventFilter is like iptables for TRACE_EVENT macros. Filters can be
-// enabled on a per-category basis, hence a single filter instance can serve
-// more than a TraceCategory. There are two use cases for filters:
-// 1. Snooping TRACE_EVENT macros without adding them to the TraceLog. This is
-// possible by setting the ENABLED_FOR_FILTERING flag on a category w/o
-// ENABLED_FOR_RECORDING (see TraceConfig for user-facing configuration).
-// 2. Filtering TRACE_EVENT macros before they are added to the TraceLog. This
-// requires both the ENABLED_FOR_FILTERING and ENABLED_FOR_RECORDING flags
-// on the category.
-// More importantly, filters must be thread-safe. The FilterTraceEvent and
-// EndEvent methods can be called concurrently as trace macros are hit on
-// different threads.
-class BASE_EXPORT TraceEventFilter {
- public:
- TraceEventFilter();
- virtual ~TraceEventFilter();
-
- // If the category is ENABLED_FOR_RECORDING, the event is added iff all the
- // filters enabled for the category return true. false causes the event to be
- // discarded.
- virtual bool FilterTraceEvent(const TraceEvent& trace_event) const = 0;
-
- // Notifies the end of a duration event when the RAII macro goes out of scope.
- virtual void EndEvent(const char* category_name,
- const char* event_name) const;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TraceEventFilter);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_TRACE_EVENT_FILTER_H_
diff --git a/base/trace_event/trace_event_filter_test_utils.cc b/base/trace_event/trace_event_filter_test_utils.cc
deleted file mode 100644
index 06548b049a..0000000000
--- a/base/trace_event/trace_event_filter_test_utils.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2016 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.
-
-#include "base/trace_event/trace_event_filter_test_utils.h"
-
-#include "base/logging.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-TestEventFilter::HitsCounter* g_hits_counter;
-} // namespace;
-
-// static
-const char TestEventFilter::kName[] = "testing_predicate";
-bool TestEventFilter::filter_return_value_;
-
-// static
-std::unique_ptr<TraceEventFilter> TestEventFilter::Factory(
- const std::string& predicate_name) {
- std::unique_ptr<TraceEventFilter> res;
- if (predicate_name == kName)
- res.reset(new TestEventFilter());
- return res;
-}
-
-TestEventFilter::TestEventFilter() {}
-TestEventFilter::~TestEventFilter() {}
-
-bool TestEventFilter::FilterTraceEvent(const TraceEvent& trace_event) const {
- if (g_hits_counter)
- g_hits_counter->filter_trace_event_hit_count++;
- return filter_return_value_;
-}
-
-void TestEventFilter::EndEvent(const char* category_name,
- const char* name) const {
- if (g_hits_counter)
- g_hits_counter->end_event_hit_count++;
-}
-
-TestEventFilter::HitsCounter::HitsCounter() {
- Reset();
- DCHECK(!g_hits_counter);
- g_hits_counter = this;
-}
-
-TestEventFilter::HitsCounter::~HitsCounter() {
- DCHECK(g_hits_counter);
- g_hits_counter = nullptr;
-}
-
-void TestEventFilter::HitsCounter::Reset() {
- filter_trace_event_hit_count = 0;
- end_event_hit_count = 0;
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/trace_event_filter_test_utils.h b/base/trace_event/trace_event_filter_test_utils.h
deleted file mode 100644
index 419068b221..0000000000
--- a/base/trace_event/trace_event_filter_test_utils.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2016 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 BASE_TRACE_EVENT_TRACE_EVENT_FILTER_TEST_UTILS_H_
-#define BASE_TRACE_EVENT_TRACE_EVENT_FILTER_TEST_UTILS_H_
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/trace_event/trace_event_filter.h"
-
-namespace base {
-namespace trace_event {
-
-class TestEventFilter : public TraceEventFilter {
- public:
- struct HitsCounter {
- HitsCounter();
- ~HitsCounter();
- void Reset();
- size_t filter_trace_event_hit_count;
- size_t end_event_hit_count;
- };
-
- static const char kName[];
-
- // Factory method for TraceLog::SetFilterFactoryForTesting().
- static std::unique_ptr<TraceEventFilter> Factory(
- const std::string& predicate_name);
-
- TestEventFilter();
- ~TestEventFilter() override;
-
- // TraceEventFilter implementation.
- bool FilterTraceEvent(const TraceEvent& trace_event) const override;
- void EndEvent(const char* category_name, const char* name) const override;
-
- static void set_filter_return_value(bool value) {
- filter_return_value_ = value;
- }
-
- private:
- static bool filter_return_value_;
-
- DISALLOW_COPY_AND_ASSIGN(TestEventFilter);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_TRACE_EVENT_FILTER_TEST_UTILS_H_
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
index cb23eb474c..f469f2f6bc 100644
--- a/base/trace_event/trace_event_impl.cc
+++ b/base/trace_event/trace_event_impl.cc
@@ -8,7 +8,6 @@
#include "base/format_macros.h"
#include "base/json/string_escape.h"
-#include "base/memory/ptr_util.h"
#include "base/process/process_handle.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -16,7 +15,6 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
#include "base/trace_event/trace_log.h"
namespace base {
@@ -360,33 +358,10 @@ void TraceEvent::AppendAsJSON(
// If id_ is set, print it out as a hex string so we don't loose any
// bits (it might be a 64-bit pointer).
- unsigned int id_flags_ = flags_ & (TRACE_EVENT_FLAG_HAS_ID |
- TRACE_EVENT_FLAG_HAS_LOCAL_ID |
- TRACE_EVENT_FLAG_HAS_GLOBAL_ID);
- if (id_flags_) {
+ if (flags_ & TRACE_EVENT_FLAG_HAS_ID) {
if (scope_ != trace_event_internal::kGlobalScope)
StringAppendF(out, ",\"scope\":\"%s\"", scope_);
-
- switch (id_flags_) {
- case TRACE_EVENT_FLAG_HAS_ID:
- StringAppendF(out, ",\"id\":\"0x%" PRIx64 "\"",
- static_cast<uint64_t>(id_));
- break;
-
- case TRACE_EVENT_FLAG_HAS_LOCAL_ID:
- StringAppendF(out, ",\"id2\":{\"local\":\"0x%" PRIx64 "\"}",
- static_cast<uint64_t>(id_));
- break;
-
- case TRACE_EVENT_FLAG_HAS_GLOBAL_ID:
- StringAppendF(out, ",\"id2\":{\"global\":\"0x%" PRIx64 "\"}",
- static_cast<uint64_t>(id_));
- break;
-
- default:
- NOTREACHED() << "More than one of the ID flags are set";
- break;
- }
+ StringAppendF(out, ",\"id\":\"0x%" PRIx64 "\"", static_cast<uint64_t>(id_));
}
if (flags_ & TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
@@ -449,42 +424,3 @@ void TraceEvent::AppendPrettyPrinted(std::ostringstream* out) const {
} // namespace trace_event
} // namespace base
-
-namespace trace_event_internal {
-
-std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
-TraceID::AsConvertableToTraceFormat() const {
- auto value = base::MakeUnique<base::trace_event::TracedValue>();
-
- if (scope_ != kGlobalScope)
- value->SetString("scope", scope_);
-
- const char* id_field_name = "id";
- if (id_flags_ == TRACE_EVENT_FLAG_HAS_GLOBAL_ID) {
- id_field_name = "global";
- value->BeginDictionary("id2");
- } else if (id_flags_ == TRACE_EVENT_FLAG_HAS_LOCAL_ID) {
- id_field_name = "local";
- value->BeginDictionary("id2");
- } else if (id_flags_ != TRACE_EVENT_FLAG_HAS_ID) {
- NOTREACHED() << "Unrecognized ID flag";
- }
-
- if (has_prefix_) {
- value->SetString(id_field_name,
- base::StringPrintf("0x%" PRIx64 "/0x%" PRIx64,
- static_cast<uint64_t>(prefix_),
- static_cast<uint64_t>(raw_id_)));
- } else {
- value->SetString(
- id_field_name,
- base::StringPrintf("0x%" PRIx64, static_cast<uint64_t>(raw_id_)));
- }
-
- if (id_flags_ != TRACE_EVENT_FLAG_HAS_ID)
- value->EndDictionary();
-
- return std::move(value);
-}
-
-} // namespace trace_event_internal
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h
index 5eef702fb9..4382217881 100644
--- a/base/trace_event/trace_event_impl.h
+++ b/base/trace_event/trace_event_impl.h
@@ -23,11 +23,16 @@
#include "base/strings/string_util.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
+#include "base/threading/thread.h"
#include "base/threading/thread_local.h"
#include "base/trace_event/trace_event_memory_overhead.h"
#include "build/build_config.h"
namespace base {
+
+class WaitableEvent;
+class MessageLoop;
+
namespace trace_event {
typedef base::Callback<bool(const char* arg_name)> ArgumentNameFilterPredicate;
diff --git a/base/trace_event/trace_event_memory_overhead.cc b/base/trace_event/trace_event_memory_overhead.cc
index 8d56e1d80e..23579cbb22 100644
--- a/base/trace_event/trace_event_memory_overhead.cc
+++ b/base/trace_event/trace_event_memory_overhead.cc
@@ -69,27 +69,27 @@ void TraceEventMemoryOverhead::AddRefCountedString(
void TraceEventMemoryOverhead::AddValue(const Value& value) {
switch (value.GetType()) {
- case Value::Type::NONE:
- case Value::Type::BOOLEAN:
- case Value::Type::INTEGER:
- case Value::Type::DOUBLE:
+ case Value::TYPE_NULL:
+ case Value::TYPE_BOOLEAN:
+ case Value::TYPE_INTEGER:
+ case Value::TYPE_DOUBLE:
Add("FundamentalValue", sizeof(Value));
break;
- case Value::Type::STRING: {
- const Value* string_value = nullptr;
+ case Value::TYPE_STRING: {
+ const StringValue* string_value = nullptr;
value.GetAsString(&string_value);
- Add("StringValue", sizeof(Value));
+ Add("StringValue", sizeof(StringValue));
AddString(string_value->GetString());
} break;
- case Value::Type::BINARY: {
+ case Value::TYPE_BINARY: {
const BinaryValue* binary_value = nullptr;
value.GetAsBinary(&binary_value);
Add("BinaryValue", sizeof(BinaryValue) + binary_value->GetSize());
} break;
- case Value::Type::DICTIONARY: {
+ case Value::TYPE_DICTIONARY: {
const DictionaryValue* dictionary_value = nullptr;
value.GetAsDictionary(&dictionary_value);
Add("DictionaryValue", sizeof(DictionaryValue));
@@ -100,7 +100,7 @@ void TraceEventMemoryOverhead::AddValue(const Value& value) {
}
} break;
- case Value::Type::LIST: {
+ case Value::TYPE_LIST: {
const ListValue* list_value = nullptr;
value.GetAsList(&list_value);
Add("ListValue", sizeof(ListValue));
diff --git a/base/trace_event/trace_event_synthetic_delay.h b/base/trace_event/trace_event_synthetic_delay.h
index e86f9eee2c..59e2842f71 100644
--- a/base/trace_event/trace_event_synthetic_delay.h
+++ b/base/trace_event/trace_event_synthetic_delay.h
@@ -62,6 +62,9 @@
trace_event_internal::GetOrCreateDelay(name, &impl_ptr)->End(); \
} while (false)
+template <typename Type>
+struct DefaultSingletonTraits;
+
namespace base {
namespace trace_event {
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
index 82a552aa4e..ff8ec2de78 100644
--- a/base/trace_event/trace_event_unittest.cc
+++ b/base/trace_event/trace_event_unittest.cc
@@ -18,7 +18,6 @@
#include "base/json/json_writer.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_handle.h"
@@ -30,12 +29,7 @@
#include "base/threading/platform_thread.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
-#include "base/trace_event/event_name_filter.h"
-#include "base/trace_event/heap_profiler_event_filter.h"
#include "base/trace_event/trace_buffer.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_filter.h"
-#include "base/trace_event/trace_event_filter_test_utils.h"
#include "base/trace_event/trace_event_synthetic_delay.h"
#include "base/values.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -73,6 +67,9 @@ class TraceEventTestFixture : public testing::Test {
WaitableEvent* flush_complete_event,
const scoped_refptr<base::RefCountedString>& events_str,
bool has_more_events);
+ void OnWatchEventMatched() {
+ ++event_watch_notification_;
+ }
DictionaryValue* FindMatchingTraceEntry(const JsonKeyValue* key_values);
DictionaryValue* FindNamePhase(const char* name, const char* phase);
DictionaryValue* FindNamePhaseKeyValue(const char* name,
@@ -94,6 +91,7 @@ class TraceEventTestFixture : public testing::Test {
}
void BeginSpecificTrace(const std::string& filter) {
+ event_watch_notification_ = 0;
TraceLog::GetInstance()->SetEnabled(TraceConfig(filter, ""),
TraceLog::RECORDING_MODE);
}
@@ -137,8 +135,7 @@ class TraceEventTestFixture : public testing::Test {
}
void EndTraceAndFlushAsync(WaitableEvent* flush_complete_event) {
- TraceLog::GetInstance()->SetDisabled(TraceLog::RECORDING_MODE |
- TraceLog::FILTERING_MODE);
+ TraceLog::GetInstance()->SetDisabled();
TraceLog::GetInstance()->Flush(
base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
base::Unretained(static_cast<TraceEventTestFixture*>(this)),
@@ -154,6 +151,7 @@ class TraceEventTestFixture : public testing::Test {
ASSERT_TRUE(tracelog);
ASSERT_FALSE(tracelog->IsEnabled());
trace_buffer_.SetOutputCallback(json_output_.GetCallback());
+ event_watch_notification_ = 0;
num_flush_callbacks_ = 0;
}
void TearDown() override {
@@ -170,6 +168,7 @@ class TraceEventTestFixture : public testing::Test {
ListValue trace_parsed_;
TraceResultBuffer trace_buffer_;
TraceResultBuffer::SimpleOutput json_output_;
+ int event_watch_notification_;
size_t num_flush_callbacks_;
private:
@@ -264,7 +263,7 @@ DictionaryValue* TraceEventTestFixture::FindMatchingTraceEntry(
for (size_t i = 0; i < trace_parsed_count; i++) {
Value* value = NULL;
trace_parsed_.Get(i, &value);
- if (!value || value->GetType() != Value::Type::DICTIONARY)
+ if (!value || value->GetType() != Value::TYPE_DICTIONARY)
continue;
DictionaryValue* dict = static_cast<DictionaryValue*>(value);
@@ -282,7 +281,7 @@ void TraceEventTestFixture::DropTracedMetadataRecords() {
for (size_t i = 0; i < old_trace_parsed_size; i++) {
Value* value = nullptr;
old_trace_parsed->Get(i, &value);
- if (!value || value->GetType() != Value::Type::DICTIONARY) {
+ if (!value || value->GetType() != Value::TYPE_DICTIONARY) {
trace_parsed_.Append(value->CreateDeepCopy());
continue;
}
@@ -371,7 +370,7 @@ const DictionaryValue* FindTraceEntry(
match_after_this_item = NULL;
continue;
}
- if (!value || value->GetType() != Value::Type::DICTIONARY)
+ if (!value || value->GetType() != Value::TYPE_DICTIONARY)
continue;
const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
@@ -389,7 +388,7 @@ std::vector<const DictionaryValue*> FindTraceEntries(
for (size_t i = 0; i < trace_parsed_count; i++) {
const Value* value = NULL;
trace_parsed.Get(i, &value);
- if (!value || value->GetType() != Value::Type::DICTIONARY)
+ if (!value || value->GetType() != Value::TYPE_DICTIONARY)
continue;
const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
@@ -461,10 +460,9 @@ void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) {
"b", 1415);
TRACE_COUNTER_WITH_TIMESTAMP1("all", "TRACE_COUNTER_WITH_TIMESTAMP1 call",
- TimeTicks::FromInternalValue(42), 31415);
+ 42, 31415);
TRACE_COUNTER_WITH_TIMESTAMP2("all", "TRACE_COUNTER_WITH_TIMESTAMP2 call",
- TimeTicks::FromInternalValue(42),
- "a", 30000, "b", 1415);
+ 42, "a", 30000, "b", 1415);
TRACE_COUNTER_ID1("all", "TRACE_COUNTER_ID1 call", 0x319009, 31415);
TRACE_COUNTER_ID2("all", "TRACE_COUNTER_ID2 call", 0x319009,
@@ -472,14 +470,14 @@ void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) {
TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("all",
"TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call",
- kAsyncId, kThreadId, TimeTicks::FromInternalValue(12345));
+ kAsyncId, kThreadId, 12345);
TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0("all",
"TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0 call",
- kAsyncId, kThreadId, TimeTicks::FromInternalValue(23456));
+ kAsyncId, kThreadId, 23456);
TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("all",
"TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call",
- kAsyncId2, kThreadId, TimeTicks::FromInternalValue(34567));
+ kAsyncId2, kThreadId, 34567);
TRACE_EVENT_ASYNC_STEP_PAST0("all", "TRACE_EVENT_ASYNC_STEP_PAST0 call",
kAsyncId2, "step_end1");
TRACE_EVENT_ASYNC_STEP_PAST1("all", "TRACE_EVENT_ASYNC_STEP_PAST1 call",
@@ -487,7 +485,7 @@ void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) {
TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0("all",
"TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0 call",
- kAsyncId2, kThreadId, TimeTicks::FromInternalValue(45678));
+ kAsyncId2, kThreadId, 45678);
TRACE_EVENT_OBJECT_CREATED_WITH_ID("all", "tracked object 1", 0x42);
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
@@ -519,24 +517,6 @@ void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) {
context_id);
TRACE_EVENT_SCOPED_CONTEXT("all", "TRACE_EVENT_SCOPED_CONTEXT call",
context_id);
-
- TRACE_LINK_IDS("all", "TRACE_LINK_IDS simple call", 0x1000, 0x2000);
- TRACE_LINK_IDS("all", "TRACE_LINK_IDS scoped call",
- TRACE_ID_WITH_SCOPE("scope 1", 0x1000),
- TRACE_ID_WITH_SCOPE("scope 2", 0x2000));
- TRACE_LINK_IDS("all", "TRACE_LINK_IDS to a local ID", 0x1000,
- TRACE_ID_LOCAL(0x2000));
- TRACE_LINK_IDS("all", "TRACE_LINK_IDS to a global ID", 0x1000,
- TRACE_ID_GLOBAL(0x2000));
- TRACE_LINK_IDS("all", "TRACE_LINK_IDS to a composite ID", 0x1000,
- TRACE_ID_WITH_SCOPE("scope 1", 0x2000, 0x3000));
-
- TRACE_EVENT_ASYNC_BEGIN0("all", "async default process scope", 0x1000);
- TRACE_EVENT_ASYNC_BEGIN0("all", "async local id", TRACE_ID_LOCAL(0x2000));
- TRACE_EVENT_ASYNC_BEGIN0("all", "async global id", TRACE_ID_GLOBAL(0x3000));
- TRACE_EVENT_ASYNC_BEGIN0("all", "async global id with scope string",
- TRACE_ID_WITH_SCOPE("scope string",
- TRACE_ID_GLOBAL(0x4000)));
} // Scope close causes TRACE_EVENT0 etc to send their END events.
if (task_complete_event)
@@ -977,144 +957,6 @@ void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed) {
EXPECT_TRUE((item && item->GetString("id", &id)));
EXPECT_EQ("0x20151021", id);
}
-
- EXPECT_FIND_("TRACE_LINK_IDS simple call");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("=", ph);
-
- EXPECT_FALSE((item && item->HasKey("scope")));
- std::string id1;
- EXPECT_TRUE((item && item->GetString("id", &id1)));
- EXPECT_EQ("0x1000", id1);
-
- EXPECT_FALSE((item && item->HasKey("args.linked_id.scope")));
- std::string id2;
- EXPECT_TRUE((item && item->GetString("args.linked_id.id", &id2)));
- EXPECT_EQ("0x2000", id2);
- }
-
- EXPECT_FIND_("TRACE_LINK_IDS scoped call");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("=", ph);
-
- std::string scope1;
- EXPECT_TRUE((item && item->GetString("scope", &scope1)));
- EXPECT_EQ("scope 1", scope1);
- std::string id1;
- EXPECT_TRUE((item && item->GetString("id", &id1)));
- EXPECT_EQ("0x1000", id1);
-
- std::string scope2;
- EXPECT_TRUE((item && item->GetString("args.linked_id.scope", &scope2)));
- EXPECT_EQ("scope 2", scope2);
- std::string id2;
- EXPECT_TRUE((item && item->GetString("args.linked_id.id", &id2)));
- EXPECT_EQ("0x2000", id2);
- }
-
- EXPECT_FIND_("TRACE_LINK_IDS to a local ID");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("=", ph);
-
- EXPECT_FALSE((item && item->HasKey("scope")));
- std::string id1;
- EXPECT_TRUE((item && item->GetString("id", &id1)));
- EXPECT_EQ("0x1000", id1);
-
- EXPECT_FALSE((item && item->HasKey("args.linked_id.scope")));
- std::string id2;
- EXPECT_TRUE((item && item->GetString("args.linked_id.id2.local", &id2)));
- EXPECT_EQ("0x2000", id2);
- }
-
- EXPECT_FIND_("TRACE_LINK_IDS to a global ID");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("=", ph);
-
- EXPECT_FALSE((item && item->HasKey("scope")));
- std::string id1;
- EXPECT_TRUE((item && item->GetString("id", &id1)));
- EXPECT_EQ("0x1000", id1);
-
- EXPECT_FALSE((item && item->HasKey("args.linked_id.scope")));
- std::string id2;
- EXPECT_TRUE((item && item->GetString("args.linked_id.id2.global", &id2)));
- EXPECT_EQ("0x2000", id2);
- }
-
- EXPECT_FIND_("TRACE_LINK_IDS to a composite ID");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("=", ph);
-
- EXPECT_FALSE(item->HasKey("scope"));
- std::string id1;
- EXPECT_TRUE(item->GetString("id", &id1));
- EXPECT_EQ("0x1000", id1);
-
- std::string scope;
- EXPECT_TRUE(item->GetString("args.linked_id.scope", &scope));
- EXPECT_EQ("scope 1", scope);
- std::string id2;
- EXPECT_TRUE(item->GetString("args.linked_id.id", &id2));
- EXPECT_EQ(id2, "0x2000/0x3000");
- }
-
- EXPECT_FIND_("async default process scope");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("S", ph);
-
- std::string id;
- EXPECT_TRUE((item && item->GetString("id", &id)));
- EXPECT_EQ("0x1000", id);
- }
-
- EXPECT_FIND_("async local id");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("S", ph);
-
- std::string id;
- EXPECT_TRUE((item && item->GetString("id2.local", &id)));
- EXPECT_EQ("0x2000", id);
- }
-
- EXPECT_FIND_("async global id");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("S", ph);
-
- std::string id;
- EXPECT_TRUE((item && item->GetString("id2.global", &id)));
- EXPECT_EQ("0x3000", id);
- }
-
- EXPECT_FIND_("async global id with scope string");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("S", ph);
-
- std::string id;
- EXPECT_TRUE((item && item->GetString("id2.global", &id)));
- EXPECT_EQ("0x4000", id);
- std::string scope;
- EXPECT_TRUE((item && item->GetString("scope", &scope)));
- EXPECT_EQ("scope string", scope);
- }
}
void TraceManyInstantEvents(int thread_id, int num_events,
@@ -1139,7 +981,7 @@ void ValidateInstantEventPresentOnEveryThread(const ListValue& trace_parsed,
for (size_t i = 0; i < trace_parsed_count; i++) {
const Value* value = NULL;
trace_parsed.Get(i, &value);
- if (!value || value->GetType() != Value::Type::DICTIONARY)
+ if (!value || value->GetType() != Value::TYPE_DICTIONARY)
continue;
const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
std::string name;
@@ -1588,6 +1430,59 @@ TEST_F(TraceEventTestFixture, Categories) {
}
+// Test EVENT_WATCH_NOTIFICATION
+TEST_F(TraceEventTestFixture, EventWatchNotification) {
+ // Basic one occurrence.
+ BeginTrace();
+ TraceLog::WatchEventCallback callback =
+ base::Bind(&TraceEventTestFixture::OnWatchEventMatched,
+ base::Unretained(this));
+ TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+ TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
+ EndTraceAndFlush();
+ EXPECT_EQ(event_watch_notification_, 1);
+
+ // Auto-reset after end trace.
+ BeginTrace();
+ TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+ EndTraceAndFlush();
+ BeginTrace();
+ TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
+ EndTraceAndFlush();
+ EXPECT_EQ(event_watch_notification_, 0);
+
+ // Multiple occurrence.
+ BeginTrace();
+ int num_occurrences = 5;
+ TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+ for (int i = 0; i < num_occurrences; ++i)
+ TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
+ EndTraceAndFlush();
+ EXPECT_EQ(event_watch_notification_, num_occurrences);
+
+ // Wrong category.
+ BeginTrace();
+ TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+ TRACE_EVENT_INSTANT0("wrong_cat", "event", TRACE_EVENT_SCOPE_THREAD);
+ EndTraceAndFlush();
+ EXPECT_EQ(event_watch_notification_, 0);
+
+ // Wrong name.
+ BeginTrace();
+ TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+ TRACE_EVENT_INSTANT0("cat", "wrong_event", TRACE_EVENT_SCOPE_THREAD);
+ EndTraceAndFlush();
+ EXPECT_EQ(event_watch_notification_, 0);
+
+ // Canceled.
+ BeginTrace();
+ TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+ TraceLog::GetInstance()->CancelWatchEvent();
+ TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
+ EndTraceAndFlush();
+ EXPECT_EQ(event_watch_notification_, 0);
+}
+
// Test ASYNC_BEGIN/END events
TEST_F(TraceEventTestFixture, AsyncBeginEndEvents) {
BeginTrace();
@@ -2158,6 +2053,55 @@ TEST_F(TraceEventTestFixture, TraceWithDisabledByDefaultCategoryFilters) {
trace_log->SetDisabled();
}
+TEST_F(TraceEventTestFixture, TraceSampling) {
+ TraceLog::GetInstance()->SetEnabled(
+ TraceConfig(kRecordAllCategoryFilter, "record-until-full,enable-sampling"),
+ TraceLog::RECORDING_MODE);
+
+ TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "cc", "Stuff");
+ TraceLog::GetInstance()->WaitSamplingEventForTesting();
+ TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "cc", "Things");
+ TraceLog::GetInstance()->WaitSamplingEventForTesting();
+
+ EndTraceAndFlush();
+
+ // Make sure we hit at least once.
+ EXPECT_TRUE(FindNamePhase("Stuff", "P"));
+ EXPECT_TRUE(FindNamePhase("Things", "P"));
+}
+
+TEST_F(TraceEventTestFixture, TraceSamplingScope) {
+ TraceLog::GetInstance()->SetEnabled(
+ TraceConfig(kRecordAllCategoryFilter, "record-until-full,enable-sampling"),
+ TraceLog::RECORDING_MODE);
+
+ TRACE_EVENT_SCOPED_SAMPLING_STATE("AAA", "name");
+ TraceLog::GetInstance()->WaitSamplingEventForTesting();
+ {
+ EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "AAA");
+ TRACE_EVENT_SCOPED_SAMPLING_STATE("BBB", "name");
+ TraceLog::GetInstance()->WaitSamplingEventForTesting();
+ EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "BBB");
+ }
+ TraceLog::GetInstance()->WaitSamplingEventForTesting();
+ {
+ EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "AAA");
+ TRACE_EVENT_SCOPED_SAMPLING_STATE("CCC", "name");
+ TraceLog::GetInstance()->WaitSamplingEventForTesting();
+ EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "CCC");
+ }
+ TraceLog::GetInstance()->WaitSamplingEventForTesting();
+ {
+ EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "AAA");
+ TRACE_EVENT_SET_SAMPLING_STATE("DDD", "name");
+ TraceLog::GetInstance()->WaitSamplingEventForTesting();
+ EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "DDD");
+ }
+ TraceLog::GetInstance()->WaitSamplingEventForTesting();
+ EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "DDD");
+
+ EndTraceAndFlush();
+}
class MyData : public ConvertableToTraceFormat {
public:
@@ -2346,7 +2290,7 @@ TEST_F(TraceEventTestFixture, PrimitiveArgs) {
dict->GetDictionary("args", &args_dict);
ASSERT_TRUE(args_dict);
EXPECT_TRUE(args_dict->Get("float_one", &value));
- EXPECT_TRUE(value->IsType(Value::Type::DOUBLE));
+ EXPECT_TRUE(value->IsType(Value::TYPE_DOUBLE));
EXPECT_TRUE(value->GetAsDouble(&double_value));
EXPECT_EQ(1, double_value);
@@ -2356,7 +2300,7 @@ TEST_F(TraceEventTestFixture, PrimitiveArgs) {
dict->GetDictionary("args", &args_dict);
ASSERT_TRUE(args_dict);
EXPECT_TRUE(args_dict->Get("float_half", &value));
- EXPECT_TRUE(value->IsType(Value::Type::DOUBLE));
+ EXPECT_TRUE(value->IsType(Value::TYPE_DOUBLE));
EXPECT_TRUE(value->GetAsDouble(&double_value));
EXPECT_EQ(0.5, double_value);
@@ -2366,7 +2310,7 @@ TEST_F(TraceEventTestFixture, PrimitiveArgs) {
dict->GetDictionary("args", &args_dict);
ASSERT_TRUE(args_dict);
EXPECT_TRUE(args_dict->Get("float_neghalf", &value));
- EXPECT_TRUE(value->IsType(Value::Type::DOUBLE));
+ EXPECT_TRUE(value->IsType(Value::TYPE_DOUBLE));
EXPECT_TRUE(value->GetAsDouble(&double_value));
EXPECT_EQ(-0.5, double_value);
@@ -2536,6 +2480,233 @@ TEST_F(TraceEventTestFixture, ArgsWhitelisting) {
EXPECT_EQ(args_string, "__stripped__");
}
+class TraceEventCallbackTest : public TraceEventTestFixture {
+ public:
+ void SetUp() override {
+ TraceEventTestFixture::SetUp();
+ ASSERT_EQ(NULL, s_instance);
+ s_instance = this;
+ }
+ void TearDown() override {
+ TraceLog::GetInstance()->SetDisabled();
+ ASSERT_TRUE(s_instance);
+ s_instance = NULL;
+ TraceEventTestFixture::TearDown();
+ }
+
+ protected:
+ // For TraceEventCallbackAndRecordingX tests.
+ void VerifyCallbackAndRecordedEvents(size_t expected_callback_count,
+ size_t expected_recorded_count) {
+ // Callback events.
+ EXPECT_EQ(expected_callback_count, collected_events_names_.size());
+ for (size_t i = 0; i < collected_events_names_.size(); ++i) {
+ EXPECT_EQ("callback", collected_events_categories_[i]);
+ EXPECT_EQ("yes", collected_events_names_[i]);
+ }
+
+ // Recorded events.
+ EXPECT_EQ(expected_recorded_count, trace_parsed_.GetSize());
+ EXPECT_TRUE(FindTraceEntry(trace_parsed_, "recording"));
+ EXPECT_FALSE(FindTraceEntry(trace_parsed_, "callback"));
+ EXPECT_TRUE(FindTraceEntry(trace_parsed_, "yes"));
+ EXPECT_FALSE(FindTraceEntry(trace_parsed_, "no"));
+ }
+
+ void VerifyCollectedEvent(size_t i,
+ unsigned phase,
+ const std::string& category,
+ const std::string& name) {
+ EXPECT_EQ(phase, collected_events_phases_[i]);
+ EXPECT_EQ(category, collected_events_categories_[i]);
+ EXPECT_EQ(name, collected_events_names_[i]);
+ }
+
+ std::vector<std::string> collected_events_categories_;
+ std::vector<std::string> collected_events_names_;
+ std::vector<unsigned char> collected_events_phases_;
+ std::vector<TimeTicks> collected_events_timestamps_;
+
+ static TraceEventCallbackTest* s_instance;
+ static void Callback(TimeTicks timestamp,
+ char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ const char* scope,
+ unsigned long long id,
+ int num_args,
+ const char* const arg_names[],
+ const unsigned char arg_types[],
+ const unsigned long long arg_values[],
+ unsigned int flags) {
+ s_instance->collected_events_phases_.push_back(phase);
+ s_instance->collected_events_categories_.push_back(
+ TraceLog::GetCategoryGroupName(category_group_enabled));
+ s_instance->collected_events_names_.push_back(name);
+ s_instance->collected_events_timestamps_.push_back(timestamp);
+ }
+};
+
+TraceEventCallbackTest* TraceEventCallbackTest::s_instance;
+
+TEST_F(TraceEventCallbackTest, TraceEventCallback) {
+ TRACE_EVENT_INSTANT0("all", "before enable", TRACE_EVENT_SCOPE_THREAD);
+ TraceLog::GetInstance()->SetEventCallbackEnabled(
+ TraceConfig(kRecordAllCategoryFilter, ""), Callback);
+ TRACE_EVENT_INSTANT0("all", "event1", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("all", "event2", TRACE_EVENT_SCOPE_GLOBAL);
+ {
+ TRACE_EVENT0("all", "duration");
+ TRACE_EVENT_INSTANT0("all", "event3", TRACE_EVENT_SCOPE_GLOBAL);
+ }
+ TraceLog::GetInstance()->SetEventCallbackDisabled();
+ TRACE_EVENT_INSTANT0("all", "after callback removed",
+ TRACE_EVENT_SCOPE_GLOBAL);
+ ASSERT_EQ(5u, collected_events_names_.size());
+ EXPECT_EQ("event1", collected_events_names_[0]);
+ EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_events_phases_[0]);
+ EXPECT_EQ("event2", collected_events_names_[1]);
+ EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_events_phases_[1]);
+ EXPECT_EQ("duration", collected_events_names_[2]);
+ EXPECT_EQ(TRACE_EVENT_PHASE_BEGIN, collected_events_phases_[2]);
+ EXPECT_EQ("event3", collected_events_names_[3]);
+ EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_events_phases_[3]);
+ EXPECT_EQ("duration", collected_events_names_[4]);
+ EXPECT_EQ(TRACE_EVENT_PHASE_END, collected_events_phases_[4]);
+ for (size_t i = 1; i < collected_events_timestamps_.size(); i++) {
+ EXPECT_LE(collected_events_timestamps_[i - 1],
+ collected_events_timestamps_[i]);
+ }
+}
+
+TEST_F(TraceEventCallbackTest, TraceEventCallbackWhileFull) {
+ TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+ TraceLog::RECORDING_MODE);
+ do {
+ TRACE_EVENT_INSTANT0("all", "badger badger", TRACE_EVENT_SCOPE_GLOBAL);
+ } while (!TraceLog::GetInstance()->BufferIsFull());
+ TraceLog::GetInstance()->SetEventCallbackEnabled(
+ TraceConfig(kRecordAllCategoryFilter, ""), Callback);
+ TRACE_EVENT_INSTANT0("all", "a snake", TRACE_EVENT_SCOPE_GLOBAL);
+ TraceLog::GetInstance()->SetEventCallbackDisabled();
+ ASSERT_EQ(1u, collected_events_names_.size());
+ EXPECT_EQ("a snake", collected_events_names_[0]);
+}
+
+// 1: Enable callback, enable recording, disable callback, disable recording.
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording1) {
+ TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TraceLog::GetInstance()->SetEventCallbackEnabled(TraceConfig("callback", ""),
+ Callback);
+ TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TraceLog::GetInstance()->SetEnabled(TraceConfig("recording", ""),
+ TraceLog::RECORDING_MODE);
+ TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TraceLog::GetInstance()->SetEventCallbackDisabled();
+ TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ EndTraceAndFlush();
+ TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+
+ DropTracedMetadataRecords();
+ VerifyCallbackAndRecordedEvents(2, 2);
+}
+
+// 2: Enable callback, enable recording, disable recording, disable callback.
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording2) {
+ TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TraceLog::GetInstance()->SetEventCallbackEnabled(TraceConfig("callback", ""),
+ Callback);
+ TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TraceLog::GetInstance()->SetEnabled(TraceConfig("recording", ""),
+ TraceLog::RECORDING_MODE);
+ TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ EndTraceAndFlush();
+ TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TraceLog::GetInstance()->SetEventCallbackDisabled();
+ TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+
+ DropTracedMetadataRecords();
+ VerifyCallbackAndRecordedEvents(3, 1);
+}
+
+// 3: Enable recording, enable callback, disable callback, disable recording.
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording3) {
+ TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TraceLog::GetInstance()->SetEnabled(TraceConfig("recording", ""),
+ TraceLog::RECORDING_MODE);
+ TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TraceLog::GetInstance()->SetEventCallbackEnabled(TraceConfig("callback", ""),
+ Callback);
+ TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TraceLog::GetInstance()->SetEventCallbackDisabled();
+ TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ EndTraceAndFlush();
+ TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+
+ DropTracedMetadataRecords();
+ VerifyCallbackAndRecordedEvents(1, 3);
+}
+
+// 4: Enable recording, enable callback, disable recording, disable callback.
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording4) {
+ TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TraceLog::GetInstance()->SetEnabled(TraceConfig("recording", ""),
+ TraceLog::RECORDING_MODE);
+ TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TraceLog::GetInstance()->SetEventCallbackEnabled(TraceConfig("callback", ""),
+ Callback);
+ TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ EndTraceAndFlush();
+ TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+ TraceLog::GetInstance()->SetEventCallbackDisabled();
+ TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+ TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+
+ DropTracedMetadataRecords();
+ VerifyCallbackAndRecordedEvents(2, 2);
+}
+
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecordingDuration) {
+ TraceLog::GetInstance()->SetEventCallbackEnabled(
+ TraceConfig(kRecordAllCategoryFilter, ""), Callback);
+ {
+ TRACE_EVENT0("callback", "duration1");
+ TraceLog::GetInstance()->SetEnabled(
+ TraceConfig(kRecordAllCategoryFilter, ""), TraceLog::RECORDING_MODE);
+ TRACE_EVENT0("callback", "duration2");
+ EndTraceAndFlush();
+ TRACE_EVENT0("callback", "duration3");
+ }
+ TraceLog::GetInstance()->SetEventCallbackDisabled();
+
+ ASSERT_EQ(6u, collected_events_names_.size());
+ VerifyCollectedEvent(0, TRACE_EVENT_PHASE_BEGIN, "callback", "duration1");
+ VerifyCollectedEvent(1, TRACE_EVENT_PHASE_BEGIN, "callback", "duration2");
+ VerifyCollectedEvent(2, TRACE_EVENT_PHASE_BEGIN, "callback", "duration3");
+ VerifyCollectedEvent(3, TRACE_EVENT_PHASE_END, "callback", "duration3");
+ VerifyCollectedEvent(4, TRACE_EVENT_PHASE_END, "callback", "duration2");
+ VerifyCollectedEvent(5, TRACE_EVENT_PHASE_END, "callback", "duration1");
+}
+
TEST_F(TraceEventTestFixture, TraceBufferVectorReportFull) {
TraceLog* trace_log = TraceLog::GetInstance();
trace_log->SetEnabled(
@@ -2544,9 +2715,9 @@ TEST_F(TraceEventTestFixture, TraceBufferVectorReportFull) {
TraceBuffer::CreateTraceBufferVectorOfSize(100));
do {
TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TimeTicks::Now());
+ "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TimeTicks::Now());
+ "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
} while (!trace_log->BufferIsFull());
EndTraceAndFlush();
@@ -2757,9 +2928,29 @@ TEST_F(TraceEventTestFixture, ConvertTraceConfigToInternalOptions) {
trace_log->GetInternalOptionsFromTraceConfig(
TraceConfig(kRecordAllCategoryFilter, ECHO_TO_CONSOLE)));
- EXPECT_EQ(TraceLog::kInternalEchoToConsole,
- trace_log->GetInternalOptionsFromTraceConfig(
- TraceConfig("*", "trace-to-console,enable-systrace")));
+ EXPECT_EQ(
+ TraceLog::kInternalRecordUntilFull | TraceLog::kInternalEnableSampling,
+ trace_log->GetInternalOptionsFromTraceConfig(
+ TraceConfig(kRecordAllCategoryFilter,
+ "record-until-full,enable-sampling")));
+
+ EXPECT_EQ(
+ TraceLog::kInternalRecordContinuously | TraceLog::kInternalEnableSampling,
+ trace_log->GetInternalOptionsFromTraceConfig(
+ TraceConfig(kRecordAllCategoryFilter,
+ "record-continuously,enable-sampling")));
+
+ EXPECT_EQ(
+ TraceLog::kInternalEchoToConsole | TraceLog::kInternalEnableSampling,
+ trace_log->GetInternalOptionsFromTraceConfig(
+ TraceConfig(kRecordAllCategoryFilter,
+ "trace-to-console,enable-sampling")));
+
+ EXPECT_EQ(
+ TraceLog::kInternalEchoToConsole | TraceLog::kInternalEnableSampling,
+ trace_log->GetInternalOptionsFromTraceConfig(
+ TraceConfig("*",
+ "trace-to-console,enable-sampling,enable-systrace")));
}
void SetBlockingFlagAndBlockUntilStopped(WaitableEvent* task_start_event,
@@ -2918,9 +3109,9 @@ TEST_F(TraceEventTestFixture, TimeOffset) {
TRACE_EVENT0("all", "duration2");
}
TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TimeTicks::Now());
+ "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TimeTicks::Now());
+ "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
EndTraceAndFlush();
DropTracedMetadataRecords();
@@ -2982,213 +3173,6 @@ TEST_F(TraceEventTestFixture, SyntheticDelayConfigurationToString) {
EXPECT_EQ(filter, config.ToCategoryFilterString());
}
-TEST_F(TraceEventTestFixture, TraceFilteringMode) {
- const char config_json[] =
- "{"
- " \"event_filters\": ["
- " {"
- " \"filter_predicate\": \"testing_predicate\", "
- " \"included_categories\": [\"*\"]"
- " }"
- " ]"
- "}";
-
- // Run RECORDING_MODE within FILTERING_MODE:
- TestEventFilter::HitsCounter filter_hits_counter;
- TestEventFilter::set_filter_return_value(true);
- TraceLog::GetInstance()->SetFilterFactoryForTesting(TestEventFilter::Factory);
-
- // Only filtering mode is enabled with test filters.
- TraceLog::GetInstance()->SetEnabled(TraceConfig(config_json),
- TraceLog::FILTERING_MODE);
- EXPECT_EQ(TraceLog::FILTERING_MODE, TraceLog::GetInstance()->enabled_modes());
- {
- void* ptr = this;
- TRACE_EVENT0("c0", "name0");
- TRACE_EVENT_ASYNC_BEGIN0("c1", "name1", ptr);
- TRACE_EVENT_INSTANT0("c0", "name0", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_ASYNC_END0("c1", "name1", ptr);
- }
-
- // Recording mode is enabled when filtering mode is turned on.
- TraceLog::GetInstance()->SetEnabled(TraceConfig("", ""),
- TraceLog::RECORDING_MODE);
- EXPECT_EQ(TraceLog::RECORDING_MODE | TraceLog::FILTERING_MODE,
- TraceLog::GetInstance()->enabled_modes());
- {
- TRACE_EVENT0("c2", "name2");
- }
- // Only recording mode is disabled and filtering mode will continue to run.
- TraceLog::GetInstance()->SetDisabled(TraceLog::RECORDING_MODE);
- EXPECT_EQ(TraceLog::FILTERING_MODE, TraceLog::GetInstance()->enabled_modes());
-
- {
- TRACE_EVENT0("c0", "name0");
- }
- // Filtering mode is disabled and no tracing mode should be enabled.
- TraceLog::GetInstance()->SetDisabled(TraceLog::FILTERING_MODE);
- EXPECT_EQ(0, TraceLog::GetInstance()->enabled_modes());
-
- EndTraceAndFlush();
- EXPECT_FALSE(FindMatchingValue("cat", "c0"));
- EXPECT_FALSE(FindMatchingValue("cat", "c1"));
- EXPECT_FALSE(FindMatchingValue("name", "name0"));
- EXPECT_FALSE(FindMatchingValue("name", "name1"));
- EXPECT_TRUE(FindMatchingValue("cat", "c2"));
- EXPECT_TRUE(FindMatchingValue("name", "name2"));
- EXPECT_EQ(6u, filter_hits_counter.filter_trace_event_hit_count);
- EXPECT_EQ(3u, filter_hits_counter.end_event_hit_count);
- Clear();
- filter_hits_counter.Reset();
-
- // Run FILTERING_MODE within RECORDING_MODE:
- // Only recording mode is enabled and all events must be recorded.
- TraceLog::GetInstance()->SetEnabled(TraceConfig("", ""),
- TraceLog::RECORDING_MODE);
- EXPECT_EQ(TraceLog::RECORDING_MODE, TraceLog::GetInstance()->enabled_modes());
- {
- TRACE_EVENT0("c0", "name0");
- }
-
- // Filtering mode is also enabled and all events must be filtered-out.
- TestEventFilter::set_filter_return_value(false);
- TraceLog::GetInstance()->SetEnabled(TraceConfig(config_json),
- TraceLog::FILTERING_MODE);
- EXPECT_EQ(TraceLog::RECORDING_MODE | TraceLog::FILTERING_MODE,
- TraceLog::GetInstance()->enabled_modes());
- {
- TRACE_EVENT0("c1", "name1");
- }
- // Only filtering mode is disabled and recording mode should continue to run
- // with all events being recorded.
- TraceLog::GetInstance()->SetDisabled(TraceLog::FILTERING_MODE);
- EXPECT_EQ(TraceLog::RECORDING_MODE, TraceLog::GetInstance()->enabled_modes());
-
- {
- TRACE_EVENT0("c2", "name2");
- }
- // Recording mode is disabled and no tracing mode should be enabled.
- TraceLog::GetInstance()->SetDisabled(TraceLog::RECORDING_MODE);
- EXPECT_EQ(0, TraceLog::GetInstance()->enabled_modes());
-
- EndTraceAndFlush();
- EXPECT_TRUE(FindMatchingValue("cat", "c0"));
- EXPECT_TRUE(FindMatchingValue("cat", "c2"));
- EXPECT_TRUE(FindMatchingValue("name", "name0"));
- EXPECT_TRUE(FindMatchingValue("name", "name2"));
- EXPECT_FALSE(FindMatchingValue("cat", "c1"));
- EXPECT_FALSE(FindMatchingValue("name", "name1"));
- EXPECT_EQ(1u, filter_hits_counter.filter_trace_event_hit_count);
- EXPECT_EQ(1u, filter_hits_counter.end_event_hit_count);
- Clear();
-}
-
-TEST_F(TraceEventTestFixture, EventFiltering) {
- const char config_json[] =
- "{"
- " \"included_categories\": ["
- " \"filtered_cat\","
- " \"unfiltered_cat\"],"
- " \"event_filters\": ["
- " {"
- " \"filter_predicate\": \"testing_predicate\", "
- " \"included_categories\": [\"filtered_cat\"]"
- " }"
- " "
- " ]"
- "}";
-
- TestEventFilter::HitsCounter filter_hits_counter;
- TestEventFilter::set_filter_return_value(true);
- TraceLog::GetInstance()->SetFilterFactoryForTesting(TestEventFilter::Factory);
-
- TraceConfig trace_config(config_json);
- TraceLog::GetInstance()->SetEnabled(
- trace_config, TraceLog::RECORDING_MODE | TraceLog::FILTERING_MODE);
- ASSERT_TRUE(TraceLog::GetInstance()->IsEnabled());
-
- TRACE_EVENT0("filtered_cat", "a snake");
- TRACE_EVENT0("filtered_cat", "a mushroom");
- TRACE_EVENT0("unfiltered_cat", "a horse");
-
- // This is scoped so we can test the end event being filtered.
- { TRACE_EVENT0("filtered_cat", "another cat whoa"); }
-
- EndTraceAndFlush();
-
- EXPECT_EQ(3u, filter_hits_counter.filter_trace_event_hit_count);
- EXPECT_EQ(1u, filter_hits_counter.end_event_hit_count);
-}
-
-TEST_F(TraceEventTestFixture, EventWhitelistFiltering) {
- std::string config_json = StringPrintf(
- "{"
- " \"included_categories\": ["
- " \"filtered_cat\","
- " \"unfiltered_cat\"],"
- " \"event_filters\": ["
- " {"
- " \"filter_predicate\": \"%s\", "
- " \"included_categories\": [\"*\"], "
- " \"excluded_categories\": [\"unfiltered_cat\"], "
- " \"filter_args\": {"
- " \"event_name_whitelist\": [\"a snake\", \"a dog\"]"
- " }"
- " }"
- " "
- " ]"
- "}",
- EventNameFilter::kName);
-
- TraceConfig trace_config(config_json);
- TraceLog::GetInstance()->SetEnabled(
- trace_config, TraceLog::RECORDING_MODE | TraceLog::FILTERING_MODE);
- EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
-
- TRACE_EVENT0("filtered_cat", "a snake");
- TRACE_EVENT0("filtered_cat", "a mushroom");
- TRACE_EVENT0("unfiltered_cat", "a cat");
-
- EndTraceAndFlush();
-
- EXPECT_TRUE(FindMatchingValue("name", "a snake"));
- EXPECT_FALSE(FindMatchingValue("name", "a mushroom"));
- EXPECT_TRUE(FindMatchingValue("name", "a cat"));
-}
-
-TEST_F(TraceEventTestFixture, HeapProfilerFiltering) {
- std::string config_json = StringPrintf(
- "{"
- " \"included_categories\": ["
- " \"filtered_cat\","
- " \"unfiltered_cat\"],"
- " \"excluded_categories\": [\"excluded_cat\"],"
- " \"event_filters\": ["
- " {"
- " \"filter_predicate\": \"%s\", "
- " \"included_categories\": [\"*\"]"
- " }"
- " ]"
- "}",
- HeapProfilerEventFilter::kName);
-
- TraceConfig trace_config(config_json);
- TraceLog::GetInstance()->SetEnabled(
- trace_config, TraceLog::RECORDING_MODE | TraceLog::FILTERING_MODE);
- EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
-
- TRACE_EVENT0("filtered_cat", "a snake");
- TRACE_EVENT0("excluded_cat", "a mushroom");
- TRACE_EVENT0("unfiltered_cat", "a cat");
-
- EndTraceAndFlush();
-
- // The predicate should not change behavior of the trace events.
- EXPECT_TRUE(FindMatchingValue("name", "a snake"));
- EXPECT_FALSE(FindMatchingValue("name", "a mushroom"));
- EXPECT_TRUE(FindMatchingValue("name", "a cat"));
-}
-
TEST_F(TraceEventTestFixture, ClockSyncEventsAreAlwaysAddedToTrace) {
BeginSpecificTrace("-*");
TRACE_EVENT_CLOCK_SYNC_RECEIVER(1);
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc
index 10b090ae57..12cebc6f65 100644
--- a/base/trace_event/trace_log.cc
+++ b/base/trace_event/trace_log.cc
@@ -13,43 +13,41 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/leak_annotations.h"
+#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/message_loop/message_loop.h"
#include "base/process/process_metrics.h"
#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/stringprintf.h"
#include "base/sys_info.h"
-// post_task.h pulls in a lot of code not needed on Arc++.
-#if 0
-#include "base/task_scheduler/post_task.h"
-#endif
+#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/event_name_filter.h"
#include "base/trace_event/heap_profiler.h"
#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
-#include "base/trace_event/heap_profiler_event_filter.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_buffer.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_synthetic_delay.h"
+#include "base/trace_event/trace_sampling_thread.h"
#include "build/build_config.h"
#if defined(OS_WIN)
#include "base/trace_event/trace_event_etw_export_win.h"
#endif
+// The thread buckets for the sampling profiler.
+BASE_EXPORT TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3];
+
namespace base {
namespace internal {
@@ -88,13 +86,35 @@ const size_t kEchoToConsoleTraceEventBufferChunks = 256;
const size_t kTraceEventBufferSizeInBytes = 100 * 1024;
const int kThreadFlushTimeoutMs = 3000;
-#define MAX_TRACE_EVENT_FILTERS 32
-
-// List of TraceEventFilter objects from the most recent tracing session.
-std::vector<std::unique_ptr<TraceEventFilter>>& GetCategoryGroupFilters() {
- static auto* filters = new std::vector<std::unique_ptr<TraceEventFilter>>();
- return *filters;
-}
+#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};
+// Indexes here have to match the g_category_groups array indexes above.
+const int g_category_already_shutdown = 1;
+const int g_category_categories_exhausted = 2;
+const int g_category_metadata = 3;
+const int g_num_builtin_categories = 4;
+// Skip default categories.
+base::subtle::AtomicWord g_category_index = g_num_builtin_categories;
+
+// 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.
+LazyInstance<ThreadLocalPointer<const char>>::Leaky g_current_thread_name =
+ LAZY_INSTANCE_INITIALIZER;
ThreadTicks ThreadNow() {
return ThreadTicks::IsSupported() ? ThreadTicks::Now() : ThreadTicks();
@@ -118,7 +138,7 @@ void InitializeMetadataEvent(TraceEvent* trace_event,
TimeTicks(),
ThreadTicks(),
TRACE_EVENT_PHASE_METADATA,
- CategoryRegistry::kCategoryMetadata->state_ptr(),
+ &g_category_group_enabled[g_category_metadata],
metadata_name,
trace_event_internal::kGlobalScope, // scope
trace_event_internal::kNoId, // id
@@ -154,24 +174,11 @@ void MakeHandle(uint32_t chunk_seq,
DCHECK(chunk_seq);
DCHECK(chunk_index <= TraceBufferChunk::kMaxChunkIndex);
DCHECK(event_index < TraceBufferChunk::kTraceBufferChunkSize);
- DCHECK(chunk_index <= std::numeric_limits<uint16_t>::max());
handle->chunk_seq = chunk_seq;
handle->chunk_index = static_cast<uint16_t>(chunk_index);
handle->event_index = static_cast<uint16_t>(event_index);
}
-template <typename Function>
-void ForEachCategoryFilter(const unsigned char* category_group_enabled,
- Function filter_fn) {
- const TraceCategory* category =
- CategoryRegistry::GetCategoryByStatePtr(category_group_enabled);
- uint32_t filter_bitmap = category->enabled_filters();
- for (int index = 0; filter_bitmap != 0; filter_bitmap >>= 1, index++) {
- if (filter_bitmap & 1 && GetCategoryGroupFilters()[index])
- filter_fn(GetCategoryGroupFilters()[index].get());
- }
-}
-
} // namespace
// A helper class that allows the lock to be acquired in the middle of the scope
@@ -345,20 +352,33 @@ TraceLog* TraceLog::GetInstance() {
}
TraceLog::TraceLog()
- : enabled_modes_(0),
+ : mode_(DISABLED),
num_traces_recorded_(0),
+ event_callback_(0),
dispatching_to_observer_list_(false),
process_sort_index_(0),
process_id_hash_(0),
process_id_(0),
+ watch_category_(0),
trace_options_(kInternalRecordUntilFull),
+ sampling_thread_handle_(0),
trace_config_(TraceConfig()),
+ event_callback_trace_config_(TraceConfig()),
thread_shared_chunk_index_(0),
generation_(0),
- use_worker_thread_(false),
- filter_factory_for_testing_(nullptr) {
- CategoryRegistry::Initialize();
-
+ 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");
+ }
#if defined(OS_NACL) // NaCl shouldn't expose the process id.
SetProcessID(0);
#else
@@ -394,9 +414,7 @@ void TraceLog::InitializeThreadLocalEventBufferIfSupported() {
}
}
-bool TraceLog::OnMemoryDump(const MemoryDumpArgs& args,
- ProcessMemoryDump* pmd) {
- ALLOW_UNUSED_PARAM(args);
+bool TraceLog::OnMemoryDump(const MemoryDumpArgs&, ProcessMemoryDump* pmd) {
// TODO(ssid): Use MemoryDumpArgs to create light dumps when requested
// (crbug.com/499731).
TraceEventMemoryOverhead overhead;
@@ -418,111 +436,61 @@ const unsigned char* TraceLog::GetCategoryGroupEnabled(
const char* category_group) {
TraceLog* tracelog = GetInstance();
if (!tracelog) {
- DCHECK(!CategoryRegistry::kCategoryAlreadyShutdown->is_enabled());
- return CategoryRegistry::kCategoryAlreadyShutdown->state_ptr();
- }
- TraceCategory* category = CategoryRegistry::GetCategoryByName(category_group);
- if (!category) {
- // Slow path: in the case of a new category we have to repeat the check
- // holding the lock, as multiple threads might have reached this point
- // at the same time.
- auto category_initializer = [](TraceCategory* category) {
- TraceLog::GetInstance()->UpdateCategoryState(category);
- };
- AutoLock lock(tracelog->lock_);
- CategoryRegistry::GetOrCreateCategoryLocked(
- category_group, category_initializer, &category);
+ DCHECK(!g_category_group_enabled[g_category_already_shutdown]);
+ return &g_category_group_enabled[g_category_already_shutdown];
}
- DCHECK(category->state_ptr());
- return category->state_ptr();
+ return tracelog->GetCategoryGroupEnabledInternal(category_group);
}
const char* TraceLog::GetCategoryGroupName(
const unsigned char* category_group_enabled) {
- return CategoryRegistry::GetCategoryByStatePtr(category_group_enabled)
- ->name();
+ // 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 &&
+ 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];
}
-void TraceLog::UpdateCategoryState(TraceCategory* category) {
- lock_.AssertAcquired();
- DCHECK(category->is_valid());
- unsigned char state_flags = 0;
- if (enabled_modes_ & RECORDING_MODE &&
- trace_config_.IsCategoryGroupEnabled(category->name())) {
- state_flags |= TraceCategory::ENABLED_FOR_RECORDING;
+void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) {
+ unsigned char enabled_flag = 0;
+ const char* category_group = g_category_groups[category_index];
+ if (mode_ == RECORDING_MODE &&
+ trace_config_.IsCategoryGroupEnabled(category_group)) {
+ enabled_flag |= 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 (event_callback_ &&
+ event_callback_trace_config_.IsCategoryGroupEnabled(category_group)) {
+ enabled_flag |= ENABLED_FOR_EVENT_CALLBACK;
}
#if defined(OS_WIN)
if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled(
- category->name())) {
- state_flags |= TraceCategory::ENABLED_FOR_ETW_EXPORT;
+ category_group)) {
+ enabled_flag |= ENABLED_FOR_ETW_EXPORT;
}
#endif
- uint32_t enabled_filters_bitmap = 0;
- int index = 0;
- for (const auto& event_filter : enabled_event_filters_) {
- if (event_filter.IsCategoryGroupEnabled(category->name())) {
- state_flags |= TraceCategory::ENABLED_FOR_FILTERING;
- DCHECK(GetCategoryGroupFilters()[index]);
- enabled_filters_bitmap |= 1 << index;
- }
- if (index++ >= MAX_TRACE_EVENT_FILTERS) {
- NOTREACHED();
- break;
- }
- }
- category->set_enabled_filters(enabled_filters_bitmap);
- category->set_state(state_flags);
-}
+ // 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 (mode_ == RECORDING_MODE && !strcmp(category_group, "__metadata"))
+ enabled_flag |= ENABLED_FOR_RECORDING;
-void TraceLog::UpdateCategoryRegistry() {
- lock_.AssertAcquired();
- CreateFiltersForTraceConfig();
- for (TraceCategory& category : CategoryRegistry::GetAllCategories()) {
- UpdateCategoryState(&category);
- }
+ g_category_group_enabled[category_index] = enabled_flag;
}
-void TraceLog::CreateFiltersForTraceConfig() {
- if (!(enabled_modes_ & FILTERING_MODE))
- return;
-
- // Filters were already added and tracing could be enabled. Filters list
- // cannot be changed when trace events are using them.
- if (GetCategoryGroupFilters().size())
- return;
-
- for (auto& filter_config : enabled_event_filters_) {
- if (GetCategoryGroupFilters().size() >= MAX_TRACE_EVENT_FILTERS) {
- NOTREACHED()
- << "Too many trace event filters installed in the current session";
- break;
- }
-
- std::unique_ptr<TraceEventFilter> new_filter;
- const std::string& predicate_name = filter_config.predicate_name();
- if (predicate_name == EventNameFilter::kName) {
- auto whitelist = MakeUnique<std::unordered_set<std::string>>();
- CHECK(filter_config.GetArgAsSet("event_name_whitelist", &*whitelist));
- new_filter = MakeUnique<EventNameFilter>(std::move(whitelist));
- } else if (predicate_name == HeapProfilerEventFilter::kName) {
- new_filter = MakeUnique<HeapProfilerEventFilter>();
- } else {
- if (filter_factory_for_testing_)
- new_filter = filter_factory_for_testing_(predicate_name);
- CHECK(new_filter) << "Unknown trace filter " << predicate_name;
- }
- GetCategoryGroupFilters().push_back(std::move(new_filter));
- }
+void TraceLog::UpdateCategoryGroupEnabledFlags() {
+ size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
+ for (size_t i = 0; i < category_index; i++)
+ UpdateCategoryGroupEnabledFlag(i);
}
void TraceLog::UpdateSyntheticDelaysFromTraceConfig() {
@@ -554,16 +522,67 @@ 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];
+ }
+ }
+
+ unsigned char* category_group_enabled = NULL;
+ // 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";
+ 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[g_category_categories_exhausted];
+ }
+ return category_group_enabled;
+}
+
void TraceLog::GetKnownCategoryGroups(
std::vector<std::string>* category_groups) {
- for (const auto& category : CategoryRegistry::GetAllCategories()) {
- if (!CategoryRegistry::IsBuiltinCategory(&category))
- category_groups->push_back(category.name());
- }
+ AutoLock lock(lock_);
+ size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
+ for (size_t i = g_num_builtin_categories; i < category_index; i++)
+ category_groups->push_back(g_category_groups[i]);
}
-void TraceLog::SetEnabled(const TraceConfig& trace_config,
- uint8_t modes_to_enable) {
+void TraceLog::SetEnabled(const TraceConfig& trace_config, Mode mode) {
std::vector<EnabledStateObserver*> observer_list;
std::map<AsyncEnabledStateObserver*, RegisteredAsyncObserver> observer_map;
{
@@ -577,58 +596,28 @@ void TraceLog::SetEnabled(const TraceConfig& trace_config,
InternalTraceOptions old_options = trace_options();
- if (dispatching_to_observer_list_) {
- // TODO(ssid): Change to NOTREACHED after fixing crbug.com/625170.
- DLOG(ERROR)
- << "Cannot manipulate TraceLog::Enabled state from an observer.";
- return;
- }
+ if (IsEnabled()) {
+ if (new_options != old_options) {
+ DLOG(ERROR) << "Attempting to re-enable tracing with a different "
+ << "set of options.";
+ }
- // Clear all filters from previous tracing session. These filters are not
- // cleared at the end of tracing because some threads which hit trace event
- // when disabling, could try to use the filters.
- if (!enabled_modes_)
- GetCategoryGroupFilters().clear();
-
- // Update trace config for recording.
- const bool already_recording = enabled_modes_ & RECORDING_MODE;
- if (modes_to_enable & RECORDING_MODE) {
- if (already_recording) {
- // TODO(ssid): Stop suporting enabling of RECODING_MODE when already
- // enabled crbug.com/625170.
- DCHECK_EQ(new_options, old_options) << "Attempting to re-enable "
- "tracing with a different set "
- "of options.";
- trace_config_.Merge(trace_config);
- } else {
- trace_config_ = trace_config;
+ if (mode != mode_) {
+ DLOG(ERROR) << "Attempting to re-enable tracing with a different mode.";
}
- }
- // Update event filters.
- if (modes_to_enable & FILTERING_MODE) {
- DCHECK(!trace_config.event_filters().empty())
- << "Attempting to enable filtering without any filters";
- DCHECK(enabled_event_filters_.empty()) << "Attempting to re-enable "
- "filtering when filters are "
- "already enabled.";
-
- // Use the given event filters only if filtering was not enabled.
- if (enabled_event_filters_.empty())
- enabled_event_filters_ = trace_config.event_filters();
+ trace_config_.Merge(trace_config);
+ UpdateCategoryGroupEnabledFlags();
+ return;
}
- // Keep the |trace_config_| updated with only enabled filters in case anyone
- // tries to read it using |GetCurrentTraceConfig| (even if filters are
- // empty).
- trace_config_.SetEventFilters(enabled_event_filters_);
-
- enabled_modes_ |= modes_to_enable;
- UpdateCategoryRegistry();
- // Do not notify observers or create trace buffer if only enabled for
- // filtering or if recording was already enabled.
- if (!(modes_to_enable & RECORDING_MODE) || already_recording)
+ if (dispatching_to_observer_list_) {
+ DLOG(ERROR)
+ << "Cannot manipulate TraceLog::Enabled state from an observer.";
return;
+ }
+
+ mode_ = mode;
if (new_options != old_options) {
subtle::NoBarrier_Store(&trace_options_, new_options);
@@ -637,16 +626,34 @@ void TraceLog::SetEnabled(const TraceConfig& trace_config,
num_traces_recorded_++;
- UpdateCategoryRegistry();
+ trace_config_ = TraceConfig(trace_config);
+ UpdateCategoryGroupEnabledFlags();
UpdateSyntheticDelaysFromTraceConfig();
+ if (new_options & kInternalEnableSampling) {
+ sampling_thread_.reset(new TraceSamplingThread);
+ sampling_thread_->RegisterSampleBucket(
+ &g_trace_state[0], "bucket0",
+ Bind(&TraceSamplingThread::DefaultSamplingCallback));
+ sampling_thread_->RegisterSampleBucket(
+ &g_trace_state[1], "bucket1",
+ Bind(&TraceSamplingThread::DefaultSamplingCallback));
+ sampling_thread_->RegisterSampleBucket(
+ &g_trace_state[2], "bucket2",
+ Bind(&TraceSamplingThread::DefaultSamplingCallback));
+ if (!PlatformThread::Create(0, sampling_thread_.get(),
+ &sampling_thread_handle_)) {
+ DCHECK(false) << "failed to create thread";
+ }
+ }
+
dispatching_to_observer_list_ = true;
observer_list = enabled_state_observer_list_;
observer_map = async_observers_;
}
// Notify observers outside the lock in case they trigger trace events.
- for (EnabledStateObserver* observer : observer_list)
- observer->OnTraceLogEnabled();
+ for (size_t i = 0; i < observer_list.size(); ++i)
+ observer_list[i]->OnTraceLogEnabled();
for (const auto& it : observer_map) {
it.second.task_runner->PostTask(
FROM_HERE, Bind(&AsyncEnabledStateObserver::OnTraceLogEnabled,
@@ -669,9 +676,10 @@ void TraceLog::SetArgumentFilterPredicate(
TraceLog::InternalTraceOptions TraceLog::GetInternalOptionsFromTraceConfig(
const TraceConfig& config) {
- InternalTraceOptions ret = config.IsArgumentFilterEnabled()
- ? kInternalEnableArgumentFilter
- : kInternalNone;
+ InternalTraceOptions ret =
+ config.IsSamplingEnabled() ? kInternalEnableSampling : kInternalNone;
+ if (config.IsArgumentFilterEnabled())
+ ret |= kInternalEnableArgumentFilter;
switch (config.GetTraceRecordMode()) {
case RECORD_UNTIL_FULL:
return ret | kInternalRecordUntilFull;
@@ -693,44 +701,37 @@ TraceConfig TraceLog::GetCurrentTraceConfig() const {
void TraceLog::SetDisabled() {
AutoLock lock(lock_);
- SetDisabledWhileLocked(RECORDING_MODE);
-}
-
-void TraceLog::SetDisabled(uint8_t modes_to_disable) {
- AutoLock lock(lock_);
- SetDisabledWhileLocked(modes_to_disable);
+ SetDisabledWhileLocked();
}
-void TraceLog::SetDisabledWhileLocked(uint8_t modes_to_disable) {
+void TraceLog::SetDisabledWhileLocked() {
lock_.AssertAcquired();
- if (!(enabled_modes_ & modes_to_disable))
+ if (!IsEnabled())
return;
if (dispatching_to_observer_list_) {
- // TODO(ssid): Change to NOTREACHED after fixing crbug.com/625170.
DLOG(ERROR)
<< "Cannot manipulate TraceLog::Enabled state from an observer.";
return;
}
- bool is_recording_mode_disabled =
- (enabled_modes_ & RECORDING_MODE) && (modes_to_disable & RECORDING_MODE);
- enabled_modes_ &= ~modes_to_disable;
-
- if (modes_to_disable & FILTERING_MODE)
- enabled_event_filters_.clear();
-
- if (modes_to_disable & RECORDING_MODE)
- trace_config_.Clear();
+ mode_ = DISABLED;
- UpdateCategoryRegistry();
-
- // Add metadata events and notify observers only if recording mode was
- // disabled now.
- if (!is_recording_mode_disabled)
- return;
+ if (sampling_thread_.get()) {
+ // Stop the sampling thread.
+ sampling_thread_->Stop();
+ lock_.Release();
+ PlatformThread::Join(sampling_thread_handle_);
+ lock_.Acquire();
+ sampling_thread_handle_ = PlatformThreadHandle();
+ sampling_thread_.reset();
+ }
+ trace_config_.Clear();
+ subtle::NoBarrier_Store(&watch_category_, 0);
+ watch_event_name_ = "";
+ UpdateCategoryGroupEnabledFlags();
AddMetadataEventsWhileLocked();
// Remove metadata events so they will not get added to a subsequent trace.
@@ -746,8 +747,8 @@ void TraceLog::SetDisabledWhileLocked(uint8_t modes_to_disable) {
// Dispatch to observers outside the lock in case the observer triggers a
// trace event.
AutoUnlock unlock(lock_);
- for (EnabledStateObserver* observer : observer_list)
- observer->OnTraceLogDisabled();
+ for (size_t i = 0; i < observer_list.size(); ++i)
+ observer_list[i]->OnTraceLogDisabled();
for (const auto& it : observer_map) {
it.second.task_runner->PostTask(
FROM_HERE, Bind(&AsyncEnabledStateObserver::OnTraceLogDisabled,
@@ -830,10 +831,25 @@ void TraceLog::CheckIfBufferIsFullWhileLocked() {
if (buffer_limit_reached_timestamp_.is_null()) {
buffer_limit_reached_timestamp_ = OffsetNow();
}
- SetDisabledWhileLocked(RECORDING_MODE);
+ SetDisabledWhileLocked();
}
}
+void TraceLog::SetEventCallbackEnabled(const TraceConfig& trace_config,
+ EventCallback cb) {
+ AutoLock lock(lock_);
+ subtle::NoBarrier_Store(&event_callback_,
+ reinterpret_cast<subtle::AtomicWord>(cb));
+ event_callback_trace_config_ = trace_config;
+ UpdateCategoryGroupEnabledFlags();
+}
+
+void TraceLog::SetEventCallbackDisabled() {
+ AutoLock lock(lock_);
+ subtle::NoBarrier_Store(&event_callback_, 0);
+ UpdateCategoryGroupEnabledFlags();
+}
+
// Flush() works as the following:
// 1. Flush() is called in thread A whose task runner is saved in
// flush_task_runner_;
@@ -870,7 +886,7 @@ void TraceLog::FlushInternal(const TraceLog::OutputCallback& cb,
return;
}
- int gen = generation();
+ int generation = this->generation();
// Copy of thread_message_loops_ to be used without locking.
std::vector<scoped_refptr<SingleThreadTaskRunner>>
thread_message_loop_task_runners;
@@ -888,24 +904,29 @@ void TraceLog::FlushInternal(const TraceLog::OutputCallback& cb,
std::move(thread_shared_chunk_));
}
- for (MessageLoop* loop : thread_message_loops_)
- thread_message_loop_task_runners.push_back(loop->task_runner());
+ if (thread_message_loops_.size()) {
+ for (hash_set<MessageLoop*>::const_iterator it =
+ thread_message_loops_.begin();
+ it != thread_message_loops_.end(); ++it) {
+ thread_message_loop_task_runners.push_back((*it)->task_runner());
+ }
+ }
}
- if (!thread_message_loop_task_runners.empty()) {
- for (auto& task_runner : thread_message_loop_task_runners) {
- task_runner->PostTask(
+ if (thread_message_loop_task_runners.size()) {
+ for (size_t i = 0; i < thread_message_loop_task_runners.size(); ++i) {
+ thread_message_loop_task_runners[i]->PostTask(
FROM_HERE, Bind(&TraceLog::FlushCurrentThread, Unretained(this),
- gen, discard_events));
+ generation, discard_events));
}
flush_task_runner_->PostDelayedTask(
- FROM_HERE, Bind(&TraceLog::OnFlushTimeout, Unretained(this), gen,
+ FROM_HERE, Bind(&TraceLog::OnFlushTimeout, Unretained(this), generation,
discard_events),
TimeDelta::FromMilliseconds(kThreadFlushTimeoutMs));
return;
}
- FinishFlush(gen, discard_events);
+ FinishFlush(generation, discard_events);
}
// Usually it runs on a different thread.
@@ -969,21 +990,13 @@ void TraceLog::FinishFlush(int generation, bool discard_events) {
return;
}
- if (use_worker_thread_) {
-#if 0
- base::PostTaskWithTraits(
- FROM_HERE, base::TaskTraits()
- .MayBlock()
- .WithPriority(base::TaskPriority::BACKGROUND)
- .WithShutdownBehavior(
- base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN),
- Bind(&TraceLog::ConvertTraceEventsToTraceFormat,
- Passed(&previous_logged_events), flush_output_callback,
- argument_filter_predicate));
+ if (use_worker_thread_ &&
+ WorkerPool::PostTask(
+ FROM_HERE, Bind(&TraceLog::ConvertTraceEventsToTraceFormat,
+ Passed(&previous_logged_events),
+ flush_output_callback, argument_filter_predicate),
+ true)) {
return;
-#else
- NOTREACHED();
-#endif
}
ConvertTraceEventsToTraceFormat(std::move(previous_logged_events),
@@ -1006,7 +1019,7 @@ void TraceLog::FlushCurrentThread(int generation, bool discard_events) {
AutoLock lock(lock_);
if (!CheckGeneration(generation) || !flush_task_runner_ ||
- !thread_message_loops_.empty())
+ thread_message_loops_.size())
return;
flush_task_runner_->PostTask(
@@ -1210,13 +1223,10 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
TimeTicks offset_event_timestamp = OffsetTimestamp(timestamp);
ThreadTicks thread_now = ThreadNow();
- ThreadLocalEventBuffer* thread_local_event_buffer = nullptr;
- if (*category_group_enabled & RECORDING_MODE) {
- // |thread_local_event_buffer_| can be null if the current thread doesn't
- // have a message loop or the message loop is blocked.
- InitializeThreadLocalEventBufferIfSupported();
- thread_local_event_buffer = thread_local_event_buffer_.Get();
- }
+ // |thread_local_event_buffer_| can be null if the current thread doesn't have
+ // a message loop or the message loop is blocked.
+ InitializeThreadLocalEventBufferIfSupported();
+ auto* thread_local_event_buffer = thread_local_event_buffer_.Get();
// Check and update the current thread name only if the event is for the
// current thread to avoid locks in most cases.
@@ -1227,9 +1237,9 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
// call (if any), but don't bother if the new name is empty. Note this will
// not detect a thread name change within the same char* buffer address: we
// favor common case performance over corner case correctness.
- static auto* current_thread_name = new ThreadLocalPointer<const char>();
- if (new_name != current_thread_name->Get() && new_name && *new_name) {
- current_thread_name->Set(new_name);
+ if (new_name != g_current_thread_name.Get().Get() && new_name &&
+ *new_name) {
+ g_current_thread_name.Get().Set(new_name);
AutoLock thread_info_lock(thread_info_lock_);
@@ -1247,7 +1257,7 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
bool found = std::find(existing_names.begin(), existing_names.end(),
new_name) != existing_names.end();
if (!found) {
- if (!existing_names.empty())
+ if (existing_names.size())
existing_name->second.push_back(',');
existing_name->second.append(new_name);
}
@@ -1258,37 +1268,14 @@ 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 & TraceCategory::ENABLED_FOR_ETW_EXPORT)
+ if (*category_group_enabled & ENABLED_FOR_ETW_EXPORT)
TraceEventETWExport::AddEvent(phase, category_group_enabled, name, id,
num_args, arg_names, arg_types, arg_values,
convertable_values);
#endif // OS_WIN
std::string console_message;
- std::unique_ptr<TraceEvent> filtered_trace_event;
- bool disabled_by_filters = false;
- 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,
- bind_id, num_args, arg_names, arg_types,
- arg_values, convertable_values, flags);
-
- disabled_by_filters = true;
- ForEachCategoryFilter(
- category_group_enabled, [&new_trace_event, &disabled_by_filters](
- TraceEventFilter* trace_event_filter) {
- if (trace_event_filter->FilterTraceEvent(*new_trace_event))
- disabled_by_filters = false;
- });
- if (!disabled_by_filters)
- filtered_trace_event = std::move(new_trace_event);
- }
-
- // 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 & TraceCategory::ENABLED_FOR_RECORDING) &&
- !disabled_by_filters) {
+ if (*category_group_enabled & ENABLED_FOR_RECORDING) {
OptionalAutoLock lock(&lock_);
TraceEvent* trace_event = NULL;
@@ -1300,14 +1287,21 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
}
if (trace_event) {
- 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);
- }
+ 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();
@@ -1321,9 +1315,53 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
}
}
- if (!console_message.empty())
+ if (console_message.size())
LOG(ERROR) << console_message;
+ if (reinterpret_cast<const unsigned char*>(
+ subtle::NoBarrier_Load(&watch_category_)) == category_group_enabled) {
+ bool event_name_matches;
+ WatchEventCallback watch_event_callback_copy;
+ {
+ AutoLock lock(lock_);
+ event_name_matches = watch_event_name_ == name;
+ watch_event_callback_copy = watch_event_callback_;
+ }
+ if (event_name_matches) {
+ if (!watch_event_callback_copy.is_null())
+ watch_event_callback_copy.Run();
+ }
+ }
+
+ if (*category_group_enabled & ENABLED_FOR_EVENT_CALLBACK) {
+ EventCallback event_callback = reinterpret_cast<EventCallback>(
+ subtle::NoBarrier_Load(&event_callback_));
+ if (event_callback) {
+ event_callback(
+ offset_event_timestamp,
+ phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase,
+ category_group_enabled, name, scope, id, num_args, arg_names,
+ arg_types, arg_values, flags);
+ }
+ }
+
+ // TODO(primiano): Add support for events with copied name crbug.com/581078
+ if (!(flags & TRACE_EVENT_FLAG_COPY)) {
+ if (AllocationContextTracker::capture_mode() ==
+ AllocationContextTracker::CaptureMode::PSEUDO_STACK) {
+ if (phase == TRACE_EVENT_PHASE_BEGIN ||
+ phase == TRACE_EVENT_PHASE_COMPLETE) {
+ AllocationContextTracker::GetInstanceForCurrentThread()
+ ->PushPseudoStackFrame(name);
+ } else if (phase == TRACE_EVENT_PHASE_END) {
+ // The pop for |TRACE_EVENT_PHASE_COMPLETE| events
+ // is in |TraceLog::UpdateTraceEventDuration|.
+ AllocationContextTracker::GetInstanceForCurrentThread()
+ ->PopPseudoStackFrame(name);
+ }
+ }
+ }
+
return handle;
}
@@ -1381,9 +1419,9 @@ std::string TraceLog::EventToConsoleMessage(unsigned char phase,
thread_colors_[thread_name]);
size_t depth = 0;
- auto it = thread_event_start_times_.find(thread_id);
- if (it != thread_event_start_times_.end())
- depth = it->second.size();
+ if (thread_event_start_times_.find(thread_id) !=
+ thread_event_start_times_.end())
+ depth = thread_event_start_times_[thread_id].size();
for (size_t i = 0; i < depth; ++i)
log << "| ";
@@ -1401,18 +1439,6 @@ std::string TraceLog::EventToConsoleMessage(unsigned char phase,
return log.str();
}
-void TraceLog::EndFilteredEvent(const unsigned char* category_group_enabled,
- const char* name,
- TraceEventHandle handle) {
- ALLOW_UNUSED_PARAM(handle);
- const char* category_name = GetCategoryGroupName(category_group_enabled);
- ForEachCategoryFilter(
- category_group_enabled,
- [name, category_name](TraceEventFilter* trace_event_filter) {
- trace_event_filter->EndEvent(category_name, name);
- });
-}
-
void TraceLog::UpdateTraceEventDuration(
const unsigned char* category_group_enabled,
const char* name,
@@ -1434,29 +1460,17 @@ void TraceLog::UpdateTraceEventDuration(
#if defined(OS_WIN)
// Generate an ETW event that marks the end of a complete event.
- if (category_group_enabled_local & TraceCategory::ENABLED_FOR_ETW_EXPORT)
+ if (category_group_enabled_local & ENABLED_FOR_ETW_EXPORT)
TraceEventETWExport::AddCompleteEndEvent(name);
#endif // OS_WIN
std::string console_message;
- if (category_group_enabled_local & TraceCategory::ENABLED_FOR_RECORDING) {
+ if (category_group_enabled_local & ENABLED_FOR_RECORDING) {
OptionalAutoLock lock(&lock_);
TraceEvent* trace_event = GetEventByHandleInternal(handle, &lock);
if (trace_event) {
DCHECK(trace_event->phase() == TRACE_EVENT_PHASE_COMPLETE);
- // TEMP(oysteine) to debug crbug.com/638744
- if (trace_event->duration().ToInternalValue() != -1) {
- DVLOG(1) << "TraceHandle: chunk_seq " << handle.chunk_seq
- << ", chunk_index " << handle.chunk_index << ", event_index "
- << handle.event_index;
-
- std::string serialized_event;
- trace_event->AppendAsJSON(&serialized_event, ArgumentFilterPredicate());
- DVLOG(1) << "TraceEvent: " << serialized_event;
- lock_.AssertAcquired();
- }
-
trace_event->UpdateDuration(now, thread_now);
#if defined(OS_ANDROID)
trace_event->SendToATrace();
@@ -1467,13 +1481,47 @@ void TraceLog::UpdateTraceEventDuration(
console_message =
EventToConsoleMessage(TRACE_EVENT_PHASE_END, now, trace_event);
}
+
+ if (AllocationContextTracker::capture_mode() ==
+ AllocationContextTracker::CaptureMode::PSEUDO_STACK) {
+ // The corresponding push is in |AddTraceEventWithThreadIdAndTimestamp|.
+ AllocationContextTracker::GetInstanceForCurrentThread()
+ ->PopPseudoStackFrame(name);
+ }
}
- if (!console_message.empty())
+ if (console_message.size())
LOG(ERROR) << console_message;
- if (category_group_enabled_local & TraceCategory::ENABLED_FOR_FILTERING)
- EndFilteredEvent(category_group_enabled, name, handle);
+ if (category_group_enabled_local & ENABLED_FOR_EVENT_CALLBACK) {
+ EventCallback event_callback = reinterpret_cast<EventCallback>(
+ subtle::NoBarrier_Load(&event_callback_));
+ if (event_callback) {
+ event_callback(
+ now, TRACE_EVENT_PHASE_END, category_group_enabled, name,
+ trace_event_internal::kGlobalScope, trace_event_internal::kNoId, 0,
+ nullptr, nullptr, nullptr, TRACE_EVENT_FLAG_NONE);
+ }
+ }
+}
+
+void TraceLog::SetWatchEvent(const std::string& category_name,
+ const std::string& event_name,
+ const WatchEventCallback& callback) {
+ const unsigned char* category =
+ GetCategoryGroupEnabled(category_name.c_str());
+ AutoLock lock(lock_);
+ subtle::NoBarrier_Store(&watch_category_,
+ reinterpret_cast<subtle::AtomicWord>(category));
+ watch_event_name_ = event_name;
+ watch_event_callback_ = callback;
+}
+
+void TraceLog::CancelWatchEvent() {
+ AutoLock lock(lock_);
+ subtle::NoBarrier_Store(&watch_category_, 0);
+ watch_event_name_ = "";
+ watch_event_callback_.Reset();
}
uint64_t TraceLog::MangleEventId(uint64_t id) {
@@ -1503,37 +1551,42 @@ void TraceLog::AddMetadataEventsWhileLocked() {
"sort_index", process_sort_index_);
}
- if (!process_name_.empty()) {
+ if (process_name_.size()) {
InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
current_thread_id, "process_name", "name",
process_name_);
}
- if (!process_labels_.empty()) {
+ if (process_labels_.size() > 0) {
std::vector<std::string> labels;
- for (const auto& it : process_labels_)
- labels.push_back(it.second);
+ for (base::hash_map<int, std::string>::iterator it =
+ process_labels_.begin();
+ it != process_labels_.end(); it++) {
+ labels.push_back(it->second);
+ }
InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
current_thread_id, "process_labels", "labels",
base::JoinString(labels, ","));
}
// Thread sort indices.
- for (const auto& it : thread_sort_indices_) {
- if (it.second == 0)
+ for (hash_map<int, int>::iterator it = thread_sort_indices_.begin();
+ it != thread_sort_indices_.end(); it++) {
+ if (it->second == 0)
continue;
InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- it.first, "thread_sort_index", "sort_index",
- it.second);
+ it->first, "thread_sort_index", "sort_index",
+ it->second);
}
// Thread names.
AutoLock thread_info_lock(thread_info_lock_);
- for (const auto& it : thread_names_) {
- if (it.second.empty())
+ for (hash_map<int, std::string>::iterator it = thread_names_.begin();
+ it != thread_names_.end(); it++) {
+ if (it->second.empty())
continue;
InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- it.first, "thread_name", "name", it.second);
+ it->first, "thread_name", "name", it->second);
}
// If buffer is full, add a metadata record to report this.
@@ -1545,9 +1598,14 @@ void TraceLog::AddMetadataEventsWhileLocked() {
}
}
+void TraceLog::WaitSamplingEventForTesting() {
+ if (!sampling_thread_)
+ return;
+ sampling_thread_->WaitSamplingEventForTesting();
+}
+
void TraceLog::DeleteForTesting() {
internal::DeleteTraceLogForTesting::Delete();
- CategoryRegistry::ResetForTesting();
}
TraceEvent* TraceLog::GetEventByHandle(TraceEventHandle handle) {
@@ -1559,10 +1617,6 @@ TraceEvent* TraceLog::GetEventByHandleInternal(TraceEventHandle handle,
if (!handle.chunk_seq)
return NULL;
- DCHECK(handle.chunk_seq);
- DCHECK(handle.chunk_index <= TraceBufferChunk::kMaxChunkIndex);
- DCHECK(handle.event_index < TraceBufferChunk::kTraceBufferChunkSize);
-
if (thread_local_event_buffer_.Get()) {
TraceEvent* trace_event =
thread_local_event_buffer_.Get()->GetEventByHandle(handle);
@@ -1589,10 +1643,10 @@ void TraceLog::SetProcessID(int process_id) {
process_id_ = process_id;
// Create a FNV hash from the process ID for XORing.
// See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details.
- const unsigned long long kOffsetBasis = 14695981039346656037ull;
- const unsigned long long kFnvPrime = 1099511628211ull;
- const unsigned long long pid = static_cast<unsigned long long>(process_id_);
- process_id_hash_ = (kOffsetBasis ^ pid) * kFnvPrime;
+ unsigned long long offset_basis = 14695981039346656037ull;
+ unsigned long long fnv_prime = 1099511628211ull;
+ unsigned long long pid = static_cast<unsigned long long>(process_id_);
+ process_id_hash_ = (offset_basis ^ pid) * fnv_prime;
}
void TraceLog::SetProcessSortIndex(int sort_index) {
@@ -1600,7 +1654,7 @@ void TraceLog::SetProcessSortIndex(int sort_index) {
process_sort_index_ = sort_index;
}
-void TraceLog::SetProcessName(const char* process_name) {
+void TraceLog::SetProcessName(const std::string& process_name) {
AutoLock lock(lock_);
process_name_ = process_name;
}
@@ -1616,7 +1670,12 @@ void TraceLog::UpdateProcessLabel(int label_id,
void TraceLog::RemoveProcessLabel(int label_id) {
AutoLock lock(lock_);
- process_labels_.erase(label_id);
+ base::hash_map<int, std::string>::iterator it =
+ process_labels_.find(label_id);
+ if (it == process_labels_.end())
+ return;
+
+ process_labels_.erase(it);
}
void TraceLog::SetThreadSortIndex(PlatformThreadId thread_id, int sort_index) {
@@ -1634,39 +1693,42 @@ size_t TraceLog::GetObserverCountForTest() const {
void TraceLog::SetCurrentThreadBlocksMessageLoop() {
thread_blocks_message_loop_.Set(true);
- // This will flush the thread local buffer.
- delete thread_local_event_buffer_.Get();
+ if (thread_local_event_buffer_.Get()) {
+ // This will flush the thread local buffer.
+ delete thread_local_event_buffer_.Get();
+ }
}
TraceBuffer* TraceLog::CreateTraceBuffer() {
HEAP_PROFILER_SCOPED_IGNORE;
InternalTraceOptions options = trace_options();
- if (options & kInternalRecordContinuously) {
+ if (options & kInternalRecordContinuously)
return TraceBuffer::CreateTraceBufferRingBuffer(
kTraceEventRingBufferChunks);
- }
- if (options & kInternalEchoToConsole) {
+ else if (options & kInternalEchoToConsole)
return TraceBuffer::CreateTraceBufferRingBuffer(
kEchoToConsoleTraceEventBufferChunks);
- }
- if (options & kInternalRecordAsMuchAsPossible) {
+ else if (options & kInternalRecordAsMuchAsPossible)
return TraceBuffer::CreateTraceBufferVectorOfSize(
kTraceEventVectorBigBufferChunks);
- }
return TraceBuffer::CreateTraceBufferVectorOfSize(
kTraceEventVectorBufferChunks);
}
#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 (TraceCategory& category : CategoryRegistry::GetAllCategories()) {
+ for (size_t i = 0; i < category_index; i++) {
+ const char* category_group = g_category_groups[i];
+ DCHECK(category_group);
if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled(
- category.name())) {
- category.set_state_flag(TraceCategory::ENABLED_FOR_ETW_EXPORT);
+ category_group)) {
+ g_category_group_enabled[i] |= ENABLED_FOR_ETW_EXPORT;
} else {
- category.clear_state_flag(TraceCategory::ENABLED_FOR_ETW_EXPORT);
+ g_category_group_enabled[i] &= ~ENABLED_FOR_ETW_EXPORT;
}
}
}
diff --git a/base/trace_event/trace_log.h b/base/trace_event/trace_log.h
index 88b6e588e4..e4407e81bd 100644
--- a/base/trace_event/trace_log.h
+++ b/base/trace_event/trace_log.h
@@ -26,17 +26,15 @@ namespace base {
template <typename Type>
struct DefaultSingletonTraits;
-class MessageLoop;
class RefCountedString;
namespace trace_event {
-struct TraceCategory;
class TraceBuffer;
class TraceBufferChunk;
class TraceEvent;
-class TraceEventFilter;
class TraceEventMemoryOverhead;
+class TraceSamplingThread;
struct BASE_EXPORT TraceLogStatus {
TraceLogStatus();
@@ -47,14 +45,22 @@ struct BASE_EXPORT TraceLogStatus {
class BASE_EXPORT TraceLog : public MemoryDumpProvider {
public:
- // Argument passed to TraceLog::SetEnabled.
- enum Mode : uint8_t {
- // Enables normal tracing (recording trace events in the trace buffer).
- RECORDING_MODE = 1 << 0,
-
- // Trace events are enabled just for filtering but not for recording. Only
- // event filters config of |trace_config| argument is used.
- FILTERING_MODE = 1 << 1
+ enum Mode {
+ DISABLED = 0,
+ RECORDING_MODE
+ };
+
+ // The pointer returned from GetCategoryGroupEnabledInternal() points to a
+ // value with zero or more of the following bits. Used in this class only.
+ // The TRACE_EVENT macros should only use the value as a bool.
+ // These values must be in sync with macro values in TraceEvent.h in Blink.
+ enum CategoryGroupEnabledFlags {
+ // Category group enabled for the recording mode.
+ ENABLED_FOR_RECORDING = 1 << 0,
+ // Category group enabled by SetEventCallbackEnabled().
+ ENABLED_FOR_EVENT_CALLBACK = 1 << 2,
+ // Category group enabled to export events to ETW.
+ ENABLED_FOR_ETW_EXPORT = 1 << 3
};
static TraceLog* GetInstance();
@@ -70,30 +76,16 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
// if the current thread supports that (has a message loop).
void InitializeThreadLocalEventBufferIfSupported();
- // See TraceConfig comments for details on how to control which categories
- // will be traced. SetDisabled must be called distinctly for each mode that is
- // enabled. If tracing has already been enabled for recording, category filter
- // (enabled and disabled categories) will be merged into the current category
- // filter. Enabling RECORDING_MODE does not enable filters. Trace event
- // filters will be used only if FILTERING_MODE is set on |modes_to_enable|.
- // Conversely to RECORDING_MODE, FILTERING_MODE doesn't support upgrading,
- // i.e. filters can only be enabled if not previously enabled.
- void SetEnabled(const TraceConfig& trace_config, uint8_t modes_to_enable);
-
- // TODO(ssid): Remove the default SetEnabled and IsEnabled. They should take
- // Mode as argument.
-
- // Disables tracing for all categories for the specified |modes_to_disable|
- // only. Only RECORDING_MODE is taken as default |modes_to_disable|.
- void SetDisabled();
- void SetDisabled(uint8_t modes_to_disable);
+ // Enables normal tracing (recording trace events in the trace buffer).
+ // See TraceConfig comments for details on how to control what categories
+ // will be traced. If tracing has already been enabled, |category_filter| will
+ // be merged into the current category filter.
+ void SetEnabled(const TraceConfig& trace_config, Mode mode);
- // Returns true if TraceLog is enabled on recording mode.
- // Note: Returns false even if FILTERING_MODE is enabled.
- bool IsEnabled() { return enabled_modes_ & RECORDING_MODE; }
+ // Disables normal tracing for all categories.
+ void SetDisabled();
- // Returns a bitmap of enabled modes from TraceLog::Mode.
- uint8_t enabled_modes() { return enabled_modes_; }
+ bool IsEnabled() { return mode_ != DISABLED; }
// The number of times we have begun recording traces. If tracing is off,
// returns -1. If tracing is on, then it returns the number of times we have
@@ -156,6 +148,31 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
// objects.
void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+ // Not using base::Callback because of its limited by 7 parameters.
+ // Also, using primitive type allows directly passing callback from WebCore.
+ // WARNING: It is possible for the previously set callback to be called
+ // after a call to SetEventCallbackEnabled() that replaces or a call to
+ // SetEventCallbackDisabled() that disables the callback.
+ // This callback may be invoked on any thread.
+ // For TRACE_EVENT_PHASE_COMPLETE events, the client will still receive pairs
+ // of TRACE_EVENT_PHASE_BEGIN and TRACE_EVENT_PHASE_END events to keep the
+ // interface simple.
+ typedef void (*EventCallback)(TimeTicks timestamp,
+ char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ const char* scope,
+ unsigned long long id,
+ int num_args,
+ const char* const arg_names[],
+ const unsigned char arg_types[],
+ const unsigned long long arg_values[],
+ unsigned int flags);
+
+ // Enable tracing for EventCallback.
+ void SetEventCallbackEnabled(const TraceConfig& trace_config,
+ EventCallback cb);
+ void SetEventCallbackDisabled();
void SetArgumentFilterPredicate(
const ArgumentFilterPredicate& argument_filter_predicate);
@@ -269,9 +286,14 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
const char* name,
TraceEventHandle handle);
- void EndFilteredEvent(const unsigned char* category_group_enabled,
- const char* name,
- TraceEventHandle handle);
+ // For every matching event, the callback will be called.
+ typedef base::Callback<void()> WatchEventCallback;
+ void SetWatchEvent(const std::string& category_name,
+ const std::string& event_name,
+ const WatchEventCallback& callback);
+ // Cancel the watch event. If tracing is enabled, this may race with the
+ // watch event notification firing.
+ void CancelWatchEvent();
int process_id() const { return process_id_; }
@@ -279,12 +301,7 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
// Exposed for unittesting:
- // Testing factory for TraceEventFilter.
- typedef std::unique_ptr<TraceEventFilter> (*FilterFactoryForTesting)(
- const std::string& /* predicate_name */);
- void SetFilterFactoryForTesting(FilterFactoryForTesting factory) {
- filter_factory_for_testing_ = factory;
- }
+ void WaitSamplingEventForTesting();
// Allows deleting our singleton instance.
static void DeleteForTesting();
@@ -299,9 +316,8 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
// on their sort index, ascending, then by their name, and then tid.
void SetProcessSortIndex(int sort_index);
- // Sets the name of the process. |process_name| should be a string literal
- // since it is a whitelisted argument for background field trials.
- void SetProcessName(const char* process_name);
+ // Sets the name of the process.
+ void SetProcessName(const std::string& process_name);
// Processes can have labels in addition to their names. Use labels, for
// instance, to list out the web page titles that a process is handling.
@@ -355,14 +371,12 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
ProcessMemoryDump* pmd) override;
// Enable/disable each category group based on the current mode_,
- // category_filter_ and event_filters_enabled_.
- // Enable the category group in the recording mode if category_filter_ matches
- // the category group, is not null. Enable category for filtering if any
- // filter in event_filters_enabled_ enables it.
- void UpdateCategoryRegistry();
- void UpdateCategoryState(TraceCategory* category);
-
- void CreateFiltersForTraceConfig();
+ // category_filter_, event_callback_ and event_callback_category_filter_.
+ // Enable the category group in the enabled mode if category_filter_ matches
+ // the category group, or event_callback_ is not null and
+ // event_callback_category_filter_ matches the category group.
+ void UpdateCategoryGroupEnabledFlags();
+ void UpdateCategoryGroupEnabledFlag(size_t category_index);
// Configure synthetic delays based on the values set in the current
// trace config.
@@ -377,6 +391,7 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
TraceLog();
~TraceLog() override;
+ const unsigned char* GetCategoryGroupEnabledInternal(const char* name);
void AddMetadataEventsWhileLocked();
InternalTraceOptions trace_options() const {
@@ -394,7 +409,7 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
TraceEvent* AddEventToThreadSharedChunkWhileLocked(TraceEventHandle* handle,
bool check_buffer_is_full);
void CheckIfBufferIsFullWhileLocked();
- void SetDisabledWhileLocked(uint8_t modes);
+ void SetDisabledWhileLocked();
TraceEvent* GetEventByHandleInternal(TraceEventHandle handle,
OptionalAutoLock* lock);
@@ -433,6 +448,7 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
static const InternalTraceOptions kInternalRecordUntilFull;
static const InternalTraceOptions kInternalRecordContinuously;
static const InternalTraceOptions kInternalEchoToConsole;
+ static const InternalTraceOptions kInternalEnableSampling;
static const InternalTraceOptions kInternalRecordAsMuchAsPossible;
static const InternalTraceOptions kInternalEnableArgumentFilter;
@@ -442,10 +458,11 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
// This lock protects accesses to thread_names_, thread_event_start_times_
// and thread_colors_.
Lock thread_info_lock_;
- uint8_t enabled_modes_; // See TraceLog::Mode.
+ Mode mode_;
int num_traces_recorded_;
std::unique_ptr<TraceBuffer> logged_events_;
std::vector<std::unique_ptr<TraceEvent>> metadata_events_;
+ subtle::AtomicWord /* EventCallback */ event_callback_;
bool dispatching_to_observer_list_;
std::vector<EnabledStateObserver*> enabled_state_observer_list_;
std::map<AsyncEnabledStateObserver*, RegisteredAsyncObserver>
@@ -470,10 +487,19 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
TimeDelta time_offset_;
+ // Allow tests to wake up when certain events occur.
+ WatchEventCallback watch_event_callback_;
+ subtle::AtomicWord /* const unsigned char* */ watch_category_;
+ std::string watch_event_name_;
+
subtle::AtomicWord /* Options */ trace_options_;
+ // Sampling thread handles.
+ std::unique_ptr<TraceSamplingThread> sampling_thread_;
+ PlatformThreadHandle sampling_thread_handle_;
+
TraceConfig trace_config_;
- TraceConfig::EventFilters enabled_event_filters_;
+ TraceConfig event_callback_trace_config_;
ThreadLocalPointer<ThreadLocalEventBuffer> thread_local_event_buffer_;
ThreadLocalBoolean thread_blocks_message_loop_;
@@ -496,8 +522,6 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
subtle::AtomicWord generation_;
bool use_worker_thread_;
- FilterFactoryForTesting filter_factory_for_testing_;
-
DISALLOW_COPY_AND_ASSIGN(TraceLog);
};
diff --git a/base/trace_event/trace_log_constants.cc b/base/trace_event/trace_log_constants.cc
index 65dca2e4d6..cd2ff0dad3 100644
--- a/base/trace_event/trace_log_constants.cc
+++ b/base/trace_event/trace_log_constants.cc
@@ -14,7 +14,8 @@ const TraceLog::InternalTraceOptions
TraceLog::kInternalRecordUntilFull = 1 << 0;
const TraceLog::InternalTraceOptions
TraceLog::kInternalRecordContinuously = 1 << 1;
-// 1 << 2 is reserved for the DEPRECATED kInternalEnableSampling. DO NOT USE.
+const TraceLog::InternalTraceOptions
+ TraceLog::kInternalEnableSampling = 1 << 2;
const TraceLog::InternalTraceOptions
TraceLog::kInternalEchoToConsole = 1 << 3;
const TraceLog::InternalTraceOptions
diff --git a/base/trace_event/trace_sampling_thread.cc b/base/trace_event/trace_sampling_thread.cc
new file mode 100644
index 0000000000..5a0d2f8a02
--- /dev/null
+++ b/base/trace_event/trace_sampling_thread.cc
@@ -0,0 +1,107 @@
+// Copyright 2015 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.
+
+#include <stddef.h>
+
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/trace_log.h"
+#include "base/trace_event/trace_sampling_thread.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceBucketData {
+ public:
+ TraceBucketData(base::subtle::AtomicWord* bucket,
+ const char* name,
+ TraceSampleCallback callback);
+ ~TraceBucketData();
+
+ TRACE_EVENT_API_ATOMIC_WORD* bucket;
+ const char* bucket_name;
+ TraceSampleCallback callback;
+};
+
+TraceSamplingThread::TraceSamplingThread()
+ : thread_running_(false),
+ waitable_event_for_testing_(WaitableEvent::ResetPolicy::AUTOMATIC,
+ WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+TraceSamplingThread::~TraceSamplingThread() {}
+
+void TraceSamplingThread::ThreadMain() {
+ PlatformThread::SetName("Sampling Thread");
+ thread_running_ = true;
+ const int kSamplingFrequencyMicroseconds = 1000;
+ while (!cancellation_flag_.IsSet()) {
+ PlatformThread::Sleep(
+ TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds));
+ GetSamples();
+ waitable_event_for_testing_.Signal();
+ }
+}
+
+// static
+void TraceSamplingThread::DefaultSamplingCallback(
+ TraceBucketData* bucket_data) {
+ TRACE_EVENT_API_ATOMIC_WORD category_and_name =
+ TRACE_EVENT_API_ATOMIC_LOAD(*bucket_data->bucket);
+ if (!category_and_name)
+ return;
+ const char* const combined =
+ reinterpret_cast<const char* const>(category_and_name);
+ const char* category_group;
+ const char* name;
+ ExtractCategoryAndName(combined, &category_group, &name);
+ TRACE_EVENT_API_ADD_TRACE_EVENT(
+ TRACE_EVENT_PHASE_SAMPLE,
+ TraceLog::GetCategoryGroupEnabled(category_group), name,
+ trace_event_internal::kGlobalScope, trace_event_internal::kNoId, 0,
+ NULL, NULL, NULL, NULL, 0);
+}
+
+void TraceSamplingThread::GetSamples() {
+ for (size_t i = 0; i < sample_buckets_.size(); ++i) {
+ TraceBucketData* bucket_data = &sample_buckets_[i];
+ bucket_data->callback.Run(bucket_data);
+ }
+}
+
+void TraceSamplingThread::RegisterSampleBucket(
+ TRACE_EVENT_API_ATOMIC_WORD* bucket,
+ const char* const name,
+ TraceSampleCallback callback) {
+ // Access to sample_buckets_ doesn't cause races with the sampling thread
+ // that uses the sample_buckets_, because it is guaranteed that
+ // RegisterSampleBucket is called before the sampling thread is created.
+ DCHECK(!thread_running_);
+ sample_buckets_.push_back(TraceBucketData(bucket, name, callback));
+}
+
+// static
+void TraceSamplingThread::ExtractCategoryAndName(const char* combined,
+ const char** category,
+ const char** name) {
+ *category = combined;
+ *name = &combined[strlen(combined) + 1];
+}
+
+void TraceSamplingThread::Stop() {
+ cancellation_flag_.Set();
+}
+
+void TraceSamplingThread::WaitSamplingEventForTesting() {
+ waitable_event_for_testing_.Wait();
+}
+
+TraceBucketData::TraceBucketData(base::subtle::AtomicWord* bucket,
+ const char* name,
+ TraceSampleCallback callback)
+ : bucket(bucket), bucket_name(name), callback(callback) {}
+
+TraceBucketData::~TraceBucketData() {}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/trace_sampling_thread.h b/base/trace_event/trace_sampling_thread.h
new file mode 100644
index 0000000000..f976a80e07
--- /dev/null
+++ b/base/trace_event/trace_sampling_thread.h
@@ -0,0 +1,54 @@
+// Copyright 2015 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 BASE_TRACE_EVENT_TRACE_SAMPLING_THREAD_H_
+#define BASE_TRACE_EVENT_TRACE_SAMPLING_THREAD_H_
+
+#include "base/synchronization/cancellation_flag.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceBucketData;
+typedef base::Callback<void(TraceBucketData*)> TraceSampleCallback;
+
+// This object must be created on the IO thread.
+class TraceSamplingThread : public PlatformThread::Delegate {
+ public:
+ TraceSamplingThread();
+ ~TraceSamplingThread() override;
+
+ // Implementation of PlatformThread::Delegate:
+ void ThreadMain() override;
+
+ static void DefaultSamplingCallback(TraceBucketData* bucket_data);
+
+ void Stop();
+ void WaitSamplingEventForTesting();
+
+ private:
+ friend class TraceLog;
+
+ void GetSamples();
+ // Not thread-safe. Once the ThreadMain has been called, this can no longer
+ // be called.
+ void RegisterSampleBucket(TRACE_EVENT_API_ATOMIC_WORD* bucket,
+ const char* const name,
+ TraceSampleCallback callback);
+ // Splits a combined "category\0name" into the two component parts.
+ static void ExtractCategoryAndName(const char* combined,
+ const char** category,
+ const char** name);
+ std::vector<TraceBucketData> sample_buckets_;
+ bool thread_running_;
+ CancellationFlag cancellation_flag_;
+ WaitableEvent waitable_event_for_testing_;
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_TRACE_SAMPLING_THREAD_H_