summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHidehiko Abe <hidehiko@google.com>2018-06-04 10:22:00 -0700
committerandroid-build-merger <android-build-merger@google.com>2018-06-04 10:22:00 -0700
commite2c1a37558287288715a7f1bdb73ac9e66d1dff1 (patch)
tree3c20b00d2e41637aceb9bd58acc79a0ec787922a
parentb5e42b358cbe884964bdcb710a8037cc6038d68a (diff)
parentad62a8245af1d123a106c870203a777260d231f8 (diff)
downloadlibchrome-e2c1a37558287288715a7f1bdb73ac9e66d1dff1.tar.gz
Remove trace_event.
am: ad62a8245a Change-Id: I671033cdf0bcb8c67b657127cbfc5f77a211565a
-rw-r--r--Android.bp50
-rw-r--r--base/memory/shared_memory_posix.cc9
-rw-r--r--base/memory/shared_memory_tracker.cc92
-rw-r--r--base/memory/shared_memory_tracker.h56
-rw-r--r--base/profiler/scoped_profile.cc34
-rw-r--r--base/profiler/scoped_profile.h76
-rw-r--r--base/profiler/scoped_tracker.cc26
-rw-r--r--base/profiler/scoped_tracker.h77
-rw-r--r--base/test/test_pending_task.cc6
-rw-r--r--base/test/test_pending_task.h6
-rw-r--r--base/test/trace_event_analyzer.cc1027
-rw-r--r--base/test/trace_event_analyzer.h810
-rw-r--r--base/test/trace_event_analyzer_unittest.cc961
-rw-r--r--base/threading/thread_id_name_manager.cc8
-rw-r--r--base/trace_event/category_registry.cc156
-rw-r--r--base/trace_event/category_registry.h93
-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.h17
-rw-r--r--base/trace_event/heap_profiler_allocation_context.cc88
-rw-r--r--base/trace_event/heap_profiler_allocation_context.h131
-rw-r--r--base/trace_event/heap_profiler_allocation_context_tracker.cc250
-rw-r--r--base/trace_event/heap_profiler_allocation_context_tracker.h121
-rw-r--r--base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc321
-rw-r--r--base/trace_event/heap_profiler_allocation_register.cc194
-rw-r--r--base/trace_event/heap_profiler_allocation_register.h385
-rw-r--r--base/trace_event/heap_profiler_allocation_register_posix.cc58
-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.cc322
-rw-r--r--base/trace_event/heap_profiler_heap_dump_writer.h113
-rw-r--r--base/trace_event/heap_profiler_stack_frame_deduplicator.cc131
-rw-r--r--base/trace_event/heap_profiler_stack_frame_deduplicator.h81
-rw-r--r--base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc152
-rw-r--r--base/trace_event/heap_profiler_type_name_deduplicator.cc115
-rw-r--r--base/trace_event/heap_profiler_type_name_deduplicator.h45
-rw-r--r--base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc96
-rw-r--r--base/trace_event/malloc_dump_provider.cc378
-rw-r--r--base/trace_event/malloc_dump_provider.h69
-rw-r--r--base/trace_event/memory_allocator_dump.cc110
-rw-r--r--base/trace_event/memory_allocator_dump.h115
-rw-r--r--base/trace_event/memory_allocator_dump_guid.cc38
-rw-r--r--base/trace_event/memory_allocator_dump_guid.h51
-rw-r--r--base/trace_event/memory_allocator_dump_unittest.cc200
-rw-r--r--base/trace_event/memory_dump_manager.cc991
-rw-r--r--base/trace_event/memory_dump_manager.h354
-rw-r--r--base/trace_event/memory_dump_manager_unittest.cc1311
-rw-r--r--base/trace_event/memory_dump_provider.h82
-rw-r--r--base/trace_event/memory_dump_provider_info.cc43
-rw-r--r--base/trace_event/memory_dump_provider_info.h108
-rw-r--r--base/trace_event/memory_dump_request_args.cc68
-rw-r--r--base/trace_event/memory_dump_request_args.h119
-rw-r--r--base/trace_event/memory_dump_scheduler.cc328
-rw-r--r--base/trace_event/memory_dump_scheduler.h163
-rw-r--r--base/trace_event/memory_dump_scheduler_unittest.cc101
-rw-r--r--base/trace_event/memory_dump_session_state.cc37
-rw-r--r--base/trace_event/memory_dump_session_state.h77
-rw-r--r--base/trace_event/memory_infra_background_whitelist.cc258
-rw-r--r--base/trace_event/memory_infra_background_whitelist.h33
-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.cc367
-rw-r--r--base/trace_event/process_memory_dump.h222
-rw-r--r--base/trace_event/process_memory_dump_unittest.cc306
-rw-r--r--base/trace_event/process_memory_maps.cc77
-rw-r--r--base/trace_event/process_memory_maps.h72
-rw-r--r--base/trace_event/process_memory_totals.cc47
-rw-r--r--base/trace_event/process_memory_totals.h63
-rw-r--r--base/trace_event/trace_buffer.cc345
-rw-r--r--base/trace_event/trace_buffer.h130
-rw-r--r--base/trace_event/trace_category.h109
-rw-r--r--base/trace_event/trace_config.cc592
-rw-r--r--base/trace_event/trace_config.h300
-rw-r--r--base/trace_event/trace_config_category_filter.cc297
-rw-r--r--base/trace_event/trace_config_category_filter.h86
-rw-r--r--base/trace_event/trace_config_memory_test_util.h160
-rw-r--r--base/trace_event/trace_config_unittest.cc708
-rw-r--r--base/trace_event/trace_event.h38
-rw-r--r--base/trace_event/trace_event_argument.cc473
-rw-r--r--base/trace_event/trace_event_argument.h92
-rw-r--r--base/trace_event/trace_event_argument_unittest.cc165
-rw-r--r--base/trace_event/trace_event_filter.cc17
-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.cc490
-rw-r--r--base/trace_event/trace_event_impl.h184
-rw-r--r--base/trace_event/trace_event_memory_overhead.cc156
-rw-r--r--base/trace_event/trace_event_memory_overhead.h77
-rw-r--r--base/trace_event/trace_event_synthetic_delay.cc235
-rw-r--r--base/trace_event/trace_event_synthetic_delay.h164
-rw-r--r--base/trace_event/trace_event_synthetic_delay_unittest.cc157
-rw-r--r--base/trace_event/trace_event_system_stats_monitor.h76
-rw-r--r--base/trace_event/trace_event_unittest.cc3220
-rw-r--r--base/trace_event/trace_log.cc1749
-rw-r--r--base/trace_event/trace_log.h507
-rw-r--r--base/trace_event/trace_log_constants.cc26
-rw-r--r--libchrome_tools/patch/task_scheduler.patch31
-rw-r--r--libchrome_tools/patch/trace_event.patch191
101 files changed, 268 insertions, 23994 deletions
diff --git a/Android.bp b/Android.bp
index 55efa6a35f..b4bb28feb7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -191,8 +191,6 @@ libchromeCommonSrc = [
"base/process/process_metrics.cc",
"base/process/process_metrics_posix.cc",
"base/process/process_posix.cc",
- "base/profiler/scoped_profile.cc",
- "base/profiler/scoped_tracker.cc",
"base/profiler/tracked_time.cc",
"base/rand_util.cc",
"base/rand_util_posix.cc",
@@ -256,39 +254,6 @@ libchromeCommonSrc = [
"base/time/time_posix.cc",
"base/timer/elapsed_timer.cc",
"base/timer/timer.cc",
- "base/trace_event/category_registry.cc",
- "base/trace_event/event_name_filter.cc",
- "base/trace_event/heap_profiler_allocation_context.cc",
- "base/trace_event/heap_profiler_allocation_context_tracker.cc",
- "base/trace_event/heap_profiler_allocation_register.cc",
- "base/trace_event/heap_profiler_allocation_register_posix.cc",
- "base/trace_event/heap_profiler_event_filter.cc",
- "base/trace_event/heap_profiler_heap_dump_writer.cc",
- "base/trace_event/heap_profiler_stack_frame_deduplicator.cc",
- "base/trace_event/heap_profiler_type_name_deduplicator.cc",
- "base/trace_event/malloc_dump_provider.cc",
- "base/trace_event/memory_allocator_dump.cc",
- "base/trace_event/memory_allocator_dump_guid.cc",
- "base/trace_event/memory_dump_manager.cc",
- "base/trace_event/memory_dump_provider_info.cc",
- "base/trace_event/memory_dump_request_args.cc",
- "base/trace_event/memory_dump_scheduler.cc",
- "base/trace_event/memory_dump_session_state.cc",
- "base/trace_event/memory_infra_background_whitelist.cc",
- "base/trace_event/memory_usage_estimator.cc",
- "base/trace_event/process_memory_dump.cc",
- "base/trace_event/process_memory_maps.cc",
- "base/trace_event/process_memory_totals.cc",
- "base/trace_event/trace_buffer.cc",
- "base/trace_event/trace_config.cc",
- "base/trace_event/trace_config_category_filter.cc",
- "base/trace_event/trace_event_argument.cc",
- "base/trace_event/trace_event_filter.cc",
- "base/trace_event/trace_event_impl.cc",
- "base/trace_event/trace_event_memory_overhead.cc",
- "base/trace_event/trace_event_synthetic_delay.cc",
- "base/trace_event/trace_log.cc",
- "base/trace_event/trace_log_constants.cc",
"base/tracked_objects.cc",
"base/tracking_info.cc",
"base/unguessable_token.cc",
@@ -318,7 +283,6 @@ libchromeLinuxSrc = [
"base/files/file_path_watcher_linux.cc",
"base/files/file_util_linux.cc",
"base/memory/shared_memory_posix.cc",
- "base/memory/shared_memory_tracker.cc",
"base/posix/unix_domain_socket_linux.cc",
"base/process/internal_linux.cc",
"base/process/memory_linux.cc",
@@ -571,7 +535,6 @@ cc_test {
"base/test/test_simple_task_runner.cc",
"base/test/test_switches.cc",
"base/test/test_timeouts.cc",
- "base/test/trace_event_analyzer.cc",
"base/threading/non_thread_safe_unittest.cc",
"base/threading/platform_thread_unittest.cc",
"base/threading/simple_thread_unittest.cc",
@@ -587,19 +550,6 @@ cc_test {
"base/time/time_unittest.cc",
"base/timer/hi_res_timer_manager_unittest.cc",
"base/timer/timer_unittest.cc",
- "base/trace_event/event_name_filter_unittest.cc",
- "base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc",
- "base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc",
- "base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc",
- "base/trace_event/memory_allocator_dump_unittest.cc",
- "base/trace_event/memory_dump_manager_unittest.cc",
- "base/trace_event/memory_usage_estimator_unittest.cc",
- "base/trace_event/process_memory_dump_unittest.cc",
- "base/trace_event/trace_config_unittest.cc",
- "base/trace_event/trace_event_argument_unittest.cc",
- "base/trace_event/trace_event_filter_test_utils.cc",
- "base/trace_event/trace_event_synthetic_delay_unittest.cc",
- "base/trace_event/trace_event_unittest.cc",
"base/tracked_objects_unittest.cc",
"base/tuple_unittest.cc",
"base/values_unittest.cc",
diff --git a/base/memory/shared_memory_posix.cc b/base/memory/shared_memory_posix.cc
index 287e55d823..3443cd9b4a 100644
--- a/base/memory/shared_memory_posix.cc
+++ b/base/memory/shared_memory_posix.cc
@@ -15,7 +15,8 @@
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/memory/shared_memory_helper.h"
-#include "base/memory/shared_memory_tracker.h"
+// Unsupported in libchrome.
+// #include "base/memory/shared_memory_tracker.h"
#include "base/posix/eintr_wrapper.h"
#include "base/posix/safe_strerror.h"
#include "base/process/process_metrics.h"
@@ -290,7 +291,8 @@ bool SharedMemory::MapAt(off_t offset, size_t bytes) {
DCHECK_EQ(0U,
reinterpret_cast<uintptr_t>(memory_) &
(SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
- SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
+ // Unsupported in libchrome.
+ // SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
} else {
memory_ = NULL;
}
@@ -303,7 +305,8 @@ bool SharedMemory::Unmap() {
return false;
munmap(memory_, mapped_size_);
- SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
+ // Unsupported in libchrome.
+ // SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
memory_ = NULL;
mapped_size_ = 0;
return true;
diff --git a/base/memory/shared_memory_tracker.cc b/base/memory/shared_memory_tracker.cc
deleted file mode 100644
index 8613f59533..0000000000
--- a/base/memory/shared_memory_tracker.cc
+++ /dev/null
@@ -1,92 +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/memory/shared_memory_tracker.h"
-
-#include "base/memory/shared_memory.h"
-#include "base/strings/stringprintf.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/process_memory_dump.h"
-
-namespace base {
-
-SharedMemoryTracker::Usage::Usage() = default;
-
-SharedMemoryTracker::Usage::Usage(const Usage& rhs) = default;
-
-SharedMemoryTracker::Usage::~Usage() = default;
-
-// static
-SharedMemoryTracker* SharedMemoryTracker::GetInstance() {
- static SharedMemoryTracker* instance = new SharedMemoryTracker;
- return instance;
-}
-
-void SharedMemoryTracker::IncrementMemoryUsage(
- const SharedMemory& shared_memory) {
- Usage usage;
- // |shared_memory|'s unique ID must be generated here and it'd be too late at
- // OnMemoryDump. An ID is generated with a SharedMemoryHandle, but the handle
- // might already be closed at that time. Now IncrementMemoryUsage is called
- // just after mmap and the handle must live then. See the discussion at
- // crbug.com/604726#c30.
- SharedMemory::UniqueId id;
- if (!shared_memory.GetUniqueId(&id))
- return;
- usage.unique_id = id;
- usage.size = shared_memory.mapped_size();
- AutoLock hold(usages_lock_);
- usages_[&shared_memory] = usage;
-}
-
-void SharedMemoryTracker::DecrementMemoryUsage(
- const SharedMemory& shared_memory) {
- AutoLock hold(usages_lock_);
- usages_.erase(&shared_memory);
-}
-
-bool SharedMemoryTracker::OnMemoryDump(const trace_event::MemoryDumpArgs& args,
- trace_event::ProcessMemoryDump* pmd) {
- std::unordered_map<SharedMemory::UniqueId, size_t, SharedMemory::UniqueIdHash>
- sizes;
- {
- AutoLock hold(usages_lock_);
- for (const auto& usage : usages_)
- sizes[usage.second.unique_id] += usage.second.size;
- }
- for (auto& size : sizes) {
- const SharedMemory::UniqueId& id = size.first;
- std::string dump_name = StringPrintf("%s/%lld.%lld", "shared_memory",
- static_cast<long long>(id.first),
- static_cast<long long>(id.second));
- auto guid = trace_event::MemoryAllocatorDumpGuid(dump_name);
- trace_event::MemoryAllocatorDump* local_dump =
- pmd->CreateAllocatorDump(dump_name);
- // TODO(hajimehoshi): The size is not resident size but virtual size so far.
- // Fix this to record resident size.
- local_dump->AddScalar(trace_event::MemoryAllocatorDump::kNameSize,
- trace_event::MemoryAllocatorDump::kUnitsBytes,
- size.second);
- trace_event::MemoryAllocatorDump* global_dump =
- pmd->CreateSharedGlobalAllocatorDump(guid);
- global_dump->AddScalar(trace_event::MemoryAllocatorDump::kNameSize,
- trace_event::MemoryAllocatorDump::kUnitsBytes,
- size.second);
- // TOOD(hajimehoshi): Detect which the shared memory comes from browser,
- // renderer or GPU process.
- // TODO(hajimehoshi): Shared memory reported by GPU and discardable is
- // currently double-counted. Add ownership edges to avoid this.
- pmd->AddOwnershipEdge(local_dump->guid(), global_dump->guid());
- }
- return true;
-}
-
-SharedMemoryTracker::SharedMemoryTracker() {
- trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
- this, "SharedMemoryTracker", nullptr);
-}
-
-SharedMemoryTracker::~SharedMemoryTracker() = default;
-
-} // namespace
diff --git a/base/memory/shared_memory_tracker.h b/base/memory/shared_memory_tracker.h
deleted file mode 100644
index fe1a3dd392..0000000000
--- a/base/memory/shared_memory_tracker.h
+++ /dev/null
@@ -1,56 +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_MEMORY_SHARED_MEMORY_TRACKER_H_
-#define BASE_MEMORY_SHARED_MEMORY_TRACKER_H_
-
-#include "base/memory/shared_memory.h"
-#include "base/synchronization/lock.h"
-#include "base/trace_event/memory_dump_provider.h"
-
-namespace base {
-
-namespace trace_event {
-class ProcessMemoryDump;
-}
-
-// SharedMemoryTracker tracks shared memory usage.
-class BASE_EXPORT SharedMemoryTracker
- : public base::trace_event::MemoryDumpProvider {
- public:
- // Returns a singleton instance.
- static SharedMemoryTracker* GetInstance();
-
- // Records shared memory usage on mapping.
- void IncrementMemoryUsage(const SharedMemory& shared_memory);
-
- // Records shared memory usage on unmapping.
- void DecrementMemoryUsage(const SharedMemory& shared_memory);
-
- private:
- struct Usage {
- Usage();
- Usage(const Usage& rhs);
- ~Usage();
- SharedMemory::UniqueId unique_id;
- size_t size;
- };
-
- SharedMemoryTracker();
- ~SharedMemoryTracker() override;
-
- // base::trace_event::MemoryDumpProvider implementation.
- bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
- base::trace_event::ProcessMemoryDump* pmd) override;
-
- // Used to lock when |usages_| is modified or read.
- Lock usages_lock_;
- std::unordered_map<const SharedMemory*, Usage> usages_;
-
- DISALLOW_COPY_AND_ASSIGN(SharedMemoryTracker);
-};
-
-} // namespace base
-
-#endif // BASE_MEMORY_SHARED_MEMORY_TRACKER_H_
diff --git a/base/profiler/scoped_profile.cc b/base/profiler/scoped_profile.cc
deleted file mode 100644
index f06a8c6f5d..0000000000
--- a/base/profiler/scoped_profile.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2011 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/profiler/scoped_profile.h"
-
-#include "base/location.h"
-#include "base/tracked_objects.h"
-
-
-namespace tracked_objects {
-
-
-ScopedProfile::ScopedProfile(const Location& location, Mode mode)
- : birth_(NULL) {
- if (mode == DISABLED)
- return;
-
- birth_ = ThreadData::TallyABirthIfActive(location);
- if (!birth_)
- return;
-
- stopwatch_.Start();
-}
-
-ScopedProfile::~ScopedProfile() {
- if (!birth_)
- return;
-
- stopwatch_.Stop();
- ThreadData::TallyRunInAScopedRegionIfTracking(birth_, stopwatch_);
-}
-
-} // namespace tracked_objects
diff --git a/base/profiler/scoped_profile.h b/base/profiler/scoped_profile.h
deleted file mode 100644
index 4df6a1bc02..0000000000
--- a/base/profiler/scoped_profile.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) 2011 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_PROFILER_SCOPED_PROFILE_H_
-#define BASE_PROFILER_SCOPED_PROFILE_H_
-
-//------------------------------------------------------------------------------
-// ScopedProfile provides basic helper functions for profiling a short
-// region of code within a scope. It is separate from the related ThreadData
-// class so that it can be included without much other cruft, and provide the
-// macros listed below.
-
-#include "base/base_export.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/profiler/tracked_time.h"
-#include "base/trace_event/heap_profiler.h"
-#include "base/tracked_objects.h"
-
-// Two level indirection is required for correct macro substitution.
-#define PASTE_COUNTER_ON_NAME2(name, counter) name##counter
-#define PASTE_COUNTER_ON_NAME(name, counter) \
- PASTE_COUNTER_ON_NAME2(name, counter)
-
-#define COUNTER_BASED_VARIABLE_NAME_FOR_PROFILING \
- PASTE_COUNTER_ON_NAME(some_profiler_variable_, __COUNTER__)
-
-// Defines the containing scope as a profiled region. This allows developers to
-// profile their code and see results on their about:profiler page, as well as
-// on the UMA dashboard and heap profiler.
-#define TRACK_RUN_IN_THIS_SCOPED_REGION(dispatch_function_name) \
- const ::tracked_objects::Location& location = \
- FROM_HERE_WITH_EXPLICIT_FUNCTION(#dispatch_function_name); \
- TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION \
- COUNTER_BASED_VARIABLE_NAME_FOR_PROFILING(location.file_name()); \
- ::tracked_objects::ScopedProfile COUNTER_BASED_VARIABLE_NAME_FOR_PROFILING( \
- location, ::tracked_objects::ScopedProfile::ENABLED)
-
-// Same as TRACK_RUN_IN_THIS_SCOPED_REGION except that there's an extra param
-// which is concatenated with the function name for better filtering.
-#define TRACK_SCOPED_REGION(category_name, dispatch_function_name) \
- const ::tracked_objects::Location& location = \
- FROM_HERE_WITH_EXPLICIT_FUNCTION("[" category_name \
- "]" dispatch_function_name); \
- TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION \
- COUNTER_BASED_VARIABLE_NAME_FOR_PROFILING(location.file_name()); \
- ::tracked_objects::ScopedProfile COUNTER_BASED_VARIABLE_NAME_FOR_PROFILING( \
- location, ::tracked_objects::ScopedProfile::ENABLED)
-
-namespace tracked_objects {
-class Births;
-
-class BASE_EXPORT ScopedProfile {
- public:
- // Mode of operation. Specifies whether ScopedProfile should be a no-op or
- // needs to create and tally a task.
- enum Mode {
- DISABLED, // Do nothing.
- ENABLED // Create and tally a task.
- };
-
- ScopedProfile(const Location& location, Mode mode);
- ~ScopedProfile();
-
- private:
- Births* birth_; // Place in code where tracking started.
- TaskStopwatch stopwatch_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedProfile);
-};
-
-} // namespace tracked_objects
-
-#endif // BASE_PROFILER_SCOPED_PROFILE_H_
diff --git a/base/profiler/scoped_tracker.cc b/base/profiler/scoped_tracker.cc
deleted file mode 100644
index d15b7de6dc..0000000000
--- a/base/profiler/scoped_tracker.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2014 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/profiler/scoped_tracker.h"
-
-#include "base/bind.h"
-
-namespace tracked_objects {
-
-namespace {
-
-ScopedProfile::Mode g_scoped_profile_mode = ScopedProfile::DISABLED;
-
-} // namespace
-
-// static
-void ScopedTracker::Enable() {
- g_scoped_profile_mode = ScopedProfile::ENABLED;
-}
-
-ScopedTracker::ScopedTracker(const Location& location)
- : scoped_profile_(location, g_scoped_profile_mode) {
-}
-
-} // namespace tracked_objects
diff --git a/base/profiler/scoped_tracker.h b/base/profiler/scoped_tracker.h
deleted file mode 100644
index a61de9115c..0000000000
--- a/base/profiler/scoped_tracker.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2014 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_PROFILER_SCOPED_TRACKER_H_
-#define BASE_PROFILER_SCOPED_TRACKER_H_
-
-//------------------------------------------------------------------------------
-// Utilities for temporarily instrumenting code to dig into issues that were
-// found using profiler data.
-
-#include "base/base_export.h"
-#include "base/bind.h"
-#include "base/callback_forward.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/profiler/scoped_profile.h"
-
-namespace tracked_objects {
-
-// ScopedTracker instruments a region within the code if the instrumentation is
-// enabled. It can be used, for example, to find out if a source of jankiness is
-// inside the instrumented code region.
-// Details:
-// 1. This class creates a task (like ones created by PostTask calls or IPC
-// message handlers). This task can be seen in chrome://profiler and is sent as
-// a part of profiler data to the UMA server. See profiler_event.proto.
-// 2. That task's lifetime is same as the lifetime of the ScopedTracker
-// instance.
-// 3. The execution time associated with the task is the wallclock time between
-// its constructor and destructor, minus wallclock times of directly nested
-// tasks.
-// 4. Task creation that this class utilizes is highly optimized.
-// 5. The class doesn't create a task unless this was enabled for the current
-// process. Search for ScopedTracker::Enable for the current list of processes
-// and channels where it's activated.
-// 6. The class is designed for temporarily instrumenting code to find
-// performance problems, after which the instrumentation must be removed.
-class BASE_EXPORT ScopedTracker {
- public:
- ScopedTracker(const Location& location);
-
- // Enables instrumentation for the remainder of the current process' life. If
- // this function is not called, all profiler instrumentations are no-ops.
- static void Enable();
-
- // Augments a |callback| with provided |location|. This is useful for
- // instrumenting cases when we know that a jank is in a callback and there are
- // many possible callbacks, but they come from a relatively small number of
- // places. We can instrument these few places and at least know which one
- // passes the janky callback.
- template <typename P1>
- static base::Callback<void(P1)> TrackCallback(
- const Location& location,
- const base::Callback<void(P1)>& callback) {
- return base::Bind(&ScopedTracker::ExecuteAndTrackCallback<P1>, location,
- callback);
- }
-
- private:
- // Executes |callback|, augmenting it with provided |location|.
- template <typename P1>
- static void ExecuteAndTrackCallback(const Location& location,
- const base::Callback<void(P1)>& callback,
- P1 p1) {
- ScopedTracker tracking_profile(location);
- callback.Run(p1);
- }
-
- const ScopedProfile scoped_profile_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedTracker);
-};
-
-} // namespace tracked_objects
-
-#endif // BASE_PROFILER_SCOPED_TRACKER_H_
diff --git a/base/test/test_pending_task.cc b/base/test/test_pending_task.cc
index 3f71a9988f..fcc48a8980 100644
--- a/base/test/test_pending_task.cc
+++ b/base/test/test_pending_task.cc
@@ -38,6 +38,8 @@ bool TestPendingTask::ShouldRunBefore(const TestPendingTask& other) const {
TestPendingTask::~TestPendingTask() {}
+// Unsupported in libchrome.
+#if 0
void TestPendingTask::AsValueInto(base::trace_event::TracedValue* state) const {
state->SetInteger("run_at", GetTimeToRun().ToInternalValue());
state->SetString("posting_function", location.ToString());
@@ -61,10 +63,14 @@ TestPendingTask::AsValue() const {
AsValueInto(state.get());
return std::move(state);
}
+#endif
std::string TestPendingTask::ToString() const {
std::string output("TestPendingTask(");
+// Unsupported in libchrome.
+#if 0
AsValue()->AppendAsTraceFormat(&output);
+#endif
output += ")";
return output;
}
diff --git a/base/test/test_pending_task.h b/base/test/test_pending_task.h
index 52ca592f25..f8e8c798b8 100644
--- a/base/test/test_pending_task.h
+++ b/base/test/test_pending_task.h
@@ -10,7 +10,8 @@
#include "base/callback.h"
#include "base/location.h"
#include "base/time/time.h"
-#include "base/trace_event/trace_event_argument.h"
+// Unsupported in libchrome.
+// #include "base/trace_event/trace_event_argument.h"
namespace base {
@@ -58,10 +59,13 @@ struct TestPendingTask {
TimeDelta delay;
TestNestability nestability;
+// Unsupported in libchrome.
+#if 0
// Functions for using test pending task with tracing, useful in unit
// testing.
void AsValueInto(base::trace_event::TracedValue* state) const;
std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+#endif
std::string ToString() const;
private:
diff --git a/base/test/trace_event_analyzer.cc b/base/test/trace_event_analyzer.cc
deleted file mode 100644
index e61337cccb..0000000000
--- a/base/test/trace_event_analyzer.cc
+++ /dev/null
@@ -1,1027 +0,0 @@
-// Copyright (c) 2012 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/test/trace_event_analyzer.h"
-
-#include <math.h>
-
-#include <algorithm>
-#include <memory>
-#include <set>
-
-#include "base/json/json_reader.h"
-#include "base/strings/pattern.h"
-#include "base/values.h"
-
-namespace trace_analyzer {
-
-// TraceEvent
-
-TraceEvent::TraceEvent()
- : thread(0, 0),
- timestamp(0),
- duration(0),
- phase(TRACE_EVENT_PHASE_BEGIN),
- other_event(NULL) {
-}
-
-TraceEvent::TraceEvent(TraceEvent&& other) = default;
-
-TraceEvent::~TraceEvent() {
-}
-
-TraceEvent& TraceEvent::operator=(TraceEvent&& rhs) = default;
-
-bool TraceEvent::SetFromJSON(const base::Value* event_value) {
- if (event_value->GetType() != base::Value::Type::DICTIONARY) {
- LOG(ERROR) << "Value must be Type::DICTIONARY";
- return false;
- }
- const base::DictionaryValue* dictionary =
- static_cast<const base::DictionaryValue*>(event_value);
-
- std::string phase_str;
- const base::DictionaryValue* args = NULL;
-
- if (!dictionary->GetString("ph", &phase_str)) {
- LOG(ERROR) << "ph is missing from TraceEvent JSON";
- return false;
- }
-
- phase = *phase_str.data();
-
- bool may_have_duration = (phase == TRACE_EVENT_PHASE_COMPLETE);
- bool require_origin = (phase != TRACE_EVENT_PHASE_METADATA);
- bool require_id = (phase == TRACE_EVENT_PHASE_ASYNC_BEGIN ||
- phase == TRACE_EVENT_PHASE_ASYNC_STEP_INTO ||
- phase == TRACE_EVENT_PHASE_ASYNC_STEP_PAST ||
- phase == TRACE_EVENT_PHASE_MEMORY_DUMP ||
- phase == TRACE_EVENT_PHASE_ENTER_CONTEXT ||
- phase == TRACE_EVENT_PHASE_LEAVE_CONTEXT ||
- phase == TRACE_EVENT_PHASE_CREATE_OBJECT ||
- phase == TRACE_EVENT_PHASE_DELETE_OBJECT ||
- phase == TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ||
- phase == TRACE_EVENT_PHASE_ASYNC_END);
-
- if (require_origin && !dictionary->GetInteger("pid", &thread.process_id)) {
- LOG(ERROR) << "pid is missing from TraceEvent JSON";
- return false;
- }
- if (require_origin && !dictionary->GetInteger("tid", &thread.thread_id)) {
- LOG(ERROR) << "tid is missing from TraceEvent JSON";
- return false;
- }
- if (require_origin && !dictionary->GetDouble("ts", &timestamp)) {
- LOG(ERROR) << "ts is missing from TraceEvent JSON";
- return false;
- }
- if (may_have_duration) {
- dictionary->GetDouble("dur", &duration);
- }
- if (!dictionary->GetString("cat", &category)) {
- LOG(ERROR) << "cat is missing from TraceEvent JSON";
- return false;
- }
- if (!dictionary->GetString("name", &name)) {
- LOG(ERROR) << "name is missing from TraceEvent JSON";
- return false;
- }
- if (!dictionary->GetDictionary("args", &args)) {
- LOG(ERROR) << "args is missing from TraceEvent JSON";
- return false;
- }
- if (require_id && !dictionary->GetString("id", &id)) {
- LOG(ERROR) << "id is missing from ASYNC_BEGIN/ASYNC_END TraceEvent JSON";
- return false;
- }
-
- // For each argument, copy the type and create a trace_analyzer::TraceValue.
- for (base::DictionaryValue::Iterator it(*args); !it.IsAtEnd();
- it.Advance()) {
- std::string str;
- bool boolean = false;
- int int_num = 0;
- double double_num = 0.0;
- if (it.value().GetAsString(&str)) {
- arg_strings[it.key()] = str;
- } else if (it.value().GetAsInteger(&int_num)) {
- arg_numbers[it.key()] = static_cast<double>(int_num);
- } else if (it.value().GetAsBoolean(&boolean)) {
- arg_numbers[it.key()] = static_cast<double>(boolean ? 1 : 0);
- } else if (it.value().GetAsDouble(&double_num)) {
- arg_numbers[it.key()] = double_num;
- }
- // Record all arguments as values.
- arg_values[it.key()] = it.value().CreateDeepCopy();
- }
-
- return true;
-}
-
-double TraceEvent::GetAbsTimeToOtherEvent() const {
- return fabs(other_event->timestamp - timestamp);
-}
-
-bool TraceEvent::GetArgAsString(const std::string& name,
- std::string* arg) const {
- const auto it = arg_strings.find(name);
- if (it != arg_strings.end()) {
- *arg = it->second;
- return true;
- }
- return false;
-}
-
-bool TraceEvent::GetArgAsNumber(const std::string& name,
- double* arg) const {
- const auto it = arg_numbers.find(name);
- if (it != arg_numbers.end()) {
- *arg = it->second;
- return true;
- }
- return false;
-}
-
-bool TraceEvent::GetArgAsValue(const std::string& name,
- std::unique_ptr<base::Value>* arg) const {
- const auto it = arg_values.find(name);
- if (it != arg_values.end()) {
- *arg = it->second->CreateDeepCopy();
- return true;
- }
- return false;
-}
-
-bool TraceEvent::HasStringArg(const std::string& name) const {
- return (arg_strings.find(name) != arg_strings.end());
-}
-
-bool TraceEvent::HasNumberArg(const std::string& name) const {
- return (arg_numbers.find(name) != arg_numbers.end());
-}
-
-bool TraceEvent::HasArg(const std::string& name) const {
- return (arg_values.find(name) != arg_values.end());
-}
-
-std::string TraceEvent::GetKnownArgAsString(const std::string& name) const {
- std::string arg_string;
- bool result = GetArgAsString(name, &arg_string);
- DCHECK(result);
- return arg_string;
-}
-
-double TraceEvent::GetKnownArgAsDouble(const std::string& name) const {
- double arg_double = 0;
- bool result = GetArgAsNumber(name, &arg_double);
- DCHECK(result);
- return arg_double;
-}
-
-int TraceEvent::GetKnownArgAsInt(const std::string& name) const {
- double arg_double = 0;
- bool result = GetArgAsNumber(name, &arg_double);
- DCHECK(result);
- return static_cast<int>(arg_double);
-}
-
-bool TraceEvent::GetKnownArgAsBool(const std::string& name) const {
- double arg_double = 0;
- bool result = GetArgAsNumber(name, &arg_double);
- DCHECK(result);
- return (arg_double != 0.0);
-}
-
-std::unique_ptr<base::Value> TraceEvent::GetKnownArgAsValue(
- const std::string& name) const {
- std::unique_ptr<base::Value> arg_value;
- bool result = GetArgAsValue(name, &arg_value);
- DCHECK(result);
- return arg_value;
-}
-
-// QueryNode
-
-QueryNode::QueryNode(const Query& query) : query_(query) {
-}
-
-QueryNode::~QueryNode() {
-}
-
-// Query
-
-Query::Query(TraceEventMember member)
- : type_(QUERY_EVENT_MEMBER),
- operator_(OP_INVALID),
- member_(member),
- number_(0),
- is_pattern_(false) {
-}
-
-Query::Query(TraceEventMember member, const std::string& arg_name)
- : type_(QUERY_EVENT_MEMBER),
- operator_(OP_INVALID),
- member_(member),
- number_(0),
- string_(arg_name),
- is_pattern_(false) {
-}
-
-Query::Query(const Query& query)
- : type_(query.type_),
- operator_(query.operator_),
- left_(query.left_),
- right_(query.right_),
- member_(query.member_),
- number_(query.number_),
- string_(query.string_),
- is_pattern_(query.is_pattern_) {
-}
-
-Query::~Query() {
-}
-
-Query Query::String(const std::string& str) {
- return Query(str);
-}
-
-Query Query::Double(double num) {
- return Query(num);
-}
-
-Query Query::Int(int32_t num) {
- return Query(static_cast<double>(num));
-}
-
-Query Query::Uint(uint32_t num) {
- return Query(static_cast<double>(num));
-}
-
-Query Query::Bool(bool boolean) {
- return Query(boolean ? 1.0 : 0.0);
-}
-
-Query Query::Phase(char phase) {
- return Query(static_cast<double>(phase));
-}
-
-Query Query::Pattern(const std::string& pattern) {
- Query query(pattern);
- query.is_pattern_ = true;
- return query;
-}
-
-bool Query::Evaluate(const TraceEvent& event) const {
- // First check for values that can convert to bool.
-
- // double is true if != 0:
- double bool_value = 0.0;
- bool is_bool = GetAsDouble(event, &bool_value);
- if (is_bool)
- return (bool_value != 0.0);
-
- // string is true if it is non-empty:
- std::string str_value;
- bool is_str = GetAsString(event, &str_value);
- if (is_str)
- return !str_value.empty();
-
- DCHECK_EQ(QUERY_BOOLEAN_OPERATOR, type_)
- << "Invalid query: missing boolean expression";
- DCHECK(left_.get());
- DCHECK(right_.get() || is_unary_operator());
-
- if (is_comparison_operator()) {
- DCHECK(left().is_value() && right().is_value())
- << "Invalid query: comparison operator used between event member and "
- "value.";
- bool compare_result = false;
- if (CompareAsDouble(event, &compare_result))
- return compare_result;
- if (CompareAsString(event, &compare_result))
- return compare_result;
- return false;
- }
- // It's a logical operator.
- switch (operator_) {
- case OP_AND:
- return left().Evaluate(event) && right().Evaluate(event);
- case OP_OR:
- return left().Evaluate(event) || right().Evaluate(event);
- case OP_NOT:
- return !left().Evaluate(event);
- default:
- NOTREACHED();
- return false;
- }
-}
-
-bool Query::CompareAsDouble(const TraceEvent& event, bool* result) const {
- double lhs, rhs;
- if (!left().GetAsDouble(event, &lhs) || !right().GetAsDouble(event, &rhs))
- return false;
- switch (operator_) {
- case OP_EQ:
- *result = (lhs == rhs);
- return true;
- case OP_NE:
- *result = (lhs != rhs);
- return true;
- case OP_LT:
- *result = (lhs < rhs);
- return true;
- case OP_LE:
- *result = (lhs <= rhs);
- return true;
- case OP_GT:
- *result = (lhs > rhs);
- return true;
- case OP_GE:
- *result = (lhs >= rhs);
- return true;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-bool Query::CompareAsString(const TraceEvent& event, bool* result) const {
- std::string lhs, rhs;
- if (!left().GetAsString(event, &lhs) || !right().GetAsString(event, &rhs))
- return false;
- switch (operator_) {
- case OP_EQ:
- if (right().is_pattern_)
- *result = base::MatchPattern(lhs, rhs);
- else if (left().is_pattern_)
- *result = base::MatchPattern(rhs, lhs);
- else
- *result = (lhs == rhs);
- return true;
- case OP_NE:
- if (right().is_pattern_)
- *result = !base::MatchPattern(lhs, rhs);
- else if (left().is_pattern_)
- *result = !base::MatchPattern(rhs, lhs);
- else
- *result = (lhs != rhs);
- return true;
- case OP_LT:
- *result = (lhs < rhs);
- return true;
- case OP_LE:
- *result = (lhs <= rhs);
- return true;
- case OP_GT:
- *result = (lhs > rhs);
- return true;
- case OP_GE:
- *result = (lhs >= rhs);
- return true;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-bool Query::EvaluateArithmeticOperator(const TraceEvent& event,
- double* num) const {
- DCHECK_EQ(QUERY_ARITHMETIC_OPERATOR, type_);
- DCHECK(left_.get());
- DCHECK(right_.get() || is_unary_operator());
-
- double lhs = 0, rhs = 0;
- if (!left().GetAsDouble(event, &lhs))
- return false;
- if (!is_unary_operator() && !right().GetAsDouble(event, &rhs))
- return false;
-
- switch (operator_) {
- case OP_ADD:
- *num = lhs + rhs;
- return true;
- case OP_SUB:
- *num = lhs - rhs;
- return true;
- case OP_MUL:
- *num = lhs * rhs;
- return true;
- case OP_DIV:
- *num = lhs / rhs;
- return true;
- case OP_MOD:
- *num = static_cast<double>(static_cast<int64_t>(lhs) %
- static_cast<int64_t>(rhs));
- return true;
- case OP_NEGATE:
- *num = -lhs;
- return true;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-bool Query::GetAsDouble(const TraceEvent& event, double* num) const {
- switch (type_) {
- case QUERY_ARITHMETIC_OPERATOR:
- return EvaluateArithmeticOperator(event, num);
- case QUERY_EVENT_MEMBER:
- return GetMemberValueAsDouble(event, num);
- case QUERY_NUMBER:
- *num = number_;
- return true;
- default:
- return false;
- }
-}
-
-bool Query::GetAsString(const TraceEvent& event, std::string* str) const {
- switch (type_) {
- case QUERY_EVENT_MEMBER:
- return GetMemberValueAsString(event, str);
- case QUERY_STRING:
- *str = string_;
- return true;
- default:
- return false;
- }
-}
-
-const TraceEvent* Query::SelectTargetEvent(const TraceEvent* event,
- TraceEventMember member) {
- if (member >= OTHER_FIRST_MEMBER && member <= OTHER_LAST_MEMBER) {
- return event->other_event;
- } else if (member >= PREV_FIRST_MEMBER && member <= PREV_LAST_MEMBER) {
- return event->prev_event;
- } else {
- return event;
- }
-}
-
-bool Query::GetMemberValueAsDouble(const TraceEvent& event,
- double* num) const {
- DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
-
- // This could be a request for a member of |event| or a member of |event|'s
- // associated previous or next event. Store the target event in the_event:
- const TraceEvent* the_event = SelectTargetEvent(&event, member_);
-
- // Request for member of associated event, but there is no associated event.
- if (!the_event)
- return false;
-
- switch (member_) {
- case EVENT_PID:
- case OTHER_PID:
- case PREV_PID:
- *num = static_cast<double>(the_event->thread.process_id);
- return true;
- case EVENT_TID:
- case OTHER_TID:
- case PREV_TID:
- *num = static_cast<double>(the_event->thread.thread_id);
- return true;
- case EVENT_TIME:
- case OTHER_TIME:
- case PREV_TIME:
- *num = the_event->timestamp;
- return true;
- case EVENT_DURATION:
- if (!the_event->has_other_event())
- return false;
- *num = the_event->GetAbsTimeToOtherEvent();
- return true;
- case EVENT_COMPLETE_DURATION:
- if (the_event->phase != TRACE_EVENT_PHASE_COMPLETE)
- return false;
- *num = the_event->duration;
- return true;
- case EVENT_PHASE:
- case OTHER_PHASE:
- case PREV_PHASE:
- *num = static_cast<double>(the_event->phase);
- return true;
- case EVENT_HAS_STRING_ARG:
- case OTHER_HAS_STRING_ARG:
- case PREV_HAS_STRING_ARG:
- *num = (the_event->HasStringArg(string_) ? 1.0 : 0.0);
- return true;
- case EVENT_HAS_NUMBER_ARG:
- case OTHER_HAS_NUMBER_ARG:
- case PREV_HAS_NUMBER_ARG:
- *num = (the_event->HasNumberArg(string_) ? 1.0 : 0.0);
- return true;
- case EVENT_ARG:
- case OTHER_ARG:
- case PREV_ARG: {
- // Search for the argument name and return its value if found.
- std::map<std::string, double>::const_iterator num_i =
- the_event->arg_numbers.find(string_);
- if (num_i == the_event->arg_numbers.end())
- return false;
- *num = num_i->second;
- return true;
- }
- case EVENT_HAS_OTHER:
- // return 1.0 (true) if the other event exists
- *num = event.other_event ? 1.0 : 0.0;
- return true;
- case EVENT_HAS_PREV:
- *num = event.prev_event ? 1.0 : 0.0;
- return true;
- default:
- return false;
- }
-}
-
-bool Query::GetMemberValueAsString(const TraceEvent& event,
- std::string* str) const {
- DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
-
- // This could be a request for a member of |event| or a member of |event|'s
- // associated previous or next event. Store the target event in the_event:
- const TraceEvent* the_event = SelectTargetEvent(&event, member_);
-
- // Request for member of associated event, but there is no associated event.
- if (!the_event)
- return false;
-
- switch (member_) {
- case EVENT_CATEGORY:
- case OTHER_CATEGORY:
- case PREV_CATEGORY:
- *str = the_event->category;
- return true;
- case EVENT_NAME:
- case OTHER_NAME:
- case PREV_NAME:
- *str = the_event->name;
- return true;
- case EVENT_ID:
- case OTHER_ID:
- case PREV_ID:
- *str = the_event->id;
- return true;
- case EVENT_ARG:
- case OTHER_ARG:
- case PREV_ARG: {
- // Search for the argument name and return its value if found.
- std::map<std::string, std::string>::const_iterator str_i =
- the_event->arg_strings.find(string_);
- if (str_i == the_event->arg_strings.end())
- return false;
- *str = str_i->second;
- return true;
- }
- default:
- return false;
- }
-}
-
-Query::Query(const std::string& str)
- : type_(QUERY_STRING),
- operator_(OP_INVALID),
- member_(EVENT_INVALID),
- number_(0),
- string_(str),
- is_pattern_(false) {
-}
-
-Query::Query(double num)
- : type_(QUERY_NUMBER),
- operator_(OP_INVALID),
- member_(EVENT_INVALID),
- number_(num),
- is_pattern_(false) {
-}
-const Query& Query::left() const {
- return left_->query();
-}
-
-const Query& Query::right() const {
- return right_->query();
-}
-
-Query Query::operator==(const Query& rhs) const {
- return Query(*this, rhs, OP_EQ);
-}
-
-Query Query::operator!=(const Query& rhs) const {
- return Query(*this, rhs, OP_NE);
-}
-
-Query Query::operator<(const Query& rhs) const {
- return Query(*this, rhs, OP_LT);
-}
-
-Query Query::operator<=(const Query& rhs) const {
- return Query(*this, rhs, OP_LE);
-}
-
-Query Query::operator>(const Query& rhs) const {
- return Query(*this, rhs, OP_GT);
-}
-
-Query Query::operator>=(const Query& rhs) const {
- return Query(*this, rhs, OP_GE);
-}
-
-Query Query::operator&&(const Query& rhs) const {
- return Query(*this, rhs, OP_AND);
-}
-
-Query Query::operator||(const Query& rhs) const {
- return Query(*this, rhs, OP_OR);
-}
-
-Query Query::operator!() const {
- return Query(*this, OP_NOT);
-}
-
-Query Query::operator+(const Query& rhs) const {
- return Query(*this, rhs, OP_ADD);
-}
-
-Query Query::operator-(const Query& rhs) const {
- return Query(*this, rhs, OP_SUB);
-}
-
-Query Query::operator*(const Query& rhs) const {
- return Query(*this, rhs, OP_MUL);
-}
-
-Query Query::operator/(const Query& rhs) const {
- return Query(*this, rhs, OP_DIV);
-}
-
-Query Query::operator%(const Query& rhs) const {
- return Query(*this, rhs, OP_MOD);
-}
-
-Query Query::operator-() const {
- return Query(*this, OP_NEGATE);
-}
-
-
-Query::Query(const Query& left, const Query& right, Operator binary_op)
- : operator_(binary_op),
- left_(new QueryNode(left)),
- right_(new QueryNode(right)),
- member_(EVENT_INVALID),
- number_(0) {
- type_ = (binary_op < OP_ADD ?
- QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
-}
-
-Query::Query(const Query& left, Operator unary_op)
- : operator_(unary_op),
- left_(new QueryNode(left)),
- member_(EVENT_INVALID),
- number_(0) {
- type_ = (unary_op < OP_ADD ?
- QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
-}
-
-namespace {
-
-// Search |events| for |query| and add matches to |output|.
-size_t FindMatchingEvents(const std::vector<TraceEvent>& events,
- const Query& query,
- TraceEventVector* output,
- bool ignore_metadata_events) {
- for (size_t i = 0; i < events.size(); ++i) {
- if (ignore_metadata_events && events[i].phase == TRACE_EVENT_PHASE_METADATA)
- continue;
- if (query.Evaluate(events[i]))
- output->push_back(&events[i]);
- }
- return output->size();
-}
-
-bool ParseEventsFromJson(const std::string& json,
- std::vector<TraceEvent>* output) {
- std::unique_ptr<base::Value> root = base::JSONReader::Read(json);
-
- base::ListValue* root_list = NULL;
- if (!root.get() || !root->GetAsList(&root_list))
- return false;
-
- for (size_t i = 0; i < root_list->GetSize(); ++i) {
- base::Value* item = NULL;
- if (root_list->Get(i, &item)) {
- TraceEvent event;
- if (event.SetFromJSON(item))
- output->push_back(std::move(event));
- else
- return false;
- }
- }
-
- return true;
-}
-
-} // namespace
-
-// TraceAnalyzer
-
-TraceAnalyzer::TraceAnalyzer()
- : ignore_metadata_events_(false),
- allow_assocation_changes_(true) {}
-
-TraceAnalyzer::~TraceAnalyzer() {
-}
-
-// static
-TraceAnalyzer* TraceAnalyzer::Create(const std::string& json_events) {
- std::unique_ptr<TraceAnalyzer> analyzer(new TraceAnalyzer());
- if (analyzer->SetEvents(json_events))
- return analyzer.release();
- return NULL;
-}
-
-bool TraceAnalyzer::SetEvents(const std::string& json_events) {
- raw_events_.clear();
- if (!ParseEventsFromJson(json_events, &raw_events_))
- return false;
- std::stable_sort(raw_events_.begin(), raw_events_.end());
- ParseMetadata();
- return true;
-}
-
-void TraceAnalyzer::AssociateBeginEndEvents() {
- using trace_analyzer::Query;
-
- Query begin(Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN));
- Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_END));
- Query match(Query::EventName() == Query::OtherName() &&
- Query::EventCategory() == Query::OtherCategory() &&
- Query::EventTid() == Query::OtherTid() &&
- Query::EventPid() == Query::OtherPid());
-
- AssociateEvents(begin, end, match);
-}
-
-void TraceAnalyzer::AssociateAsyncBeginEndEvents(bool match_pid) {
- using trace_analyzer::Query;
-
- Query begin(
- Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN) ||
- Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
- Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
- Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_END) ||
- Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
- Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
- Query match(Query::EventCategory() == Query::OtherCategory() &&
- Query::EventId() == Query::OtherId());
-
- if (match_pid) {
- match = match && Query::EventPid() == Query::OtherPid();
- }
-
- AssociateEvents(begin, end, match);
-}
-
-void TraceAnalyzer::AssociateEvents(const Query& first,
- const Query& second,
- const Query& match) {
- DCHECK(allow_assocation_changes_)
- << "AssociateEvents not allowed after FindEvents";
-
- // Search for matching begin/end event pairs. When a matching end is found,
- // it is associated with the begin event.
- std::vector<TraceEvent*> begin_stack;
- for (size_t event_index = 0; event_index < raw_events_.size();
- ++event_index) {
-
- TraceEvent& this_event = raw_events_[event_index];
-
- if (second.Evaluate(this_event)) {
- // Search stack for matching begin, starting from end.
- for (int stack_index = static_cast<int>(begin_stack.size()) - 1;
- stack_index >= 0; --stack_index) {
- TraceEvent& begin_event = *begin_stack[stack_index];
-
- // Temporarily set other to test against the match query.
- const TraceEvent* other_backup = begin_event.other_event;
- begin_event.other_event = &this_event;
- if (match.Evaluate(begin_event)) {
- // Found a matching begin/end pair.
- // Set the associated previous event
- this_event.prev_event = &begin_event;
- // Erase the matching begin event index from the stack.
- begin_stack.erase(begin_stack.begin() + stack_index);
- break;
- }
-
- // Not a match, restore original other and continue.
- begin_event.other_event = other_backup;
- }
- }
- // Even if this_event is a |second| event that has matched an earlier
- // |first| event, it can still also be a |first| event and be associated
- // with a later |second| event.
- if (first.Evaluate(this_event)) {
- begin_stack.push_back(&this_event);
- }
- }
-}
-
-void TraceAnalyzer::MergeAssociatedEventArgs() {
- for (size_t i = 0; i < raw_events_.size(); ++i) {
- // Merge all associated events with the first event.
- const TraceEvent* other = raw_events_[i].other_event;
- // Avoid looping by keeping set of encountered TraceEvents.
- std::set<const TraceEvent*> encounters;
- encounters.insert(&raw_events_[i]);
- while (other && encounters.find(other) == encounters.end()) {
- encounters.insert(other);
- raw_events_[i].arg_numbers.insert(
- other->arg_numbers.begin(),
- other->arg_numbers.end());
- raw_events_[i].arg_strings.insert(
- other->arg_strings.begin(),
- other->arg_strings.end());
- other = other->other_event;
- }
- }
-}
-
-size_t TraceAnalyzer::FindEvents(const Query& query, TraceEventVector* output) {
- allow_assocation_changes_ = false;
- output->clear();
- return FindMatchingEvents(
- raw_events_, query, output, ignore_metadata_events_);
-}
-
-const TraceEvent* TraceAnalyzer::FindFirstOf(const Query& query) {
- TraceEventVector output;
- if (FindEvents(query, &output) > 0)
- return output.front();
- return NULL;
-}
-
-const TraceEvent* TraceAnalyzer::FindLastOf(const Query& query) {
- TraceEventVector output;
- if (FindEvents(query, &output) > 0)
- return output.back();
- return NULL;
-}
-
-const std::string& TraceAnalyzer::GetThreadName(
- const TraceEvent::ProcessThreadID& thread) {
- // If thread is not found, just add and return empty string.
- return thread_names_[thread];
-}
-
-void TraceAnalyzer::ParseMetadata() {
- for (size_t i = 0; i < raw_events_.size(); ++i) {
- TraceEvent& this_event = raw_events_[i];
- // Check for thread name metadata.
- if (this_event.phase != TRACE_EVENT_PHASE_METADATA ||
- this_event.name != "thread_name")
- continue;
- std::map<std::string, std::string>::const_iterator string_it =
- this_event.arg_strings.find("name");
- if (string_it != this_event.arg_strings.end())
- thread_names_[this_event.thread] = string_it->second;
- }
-}
-
-// TraceEventVector utility functions.
-
-bool GetRateStats(const TraceEventVector& events,
- RateStats* stats,
- const RateStatsOptions* options) {
- DCHECK(stats);
- // Need at least 3 events to calculate rate stats.
- const size_t kMinEvents = 3;
- if (events.size() < kMinEvents) {
- LOG(ERROR) << "Not enough events: " << events.size();
- return false;
- }
-
- std::vector<double> deltas;
- size_t num_deltas = events.size() - 1;
- for (size_t i = 0; i < num_deltas; ++i) {
- double delta = events.at(i + 1)->timestamp - events.at(i)->timestamp;
- if (delta < 0.0) {
- LOG(ERROR) << "Events are out of order";
- return false;
- }
- deltas.push_back(delta);
- }
-
- std::sort(deltas.begin(), deltas.end());
-
- if (options) {
- if (options->trim_min + options->trim_max > events.size() - kMinEvents) {
- LOG(ERROR) << "Attempt to trim too many events";
- return false;
- }
- deltas.erase(deltas.begin(), deltas.begin() + options->trim_min);
- deltas.erase(deltas.end() - options->trim_max, deltas.end());
- }
-
- num_deltas = deltas.size();
- double delta_sum = 0.0;
- for (size_t i = 0; i < num_deltas; ++i)
- delta_sum += deltas[i];
-
- stats->min_us = *std::min_element(deltas.begin(), deltas.end());
- stats->max_us = *std::max_element(deltas.begin(), deltas.end());
- stats->mean_us = delta_sum / static_cast<double>(num_deltas);
-
- double sum_mean_offsets_squared = 0.0;
- for (size_t i = 0; i < num_deltas; ++i) {
- double offset = fabs(deltas[i] - stats->mean_us);
- sum_mean_offsets_squared += offset * offset;
- }
- stats->standard_deviation_us =
- sqrt(sum_mean_offsets_squared / static_cast<double>(num_deltas - 1));
-
- return true;
-}
-
-bool FindFirstOf(const TraceEventVector& events,
- const Query& query,
- size_t position,
- size_t* return_index) {
- DCHECK(return_index);
- for (size_t i = position; i < events.size(); ++i) {
- if (query.Evaluate(*events[i])) {
- *return_index = i;
- return true;
- }
- }
- return false;
-}
-
-bool FindLastOf(const TraceEventVector& events,
- const Query& query,
- size_t position,
- size_t* return_index) {
- DCHECK(return_index);
- for (size_t i = std::min(position + 1, events.size()); i != 0; --i) {
- if (query.Evaluate(*events[i - 1])) {
- *return_index = i - 1;
- return true;
- }
- }
- return false;
-}
-
-bool FindClosest(const TraceEventVector& events,
- const Query& query,
- size_t position,
- size_t* return_closest,
- size_t* return_second_closest) {
- DCHECK(return_closest);
- if (events.empty() || position >= events.size())
- return false;
- size_t closest = events.size();
- size_t second_closest = events.size();
- for (size_t i = 0; i < events.size(); ++i) {
- if (!query.Evaluate(*events.at(i)))
- continue;
- if (closest == events.size()) {
- closest = i;
- continue;
- }
- if (fabs(events.at(i)->timestamp - events.at(position)->timestamp) <
- fabs(events.at(closest)->timestamp - events.at(position)->timestamp)) {
- second_closest = closest;
- closest = i;
- } else if (second_closest == events.size()) {
- second_closest = i;
- }
- }
-
- if (closest < events.size() &&
- (!return_second_closest || second_closest < events.size())) {
- *return_closest = closest;
- if (return_second_closest)
- *return_second_closest = second_closest;
- return true;
- }
-
- return false;
-}
-
-size_t CountMatches(const TraceEventVector& events,
- const Query& query,
- size_t begin_position,
- size_t end_position) {
- if (begin_position >= events.size())
- return 0u;
- end_position = (end_position < events.size()) ? end_position : events.size();
- size_t count = 0u;
- for (size_t i = begin_position; i < end_position; ++i) {
- if (query.Evaluate(*events.at(i)))
- ++count;
- }
- return count;
-}
-
-} // namespace trace_analyzer
diff --git a/base/test/trace_event_analyzer.h b/base/test/trace_event_analyzer.h
deleted file mode 100644
index e43a525644..0000000000
--- a/base/test/trace_event_analyzer.h
+++ /dev/null
@@ -1,810 +0,0 @@
-// Copyright (c) 2012 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.
-
-// Use trace_analyzer::Query and trace_analyzer::TraceAnalyzer to search for
-// specific trace events that were generated by the trace_event.h API.
-//
-// Basic procedure:
-// - Get trace events JSON string from base::trace_event::TraceLog.
-// - Create TraceAnalyzer with JSON string.
-// - Call TraceAnalyzer::AssociateBeginEndEvents (optional).
-// - Call TraceAnalyzer::AssociateEvents (zero or more times).
-// - Call TraceAnalyzer::FindEvents with queries to find specific events.
-//
-// A Query is a boolean expression tree that evaluates to true or false for a
-// given trace event. Queries can be combined into a tree using boolean,
-// arithmetic and comparison operators that refer to data of an individual trace
-// event.
-//
-// The events are returned as trace_analyzer::TraceEvent objects.
-// TraceEvent contains a single trace event's data, as well as a pointer to
-// a related trace event. The related trace event is typically the matching end
-// of a begin event or the matching begin of an end event.
-//
-// The following examples use this basic setup code to construct TraceAnalyzer
-// with the json trace string retrieved from TraceLog and construct an event
-// vector for retrieving events:
-//
-// TraceAnalyzer analyzer(json_events);
-// TraceEventVector events;
-//
-// EXAMPLE 1: Find events named "my_event".
-//
-// analyzer.FindEvents(Query(EVENT_NAME) == "my_event", &events);
-//
-// EXAMPLE 2: Find begin events named "my_event" with duration > 1 second.
-//
-// Query q = (Query(EVENT_NAME) == Query::String("my_event") &&
-// Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN) &&
-// Query(EVENT_DURATION) > Query::Double(1000000.0));
-// analyzer.FindEvents(q, &events);
-//
-// EXAMPLE 3: Associating event pairs across threads.
-//
-// If the test needs to analyze something that starts and ends on different
-// threads, the test needs to use INSTANT events. The typical procedure is to
-// specify the same unique ID as a TRACE_EVENT argument on both the start and
-// finish INSTANT events. Then use the following procedure to associate those
-// events.
-//
-// Step 1: instrument code with custom begin/end trace events.
-// [Thread 1 tracing code]
-// TRACE_EVENT_INSTANT1("test_latency", "timing1_begin", "id", 3);
-// [Thread 2 tracing code]
-// TRACE_EVENT_INSTANT1("test_latency", "timing1_end", "id", 3);
-//
-// Step 2: associate these custom begin/end pairs.
-// Query begin(Query(EVENT_NAME) == Query::String("timing1_begin"));
-// Query end(Query(EVENT_NAME) == Query::String("timing1_end"));
-// Query match(Query(EVENT_ARG, "id") == Query(OTHER_ARG, "id"));
-// analyzer.AssociateEvents(begin, end, match);
-//
-// Step 3: search for "timing1_begin" events with existing other event.
-// Query q = (Query(EVENT_NAME) == Query::String("timing1_begin") &&
-// Query(EVENT_HAS_OTHER));
-// analyzer.FindEvents(q, &events);
-//
-// Step 4: analyze events, such as checking durations.
-// for (size_t i = 0; i < events.size(); ++i) {
-// double duration;
-// EXPECT_TRUE(events[i].GetAbsTimeToOtherEvent(&duration));
-// EXPECT_LT(duration, 1000000.0/60.0); // expect less than 1/60 second.
-// }
-
-
-#ifndef BASE_TEST_TRACE_EVENT_ANALYZER_H_
-#define BASE_TEST_TRACE_EVENT_ANALYZER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/trace_event/trace_event.h"
-
-namespace base {
-class Value;
-}
-
-namespace trace_analyzer {
-class QueryNode;
-
-// trace_analyzer::TraceEvent is a more convenient form of the
-// base::trace_event::TraceEvent class to make tracing-based tests easier to
-// write.
-struct TraceEvent {
- // ProcessThreadID contains a Process ID and Thread ID.
- struct ProcessThreadID {
- ProcessThreadID() : process_id(0), thread_id(0) {}
- ProcessThreadID(int process_id, int thread_id)
- : process_id(process_id), thread_id(thread_id) {}
- bool operator< (const ProcessThreadID& rhs) const {
- if (process_id != rhs.process_id)
- return process_id < rhs.process_id;
- return thread_id < rhs.thread_id;
- }
- int process_id;
- int thread_id;
- };
-
- TraceEvent();
- TraceEvent(TraceEvent&& other);
- ~TraceEvent();
-
- bool SetFromJSON(const base::Value* event_value) WARN_UNUSED_RESULT;
-
- bool operator< (const TraceEvent& rhs) const {
- return timestamp < rhs.timestamp;
- }
-
- TraceEvent& operator=(TraceEvent&& rhs);
-
- bool has_other_event() const { return other_event; }
-
- // Returns absolute duration in microseconds between this event and other
- // event. Must have already verified that other_event exists by
- // Query(EVENT_HAS_OTHER) or by calling has_other_event().
- double GetAbsTimeToOtherEvent() const;
-
- // Return the argument value if it exists and it is a string.
- bool GetArgAsString(const std::string& name, std::string* arg) const;
- // Return the argument value if it exists and it is a number.
- bool GetArgAsNumber(const std::string& name, double* arg) const;
- // Return the argument value if it exists.
- bool GetArgAsValue(const std::string& name,
- std::unique_ptr<base::Value>* arg) const;
-
- // Check if argument exists and is string.
- bool HasStringArg(const std::string& name) const;
- // Check if argument exists and is number (double, int or bool).
- bool HasNumberArg(const std::string& name) const;
- // Check if argument exists.
- bool HasArg(const std::string& name) const;
-
- // Get known existing arguments as specific types.
- // Useful when you have already queried the argument with
- // Query(HAS_NUMBER_ARG) or Query(HAS_STRING_ARG).
- std::string GetKnownArgAsString(const std::string& name) const;
- double GetKnownArgAsDouble(const std::string& name) const;
- int GetKnownArgAsInt(const std::string& name) const;
- bool GetKnownArgAsBool(const std::string& name) const;
- std::unique_ptr<base::Value> GetKnownArgAsValue(
- const std::string& name) const;
-
- // Process ID and Thread ID.
- ProcessThreadID thread;
-
- // Time since epoch in microseconds.
- // Stored as double to match its JSON representation.
- double timestamp;
- double duration;
- char phase;
- std::string category;
- std::string name;
- std::string id;
-
- // All numbers and bool values from TraceEvent args are cast to double.
- // bool becomes 1.0 (true) or 0.0 (false).
- std::map<std::string, double> arg_numbers;
- std::map<std::string, std::string> arg_strings;
- std::map<std::string, std::unique_ptr<base::Value>> arg_values;
-
- // The other event associated with this event (or NULL).
- const TraceEvent* other_event;
-
- // A back-link for |other_event|. That is, if other_event is not null, then
- // |event->other_event->prev_event == event| is always true.
- const TraceEvent* prev_event;
-};
-
-typedef std::vector<const TraceEvent*> TraceEventVector;
-
-class Query {
- public:
- Query(const Query& query);
-
- ~Query();
-
- ////////////////////////////////////////////////////////////////
- // Query literal values
-
- // Compare with the given string.
- static Query String(const std::string& str);
-
- // Compare with the given number.
- static Query Double(double num);
- static Query Int(int32_t num);
- static Query Uint(uint32_t num);
-
- // Compare with the given bool.
- static Query Bool(bool boolean);
-
- // Compare with the given phase.
- static Query Phase(char phase);
-
- // Compare with the given string pattern. Only works with == and != operators.
- // Example: Query(EVENT_NAME) == Query::Pattern("MyEvent*")
- static Query Pattern(const std::string& pattern);
-
- ////////////////////////////////////////////////////////////////
- // Query event members
-
- static Query EventPid() { return Query(EVENT_PID); }
-
- static Query EventTid() { return Query(EVENT_TID); }
-
- // Return the timestamp of the event in microseconds since epoch.
- static Query EventTime() { return Query(EVENT_TIME); }
-
- // Return the absolute time between event and other event in microseconds.
- // Only works if Query::EventHasOther() == true.
- static Query EventDuration() { return Query(EVENT_DURATION); }
-
- // Return the duration of a COMPLETE event.
- static Query EventCompleteDuration() {
- return Query(EVENT_COMPLETE_DURATION);
- }
-
- static Query EventPhase() { return Query(EVENT_PHASE); }
-
- static Query EventCategory() { return Query(EVENT_CATEGORY); }
-
- static Query EventName() { return Query(EVENT_NAME); }
-
- static Query EventId() { return Query(EVENT_ID); }
-
- static Query EventPidIs(int process_id) {
- return Query(EVENT_PID) == Query::Int(process_id);
- }
-
- static Query EventTidIs(int thread_id) {
- return Query(EVENT_TID) == Query::Int(thread_id);
- }
-
- static Query EventThreadIs(const TraceEvent::ProcessThreadID& thread) {
- return EventPidIs(thread.process_id) && EventTidIs(thread.thread_id);
- }
-
- static Query EventTimeIs(double timestamp) {
- return Query(EVENT_TIME) == Query::Double(timestamp);
- }
-
- static Query EventDurationIs(double duration) {
- return Query(EVENT_DURATION) == Query::Double(duration);
- }
-
- static Query EventPhaseIs(char phase) {
- return Query(EVENT_PHASE) == Query::Phase(phase);
- }
-
- static Query EventCategoryIs(const std::string& category) {
- return Query(EVENT_CATEGORY) == Query::String(category);
- }
-
- static Query EventNameIs(const std::string& name) {
- return Query(EVENT_NAME) == Query::String(name);
- }
-
- static Query EventIdIs(const std::string& id) {
- return Query(EVENT_ID) == Query::String(id);
- }
-
- // Evaluates to true if arg exists and is a string.
- static Query EventHasStringArg(const std::string& arg_name) {
- return Query(EVENT_HAS_STRING_ARG, arg_name);
- }
-
- // Evaluates to true if arg exists and is a number.
- // Number arguments include types double, int and bool.
- static Query EventHasNumberArg(const std::string& arg_name) {
- return Query(EVENT_HAS_NUMBER_ARG, arg_name);
- }
-
- // Evaluates to arg value (string or number).
- static Query EventArg(const std::string& arg_name) {
- return Query(EVENT_ARG, arg_name);
- }
-
- // Return true if associated event exists.
- static Query EventHasOther() { return Query(EVENT_HAS_OTHER); }
-
- // Access the associated other_event's members:
-
- static Query OtherPid() { return Query(OTHER_PID); }
-
- static Query OtherTid() { return Query(OTHER_TID); }
-
- static Query OtherTime() { return Query(OTHER_TIME); }
-
- static Query OtherPhase() { return Query(OTHER_PHASE); }
-
- static Query OtherCategory() { return Query(OTHER_CATEGORY); }
-
- static Query OtherName() { return Query(OTHER_NAME); }
-
- static Query OtherId() { return Query(OTHER_ID); }
-
- static Query OtherPidIs(int process_id) {
- return Query(OTHER_PID) == Query::Int(process_id);
- }
-
- static Query OtherTidIs(int thread_id) {
- return Query(OTHER_TID) == Query::Int(thread_id);
- }
-
- static Query OtherThreadIs(const TraceEvent::ProcessThreadID& thread) {
- return OtherPidIs(thread.process_id) && OtherTidIs(thread.thread_id);
- }
-
- static Query OtherTimeIs(double timestamp) {
- return Query(OTHER_TIME) == Query::Double(timestamp);
- }
-
- static Query OtherPhaseIs(char phase) {
- return Query(OTHER_PHASE) == Query::Phase(phase);
- }
-
- static Query OtherCategoryIs(const std::string& category) {
- return Query(OTHER_CATEGORY) == Query::String(category);
- }
-
- static Query OtherNameIs(const std::string& name) {
- return Query(OTHER_NAME) == Query::String(name);
- }
-
- static Query OtherIdIs(const std::string& id) {
- return Query(OTHER_ID) == Query::String(id);
- }
-
- // Evaluates to true if arg exists and is a string.
- static Query OtherHasStringArg(const std::string& arg_name) {
- return Query(OTHER_HAS_STRING_ARG, arg_name);
- }
-
- // Evaluates to true if arg exists and is a number.
- // Number arguments include types double, int and bool.
- static Query OtherHasNumberArg(const std::string& arg_name) {
- return Query(OTHER_HAS_NUMBER_ARG, arg_name);
- }
-
- // Evaluates to arg value (string or number).
- static Query OtherArg(const std::string& arg_name) {
- return Query(OTHER_ARG, arg_name);
- }
-
- // Access the associated prev_event's members:
-
- static Query PrevPid() { return Query(PREV_PID); }
-
- static Query PrevTid() { return Query(PREV_TID); }
-
- static Query PrevTime() { return Query(PREV_TIME); }
-
- static Query PrevPhase() { return Query(PREV_PHASE); }
-
- static Query PrevCategory() { return Query(PREV_CATEGORY); }
-
- static Query PrevName() { return Query(PREV_NAME); }
-
- static Query PrevId() { return Query(PREV_ID); }
-
- static Query PrevPidIs(int process_id) {
- return Query(PREV_PID) == Query::Int(process_id);
- }
-
- static Query PrevTidIs(int thread_id) {
- return Query(PREV_TID) == Query::Int(thread_id);
- }
-
- static Query PrevThreadIs(const TraceEvent::ProcessThreadID& thread) {
- return PrevPidIs(thread.process_id) && PrevTidIs(thread.thread_id);
- }
-
- static Query PrevTimeIs(double timestamp) {
- return Query(PREV_TIME) == Query::Double(timestamp);
- }
-
- static Query PrevPhaseIs(char phase) {
- return Query(PREV_PHASE) == Query::Phase(phase);
- }
-
- static Query PrevCategoryIs(const std::string& category) {
- return Query(PREV_CATEGORY) == Query::String(category);
- }
-
- static Query PrevNameIs(const std::string& name) {
- return Query(PREV_NAME) == Query::String(name);
- }
-
- static Query PrevIdIs(const std::string& id) {
- return Query(PREV_ID) == Query::String(id);
- }
-
- // Evaluates to true if arg exists and is a string.
- static Query PrevHasStringArg(const std::string& arg_name) {
- return Query(PREV_HAS_STRING_ARG, arg_name);
- }
-
- // Evaluates to true if arg exists and is a number.
- // Number arguments include types double, int and bool.
- static Query PrevHasNumberArg(const std::string& arg_name) {
- return Query(PREV_HAS_NUMBER_ARG, arg_name);
- }
-
- // Evaluates to arg value (string or number).
- static Query PrevArg(const std::string& arg_name) {
- return Query(PREV_ARG, arg_name);
- }
-
- ////////////////////////////////////////////////////////////////
- // Common queries:
-
- // Find BEGIN events that have a corresponding END event.
- static Query MatchBeginWithEnd() {
- return (Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN)) &&
- Query(EVENT_HAS_OTHER);
- }
-
- // Find COMPLETE events.
- static Query MatchComplete() {
- return (Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_COMPLETE));
- }
-
- // Find ASYNC_BEGIN events that have a corresponding ASYNC_END event.
- static Query MatchAsyncBeginWithNext() {
- return (Query(EVENT_PHASE) ==
- Query::Phase(TRACE_EVENT_PHASE_ASYNC_BEGIN)) &&
- Query(EVENT_HAS_OTHER);
- }
-
- // Find BEGIN events of given |name| which also have associated END events.
- static Query MatchBeginName(const std::string& name) {
- return (Query(EVENT_NAME) == Query(name)) && MatchBeginWithEnd();
- }
-
- // Find COMPLETE events of given |name|.
- static Query MatchCompleteName(const std::string& name) {
- return (Query(EVENT_NAME) == Query(name)) && MatchComplete();
- }
-
- // Match given Process ID and Thread ID.
- static Query MatchThread(const TraceEvent::ProcessThreadID& thread) {
- return (Query(EVENT_PID) == Query::Int(thread.process_id)) &&
- (Query(EVENT_TID) == Query::Int(thread.thread_id));
- }
-
- // Match event pair that spans multiple threads.
- static Query MatchCrossThread() {
- return (Query(EVENT_PID) != Query(OTHER_PID)) ||
- (Query(EVENT_TID) != Query(OTHER_TID));
- }
-
- ////////////////////////////////////////////////////////////////
- // Operators:
-
- // Boolean operators:
- Query operator==(const Query& rhs) const;
- Query operator!=(const Query& rhs) const;
- Query operator< (const Query& rhs) const;
- Query operator<=(const Query& rhs) const;
- Query operator> (const Query& rhs) const;
- Query operator>=(const Query& rhs) const;
- Query operator&&(const Query& rhs) const;
- Query operator||(const Query& rhs) const;
- Query operator!() const;
-
- // Arithmetic operators:
- // Following operators are applied to double arguments:
- Query operator+(const Query& rhs) const;
- Query operator-(const Query& rhs) const;
- Query operator*(const Query& rhs) const;
- Query operator/(const Query& rhs) const;
- Query operator-() const;
- // Mod operates on int64_t args (doubles are casted to int64_t beforehand):
- Query operator%(const Query& rhs) const;
-
- // Return true if the given event matches this query tree.
- // This is a recursive method that walks the query tree.
- bool Evaluate(const TraceEvent& event) const;
-
- private:
- enum TraceEventMember {
- EVENT_INVALID,
- EVENT_PID,
- EVENT_TID,
- EVENT_TIME,
- EVENT_DURATION,
- EVENT_COMPLETE_DURATION,
- EVENT_PHASE,
- EVENT_CATEGORY,
- EVENT_NAME,
- EVENT_ID,
- EVENT_HAS_STRING_ARG,
- EVENT_HAS_NUMBER_ARG,
- EVENT_ARG,
- EVENT_HAS_OTHER,
- EVENT_HAS_PREV,
-
- OTHER_PID,
- OTHER_TID,
- OTHER_TIME,
- OTHER_PHASE,
- OTHER_CATEGORY,
- OTHER_NAME,
- OTHER_ID,
- OTHER_HAS_STRING_ARG,
- OTHER_HAS_NUMBER_ARG,
- OTHER_ARG,
-
- PREV_PID,
- PREV_TID,
- PREV_TIME,
- PREV_PHASE,
- PREV_CATEGORY,
- PREV_NAME,
- PREV_ID,
- PREV_HAS_STRING_ARG,
- PREV_HAS_NUMBER_ARG,
- PREV_ARG,
-
- OTHER_FIRST_MEMBER = OTHER_PID,
- OTHER_LAST_MEMBER = OTHER_ARG,
-
- PREV_FIRST_MEMBER = PREV_PID,
- PREV_LAST_MEMBER = PREV_ARG,
- };
-
- enum Operator {
- OP_INVALID,
- // Boolean operators:
- OP_EQ,
- OP_NE,
- OP_LT,
- OP_LE,
- OP_GT,
- OP_GE,
- OP_AND,
- OP_OR,
- OP_NOT,
- // Arithmetic operators:
- OP_ADD,
- OP_SUB,
- OP_MUL,
- OP_DIV,
- OP_MOD,
- OP_NEGATE
- };
-
- enum QueryType {
- QUERY_BOOLEAN_OPERATOR,
- QUERY_ARITHMETIC_OPERATOR,
- QUERY_EVENT_MEMBER,
- QUERY_NUMBER,
- QUERY_STRING
- };
-
- // Compare with the given member.
- explicit Query(TraceEventMember member);
-
- // Compare with the given member argument value.
- Query(TraceEventMember member, const std::string& arg_name);
-
- // Compare with the given string.
- explicit Query(const std::string& str);
-
- // Compare with the given number.
- explicit Query(double num);
-
- // Construct a boolean Query that returns (left <binary_op> right).
- Query(const Query& left, const Query& right, Operator binary_op);
-
- // Construct a boolean Query that returns (<binary_op> left).
- Query(const Query& left, Operator unary_op);
-
- // Try to compare left_ against right_ based on operator_.
- // If either left or right does not convert to double, false is returned.
- // Otherwise, true is returned and |result| is set to the comparison result.
- bool CompareAsDouble(const TraceEvent& event, bool* result) const;
-
- // Try to compare left_ against right_ based on operator_.
- // If either left or right does not convert to string, false is returned.
- // Otherwise, true is returned and |result| is set to the comparison result.
- bool CompareAsString(const TraceEvent& event, bool* result) const;
-
- // Attempt to convert this Query to a double. On success, true is returned
- // and the double value is stored in |num|.
- bool GetAsDouble(const TraceEvent& event, double* num) const;
-
- // Attempt to convert this Query to a string. On success, true is returned
- // and the string value is stored in |str|.
- bool GetAsString(const TraceEvent& event, std::string* str) const;
-
- // Evaluate this Query as an arithmetic operator on left_ and right_.
- bool EvaluateArithmeticOperator(const TraceEvent& event,
- double* num) const;
-
- // For QUERY_EVENT_MEMBER Query: attempt to get the double value of the Query.
- bool GetMemberValueAsDouble(const TraceEvent& event, double* num) const;
-
- // For QUERY_EVENT_MEMBER Query: attempt to get the string value of the Query.
- bool GetMemberValueAsString(const TraceEvent& event, std::string* num) const;
-
- // Does this Query represent a value?
- bool is_value() const { return type_ != QUERY_BOOLEAN_OPERATOR; }
-
- bool is_unary_operator() const {
- return operator_ == OP_NOT || operator_ == OP_NEGATE;
- }
-
- bool is_comparison_operator() const {
- return operator_ != OP_INVALID && operator_ < OP_AND;
- }
-
- static const TraceEvent* SelectTargetEvent(const TraceEvent* ev,
- TraceEventMember member);
-
- const Query& left() const;
- const Query& right() const;
-
- QueryType type_;
- Operator operator_;
- scoped_refptr<QueryNode> left_;
- scoped_refptr<QueryNode> right_;
- TraceEventMember member_;
- double number_;
- std::string string_;
- bool is_pattern_;
-};
-
-// Implementation detail:
-// QueryNode allows Query to store a ref-counted query tree.
-class QueryNode : public base::RefCounted<QueryNode> {
- public:
- explicit QueryNode(const Query& query);
- const Query& query() const { return query_; }
-
- private:
- friend class base::RefCounted<QueryNode>;
- ~QueryNode();
-
- Query query_;
-};
-
-// TraceAnalyzer helps tests search for trace events.
-class TraceAnalyzer {
- public:
- ~TraceAnalyzer();
-
- // Use trace events from JSON string generated by tracing API.
- // Returns non-NULL if the JSON is successfully parsed.
- static TraceAnalyzer* Create(const std::string& json_events)
- WARN_UNUSED_RESULT;
-
- void SetIgnoreMetadataEvents(bool ignore) {
- ignore_metadata_events_ = ignore;
- }
-
- // Associate BEGIN and END events with each other. This allows Query(OTHER_*)
- // to access the associated event and enables Query(EVENT_DURATION).
- // An end event will match the most recent begin event with the same name,
- // category, process ID and thread ID. This matches what is shown in
- // about:tracing. After association, the BEGIN event will point to the
- // matching END event, but the END event will not point to the BEGIN event.
- void AssociateBeginEndEvents();
-
- // Associate ASYNC_BEGIN, ASYNC_STEP and ASYNC_END events with each other.
- // An ASYNC_END event will match the most recent ASYNC_BEGIN or ASYNC_STEP
- // event with the same name, category, and ID. This creates a singly linked
- // list of ASYNC_BEGIN->ASYNC_STEP...->ASYNC_END.
- // |match_pid| - If true, will only match async events which are running
- // under the same process ID, otherwise will allow linking
- // async events from different processes.
- void AssociateAsyncBeginEndEvents(bool match_pid = true);
-
- // AssociateEvents can be used to customize event associations by setting the
- // other_event member of TraceEvent. This should be used to associate two
- // INSTANT events.
- //
- // The assumptions are:
- // - |first| events occur before |second| events.
- // - the closest matching |second| event is the correct match.
- //
- // |first| - Eligible |first| events match this query.
- // |second| - Eligible |second| events match this query.
- // |match| - This query is run on the |first| event. The OTHER_* EventMember
- // queries will point to an eligible |second| event. The query
- // should evaluate to true if the |first|/|second| pair is a match.
- //
- // When a match is found, the pair will be associated by having the first
- // event's other_event member point to the other. AssociateEvents does not
- // clear previous associations, so it is possible to associate multiple pairs
- // of events by calling AssociateEvents more than once with different queries.
- //
- // NOTE: AssociateEvents will overwrite existing other_event associations if
- // the queries pass for events that already had a previous association.
- //
- // After calling any Find* method, it is not allowed to call AssociateEvents
- // again.
- void AssociateEvents(const Query& first,
- const Query& second,
- const Query& match);
-
- // For each event, copy its arguments to the other_event argument map. If
- // argument name already exists, it will not be overwritten.
- void MergeAssociatedEventArgs();
-
- // Find all events that match query and replace output vector.
- size_t FindEvents(const Query& query, TraceEventVector* output);
-
- // Find first event that matches query or NULL if not found.
- const TraceEvent* FindFirstOf(const Query& query);
-
- // Find last event that matches query or NULL if not found.
- const TraceEvent* FindLastOf(const Query& query);
-
- const std::string& GetThreadName(const TraceEvent::ProcessThreadID& thread);
-
- private:
- TraceAnalyzer();
-
- bool SetEvents(const std::string& json_events) WARN_UNUSED_RESULT;
-
- // Read metadata (thread names, etc) from events.
- void ParseMetadata();
-
- std::map<TraceEvent::ProcessThreadID, std::string> thread_names_;
- std::vector<TraceEvent> raw_events_;
- bool ignore_metadata_events_;
- bool allow_assocation_changes_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceAnalyzer);
-};
-
-// Utility functions for TraceEventVector.
-
-struct RateStats {
- double min_us;
- double max_us;
- double mean_us;
- double standard_deviation_us;
-};
-
-struct RateStatsOptions {
- RateStatsOptions() : trim_min(0u), trim_max(0u) {}
- // After the times between events are sorted, the number of specified elements
- // will be trimmed before calculating the RateStats. This is useful in cases
- // where extreme outliers are tolerable and should not skew the overall
- // average.
- size_t trim_min; // Trim this many minimum times.
- size_t trim_max; // Trim this many maximum times.
-};
-
-// Calculate min/max/mean and standard deviation from the times between
-// adjacent events.
-bool GetRateStats(const TraceEventVector& events,
- RateStats* stats,
- const RateStatsOptions* options);
-
-// Starting from |position|, find the first event that matches |query|.
-// Returns true if found, false otherwise.
-bool FindFirstOf(const TraceEventVector& events,
- const Query& query,
- size_t position,
- size_t* return_index);
-
-// Starting from |position|, find the last event that matches |query|.
-// Returns true if found, false otherwise.
-bool FindLastOf(const TraceEventVector& events,
- const Query& query,
- size_t position,
- size_t* return_index);
-
-// Find the closest events to |position| in time that match |query|.
-// return_second_closest may be NULL. Closeness is determined by comparing
-// with the event timestamp.
-// Returns true if found, false otherwise. If both return parameters are
-// requested, both must be found for a successful result.
-bool FindClosest(const TraceEventVector& events,
- const Query& query,
- size_t position,
- size_t* return_closest,
- size_t* return_second_closest);
-
-// Count matches, inclusive of |begin_position|, exclusive of |end_position|.
-size_t CountMatches(const TraceEventVector& events,
- const Query& query,
- size_t begin_position,
- size_t end_position);
-
-// Count all matches.
-static inline size_t CountMatches(const TraceEventVector& events,
- const Query& query) {
- return CountMatches(events, query, 0u, events.size());
-}
-
-} // namespace trace_analyzer
-
-#endif // BASE_TEST_TRACE_EVENT_ANALYZER_H_
diff --git a/base/test/trace_event_analyzer_unittest.cc b/base/test/trace_event_analyzer_unittest.cc
deleted file mode 100644
index ce7bce22a0..0000000000
--- a/base/test/trace_event_analyzer_unittest.cc
+++ /dev/null
@@ -1,961 +0,0 @@
-// Copyright (c) 2012 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/test/trace_event_analyzer.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/platform_thread.h"
-#include "base/trace_event/trace_buffer.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace trace_analyzer {
-
-namespace {
-
-class TraceEventAnalyzerTest : public testing::Test {
- public:
- void ManualSetUp();
- void OnTraceDataCollected(
- base::WaitableEvent* flush_complete_event,
- const scoped_refptr<base::RefCountedString>& json_events_str,
- bool has_more_events);
- void BeginTracing();
- void EndTracing();
-
- base::trace_event::TraceResultBuffer::SimpleOutput output_;
- base::trace_event::TraceResultBuffer buffer_;
-};
-
-void TraceEventAnalyzerTest::ManualSetUp() {
- ASSERT_TRUE(base::trace_event::TraceLog::GetInstance());
- buffer_.SetOutputCallback(output_.GetCallback());
- output_.json_output.clear();
-}
-
-void TraceEventAnalyzerTest::OnTraceDataCollected(
- base::WaitableEvent* flush_complete_event,
- const scoped_refptr<base::RefCountedString>& json_events_str,
- bool has_more_events) {
- buffer_.AddFragment(json_events_str->data());
- if (!has_more_events)
- flush_complete_event->Signal();
-}
-
-void TraceEventAnalyzerTest::BeginTracing() {
- output_.json_output.clear();
- buffer_.Start();
- base::trace_event::TraceLog::GetInstance()->SetEnabled(
- base::trace_event::TraceConfig("*", ""),
- base::trace_event::TraceLog::RECORDING_MODE);
-}
-
-void TraceEventAnalyzerTest::EndTracing() {
- base::trace_event::TraceLog::GetInstance()->SetDisabled();
- base::WaitableEvent flush_complete_event(
- base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- base::trace_event::TraceLog::GetInstance()->Flush(
- base::Bind(&TraceEventAnalyzerTest::OnTraceDataCollected,
- base::Unretained(this),
- base::Unretained(&flush_complete_event)));
- flush_complete_event.Wait();
- buffer_.Finish();
-}
-
-} // namespace
-
-TEST_F(TraceEventAnalyzerTest, NoEvents) {
- ManualSetUp();
-
- // Create an empty JSON event string:
- buffer_.Start();
- buffer_.Finish();
-
- std::unique_ptr<TraceAnalyzer> analyzer(
- TraceAnalyzer::Create(output_.json_output));
- ASSERT_TRUE(analyzer.get());
-
- // Search for all events and verify that nothing is returned.
- TraceEventVector found;
- analyzer->FindEvents(Query::Bool(true), &found);
- EXPECT_EQ(0u, found.size());
-}
-
-TEST_F(TraceEventAnalyzerTest, TraceEvent) {
- ManualSetUp();
-
- int int_num = 2;
- double double_num = 3.5;
- const char str[] = "the string";
-
- TraceEvent event;
- event.arg_numbers["false"] = 0.0;
- event.arg_numbers["true"] = 1.0;
- event.arg_numbers["int"] = static_cast<double>(int_num);
- event.arg_numbers["double"] = double_num;
- event.arg_strings["string"] = str;
- event.arg_values["dict"] = WrapUnique(new base::DictionaryValue());
-
- ASSERT_TRUE(event.HasNumberArg("false"));
- ASSERT_TRUE(event.HasNumberArg("true"));
- ASSERT_TRUE(event.HasNumberArg("int"));
- ASSERT_TRUE(event.HasNumberArg("double"));
- ASSERT_TRUE(event.HasStringArg("string"));
- ASSERT_FALSE(event.HasNumberArg("notfound"));
- ASSERT_FALSE(event.HasStringArg("notfound"));
- ASSERT_TRUE(event.HasArg("dict"));
- ASSERT_FALSE(event.HasArg("notfound"));
-
- EXPECT_FALSE(event.GetKnownArgAsBool("false"));
- EXPECT_TRUE(event.GetKnownArgAsBool("true"));
- EXPECT_EQ(int_num, event.GetKnownArgAsInt("int"));
- EXPECT_EQ(double_num, event.GetKnownArgAsDouble("double"));
- EXPECT_STREQ(str, event.GetKnownArgAsString("string").c_str());
-
- std::unique_ptr<base::Value> arg;
- EXPECT_TRUE(event.GetArgAsValue("dict", &arg));
- EXPECT_EQ(base::Value::Type::DICTIONARY, arg->GetType());
-}
-
-TEST_F(TraceEventAnalyzerTest, QueryEventMember) {
- ManualSetUp();
-
- TraceEvent event;
- event.thread.process_id = 3;
- event.thread.thread_id = 4;
- event.timestamp = 1.5;
- event.phase = TRACE_EVENT_PHASE_BEGIN;
- event.category = "category";
- event.name = "name";
- event.id = "1";
- event.arg_numbers["num"] = 7.0;
- event.arg_strings["str"] = "the string";
-
- // Other event with all different members:
- TraceEvent other;
- other.thread.process_id = 5;
- other.thread.thread_id = 6;
- other.timestamp = 2.5;
- other.phase = TRACE_EVENT_PHASE_END;
- other.category = "category2";
- other.name = "name2";
- other.id = "2";
- other.arg_numbers["num2"] = 8.0;
- other.arg_strings["str2"] = "the string 2";
-
- event.other_event = &other;
- ASSERT_TRUE(event.has_other_event());
- double duration = event.GetAbsTimeToOtherEvent();
-
- Query event_pid = Query::EventPidIs(event.thread.process_id);
- Query event_tid = Query::EventTidIs(event.thread.thread_id);
- Query event_time = Query::EventTimeIs(event.timestamp);
- Query event_duration = Query::EventDurationIs(duration);
- Query event_phase = Query::EventPhaseIs(event.phase);
- Query event_category = Query::EventCategoryIs(event.category);
- Query event_name = Query::EventNameIs(event.name);
- Query event_id = Query::EventIdIs(event.id);
- Query event_has_arg1 = Query::EventHasNumberArg("num");
- Query event_has_arg2 = Query::EventHasStringArg("str");
- Query event_arg1 =
- (Query::EventArg("num") == Query::Double(event.arg_numbers["num"]));
- Query event_arg2 =
- (Query::EventArg("str") == Query::String(event.arg_strings["str"]));
- Query event_has_other = Query::EventHasOther();
- Query other_pid = Query::OtherPidIs(other.thread.process_id);
- Query other_tid = Query::OtherTidIs(other.thread.thread_id);
- Query other_time = Query::OtherTimeIs(other.timestamp);
- Query other_phase = Query::OtherPhaseIs(other.phase);
- Query other_category = Query::OtherCategoryIs(other.category);
- Query other_name = Query::OtherNameIs(other.name);
- Query other_id = Query::OtherIdIs(other.id);
- Query other_has_arg1 = Query::OtherHasNumberArg("num2");
- Query other_has_arg2 = Query::OtherHasStringArg("str2");
- Query other_arg1 =
- (Query::OtherArg("num2") == Query::Double(other.arg_numbers["num2"]));
- Query other_arg2 =
- (Query::OtherArg("str2") == Query::String(other.arg_strings["str2"]));
-
- EXPECT_TRUE(event_pid.Evaluate(event));
- EXPECT_TRUE(event_tid.Evaluate(event));
- EXPECT_TRUE(event_time.Evaluate(event));
- EXPECT_TRUE(event_duration.Evaluate(event));
- EXPECT_TRUE(event_phase.Evaluate(event));
- EXPECT_TRUE(event_category.Evaluate(event));
- EXPECT_TRUE(event_name.Evaluate(event));
- EXPECT_TRUE(event_id.Evaluate(event));
- EXPECT_TRUE(event_has_arg1.Evaluate(event));
- EXPECT_TRUE(event_has_arg2.Evaluate(event));
- EXPECT_TRUE(event_arg1.Evaluate(event));
- EXPECT_TRUE(event_arg2.Evaluate(event));
- EXPECT_TRUE(event_has_other.Evaluate(event));
- EXPECT_TRUE(other_pid.Evaluate(event));
- EXPECT_TRUE(other_tid.Evaluate(event));
- EXPECT_TRUE(other_time.Evaluate(event));
- EXPECT_TRUE(other_phase.Evaluate(event));
- EXPECT_TRUE(other_category.Evaluate(event));
- EXPECT_TRUE(other_name.Evaluate(event));
- EXPECT_TRUE(other_id.Evaluate(event));
- EXPECT_TRUE(other_has_arg1.Evaluate(event));
- EXPECT_TRUE(other_has_arg2.Evaluate(event));
- EXPECT_TRUE(other_arg1.Evaluate(event));
- EXPECT_TRUE(other_arg2.Evaluate(event));
-
- // Evaluate event queries against other to verify the queries fail when the
- // event members are wrong.
- EXPECT_FALSE(event_pid.Evaluate(other));
- EXPECT_FALSE(event_tid.Evaluate(other));
- EXPECT_FALSE(event_time.Evaluate(other));
- EXPECT_FALSE(event_duration.Evaluate(other));
- EXPECT_FALSE(event_phase.Evaluate(other));
- EXPECT_FALSE(event_category.Evaluate(other));
- EXPECT_FALSE(event_name.Evaluate(other));
- EXPECT_FALSE(event_id.Evaluate(other));
- EXPECT_FALSE(event_has_arg1.Evaluate(other));
- EXPECT_FALSE(event_has_arg2.Evaluate(other));
- EXPECT_FALSE(event_arg1.Evaluate(other));
- EXPECT_FALSE(event_arg2.Evaluate(other));
- EXPECT_FALSE(event_has_other.Evaluate(other));
-}
-
-TEST_F(TraceEventAnalyzerTest, BooleanOperators) {
- ManualSetUp();
-
- BeginTracing();
- {
- TRACE_EVENT_INSTANT1("cat1", "name1", TRACE_EVENT_SCOPE_THREAD, "num", 1);
- TRACE_EVENT_INSTANT1("cat1", "name2", TRACE_EVENT_SCOPE_THREAD, "num", 2);
- TRACE_EVENT_INSTANT1("cat2", "name3", TRACE_EVENT_SCOPE_THREAD, "num", 3);
- TRACE_EVENT_INSTANT1("cat2", "name4", TRACE_EVENT_SCOPE_THREAD, "num", 4);
- }
- EndTracing();
-
- std::unique_ptr<TraceAnalyzer> analyzer(
- TraceAnalyzer::Create(output_.json_output));
- ASSERT_TRUE(analyzer);
- analyzer->SetIgnoreMetadataEvents(true);
-
- TraceEventVector found;
-
- // ==
-
- analyzer->FindEvents(Query::EventCategory() == Query::String("cat1"), &found);
- ASSERT_EQ(2u, found.size());
- EXPECT_STREQ("name1", found[0]->name.c_str());
- EXPECT_STREQ("name2", found[1]->name.c_str());
-
- analyzer->FindEvents(Query::EventArg("num") == Query::Int(2), &found);
- ASSERT_EQ(1u, found.size());
- EXPECT_STREQ("name2", found[0]->name.c_str());
-
- // !=
-
- analyzer->FindEvents(Query::EventCategory() != Query::String("cat1"), &found);
- ASSERT_EQ(2u, found.size());
- EXPECT_STREQ("name3", found[0]->name.c_str());
- EXPECT_STREQ("name4", found[1]->name.c_str());
-
- analyzer->FindEvents(Query::EventArg("num") != Query::Int(2), &found);
- ASSERT_EQ(3u, found.size());
- EXPECT_STREQ("name1", found[0]->name.c_str());
- EXPECT_STREQ("name3", found[1]->name.c_str());
- EXPECT_STREQ("name4", found[2]->name.c_str());
-
- // <
- analyzer->FindEvents(Query::EventArg("num") < Query::Int(2), &found);
- ASSERT_EQ(1u, found.size());
- EXPECT_STREQ("name1", found[0]->name.c_str());
-
- // <=
- analyzer->FindEvents(Query::EventArg("num") <= Query::Int(2), &found);
- ASSERT_EQ(2u, found.size());
- EXPECT_STREQ("name1", found[0]->name.c_str());
- EXPECT_STREQ("name2", found[1]->name.c_str());
-
- // >
- analyzer->FindEvents(Query::EventArg("num") > Query::Int(3), &found);
- ASSERT_EQ(1u, found.size());
- EXPECT_STREQ("name4", found[0]->name.c_str());
-
- // >=
- analyzer->FindEvents(Query::EventArg("num") >= Query::Int(4), &found);
- ASSERT_EQ(1u, found.size());
- EXPECT_STREQ("name4", found[0]->name.c_str());
-
- // &&
- analyzer->FindEvents(Query::EventName() != Query::String("name1") &&
- Query::EventArg("num") < Query::Int(3), &found);
- ASSERT_EQ(1u, found.size());
- EXPECT_STREQ("name2", found[0]->name.c_str());
-
- // ||
- analyzer->FindEvents(Query::EventName() == Query::String("name1") ||
- Query::EventArg("num") == Query::Int(3), &found);
- ASSERT_EQ(2u, found.size());
- EXPECT_STREQ("name1", found[0]->name.c_str());
- EXPECT_STREQ("name3", found[1]->name.c_str());
-
- // !
- analyzer->FindEvents(!(Query::EventName() == Query::String("name1") ||
- Query::EventArg("num") == Query::Int(3)), &found);
- ASSERT_EQ(2u, found.size());
- EXPECT_STREQ("name2", found[0]->name.c_str());
- EXPECT_STREQ("name4", found[1]->name.c_str());
-}
-
-TEST_F(TraceEventAnalyzerTest, ArithmeticOperators) {
- ManualSetUp();
-
- BeginTracing();
- {
- // These events are searched for:
- TRACE_EVENT_INSTANT2("cat1", "math1", TRACE_EVENT_SCOPE_THREAD,
- "a", 10, "b", 5);
- TRACE_EVENT_INSTANT2("cat1", "math2", TRACE_EVENT_SCOPE_THREAD,
- "a", 10, "b", 10);
- // Extra events that never match, for noise:
- TRACE_EVENT_INSTANT2("noise", "math3", TRACE_EVENT_SCOPE_THREAD,
- "a", 1, "b", 3);
- TRACE_EVENT_INSTANT2("noise", "math4", TRACE_EVENT_SCOPE_THREAD,
- "c", 10, "d", 5);
- }
- EndTracing();
-
- std::unique_ptr<TraceAnalyzer> analyzer(
- TraceAnalyzer::Create(output_.json_output));
- ASSERT_TRUE(analyzer.get());
-
- TraceEventVector found;
-
- // Verify that arithmetic operators function:
-
- // +
- analyzer->FindEvents(Query::EventArg("a") + Query::EventArg("b") ==
- Query::Int(20), &found);
- EXPECT_EQ(1u, found.size());
- EXPECT_STREQ("math2", found.front()->name.c_str());
-
- // -
- analyzer->FindEvents(Query::EventArg("a") - Query::EventArg("b") ==
- Query::Int(5), &found);
- EXPECT_EQ(1u, found.size());
- EXPECT_STREQ("math1", found.front()->name.c_str());
-
- // *
- analyzer->FindEvents(Query::EventArg("a") * Query::EventArg("b") ==
- Query::Int(50), &found);
- EXPECT_EQ(1u, found.size());
- EXPECT_STREQ("math1", found.front()->name.c_str());
-
- // /
- analyzer->FindEvents(Query::EventArg("a") / Query::EventArg("b") ==
- Query::Int(2), &found);
- EXPECT_EQ(1u, found.size());
- EXPECT_STREQ("math1", found.front()->name.c_str());
-
- // %
- analyzer->FindEvents(Query::EventArg("a") % Query::EventArg("b") ==
- Query::Int(0), &found);
- EXPECT_EQ(2u, found.size());
-
- // - (negate)
- analyzer->FindEvents(-Query::EventArg("b") == Query::Int(-10), &found);
- EXPECT_EQ(1u, found.size());
- EXPECT_STREQ("math2", found.front()->name.c_str());
-}
-
-TEST_F(TraceEventAnalyzerTest, StringPattern) {
- ManualSetUp();
-
- BeginTracing();
- {
- TRACE_EVENT_INSTANT0("cat1", "name1", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("cat1", "name2", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("cat1", "no match", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("cat1", "name3x", TRACE_EVENT_SCOPE_THREAD);
- }
- EndTracing();
-
- std::unique_ptr<TraceAnalyzer> analyzer(
- TraceAnalyzer::Create(output_.json_output));
- ASSERT_TRUE(analyzer.get());
- analyzer->SetIgnoreMetadataEvents(true);
-
- TraceEventVector found;
-
- analyzer->FindEvents(Query::EventName() == Query::Pattern("name?"), &found);
- ASSERT_EQ(2u, found.size());
- EXPECT_STREQ("name1", found[0]->name.c_str());
- EXPECT_STREQ("name2", found[1]->name.c_str());
-
- analyzer->FindEvents(Query::EventName() == Query::Pattern("name*"), &found);
- ASSERT_EQ(3u, found.size());
- EXPECT_STREQ("name1", found[0]->name.c_str());
- EXPECT_STREQ("name2", found[1]->name.c_str());
- EXPECT_STREQ("name3x", found[2]->name.c_str());
-
- analyzer->FindEvents(Query::EventName() != Query::Pattern("name*"), &found);
- ASSERT_EQ(1u, found.size());
- EXPECT_STREQ("no match", found[0]->name.c_str());
-}
-
-// Test that duration queries work.
-TEST_F(TraceEventAnalyzerTest, BeginEndDuration) {
- ManualSetUp();
-
- const base::TimeDelta kSleepTime = base::TimeDelta::FromMilliseconds(200);
- // We will search for events that have a duration of greater than 90% of the
- // sleep time, so that there is no flakiness.
- int64_t duration_cutoff_us = (kSleepTime.InMicroseconds() * 9) / 10;
-
- BeginTracing();
- {
- TRACE_EVENT_BEGIN0("cat1", "name1"); // found by duration query
- TRACE_EVENT_BEGIN0("noise", "name2"); // not searched for, just noise
- {
- TRACE_EVENT_BEGIN0("cat2", "name3"); // found by duration query
- // next event not searched for, just noise
- TRACE_EVENT_INSTANT0("noise", "name4", TRACE_EVENT_SCOPE_THREAD);
- base::PlatformThread::Sleep(kSleepTime);
- TRACE_EVENT_BEGIN0("cat2", "name5"); // not found (duration too short)
- TRACE_EVENT_END0("cat2", "name5"); // not found (duration too short)
- TRACE_EVENT_END0("cat2", "name3"); // found by duration query
- }
- TRACE_EVENT_END0("noise", "name2"); // not searched for, just noise
- TRACE_EVENT_END0("cat1", "name1"); // found by duration query
- }
- EndTracing();
-
- std::unique_ptr<TraceAnalyzer> analyzer(
- TraceAnalyzer::Create(output_.json_output));
- ASSERT_TRUE(analyzer.get());
- analyzer->AssociateBeginEndEvents();
-
- TraceEventVector found;
- analyzer->FindEvents(
- Query::MatchBeginWithEnd() &&
- Query::EventDuration() >
- Query::Int(static_cast<int>(duration_cutoff_us)) &&
- (Query::EventCategory() == Query::String("cat1") ||
- Query::EventCategory() == Query::String("cat2") ||
- Query::EventCategory() == Query::String("cat3")),
- &found);
- ASSERT_EQ(2u, found.size());
- EXPECT_STREQ("name1", found[0]->name.c_str());
- EXPECT_STREQ("name3", found[1]->name.c_str());
-}
-
-// Test that duration queries work.
-TEST_F(TraceEventAnalyzerTest, CompleteDuration) {
- ManualSetUp();
-
- const base::TimeDelta kSleepTime = base::TimeDelta::FromMilliseconds(200);
- // We will search for events that have a duration of greater than 90% of the
- // sleep time, so that there is no flakiness.
- int64_t duration_cutoff_us = (kSleepTime.InMicroseconds() * 9) / 10;
-
- BeginTracing();
- {
- TRACE_EVENT0("cat1", "name1"); // found by duration query
- TRACE_EVENT0("noise", "name2"); // not searched for, just noise
- {
- TRACE_EVENT0("cat2", "name3"); // found by duration query
- // next event not searched for, just noise
- TRACE_EVENT_INSTANT0("noise", "name4", TRACE_EVENT_SCOPE_THREAD);
- base::PlatformThread::Sleep(kSleepTime);
- TRACE_EVENT0("cat2", "name5"); // not found (duration too short)
- }
- }
- EndTracing();
-
- std::unique_ptr<TraceAnalyzer> analyzer(
- TraceAnalyzer::Create(output_.json_output));
- ASSERT_TRUE(analyzer.get());
- analyzer->AssociateBeginEndEvents();
-
- TraceEventVector found;
- analyzer->FindEvents(
- Query::EventCompleteDuration() >
- Query::Int(static_cast<int>(duration_cutoff_us)) &&
- (Query::EventCategory() == Query::String("cat1") ||
- Query::EventCategory() == Query::String("cat2") ||
- Query::EventCategory() == Query::String("cat3")),
- &found);
- ASSERT_EQ(2u, found.size());
- EXPECT_STREQ("name1", found[0]->name.c_str());
- EXPECT_STREQ("name3", found[1]->name.c_str());
-}
-
-// Test AssociateBeginEndEvents
-TEST_F(TraceEventAnalyzerTest, BeginEndAssocations) {
- ManualSetUp();
-
- BeginTracing();
- {
- TRACE_EVENT_END0("cat1", "name1"); // does not match out of order begin
- TRACE_EVENT_BEGIN0("cat1", "name2");
- TRACE_EVENT_INSTANT0("cat1", "name3", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_BEGIN0("cat1", "name1");
- TRACE_EVENT_END0("cat1", "name2");
- }
- EndTracing();
-
- std::unique_ptr<TraceAnalyzer> analyzer(
- TraceAnalyzer::Create(output_.json_output));
- ASSERT_TRUE(analyzer.get());
- analyzer->AssociateBeginEndEvents();
-
- TraceEventVector found;
- analyzer->FindEvents(Query::MatchBeginWithEnd(), &found);
- ASSERT_EQ(1u, found.size());
- EXPECT_STREQ("name2", found[0]->name.c_str());
-}
-
-// Test MergeAssociatedEventArgs
-TEST_F(TraceEventAnalyzerTest, MergeAssociatedEventArgs) {
- ManualSetUp();
-
- const char arg_string[] = "arg_string";
- BeginTracing();
- {
- TRACE_EVENT_BEGIN0("cat1", "name1");
- TRACE_EVENT_END1("cat1", "name1", "arg", arg_string);
- }
- EndTracing();
-
- std::unique_ptr<TraceAnalyzer> analyzer(
- TraceAnalyzer::Create(output_.json_output));
- ASSERT_TRUE(analyzer.get());
- analyzer->AssociateBeginEndEvents();
-
- TraceEventVector found;
- analyzer->FindEvents(Query::MatchBeginName("name1"), &found);
- ASSERT_EQ(1u, found.size());
- std::string arg_actual;
- EXPECT_FALSE(found[0]->GetArgAsString("arg", &arg_actual));
-
- analyzer->MergeAssociatedEventArgs();
- EXPECT_TRUE(found[0]->GetArgAsString("arg", &arg_actual));
- EXPECT_STREQ(arg_string, arg_actual.c_str());
-}
-
-// Test AssociateAsyncBeginEndEvents
-TEST_F(TraceEventAnalyzerTest, AsyncBeginEndAssocations) {
- ManualSetUp();
-
- BeginTracing();
- {
- TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xA); // no match / out of order
- TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xB);
- TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xC);
- TRACE_EVENT_INSTANT0("cat1", "name1", TRACE_EVENT_SCOPE_THREAD); // noise
- TRACE_EVENT0("cat1", "name1"); // noise
- TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xB);
- TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xC);
- TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xA); // no match / out of order
- }
- EndTracing();
-
- std::unique_ptr<TraceAnalyzer> analyzer(
- TraceAnalyzer::Create(output_.json_output));
- ASSERT_TRUE(analyzer.get());
- analyzer->AssociateAsyncBeginEndEvents();
-
- TraceEventVector found;
- analyzer->FindEvents(Query::MatchAsyncBeginWithNext(), &found);
- ASSERT_EQ(2u, found.size());
- EXPECT_STRCASEEQ("0xb", found[0]->id.c_str());
- EXPECT_STRCASEEQ("0xc", found[1]->id.c_str());
-}
-
-// Test AssociateAsyncBeginEndEvents
-TEST_F(TraceEventAnalyzerTest, AsyncBeginEndAssocationsWithSteps) {
- ManualSetUp();
-
- BeginTracing();
- {
- TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xA, "s1");
- TRACE_EVENT_ASYNC_END0("c", "n", 0xA);
- TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xB);
- TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xC);
- TRACE_EVENT_ASYNC_STEP_PAST0("c", "n", 0xB, "s1");
- TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xC, "s1");
- TRACE_EVENT_ASYNC_STEP_INTO1("c", "n", 0xC, "s2", "a", 1);
- TRACE_EVENT_ASYNC_END0("c", "n", 0xB);
- TRACE_EVENT_ASYNC_END0("c", "n", 0xC);
- TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xA);
- TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xA, "s2");
- }
- EndTracing();
-
- std::unique_ptr<TraceAnalyzer> analyzer(
- TraceAnalyzer::Create(output_.json_output));
- ASSERT_TRUE(analyzer.get());
- analyzer->AssociateAsyncBeginEndEvents();
-
- TraceEventVector found;
- analyzer->FindEvents(Query::MatchAsyncBeginWithNext(), &found);
- ASSERT_EQ(3u, found.size());
-
- EXPECT_STRCASEEQ("0xb", found[0]->id.c_str());
- EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, found[0]->other_event->phase);
- EXPECT_EQ(found[0], found[0]->other_event->prev_event);
- EXPECT_TRUE(found[0]->other_event->other_event);
- EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_END,
- found[0]->other_event->other_event->phase);
- EXPECT_EQ(found[0]->other_event,
- found[0]->other_event->other_event->prev_event);
-
- EXPECT_STRCASEEQ("0xc", found[1]->id.c_str());
- EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, found[1]->other_event->phase);
- EXPECT_EQ(found[1], found[1]->other_event->prev_event);
- EXPECT_TRUE(found[1]->other_event->other_event);
- EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO,
- found[1]->other_event->other_event->phase);
- EXPECT_EQ(found[1]->other_event,
- found[1]->other_event->other_event->prev_event);
- double arg_actual = 0;
- EXPECT_TRUE(found[1]->other_event->other_event->GetArgAsNumber(
- "a", &arg_actual));
- EXPECT_EQ(1.0, arg_actual);
- EXPECT_TRUE(found[1]->other_event->other_event->other_event);
- EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_END,
- found[1]->other_event->other_event->other_event->phase);
-
- EXPECT_STRCASEEQ("0xa", found[2]->id.c_str());
- EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, found[2]->other_event->phase);
-}
-
-// Test that the TraceAnalyzer custom associations work.
-TEST_F(TraceEventAnalyzerTest, CustomAssociations) {
- ManualSetUp();
-
- // Add events that begin/end in pipelined ordering with unique ID parameter
- // to match up the begin/end pairs.
- BeginTracing();
- {
- // no begin match
- TRACE_EVENT_INSTANT1("cat1", "end", TRACE_EVENT_SCOPE_THREAD, "id", 1);
- // end is cat4
- TRACE_EVENT_INSTANT1("cat2", "begin", TRACE_EVENT_SCOPE_THREAD, "id", 2);
- // end is cat5
- TRACE_EVENT_INSTANT1("cat3", "begin", TRACE_EVENT_SCOPE_THREAD, "id", 3);
- TRACE_EVENT_INSTANT1("cat4", "end", TRACE_EVENT_SCOPE_THREAD, "id", 2);
- TRACE_EVENT_INSTANT1("cat5", "end", TRACE_EVENT_SCOPE_THREAD, "id", 3);
- // no end match
- TRACE_EVENT_INSTANT1("cat6", "begin", TRACE_EVENT_SCOPE_THREAD, "id", 1);
- }
- EndTracing();
-
- std::unique_ptr<TraceAnalyzer> analyzer(
- TraceAnalyzer::Create(output_.json_output));
- ASSERT_TRUE(analyzer.get());
-
- // begin, end, and match queries to find proper begin/end pairs.
- Query begin(Query::EventName() == Query::String("begin"));
- Query end(Query::EventName() == Query::String("end"));
- Query match(Query::EventArg("id") == Query::OtherArg("id"));
- analyzer->AssociateEvents(begin, end, match);
-
- TraceEventVector found;
-
- // cat1 has no other_event.
- analyzer->FindEvents(Query::EventCategory() == Query::String("cat1") &&
- Query::EventHasOther(), &found);
- EXPECT_EQ(0u, found.size());
-
- // cat1 has no other_event.
- analyzer->FindEvents(Query::EventCategory() == Query::String("cat1") &&
- !Query::EventHasOther(), &found);
- EXPECT_EQ(1u, found.size());
-
- // cat6 has no other_event.
- analyzer->FindEvents(Query::EventCategory() == Query::String("cat6") &&
- !Query::EventHasOther(), &found);
- EXPECT_EQ(1u, found.size());
-
- // cat2 and cat4 are associated.
- analyzer->FindEvents(Query::EventCategory() == Query::String("cat2") &&
- Query::OtherCategory() == Query::String("cat4"), &found);
- EXPECT_EQ(1u, found.size());
-
- // cat4 and cat2 are not associated.
- analyzer->FindEvents(Query::EventCategory() == Query::String("cat4") &&
- Query::OtherCategory() == Query::String("cat2"), &found);
- EXPECT_EQ(0u, found.size());
-
- // cat3 and cat5 are associated.
- analyzer->FindEvents(Query::EventCategory() == Query::String("cat3") &&
- Query::OtherCategory() == Query::String("cat5"), &found);
- EXPECT_EQ(1u, found.size());
-
- // cat5 and cat3 are not associated.
- analyzer->FindEvents(Query::EventCategory() == Query::String("cat5") &&
- Query::OtherCategory() == Query::String("cat3"), &found);
- EXPECT_EQ(0u, found.size());
-}
-
-// Verify that Query literals and types are properly casted.
-TEST_F(TraceEventAnalyzerTest, Literals) {
- ManualSetUp();
-
- // Since these queries don't refer to the event data, the dummy event below
- // will never be accessed.
- TraceEvent dummy;
- char char_num = 5;
- short short_num = -5;
- EXPECT_TRUE((Query::Double(5.0) == Query::Int(char_num)).Evaluate(dummy));
- EXPECT_TRUE((Query::Double(-5.0) == Query::Int(short_num)).Evaluate(dummy));
- EXPECT_TRUE((Query::Double(1.0) == Query::Uint(1u)).Evaluate(dummy));
- EXPECT_TRUE((Query::Double(1.0) == Query::Int(1)).Evaluate(dummy));
- EXPECT_TRUE((Query::Double(-1.0) == Query::Int(-1)).Evaluate(dummy));
- EXPECT_TRUE((Query::Double(1.0) == Query::Double(1.0f)).Evaluate(dummy));
- EXPECT_TRUE((Query::Bool(true) == Query::Int(1)).Evaluate(dummy));
- EXPECT_TRUE((Query::Bool(false) == Query::Int(0)).Evaluate(dummy));
- EXPECT_TRUE((Query::Bool(true) == Query::Double(1.0f)).Evaluate(dummy));
- EXPECT_TRUE((Query::Bool(false) == Query::Double(0.0f)).Evaluate(dummy));
-}
-
-// Test GetRateStats.
-TEST_F(TraceEventAnalyzerTest, RateStats) {
- std::vector<TraceEvent> events;
- events.reserve(100);
- TraceEventVector event_ptrs;
- double timestamp = 0.0;
- double little_delta = 1.0;
- double big_delta = 10.0;
- double tiny_delta = 0.1;
- RateStats stats;
- RateStatsOptions options;
-
- // Insert 10 events, each apart by little_delta.
- for (int i = 0; i < 10; ++i) {
- timestamp += little_delta;
- TraceEvent event;
- event.timestamp = timestamp;
- events.push_back(std::move(event));
- event_ptrs.push_back(&events.back());
- }
-
- ASSERT_TRUE(GetRateStats(event_ptrs, &stats, NULL));
- EXPECT_EQ(little_delta, stats.mean_us);
- EXPECT_EQ(little_delta, stats.min_us);
- EXPECT_EQ(little_delta, stats.max_us);
- EXPECT_EQ(0.0, stats.standard_deviation_us);
-
- // Add an event apart by big_delta.
- {
- timestamp += big_delta;
- TraceEvent event;
- event.timestamp = timestamp;
- events.push_back(std::move(event));
- event_ptrs.push_back(&events.back());
- }
-
- ASSERT_TRUE(GetRateStats(event_ptrs, &stats, NULL));
- EXPECT_LT(little_delta, stats.mean_us);
- EXPECT_EQ(little_delta, stats.min_us);
- EXPECT_EQ(big_delta, stats.max_us);
- EXPECT_LT(0.0, stats.standard_deviation_us);
-
- // Trim off the biggest delta and verify stats.
- options.trim_min = 0;
- options.trim_max = 1;
- ASSERT_TRUE(GetRateStats(event_ptrs, &stats, &options));
- EXPECT_EQ(little_delta, stats.mean_us);
- EXPECT_EQ(little_delta, stats.min_us);
- EXPECT_EQ(little_delta, stats.max_us);
- EXPECT_EQ(0.0, stats.standard_deviation_us);
-
- // Add an event apart by tiny_delta.
- {
- timestamp += tiny_delta;
- TraceEvent event;
- event.timestamp = timestamp;
- events.push_back(std::move(event));
- event_ptrs.push_back(&events.back());
- }
-
- // Trim off both the biggest and tiniest delta and verify stats.
- options.trim_min = 1;
- options.trim_max = 1;
- ASSERT_TRUE(GetRateStats(event_ptrs, &stats, &options));
- EXPECT_EQ(little_delta, stats.mean_us);
- EXPECT_EQ(little_delta, stats.min_us);
- EXPECT_EQ(little_delta, stats.max_us);
- EXPECT_EQ(0.0, stats.standard_deviation_us);
-
- // Verify smallest allowed number of events.
- {
- TraceEvent event;
- TraceEventVector few_event_ptrs;
- few_event_ptrs.push_back(&event);
- few_event_ptrs.push_back(&event);
- ASSERT_FALSE(GetRateStats(few_event_ptrs, &stats, NULL));
- few_event_ptrs.push_back(&event);
- ASSERT_TRUE(GetRateStats(few_event_ptrs, &stats, NULL));
-
- // Trim off more than allowed and verify failure.
- options.trim_min = 0;
- options.trim_max = 1;
- ASSERT_FALSE(GetRateStats(few_event_ptrs, &stats, &options));
- }
-}
-
-// Test FindFirstOf and FindLastOf.
-TEST_F(TraceEventAnalyzerTest, FindOf) {
- size_t num_events = 100;
- size_t index = 0;
- TraceEventVector event_ptrs;
- EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(true), 0, &index));
- EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(true), 10, &index));
- EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(true), 0, &index));
- EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(true), 10, &index));
-
- std::vector<TraceEvent> events;
- events.resize(num_events);
- for (size_t i = 0; i < events.size(); ++i)
- event_ptrs.push_back(&events[i]);
- size_t bam_index = num_events/2;
- events[bam_index].name = "bam";
- Query query_bam = Query::EventName() == Query::String(events[bam_index].name);
-
- // FindFirstOf
- EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(false), 0, &index));
- EXPECT_TRUE(FindFirstOf(event_ptrs, Query::Bool(true), 0, &index));
- EXPECT_EQ(0u, index);
- EXPECT_TRUE(FindFirstOf(event_ptrs, Query::Bool(true), 5, &index));
- EXPECT_EQ(5u, index);
-
- EXPECT_FALSE(FindFirstOf(event_ptrs, query_bam, bam_index + 1, &index));
- EXPECT_TRUE(FindFirstOf(event_ptrs, query_bam, 0, &index));
- EXPECT_EQ(bam_index, index);
- EXPECT_TRUE(FindFirstOf(event_ptrs, query_bam, bam_index, &index));
- EXPECT_EQ(bam_index, index);
-
- // FindLastOf
- EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(false), 1000, &index));
- EXPECT_TRUE(FindLastOf(event_ptrs, Query::Bool(true), 1000, &index));
- EXPECT_EQ(num_events - 1, index);
- EXPECT_TRUE(FindLastOf(event_ptrs, Query::Bool(true), num_events - 5,
- &index));
- EXPECT_EQ(num_events - 5, index);
-
- EXPECT_FALSE(FindLastOf(event_ptrs, query_bam, bam_index - 1, &index));
- EXPECT_TRUE(FindLastOf(event_ptrs, query_bam, num_events, &index));
- EXPECT_EQ(bam_index, index);
- EXPECT_TRUE(FindLastOf(event_ptrs, query_bam, bam_index, &index));
- EXPECT_EQ(bam_index, index);
-}
-
-// Test FindClosest.
-TEST_F(TraceEventAnalyzerTest, FindClosest) {
- size_t index_1 = 0;
- size_t index_2 = 0;
- TraceEventVector event_ptrs;
- EXPECT_FALSE(FindClosest(event_ptrs, Query::Bool(true), 0,
- &index_1, &index_2));
-
- size_t num_events = 5;
- std::vector<TraceEvent> events;
- events.resize(num_events);
- for (size_t i = 0; i < events.size(); ++i) {
- // timestamps go up exponentially so the lower index is always closer in
- // time than the higher index.
- events[i].timestamp = static_cast<double>(i) * static_cast<double>(i);
- event_ptrs.push_back(&events[i]);
- }
- events[0].name = "one";
- events[2].name = "two";
- events[4].name = "three";
- Query query_named = Query::EventName() != Query::String(std::string());
- Query query_one = Query::EventName() == Query::String("one");
-
- // Only one event matches query_one, so two closest can't be found.
- EXPECT_FALSE(FindClosest(event_ptrs, query_one, 0, &index_1, &index_2));
-
- EXPECT_TRUE(FindClosest(event_ptrs, query_one, 3, &index_1, NULL));
- EXPECT_EQ(0u, index_1);
-
- EXPECT_TRUE(FindClosest(event_ptrs, query_named, 1, &index_1, &index_2));
- EXPECT_EQ(0u, index_1);
- EXPECT_EQ(2u, index_2);
-
- EXPECT_TRUE(FindClosest(event_ptrs, query_named, 4, &index_1, &index_2));
- EXPECT_EQ(4u, index_1);
- EXPECT_EQ(2u, index_2);
-
- EXPECT_TRUE(FindClosest(event_ptrs, query_named, 3, &index_1, &index_2));
- EXPECT_EQ(2u, index_1);
- EXPECT_EQ(0u, index_2);
-}
-
-// Test CountMatches.
-TEST_F(TraceEventAnalyzerTest, CountMatches) {
- TraceEventVector event_ptrs;
- EXPECT_EQ(0u, CountMatches(event_ptrs, Query::Bool(true), 0, 10));
-
- size_t num_events = 5;
- size_t num_named = 3;
- std::vector<TraceEvent> events;
- events.resize(num_events);
- for (size_t i = 0; i < events.size(); ++i)
- event_ptrs.push_back(&events[i]);
- events[0].name = "one";
- events[2].name = "two";
- events[4].name = "three";
- Query query_named = Query::EventName() != Query::String(std::string());
- Query query_one = Query::EventName() == Query::String("one");
-
- EXPECT_EQ(0u, CountMatches(event_ptrs, Query::Bool(false)));
- EXPECT_EQ(num_events, CountMatches(event_ptrs, Query::Bool(true)));
- EXPECT_EQ(num_events - 1, CountMatches(event_ptrs, Query::Bool(true),
- 1, num_events));
- EXPECT_EQ(1u, CountMatches(event_ptrs, query_one));
- EXPECT_EQ(num_events - 1, CountMatches(event_ptrs, !query_one));
- EXPECT_EQ(num_named, CountMatches(event_ptrs, query_named));
-}
-
-TEST_F(TraceEventAnalyzerTest, ComplexArgument) {
- ManualSetUp();
-
- BeginTracing();
- {
- std::unique_ptr<base::trace_event::TracedValue> value(
- new base::trace_event::TracedValue);
- value->SetString("property", "value");
- TRACE_EVENT1("cat", "name", "arg", std::move(value));
- }
- EndTracing();
-
- std::unique_ptr<TraceAnalyzer> analyzer(
- TraceAnalyzer::Create(output_.json_output));
- ASSERT_TRUE(analyzer.get());
-
- TraceEventVector events;
- analyzer->FindEvents(Query::EventName() == Query::String("name"), &events);
-
- EXPECT_EQ(1u, events.size());
- EXPECT_EQ("cat", events[0]->category);
- EXPECT_EQ("name", events[0]->name);
- EXPECT_TRUE(events[0]->HasArg("arg"));
-
- std::unique_ptr<base::Value> arg;
- events[0]->GetArgAsValue("arg", &arg);
- base::DictionaryValue* arg_dict;
- EXPECT_TRUE(arg->GetAsDictionary(&arg_dict));
- std::string property;
- EXPECT_TRUE(arg_dict->GetString("property", &property));
- EXPECT_EQ("value", property);
-}
-
-} // namespace trace_analyzer
diff --git a/base/threading/thread_id_name_manager.cc b/base/threading/thread_id_name_manager.cc
index 107e0dc498..c0ca42da30 100644
--- a/base/threading/thread_id_name_manager.cc
+++ b/base/threading/thread_id_name_manager.cc
@@ -10,7 +10,8 @@
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/strings/string_util.h"
-#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+// Unsupported in libchrome.
+// #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
namespace base {
namespace {
@@ -80,8 +81,9 @@ void ThreadIdNameManager::SetName(PlatformThreadId id,
// call GetName(which holds a lock) during the first allocation because it can
// cause a deadlock when the first allocation happens in the
// ThreadIdNameManager itself when holding the lock.
- trace_event::AllocationContextTracker::SetCurrentThreadName(
- leaked_str->c_str());
+ // Unsupported in libchrome.
+ // trace_event::AllocationContextTracker::SetCurrentThreadName(
+ // leaked_str->c_str());
}
const char* ThreadIdNameManager::GetName(PlatformThreadId id) {
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/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.h b/base/trace_event/heap_profiler.h
index cf57524627..a9cfcfde05 100644
--- a/base/trace_event/heap_profiler.h
+++ b/base/trace_event/heap_profiler.h
@@ -5,6 +5,22 @@
#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_H
#define BASE_TRACE_EVENT_HEAP_PROFILER_H
+// Replace with stub implementation.
+#if 1
+#define TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION \
+ trace_event_internal::HeapProfilerScopedTaskExecutionTracker
+
+namespace trace_event_internal {
+
+class HeapProfilerScopedTaskExecutionTracker {
+ public:
+ explicit HeapProfilerScopedTaskExecutionTracker(const char*) {}
+};
+
+} // namespace trace_event_internal
+
+#else
+
#include "base/compiler_specific.h"
#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
@@ -86,4 +102,5 @@ class BASE_EXPORT HeapProfilerScopedIgnore {
} // namespace trace_event_internal
+#endif
#endif // BASE_TRACE_EVENT_HEAP_PROFILER_H
diff --git a/base/trace_event/heap_profiler_allocation_context.cc b/base/trace_event/heap_profiler_allocation_context.cc
deleted file mode 100644
index 0f330a817e..0000000000
--- a/base/trace_event/heap_profiler_allocation_context.cc
+++ /dev/null
@@ -1,88 +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/heap_profiler_allocation_context.h"
-
-#include <cstring>
-
-#include "base/hash.h"
-#include "base/macros.h"
-
-namespace base {
-namespace trace_event {
-
-bool operator < (const StackFrame& lhs, const StackFrame& rhs) {
- return lhs.value < rhs.value;
-}
-
-bool operator == (const StackFrame& lhs, const StackFrame& rhs) {
- return lhs.value == rhs.value;
-}
-
-bool operator != (const StackFrame& lhs, const StackFrame& rhs) {
- return !(lhs.value == rhs.value);
-}
-
-Backtrace::Backtrace(): frame_count(0) {}
-
-bool operator==(const Backtrace& lhs, const Backtrace& rhs) {
- if (lhs.frame_count != rhs.frame_count) return false;
- return std::equal(lhs.frames, lhs.frames + lhs.frame_count, rhs.frames);
-}
-
-bool operator!=(const Backtrace& lhs, const Backtrace& rhs) {
- return !(lhs == rhs);
-}
-
-AllocationContext::AllocationContext(): type_name(nullptr) {}
-
-AllocationContext::AllocationContext(const Backtrace& backtrace,
- const char* type_name)
- : backtrace(backtrace), type_name(type_name) {}
-
-bool operator==(const AllocationContext& lhs, const AllocationContext& rhs) {
- return (lhs.backtrace == rhs.backtrace) && (lhs.type_name == rhs.type_name);
-}
-
-bool operator!=(const AllocationContext& lhs, const AllocationContext& rhs) {
- return !(lhs == rhs);
-}
-} // namespace trace_event
-} // namespace base
-
-namespace BASE_HASH_NAMESPACE {
-using base::trace_event::AllocationContext;
-using base::trace_event::Backtrace;
-using base::trace_event::StackFrame;
-
-size_t hash<StackFrame>::operator()(const StackFrame& frame) const {
- return hash<const void*>()(frame.value);
-}
-
-size_t hash<Backtrace>::operator()(const Backtrace& backtrace) const {
- const void* values[Backtrace::kMaxFrameCount];
- for (size_t i = 0; i != backtrace.frame_count; ++i) {
- values[i] = backtrace.frames[i].value;
- }
- return base::SuperFastHash(
- reinterpret_cast<const char*>(values),
- static_cast<int>(backtrace.frame_count * sizeof(*values)));
-}
-
-size_t hash<AllocationContext>::operator()(const AllocationContext& ctx) const {
- size_t backtrace_hash = hash<Backtrace>()(ctx.backtrace);
-
- // Multiplicative hash from [Knuth 1998]. Works best if |size_t| is 32 bits,
- // because the magic number is a prime very close to 2^32 / golden ratio, but
- // will still redistribute keys bijectively on 64-bit architectures because
- // the magic number is coprime to 2^64.
- size_t type_hash = reinterpret_cast<size_t>(ctx.type_name) * 2654435761;
-
- // Multiply one side to break the commutativity of +. Multiplication with a
- // number coprime to |numeric_limits<size_t>::max() + 1| is bijective so
- // randomness is preserved.
- return (backtrace_hash * 3) + type_hash;
-}
-
-} // BASE_HASH_NAMESPACE
diff --git a/base/trace_event/heap_profiler_allocation_context.h b/base/trace_event/heap_profiler_allocation_context.h
deleted file mode 100644
index 24e2dec73f..0000000000
--- a/base/trace_event/heap_profiler_allocation_context.h
+++ /dev/null
@@ -1,131 +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.
-
-#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
-#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/base_export.h"
-#include "base/containers/hash_tables.h"
-
-namespace base {
-namespace trace_event {
-
-// When heap profiling is enabled, tracing keeps track of the allocation
-// context for each allocation intercepted. It is generated by the
-// |AllocationContextTracker| which keeps stacks of context in TLS.
-// The tracker is initialized lazily.
-
-// The backtrace in the allocation context is a snapshot of the stack. For now,
-// this is the pseudo stack where frames are created by trace event macros. In
-// the future, we might add the option to use the native call stack. In that
-// case, |Backtrace| and |AllocationContextTracker::GetContextSnapshot| might
-// have different implementations that can be selected by a compile time flag.
-
-// The number of stack frames stored in the backtrace is a trade off between
-// memory used for tracing and accuracy. Measurements done on a prototype
-// revealed that:
-//
-// - In 60 percent of the cases, pseudo stack depth <= 7.
-// - In 87 percent of the cases, pseudo stack depth <= 9.
-// - In 95 percent of the cases, pseudo stack depth <= 11.
-//
-// See the design doc (https://goo.gl/4s7v7b) for more details.
-
-// Represents (pseudo) stack frame. Used in Backtrace class below.
-//
-// Conceptually stack frame is identified by its value, and type is used
-// mostly to properly format the value. Value is expected to be a valid
-// pointer from process' address space.
-struct BASE_EXPORT StackFrame {
- enum class Type {
- TRACE_EVENT_NAME, // const char* string
- THREAD_NAME, // const char* thread name
- PROGRAM_COUNTER, // as returned by stack tracing (e.g. by StackTrace)
- };
-
- static StackFrame FromTraceEventName(const char* name) {
- return {Type::TRACE_EVENT_NAME, name};
- }
- static StackFrame FromThreadName(const char* name) {
- return {Type::THREAD_NAME, name};
- }
- static StackFrame FromProgramCounter(const void* pc) {
- return {Type::PROGRAM_COUNTER, pc};
- }
-
- Type type;
- const void* value;
-};
-
-bool BASE_EXPORT operator < (const StackFrame& lhs, const StackFrame& rhs);
-bool BASE_EXPORT operator == (const StackFrame& lhs, const StackFrame& rhs);
-bool BASE_EXPORT operator != (const StackFrame& lhs, const StackFrame& rhs);
-
-struct BASE_EXPORT Backtrace {
- Backtrace();
-
- // If the stack is higher than what can be stored here, the bottom frames
- // (the ones closer to main()) are stored. Depth of 12 is enough for most
- // pseudo traces (see above), but not for native traces, where we need more.
- enum { kMaxFrameCount = 48 };
- StackFrame frames[kMaxFrameCount];
- size_t frame_count;
-};
-
-bool BASE_EXPORT operator==(const Backtrace& lhs, const Backtrace& rhs);
-bool BASE_EXPORT operator!=(const Backtrace& lhs, const Backtrace& rhs);
-
-// The |AllocationContext| is context metadata that is kept for every allocation
-// when heap profiling is enabled. To simplify memory management for book-
-// keeping, this struct has a fixed size.
-struct BASE_EXPORT AllocationContext {
- AllocationContext();
- AllocationContext(const Backtrace& backtrace, const char* type_name);
-
- Backtrace backtrace;
-
- // Type name of the type stored in the allocated memory. A null pointer
- // indicates "unknown type". Grouping is done by comparing pointers, not by
- // deep string comparison. In a component build, where a type name can have a
- // string literal in several dynamic libraries, this may distort grouping.
- const char* type_name;
-};
-
-bool BASE_EXPORT operator==(const AllocationContext& lhs,
- const AllocationContext& rhs);
-bool BASE_EXPORT operator!=(const AllocationContext& lhs,
- const AllocationContext& rhs);
-
-// Struct to store the size and count of the allocations.
-struct AllocationMetrics {
- size_t size;
- size_t count;
-};
-
-} // namespace trace_event
-} // namespace base
-
-namespace BASE_HASH_NAMESPACE {
-
-template <>
-struct BASE_EXPORT hash<base::trace_event::StackFrame> {
- size_t operator()(const base::trace_event::StackFrame& frame) const;
-};
-
-template <>
-struct BASE_EXPORT hash<base::trace_event::Backtrace> {
- size_t operator()(const base::trace_event::Backtrace& backtrace) const;
-};
-
-template <>
-struct BASE_EXPORT hash<base::trace_event::AllocationContext> {
- size_t operator()(const base::trace_event::AllocationContext& context) const;
-};
-
-} // BASE_HASH_NAMESPACE
-
-#endif // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.cc b/base/trace_event/heap_profiler_allocation_context_tracker.cc
deleted file mode 100644
index b47dc16edd..0000000000
--- a/base/trace_event/heap_profiler_allocation_context_tracker.cc
+++ /dev/null
@@ -1,250 +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/heap_profiler_allocation_context_tracker.h"
-
-#include <algorithm>
-#include <iterator>
-
-#include "base/atomicops.h"
-#include "base/debug/leak_annotations.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/thread_local_storage.h"
-#include "base/trace_event/heap_profiler_allocation_context.h"
-
-#if defined(OS_LINUX) || defined(OS_ANDROID)
-#include <sys/prctl.h>
-#endif
-
-namespace base {
-namespace trace_event {
-
-subtle::Atomic32 AllocationContextTracker::capture_mode_ =
- static_cast<int32_t>(AllocationContextTracker::CaptureMode::DISABLED);
-
-namespace {
-
-const size_t kMaxStackDepth = 128u;
-const size_t kMaxTaskDepth = 16u;
-AllocationContextTracker* const kInitializingSentinel =
- reinterpret_cast<AllocationContextTracker*>(-1);
-
-ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER;
-
-// This function is added to the TLS slot to clean up the instance when the
-// thread exits.
-void DestructAllocationContextTracker(void* alloc_ctx_tracker) {
- delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker);
-}
-
-// Cannot call ThreadIdNameManager::GetName because it holds a lock and causes
-// deadlock when lock is already held by ThreadIdNameManager before the current
-// allocation. Gets the thread name from kernel if available or returns a string
-// with id. This function intenionally leaks the allocated strings since they
-// are used to tag allocations even after the thread dies.
-const char* GetAndLeakThreadName() {
- char name[16];
-#if defined(OS_LINUX) || defined(OS_ANDROID)
- // If the thread name is not set, try to get it from prctl. Thread name might
- // not be set in cases where the thread started before heap profiling was
- // enabled.
- int err = prctl(PR_GET_NAME, name);
- if (!err) {
- return strdup(name);
- }
-#endif // defined(OS_LINUX) || defined(OS_ANDROID)
-
- // Use tid if we don't have a thread name.
- snprintf(name, sizeof(name), "%lu",
- static_cast<unsigned long>(PlatformThread::CurrentId()));
- return strdup(name);
-}
-
-} // namespace
-
-// static
-AllocationContextTracker*
-AllocationContextTracker::GetInstanceForCurrentThread() {
- AllocationContextTracker* tracker =
- static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get());
- if (tracker == kInitializingSentinel)
- return nullptr; // Re-entrancy case.
-
- if (!tracker) {
- g_tls_alloc_ctx_tracker.Set(kInitializingSentinel);
- tracker = new AllocationContextTracker();
- g_tls_alloc_ctx_tracker.Set(tracker);
- }
-
- return tracker;
-}
-
-AllocationContextTracker::AllocationContextTracker()
- : thread_name_(nullptr), ignore_scope_depth_(0) {
- pseudo_stack_.reserve(kMaxStackDepth);
- task_contexts_.reserve(kMaxTaskDepth);
-}
-AllocationContextTracker::~AllocationContextTracker() {}
-
-// static
-void AllocationContextTracker::SetCurrentThreadName(const char* name) {
- if (name && capture_mode() != CaptureMode::DISABLED) {
- GetInstanceForCurrentThread()->thread_name_ = name;
- }
-}
-
-// static
-void AllocationContextTracker::SetCaptureMode(CaptureMode mode) {
- // When enabling capturing, also initialize the TLS slot. This does not create
- // a TLS instance yet.
- if (mode != CaptureMode::DISABLED && !g_tls_alloc_ctx_tracker.initialized())
- g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker);
-
- // Release ordering ensures that when a thread observes |capture_mode_| to
- // be true through an acquire load, the TLS slot has been initialized.
- subtle::Release_Store(&capture_mode_, static_cast<int32_t>(mode));
-}
-
-void AllocationContextTracker::PushPseudoStackFrame(
- AllocationContextTracker::PseudoStackFrame stack_frame) {
- // 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);
- else
- NOTREACHED();
-}
-
-void AllocationContextTracker::PopPseudoStackFrame(
- AllocationContextTracker::PseudoStackFrame stack_frame) {
- // 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.
- if (pseudo_stack_.empty())
- return;
-
- // 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;
-
- pseudo_stack_.pop_back();
-}
-
-void AllocationContextTracker::PushCurrentTaskContext(const char* context) {
- DCHECK(context);
- if (task_contexts_.size() < kMaxTaskDepth)
- task_contexts_.push_back(context);
- else
- NOTREACHED();
-}
-
-void AllocationContextTracker::PopCurrentTaskContext(const char* context) {
- // Guard for stack underflow. If tracing was started with a TRACE_EVENT in
- // scope, the context was never pushed, so it is possible that pop is called
- // on an empty stack.
- if (task_contexts_.empty())
- return;
-
- DCHECK_EQ(context, task_contexts_.back())
- << "Encountered an unmatched context end";
- task_contexts_.pop_back();
-}
-
-// static
-bool AllocationContextTracker::GetContextSnapshot(AllocationContext* ctx) {
- if (ignore_scope_depth_)
- return false;
-
- 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);
-
- if (!thread_name_) {
- // Ignore the string allocation made by GetAndLeakThreadName to avoid
- // reentrancy.
- ignore_scope_depth_++;
- thread_name_ = GetAndLeakThreadName();
- ANNOTATE_LEAKING_OBJECT_PTR(thread_name_);
- DCHECK(thread_name_);
- ignore_scope_depth_--;
- }
-
- // Add the thread name as the first entry in pseudo stack.
- if (thread_name_) {
- *backtrace++ = StackFrame::FromThreadName(thread_name_);
- }
-
- switch (mode) {
- case CaptureMode::DISABLED:
- {
- break;
- }
- case CaptureMode::PSEUDO_STACK:
- {
- for (const PseudoStackFrame& stack_frame : pseudo_stack_) {
- if (backtrace == backtrace_end) {
- break;
- }
- *backtrace++ =
- StackFrame::FromTraceEventName(stack_frame.trace_event_name);
- }
- break;
- }
- case CaptureMode::NATIVE_STACK:
- {
- // Backtrace contract requires us to return bottom frames, i.e.
- // from main() and up. Stack unwinding produces top frames, i.e.
- // from this point and up until main(). We request many frames to
- // make sure we reach main(), and then copy bottom portion of them.
- const void* frames[128];
- static_assert(arraysize(frames) >= Backtrace::kMaxFrameCount,
- "not requesting enough frames to fill Backtrace");
-#if HAVE_TRACE_STACK_FRAME_POINTERS && !defined(OS_NACL)
- size_t frame_count = debug::TraceStackFramePointers(
- frames,
- arraysize(frames),
- 1 /* exclude this function from the trace */ );
-#else
- size_t frame_count = 0;
- NOTREACHED();
-#endif
-
- // 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];
- *backtrace++ = StackFrame::FromProgramCounter(frame);
- }
- break;
- }
- }
-
- 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;
- }
-
- return true;
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.h b/base/trace_event/heap_profiler_allocation_context_tracker.h
deleted file mode 100644
index 4f2a8c9502..0000000000
--- a/base/trace_event/heap_profiler_allocation_context_tracker.h
+++ /dev/null
@@ -1,121 +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.
-
-#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
-#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
-
-#include <vector>
-
-#include "base/atomicops.h"
-#include "base/base_export.h"
-#include "base/debug/stack_trace.h"
-#include "base/macros.h"
-#include "base/trace_event/heap_profiler_allocation_context.h"
-
-namespace base {
-namespace trace_event {
-
-// The allocation context tracker keeps track of thread-local context for heap
-// profiling. It includes a pseudo stack of trace events. On every allocation
-// the tracker provides a snapshot of its context in the form of an
-// |AllocationContext| that is to be stored together with the allocation
-// details.
-class BASE_EXPORT AllocationContextTracker {
- public:
- enum class CaptureMode: int32_t {
- DISABLED, // Don't capture anything
- PSEUDO_STACK, // GetContextSnapshot() returns pseudo stack trace
- 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);
-
- // Returns global capturing mode.
- inline static CaptureMode capture_mode() {
- // A little lag after heap profiling is enabled or disabled is fine, it is
- // more important that the check is as cheap as possible when capturing is
- // not enabled, so do not issue a memory barrier in the fast path.
- if (subtle::NoBarrier_Load(&capture_mode_) ==
- static_cast<int32_t>(CaptureMode::DISABLED))
- return CaptureMode::DISABLED;
-
- // In the slow path, an acquire load is required to pair with the release
- // store in |SetCaptureMode|. This is to ensure that the TLS slot for
- // the thread-local allocation context tracker has been initialized if
- // |capture_mode| returns something other than DISABLED.
- return static_cast<CaptureMode>(subtle::Acquire_Load(&capture_mode_));
- }
-
- // Returns the thread-local instance, creating one if necessary. Returns
- // always a valid instance, unless it is called re-entrantly, in which case
- // returns nullptr in the nested calls.
- static AllocationContextTracker* GetInstanceForCurrentThread();
-
- // Set the thread name in the AllocationContextTracker of the current thread
- // if capture is enabled.
- 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.
- void begin_ignore_scope() { ignore_scope_depth_++; }
- void end_ignore_scope() {
- if (ignore_scope_depth_)
- ignore_scope_depth_--;
- }
-
- // Pushes a frame onto the thread-local pseudo stack.
- void PushPseudoStackFrame(PseudoStackFrame stack_frame);
-
- // Pops a frame from the thread-local pseudo stack.
- void PopPseudoStackFrame(PseudoStackFrame stack_frame);
-
- // 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);
-
- ~AllocationContextTracker();
-
- private:
- AllocationContextTracker();
-
- static subtle::Atomic32 capture_mode_;
-
- // The pseudo stack where frames are |TRACE_EVENT| names.
- std::vector<PseudoStackFrame> pseudo_stack_;
-
- // The thread name is used as the first entry in the pseudo stack.
- const char* thread_name_;
-
- // Stack of tasks' contexts. Context serves as a different dimension than
- // pseudo stack to cluster allocations.
- std::vector<const char*> task_contexts_;
-
- uint32_t ignore_scope_depth_;
-
- DISALLOW_COPY_AND_ASSIGN(AllocationContextTracker);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc b/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
deleted file mode 100644
index 6317886b0d..0000000000
--- a/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
+++ /dev/null
@@ -1,321 +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 <stddef.h>
-
-#include <iterator>
-
-#include "base/memory/ref_counted.h"
-#include "base/pending_task.h"
-#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"
-
-namespace base {
-namespace trace_event {
-
-// Define all strings once, because the pseudo stack requires pointer equality,
-// and string interning is unreliable.
-const char kThreadName[] = "TestThread";
-const char kCupcake[] = "Cupcake";
-const char kDonut[] = "Donut";
-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\": ["
- " \"*\","
- " \"" TRACE_DISABLED_BY_DEFAULT("Testing") "\"]"
- " }"
- " ]"
- "}";
-
-// 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));
-
- auto* actual = std::begin(ctx.backtrace.frames);
- auto* actual_bottom = actual + ctx.backtrace.frame_count;
- auto expected = std::begin(expected_backtrace);
- auto expected_bottom = std::end(expected_backtrace);
-
- // Note that this requires the pointers to be equal, this is not doing a deep
- // string comparison.
- for (; actual != actual_bottom && expected != expected_bottom;
- actual++, expected++)
- ASSERT_EQ(*expected, *actual);
-
- // Ensure that the height of the stacks is the same.
- ASSERT_EQ(actual, actual_bottom);
- ASSERT_EQ(expected, expected_bottom);
-}
-
-void AssertBacktraceContainsOnlyThreadName() {
- StackFrame t = StackFrame::FromThreadName(kThreadName);
- AllocationContext ctx;
- ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx));
-
- ASSERT_EQ(1u, ctx.backtrace.frame_count);
- ASSERT_EQ(t, ctx.backtrace.frames[0]);
-}
-
-class AllocationContextTrackerTest : public testing::Test {
- public:
- void SetUp() override {
- 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);
- }
-};
-
-// Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly.
-TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) {
- StackFrame t = StackFrame::FromThreadName(kThreadName);
- StackFrame c = StackFrame::FromTraceEventName(kCupcake);
- StackFrame d = StackFrame::FromTraceEventName(kDonut);
- StackFrame e = StackFrame::FromTraceEventName(kEclair);
- StackFrame f = StackFrame::FromTraceEventName(kFroyo);
-
- AssertBacktraceContainsOnlyThreadName();
-
- {
- TRACE_EVENT0("Testing", kCupcake);
- StackFrame frame_c[] = {t, c};
- AssertBacktraceEquals(frame_c);
-
- {
- TRACE_EVENT0("Testing", kDonut);
- StackFrame frame_cd[] = {t, c, d};
- AssertBacktraceEquals(frame_cd);
- }
-
- AssertBacktraceEquals(frame_c);
-
- {
- TRACE_EVENT0("Testing", kEclair);
- StackFrame frame_ce[] = {t, c, e};
- AssertBacktraceEquals(frame_ce);
- }
-
- {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("NotTesting"), kDonut);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("Testing"), kCupcake);
- StackFrame frame_cc[] = {t, c, c};
- AssertBacktraceEquals(frame_cc);
- }
-
- AssertBacktraceEquals(frame_c);
- }
-
- AssertBacktraceContainsOnlyThreadName();
-
- {
- TRACE_EVENT0("Testing", kFroyo);
- StackFrame frame_f[] = {t, f};
- AssertBacktraceEquals(frame_f);
- }
-
- AssertBacktraceContainsOnlyThreadName();
-}
-
-// Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and
-// |TRACE_EVENT_END| macros.
-TEST_F(AllocationContextTrackerTest, PseudoStackBeginEndTrace) {
- StackFrame t = StackFrame::FromThreadName(kThreadName);
- StackFrame c = StackFrame::FromTraceEventName(kCupcake);
- StackFrame d = StackFrame::FromTraceEventName(kDonut);
- StackFrame e = StackFrame::FromTraceEventName(kEclair);
- StackFrame f = StackFrame::FromTraceEventName(kFroyo);
-
- StackFrame frame_c[] = {t, c};
- StackFrame frame_cd[] = {t, c, d};
- StackFrame frame_ce[] = {t, c, e};
- StackFrame frame_f[] = {t, f};
-
- AssertBacktraceContainsOnlyThreadName();
-
- TRACE_EVENT_BEGIN0("Testing", kCupcake);
- AssertBacktraceEquals(frame_c);
-
- TRACE_EVENT_BEGIN0("Testing", kDonut);
- AssertBacktraceEquals(frame_cd);
- TRACE_EVENT_END0("Testing", kDonut);
-
- AssertBacktraceEquals(frame_c);
-
- TRACE_EVENT_BEGIN0("Testing", kEclair);
- AssertBacktraceEquals(frame_ce);
- TRACE_EVENT_END0("Testing", kEclair);
-
- AssertBacktraceEquals(frame_c);
- TRACE_EVENT_END0("Testing", kCupcake);
-
- AssertBacktraceContainsOnlyThreadName();
-
- TRACE_EVENT_BEGIN0("Testing", kFroyo);
- AssertBacktraceEquals(frame_f);
- TRACE_EVENT_END0("Testing", kFroyo);
-
- AssertBacktraceContainsOnlyThreadName();
-}
-
-TEST_F(AllocationContextTrackerTest, PseudoStackMixedTrace) {
- StackFrame t = StackFrame::FromThreadName(kThreadName);
- StackFrame c = StackFrame::FromTraceEventName(kCupcake);
- StackFrame d = StackFrame::FromTraceEventName(kDonut);
- StackFrame e = StackFrame::FromTraceEventName(kEclair);
- StackFrame f = StackFrame::FromTraceEventName(kFroyo);
-
- StackFrame frame_c[] = {t, c};
- StackFrame frame_cd[] = {t, c, d};
- StackFrame frame_e[] = {t, e};
- StackFrame frame_ef[] = {t, e, f};
-
- AssertBacktraceContainsOnlyThreadName();
-
- TRACE_EVENT_BEGIN0("Testing", kCupcake);
- AssertBacktraceEquals(frame_c);
-
- {
- TRACE_EVENT0("Testing", kDonut);
- AssertBacktraceEquals(frame_cd);
- }
-
- AssertBacktraceEquals(frame_c);
- TRACE_EVENT_END0("Testing", kCupcake);
- AssertBacktraceContainsOnlyThreadName();
-
- {
- TRACE_EVENT0("Testing", kEclair);
- AssertBacktraceEquals(frame_e);
-
- TRACE_EVENT_BEGIN0("Testing", kFroyo);
- AssertBacktraceEquals(frame_ef);
- TRACE_EVENT_END0("Testing", kFroyo);
- AssertBacktraceEquals(frame_e);
- }
-
- AssertBacktraceContainsOnlyThreadName();
-}
-
-TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) {
- StackFrame t = StackFrame::FromThreadName(kThreadName);
- StackFrame c = StackFrame::FromTraceEventName(kCupcake);
- StackFrame f = StackFrame::FromTraceEventName(kFroyo);
-
- // Push 11 events onto the pseudo stack.
- TRACE_EVENT0("Testing", kCupcake);
- TRACE_EVENT0("Testing", kCupcake);
- TRACE_EVENT0("Testing", kCupcake);
-
- TRACE_EVENT0("Testing", kCupcake);
- TRACE_EVENT0("Testing", kCupcake);
- TRACE_EVENT0("Testing", kCupcake);
- TRACE_EVENT0("Testing", kCupcake);
-
- TRACE_EVENT0("Testing", kCupcake);
- TRACE_EVENT0("Testing", kDonut);
- TRACE_EVENT0("Testing", kEclair);
- TRACE_EVENT0("Testing", kFroyo);
-
- {
- TRACE_EVENT0("Testing", kGingerbread);
- AllocationContext ctx;
- ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx));
-
- // The pseudo stack relies on pointer equality, not deep string comparisons.
- ASSERT_EQ(t, ctx.backtrace.frames[0]);
- ASSERT_EQ(c, ctx.backtrace.frames[1]);
- ASSERT_EQ(f, ctx.backtrace.frames[11]);
- }
-
- {
- AllocationContext ctx;
- ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx));
- 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) {
- 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));
- 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));
- 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));
- ASSERT_FALSE(ctx.type_name);
-}
-
-TEST_F(AllocationContextTrackerTest, IgnoreAllocationTest) {
- TRACE_EVENT0("Testing", kCupcake);
- TRACE_EVENT0("Testing", kDonut);
- HEAP_PROFILER_SCOPED_IGNORE;
- AllocationContext ctx;
- ASSERT_FALSE(AllocationContextTracker::GetInstanceForCurrentThread()
- ->GetContextSnapshot(&ctx));
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/heap_profiler_allocation_register.cc b/base/trace_event/heap_profiler_allocation_register.cc
deleted file mode 100644
index b9f440adb6..0000000000
--- a/base/trace_event/heap_profiler_allocation_register.cc
+++ /dev/null
@@ -1,194 +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/heap_profiler_allocation_register.h"
-
-#include <algorithm>
-#include <limits>
-
-#include "base/trace_event/trace_event_memory_overhead.h"
-
-namespace base {
-namespace trace_event {
-
-AllocationRegister::ConstIterator::ConstIterator(
- const AllocationRegister& alloc_register,
- AllocationIndex index)
- : register_(alloc_register), index_(index) {}
-
-void AllocationRegister::ConstIterator::operator++() {
- index_ = register_.allocations_.Next(index_ + 1);
-}
-
-bool AllocationRegister::ConstIterator::operator!=(
- const ConstIterator& other) const {
- return index_ != other.index_;
-}
-
-AllocationRegister::Allocation AllocationRegister::ConstIterator::operator*()
- const {
- return register_.GetAllocation(index_);
-}
-
-size_t AllocationRegister::BacktraceHasher::operator()(
- const Backtrace& backtrace) const {
- const size_t kSampleLength = 10;
-
- uintptr_t total_value = 0;
-
- size_t head_end = std::min(backtrace.frame_count, kSampleLength);
- for (size_t i = 0; i != head_end; ++i) {
- total_value += reinterpret_cast<uintptr_t>(backtrace.frames[i].value);
- }
-
- size_t tail_start = backtrace.frame_count -
- std::min(backtrace.frame_count - head_end, kSampleLength);
- for (size_t i = tail_start; i != backtrace.frame_count; ++i) {
- total_value += reinterpret_cast<uintptr_t>(backtrace.frames[i].value);
- }
-
- total_value += backtrace.frame_count;
-
- // These magic constants give best results in terms of average collisions
- // per backtrace. They were found by replaying real backtraces from Linux
- // and Android against different hash functions.
- return (total_value * 131101) >> 14;
-}
-
-size_t AllocationRegister::AddressHasher::operator()(
- const void* address) const {
- // 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.
- const uintptr_t key = reinterpret_cast<uintptr_t>(address);
- const uintptr_t a = 131101;
- const uintptr_t shift = 15;
- const uintptr_t h = (key * a) >> shift;
- return h;
-}
-
-AllocationRegister::AllocationRegister()
- : AllocationRegister(kAllocationCapacity, kBacktraceCapacity) {}
-
-AllocationRegister::AllocationRegister(size_t allocation_capacity,
- size_t backtrace_capacity)
- : allocations_(allocation_capacity), backtraces_(backtrace_capacity) {
- Backtrace sentinel = {};
- sentinel.frames[0] = StackFrame::FromThreadName("[out of heap profiler mem]");
- sentinel.frame_count = 1;
-
- // Rationale for max / 2: in theory we could just start the sentinel with a
- // refcount == 0. However, using max / 2 allows short circuiting of the
- // conditional in RemoveBacktrace() keeping the sentinel logic out of the fast
- // path. From a functional viewpoint, the sentinel is safe even if we wrap
- // over refcount because .
- BacktraceMap::KVPair::second_type sentinel_refcount =
- std::numeric_limits<BacktraceMap::KVPair::second_type>::max() / 2;
- auto index_and_flag = backtraces_.Insert(sentinel, sentinel_refcount);
- DCHECK(index_and_flag.second);
- DCHECK_EQ(index_and_flag.first, kOutOfStorageBacktraceIndex);
-}
-
-AllocationRegister::~AllocationRegister() {}
-
-bool AllocationRegister::Insert(const void* address,
- size_t size,
- const AllocationContext& context) {
- DCHECK(address != nullptr);
- if (size == 0) {
- return false;
- }
-
- AllocationInfo info = {size, context.type_name,
- InsertBacktrace(context.backtrace)};
-
- // Try to insert the allocation.
- auto index_and_flag = allocations_.Insert(address, info);
- if (!index_and_flag.second &&
- index_and_flag.first != AllocationMap::kInvalidKVIndex) {
- // |address| is already there - overwrite the allocation info.
- auto& old_info = allocations_.Get(index_and_flag.first).second;
- RemoveBacktrace(old_info.backtrace_index);
- old_info = info;
- return true;
- }
-
- return index_and_flag.second;
-}
-
-void AllocationRegister::Remove(const void* address) {
- auto index = allocations_.Find(address);
- if (index == AllocationMap::kInvalidKVIndex) {
- return;
- }
-
- const AllocationInfo& info = allocations_.Get(index).second;
- RemoveBacktrace(info.backtrace_index);
- allocations_.Remove(index);
-}
-
-bool AllocationRegister::Get(const void* address,
- Allocation* out_allocation) const {
- auto index = allocations_.Find(address);
- if (index == AllocationMap::kInvalidKVIndex) {
- return false;
- }
-
- if (out_allocation) {
- *out_allocation = GetAllocation(index);
- }
- return true;
-}
-
-AllocationRegister::ConstIterator AllocationRegister::begin() const {
- return ConstIterator(*this, allocations_.Next(0));
-}
-
-AllocationRegister::ConstIterator AllocationRegister::end() const {
- return ConstIterator(*this, AllocationMap::kInvalidKVIndex);
-}
-
-void AllocationRegister::EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) const {
- size_t allocated = sizeof(AllocationRegister);
- size_t resident = sizeof(AllocationRegister) +
- allocations_.EstimateUsedMemory() +
- backtraces_.EstimateUsedMemory();
- overhead->Add("AllocationRegister", allocated, resident);
-}
-
-AllocationRegister::BacktraceMap::KVIndex AllocationRegister::InsertBacktrace(
- const Backtrace& backtrace) {
- auto index = backtraces_.Insert(backtrace, 0).first;
- if (index == BacktraceMap::kInvalidKVIndex)
- return kOutOfStorageBacktraceIndex;
- auto& backtrace_and_count = backtraces_.Get(index);
- backtrace_and_count.second++;
- return index;
-}
-
-void AllocationRegister::RemoveBacktrace(BacktraceMap::KVIndex index) {
- auto& backtrace_and_count = backtraces_.Get(index);
- if (--backtrace_and_count.second == 0 &&
- index != kOutOfStorageBacktraceIndex) {
- // Backtrace is not referenced anymore - remove it.
- backtraces_.Remove(index);
- }
-}
-
-AllocationRegister::Allocation AllocationRegister::GetAllocation(
- AllocationMap::KVIndex index) const {
- const auto& address_and_info = allocations_.Get(index);
- const auto& backtrace_and_count =
- backtraces_.Get(address_and_info.second.backtrace_index);
- return {address_and_info.first, address_and_info.second.size,
- AllocationContext(backtrace_and_count.first,
- address_and_info.second.type_name)};
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/heap_profiler_allocation_register.h b/base/trace_event/heap_profiler_allocation_register.h
deleted file mode 100644
index ac9872f001..0000000000
--- a/base/trace_event/heap_profiler_allocation_register.h
+++ /dev/null
@@ -1,385 +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.
-
-#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_REGISTER_H_
-#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_REGISTER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <utility>
-
-#include "base/bits.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#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 {
-
-class AllocationRegisterTest;
-
-namespace internal {
-
-// Allocates a region of virtual address space of |size| rounded up to the
-// system page size. The memory is zeroed by the system. A guard page is
-// added after the end.
-void* AllocateGuardedVirtualMemory(size_t size);
-
-// Frees a region of virtual address space allocated by a call to
-// |AllocateVirtualMemory|.
-void FreeGuardedVirtualMemory(void* address, size_t allocated_size);
-
-// Hash map that mmaps memory only once in the constructor. Its API is
-// similar to std::unordered_map, only index (KVIndex) is used to address
-template <size_t NumBuckets, class Key, class Value, class KeyHasher>
-class FixedHashMap {
- // To keep things simple we don't call destructors.
- static_assert(is_trivially_destructible<Key>::value &&
- is_trivially_destructible<Value>::value,
- "Key and Value shouldn't have destructors");
- public:
- 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).
- using KVIndex = size_t;
- enum : KVIndex { kInvalidKVIndex = static_cast<KVIndex>(-1) };
-
- // Capacity controls how many items this hash map can hold, and largely
- // affects memory footprint.
- explicit FixedHashMap(size_t capacity)
- : num_cells_(capacity),
- num_inserts_dropped_(0),
- cells_(static_cast<Cell*>(
- AllocateGuardedVirtualMemory(num_cells_ * sizeof(Cell)))),
- buckets_(static_cast<Bucket*>(
- AllocateGuardedVirtualMemory(NumBuckets * sizeof(Bucket)))),
- free_list_(nullptr),
- next_unused_cell_(0) {}
-
- ~FixedHashMap() {
- FreeGuardedVirtualMemory(cells_, num_cells_ * sizeof(Cell));
- FreeGuardedVirtualMemory(buckets_, NumBuckets * sizeof(Bucket));
- }
-
- // Returns {kInvalidKVIndex, false} if the table is full.
- std::pair<KVIndex, bool> Insert(const Key& key, const Value& value) {
- Cell** p_cell = Lookup(key);
- Cell* cell = *p_cell;
- if (cell) {
- return {static_cast<KVIndex>(cell - cells_), false}; // not inserted
- }
-
- // Get a free cell and link it.
- cell = GetFreeCell();
- if (!cell) {
- if (num_inserts_dropped_ <
- std::numeric_limits<decltype(num_inserts_dropped_)>::max()) {
- ++num_inserts_dropped_;
- }
- return {kInvalidKVIndex, false};
- }
- *p_cell = cell;
- cell->p_prev = p_cell;
- cell->next = nullptr;
-
- // Initialize key/value pair. Since key is 'const Key' this is the
- // only way to initialize it.
- new (&cell->kv) KVPair(key, value);
-
- return {static_cast<KVIndex>(cell - cells_), true}; // inserted
- }
-
- void Remove(KVIndex index) {
- DCHECK_LT(index, next_unused_cell_);
-
- Cell* cell = &cells_[index];
-
- // Unlink the cell.
- *cell->p_prev = cell->next;
- if (cell->next) {
- cell->next->p_prev = cell->p_prev;
- }
- cell->p_prev = nullptr; // mark as free
-
- // Add it to the free list.
- cell->next = free_list_;
- free_list_ = cell;
- }
-
- KVIndex Find(const Key& key) const {
- Cell* cell = *Lookup(key);
- return cell ? static_cast<KVIndex>(cell - cells_) : kInvalidKVIndex;
- }
-
- KVPair& Get(KVIndex index) {
- return cells_[index].kv;
- }
-
- const KVPair& Get(KVIndex index) const {
- return cells_[index].kv;
- }
-
- // Finds next index that has a KVPair associated with it. Search starts
- // with the specified index. Returns kInvalidKVIndex if nothing was found.
- // To find the first valid index, call this function with 0. Continue
- // calling with the last_index + 1 until kInvalidKVIndex is returned.
- KVIndex Next(KVIndex index) const {
- for (;index < next_unused_cell_; ++index) {
- if (cells_[index].p_prev) {
- return index;
- }
- }
- return kInvalidKVIndex;
- }
-
- // Estimates number of bytes used in allocated memory regions.
- size_t EstimateUsedMemory() const {
- size_t page_size = base::GetPageSize();
- // |next_unused_cell_| is the first cell that wasn't touched, i.e.
- // it's the number of touched cells.
- return bits::Align(sizeof(Cell) * next_unused_cell_, page_size) +
- bits::Align(sizeof(Bucket) * NumBuckets, page_size);
- }
-
- size_t num_inserts_dropped() const { return num_inserts_dropped_; }
-
- private:
- friend base::trace_event::AllocationRegisterTest;
-
- struct Cell {
- KVPair kv;
- Cell* next;
-
- // Conceptually this is |prev| in a doubly linked list. However, buckets
- // also participate in the bucket's cell list - they point to the list's
- // head and also need to be linked / unlinked properly. To treat these two
- // cases uniformly, instead of |prev| we're storing "pointer to a Cell*
- // that points to this Cell" kind of thing. So |p_prev| points to a bucket
- // for the first cell in a list, and points to |next| of the previous cell
- // for any other cell. With that Lookup() is the only function that handles
- // buckets / cells differently.
- // If |p_prev| is nullptr, the cell is in the free list.
- Cell** p_prev;
- };
-
- using Bucket = Cell*;
-
- // Returns a pointer to the cell that contains or should contain the entry
- // for |key|. The pointer may point at an element of |buckets_| or at the
- // |next| member of an element of |cells_|.
- Cell** Lookup(const Key& key) const {
- // The list head is in |buckets_| at the hash offset.
- Cell** p_cell = &buckets_[Hash(key)];
-
- // Chase down the list until the cell that holds |key| is found,
- // or until the list ends.
- while (*p_cell && (*p_cell)->kv.first != key) {
- p_cell = &(*p_cell)->next;
- }
-
- return p_cell;
- }
-
- // Returns a cell that is not being used to store an entry (either by
- // recycling from the free list or by taking a fresh cell). May return
- // nullptr if the hash table has run out of memory.
- Cell* GetFreeCell() {
- // First try to re-use a cell from the free list.
- if (free_list_) {
- Cell* cell = free_list_;
- free_list_ = cell->next;
- return cell;
- }
-
- // If the hash table has too little capacity (when too little address space
- // was reserved for |cells_|), return nullptr.
- if (next_unused_cell_ >= num_cells_) {
- return nullptr;
- }
-
- // Otherwise pick the next cell that has not been touched before.
- return &cells_[next_unused_cell_++];
- }
-
- // Returns a value in the range [0, NumBuckets - 1] (inclusive).
- size_t Hash(const Key& key) const {
- if (NumBuckets == (NumBuckets & ~(NumBuckets - 1))) {
- // NumBuckets is a power of 2.
- return KeyHasher()(key) & (NumBuckets - 1);
- } else {
- return KeyHasher()(key) % NumBuckets;
- }
- }
-
- // Number of cells.
- size_t const num_cells_;
-
- // Number of calls to Insert() that were lost because the hashtable was full.
- size_t num_inserts_dropped_;
-
- // The array of cells. This array is backed by mmapped memory. Lower indices
- // are accessed first, higher indices are accessed only when the |free_list_|
- // is empty. This is to minimize the amount of resident memory used.
- Cell* const cells_;
-
- // The array of buckets (pointers into |cells_|). |buckets_[Hash(key)]| will
- // contain the pointer to the linked list of cells for |Hash(key)|.
- // This array is backed by mmapped memory.
- mutable Bucket* buckets_;
-
- // The head of the free list.
- Cell* free_list_;
-
- // The index of the first element of |cells_| that has not been used before.
- // If the free list is empty and a new cell is needed, the cell at this index
- // is used. This is the high water mark for the number of entries stored.
- size_t next_unused_cell_;
-
- DISALLOW_COPY_AND_ASSIGN(FixedHashMap);
-};
-
-} // namespace internal
-
-class TraceEventMemoryOverhead;
-
-// The allocation register keeps track of all allocations that have not been
-// freed. Internally it has two hashtables: one for Backtraces and one for
-// actual allocations. Sizes of both hashtables are fixed, and this class
-// allocates (mmaps) only in its constructor.
-//
-// When either hash table hits max size, new inserts are dropped.
-class BASE_EXPORT AllocationRegister {
- public:
- // Details about an allocation.
- struct Allocation {
- const void* address;
- size_t size;
- AllocationContext context;
- };
-
- // An iterator that iterates entries in no particular order.
- class BASE_EXPORT ConstIterator {
- public:
- void operator++();
- bool operator!=(const ConstIterator& other) const;
- Allocation operator*() const;
-
- private:
- friend class AllocationRegister;
- using AllocationIndex = size_t;
-
- ConstIterator(const AllocationRegister& alloc_register,
- AllocationIndex index);
-
- const AllocationRegister& register_;
- AllocationIndex index_;
- };
-
- AllocationRegister();
- AllocationRegister(size_t allocation_capacity, size_t backtrace_capacity);
-
- ~AllocationRegister();
-
- // Inserts allocation details into the table. If the address was present
- // already, its details are updated. |address| must not be null.
- //
- // Returns true if an insert occurred. Inserts may fail because the table
- // is full.
- bool Insert(const void* address,
- size_t size,
- const AllocationContext& context);
-
- // Removes the address from the table if it is present. It is ok to call this
- // with a null pointer.
- void Remove(const void* address);
-
- // Finds allocation for the address and fills |out_allocation|.
- bool Get(const void* address, Allocation* out_allocation) const;
-
- ConstIterator begin() const;
- ConstIterator end() const;
-
- // Estimates memory overhead including |sizeof(AllocationRegister)|.
- void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) const;
-
- 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)
- 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
-
- struct BacktraceHasher {
- size_t operator () (const Backtrace& backtrace) const;
- };
-
- using BacktraceMap = internal::FixedHashMap<
- kBacktraceBuckets,
- Backtrace,
- size_t, // Number of references to the backtrace (the key). Incremented
- // when an allocation that references the backtrace is inserted,
- // and decremented when the allocation is removed. When the
- // number drops to zero, the backtrace is removed from the map.
- BacktraceHasher>;
-
- struct AllocationInfo {
- size_t size;
- const char* type_name;
- BacktraceMap::KVIndex backtrace_index;
- };
-
- struct AddressHasher {
- size_t operator () (const void* address) const;
- };
-
- using AllocationMap = internal::FixedHashMap<
- kAllocationBuckets,
- const void*,
- AllocationInfo,
- AddressHasher>;
-
- BacktraceMap::KVIndex InsertBacktrace(const Backtrace& backtrace);
- void RemoveBacktrace(BacktraceMap::KVIndex index);
-
- Allocation GetAllocation(AllocationMap::KVIndex) const;
-
- AllocationMap allocations_;
- BacktraceMap backtraces_;
-
- // Sentinel used when the |backtraces_| table is full.
- //
- // This is a slightly abstraction to allow for constant propagation. It
- // knows that the sentinel will be the first item inserted into the table
- // and that the first index retuned will be 0. The constructor DCHECKs
- // this assumption.
- enum : BacktraceMap::KVIndex { kOutOfStorageBacktraceIndex = 0 };
-
- DISALLOW_COPY_AND_ASSIGN(AllocationRegister);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_REGISTER_H_
diff --git a/base/trace_event/heap_profiler_allocation_register_posix.cc b/base/trace_event/heap_profiler_allocation_register_posix.cc
deleted file mode 100644
index 94eeb4df88..0000000000
--- a/base/trace_event/heap_profiler_allocation_register_posix.cc
+++ /dev/null
@@ -1,58 +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/heap_profiler_allocation_register.h"
-
-#include <stddef.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include "base/bits.h"
-#include "base/logging.h"
-#include "base/process/process_metrics.h"
-
-#ifndef MAP_ANONYMOUS
-#define MAP_ANONYMOUS MAP_ANON
-#endif
-
-namespace base {
-namespace trace_event {
-namespace internal {
-
-namespace {
-size_t GetGuardSize() {
- return GetPageSize();
-}
-}
-
-void* AllocateGuardedVirtualMemory(size_t size) {
- size = bits::Align(size, GetPageSize());
-
- // Add space for a guard page at the end.
- size_t map_size = size + GetGuardSize();
-
- void* addr = mmap(nullptr, map_size, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-
- PCHECK(addr != MAP_FAILED);
-
- // Mark the last page of the allocated address space as inaccessible
- // (PROT_NONE). The read/write accessible space is still at least |min_size|
- // bytes.
- void* guard_addr =
- reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) + size);
- int result = mprotect(guard_addr, GetGuardSize(), PROT_NONE);
- PCHECK(result == 0);
-
- return addr;
-}
-
-void FreeGuardedVirtualMemory(void* address, size_t allocated_size) {
- size_t size = bits::Align(allocated_size, GetPageSize()) + GetGuardSize();
- munmap(address, size);
-}
-
-} // namespace internal
-} // namespace trace_event
-} // namespace base
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
deleted file mode 100644
index 8043fff995..0000000000
--- a/base/trace_event/heap_profiler_heap_dump_writer.cc
+++ /dev/null
@@ -1,322 +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/heap_profiler_heap_dump_writer.h"
-
-#include <stdint.h>
-
-#include <algorithm>
-#include <iterator>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include "base/format_macros.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/strings/stringprintf.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_session_state.h"
-#include "base/trace_event/trace_config.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "base/trace_event/trace_log.h"
-
-// Most of what the |HeapDumpWriter| does is aggregating detailed information
-// about the heap and deciding what to dump. The Input to this process is a list
-// of |AllocationContext|s and size pairs.
-//
-// The pairs are grouped into |Bucket|s. A bucket is a group of (context, size)
-// pairs where the properties of the contexts share a prefix. (Type name is
-// considered a list of length one here.) First all pairs are put into one
-// bucket that represents the entire heap. Then this bucket is recursively
-// broken down into smaller buckets. Each bucket keeps track of whether further
-// breakdown is possible.
-
-namespace base {
-namespace trace_event {
-namespace internal {
-namespace {
-
-// Denotes a property of |AllocationContext| to break down by.
-enum class BreakDownMode { kByBacktrace, kByTypeName };
-
-// A group of bytes for which the context shares a prefix.
-struct Bucket {
- Bucket()
- : size(0),
- count(0),
- backtrace_cursor(0),
- is_broken_down_by_type_name(false) {}
-
- std::vector<std::pair<const AllocationContext*, AllocationMetrics>>
- metrics_by_context;
-
- // The sum of the sizes of |metrics_by_context|.
- size_t size;
-
- // The sum of number of allocations of |metrics_by_context|.
- size_t count;
-
- // The index of the stack frame that has not yet been broken down by. For all
- // elements in this bucket, the stack frames 0 up to (but not including) the
- // cursor, must be equal.
- size_t backtrace_cursor;
-
- // When true, the type name for all elements in this bucket must be equal.
- bool is_broken_down_by_type_name;
-};
-
-// Comparison operator to order buckets by their size.
-bool operator<(const Bucket& lhs, const Bucket& rhs) {
- return lhs.size < rhs.size;
-}
-
-// Groups the allocations in the bucket by |break_by|. The buckets in the
-// returned list will have |backtrace_cursor| advanced or
-// |is_broken_down_by_type_name| set depending on the property to group by.
-std::vector<Bucket> GetSubbuckets(const Bucket& bucket,
- BreakDownMode break_by) {
- base::hash_map<const void*, Bucket> breakdown;
-
-
- if (break_by == BreakDownMode::kByBacktrace) {
- for (const auto& context_and_metrics : bucket.metrics_by_context) {
- const Backtrace& backtrace = context_and_metrics.first->backtrace;
- const StackFrame* begin = std::begin(backtrace.frames);
- const StackFrame* end = begin + backtrace.frame_count;
- const StackFrame* cursor = begin + bucket.backtrace_cursor;
-
- DCHECK_LE(cursor, end);
-
- if (cursor != end) {
- Bucket& subbucket = breakdown[cursor->value];
- subbucket.size += context_and_metrics.second.size;
- subbucket.count += context_and_metrics.second.count;
- subbucket.metrics_by_context.push_back(context_and_metrics);
- subbucket.backtrace_cursor = bucket.backtrace_cursor + 1;
- subbucket.is_broken_down_by_type_name =
- bucket.is_broken_down_by_type_name;
- DCHECK_GT(subbucket.size, 0u);
- DCHECK_GT(subbucket.count, 0u);
- }
- }
- } else if (break_by == BreakDownMode::kByTypeName) {
- if (!bucket.is_broken_down_by_type_name) {
- for (const auto& context_and_metrics : bucket.metrics_by_context) {
- const AllocationContext* context = context_and_metrics.first;
- Bucket& subbucket = breakdown[context->type_name];
- subbucket.size += context_and_metrics.second.size;
- subbucket.count += context_and_metrics.second.count;
- subbucket.metrics_by_context.push_back(context_and_metrics);
- subbucket.backtrace_cursor = bucket.backtrace_cursor;
- subbucket.is_broken_down_by_type_name = true;
- DCHECK_GT(subbucket.size, 0u);
- DCHECK_GT(subbucket.count, 0u);
- }
- }
- }
-
- std::vector<Bucket> buckets;
- buckets.reserve(breakdown.size());
- for (auto key_bucket : breakdown)
- buckets.push_back(key_bucket.second);
-
- return buckets;
-}
-
-// Breaks down the bucket by |break_by|. Returns only buckets that contribute
-// more than |min_size_bytes| to the total size. The long tail is omitted.
-std::vector<Bucket> BreakDownBy(const Bucket& bucket,
- BreakDownMode break_by,
- size_t min_size_bytes) {
- std::vector<Bucket> buckets = GetSubbuckets(bucket, break_by);
-
- // Ensure that |buckets| is a max-heap (the data structure, not memory heap),
- // so its front contains the largest bucket. Buckets should be iterated
- // ordered by size, but sorting the vector is overkill because the long tail
- // of small buckets will be discarded. By using a max-heap, the optimal case
- // where all but the first bucket are discarded is O(n). The worst case where
- // no bucket is discarded is doing a heap sort, which is O(n log n).
- std::make_heap(buckets.begin(), buckets.end());
-
- // Keep including buckets until adding one would increase the number of
- // bytes accounted for by |min_size_bytes|. The large buckets end up in
- // [it, end()), [begin(), it) is the part that contains the max-heap
- // of small buckets.
- std::vector<Bucket>::iterator it;
- for (it = buckets.end(); it != buckets.begin(); --it) {
- if (buckets.front().size < min_size_bytes)
- break;
-
- // Put the largest bucket in [begin, it) at |it - 1| and max-heapify
- // [begin, it - 1). This puts the next largest bucket at |buckets.front()|.
- std::pop_heap(buckets.begin(), it);
- }
-
- // At this point, |buckets| looks like this (numbers are bucket sizes):
- //
- // <-- max-heap of small buckets --->
- // <-- large buckets by ascending size -->
- // [ 19 | 11 | 13 | 7 | 2 | 5 | ... | 83 | 89 | 97 ]
- // ^ ^ ^
- // | | |
- // begin() it end()
-
- // Discard the long tail of buckets that contribute less than a percent.
- buckets.erase(buckets.begin(), it);
-
- return buckets;
-}
-
-} // namespace
-
-bool operator<(Entry lhs, Entry rhs) {
- // There is no need to compare |size|. If the backtrace and type name are
- // equal then the sizes must be equal as well.
- return std::tie(lhs.stack_frame_id, lhs.type_id) <
- std::tie(rhs.stack_frame_id, rhs.type_id);
-}
-
-HeapDumpWriter::HeapDumpWriter(StackFrameDeduplicator* stack_frame_deduplicator,
- TypeNameDeduplicator* type_name_deduplicator,
- uint32_t breakdown_threshold_bytes)
- : stack_frame_deduplicator_(stack_frame_deduplicator),
- type_name_deduplicator_(type_name_deduplicator),
- breakdown_threshold_bytes_(breakdown_threshold_bytes) {
-}
-
-HeapDumpWriter::~HeapDumpWriter() {}
-
-bool HeapDumpWriter::AddEntryForBucket(const Bucket& bucket) {
- // The contexts in the bucket are all different, but the [begin, cursor) range
- // is equal for all contexts in the bucket, and the type names are the same if
- // |is_broken_down_by_type_name| is set.
- DCHECK(!bucket.metrics_by_context.empty());
-
- const AllocationContext* context = bucket.metrics_by_context.front().first;
-
- const StackFrame* backtrace_begin = std::begin(context->backtrace.frames);
- const StackFrame* backtrace_end = backtrace_begin + bucket.backtrace_cursor;
- DCHECK_LE(bucket.backtrace_cursor, arraysize(context->backtrace.frames));
-
- Entry entry;
- entry.stack_frame_id = stack_frame_deduplicator_->Insert(
- backtrace_begin, backtrace_end);
-
- // Deduplicate the type name, or use ID -1 if type name is not set.
- entry.type_id = bucket.is_broken_down_by_type_name
- ? type_name_deduplicator_->Insert(context->type_name)
- : -1;
-
- entry.size = bucket.size;
- entry.count = bucket.count;
-
- auto position_and_inserted = entries_.insert(entry);
- return position_and_inserted.second;
-}
-
-void HeapDumpWriter::BreakDown(const Bucket& bucket) {
- auto by_backtrace = BreakDownBy(bucket,
- BreakDownMode::kByBacktrace,
- breakdown_threshold_bytes_);
- auto by_type_name = BreakDownBy(bucket,
- BreakDownMode::kByTypeName,
- breakdown_threshold_bytes_);
-
- // Insert entries for the buckets. If a bucket was not present before, it has
- // not been broken down before, so recursively continue breaking down in that
- // case. There might be multiple routes to the same entry (first break down
- // by type name, then by backtrace, or first by backtrace and then by type),
- // so a set is used to avoid dumping and breaking down entries more than once.
-
- for (const Bucket& subbucket : by_backtrace)
- if (AddEntryForBucket(subbucket))
- BreakDown(subbucket);
-
- for (const Bucket& subbucket : by_type_name)
- if (AddEntryForBucket(subbucket))
- BreakDown(subbucket);
-}
-
-const std::set<Entry>& HeapDumpWriter::Summarize(
- const hash_map<AllocationContext, AllocationMetrics>& metrics_by_context) {
- // Start with one bucket that represents the entire heap. Iterate by
- // reference, because the allocation contexts are going to point to allocation
- // contexts stored in |metrics_by_context|.
- Bucket root_bucket;
- for (const auto& context_and_metrics : metrics_by_context) {
- DCHECK_GT(context_and_metrics.second.size, 0u);
- DCHECK_GT(context_and_metrics.second.count, 0u);
- const AllocationContext* context = &context_and_metrics.first;
- root_bucket.metrics_by_context.push_back(
- std::make_pair(context, context_and_metrics.second));
- root_bucket.size += context_and_metrics.second.size;
- root_bucket.count += context_and_metrics.second.count;
- }
-
- AddEntryForBucket(root_bucket);
-
- // Recursively break down the heap and fill |entries_| with entries to dump.
- BreakDown(root_bucket);
-
- return entries_;
-}
-
-std::unique_ptr<TracedValue> Serialize(const std::set<Entry>& entries) {
- std::string buffer;
- std::unique_ptr<TracedValue> traced_value(new TracedValue);
-
- traced_value->BeginArray("entries");
-
- for (const Entry& entry : entries) {
- traced_value->BeginDictionary();
-
- // Format size as hexadecimal string into |buffer|.
- SStringPrintf(&buffer, "%" PRIx64, static_cast<uint64_t>(entry.size));
- traced_value->SetString("size", buffer);
-
- SStringPrintf(&buffer, "%" PRIx64, static_cast<uint64_t>(entry.count));
- traced_value->SetString("count", buffer);
-
- if (entry.stack_frame_id == -1) {
- // An empty backtrace (which will have ID -1) is represented by the empty
- // string, because there is no leaf frame to reference in |stackFrames|.
- traced_value->SetString("bt", "");
- } else {
- // Format index of the leaf frame as a string, because |stackFrames| is a
- // dictionary, not an array.
- SStringPrintf(&buffer, "%i", entry.stack_frame_id);
- traced_value->SetString("bt", buffer);
- }
-
- // Type ID -1 (cumulative size for all types) is represented by the absence
- // of the "type" key in the dictionary.
- if (entry.type_id != -1) {
- // Format the type ID as a string.
- SStringPrintf(&buffer, "%i", entry.type_id);
- traced_value->SetString("type", buffer);
- }
-
- traced_value->EndDictionary();
- }
-
- traced_value->EndArray(); // "entries"
- return traced_value;
-}
-
-} // namespace internal
-
-std::unique_ptr<TracedValue> ExportHeapDump(
- const hash_map<AllocationContext, AllocationMetrics>& metrics_by_context,
- const MemoryDumpSessionState& session_state) {
- internal::HeapDumpWriter writer(
- session_state.stack_frame_deduplicator(),
- session_state.type_name_deduplicator(),
- session_state.heap_profiler_breakdown_threshold_bytes());
- return Serialize(writer.Summarize(metrics_by_context));
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/heap_profiler_heap_dump_writer.h b/base/trace_event/heap_profiler_heap_dump_writer.h
deleted file mode 100644
index 6e9d29de87..0000000000
--- a/base/trace_event/heap_profiler_heap_dump_writer.h
+++ /dev/null
@@ -1,113 +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.
-
-#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
-#define BASE_TRACE_EVENT_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
-
-#include <stddef.h>
-
-#include <memory>
-#include <set>
-
-#include "base/base_export.h"
-#include "base/containers/hash_tables.h"
-#include "base/macros.h"
-#include "base/trace_event/heap_profiler_allocation_context.h"
-
-namespace base {
-namespace trace_event {
-
-class MemoryDumpSessionState;
-class StackFrameDeduplicator;
-class TracedValue;
-class TypeNameDeduplicator;
-
-// Aggregates |metrics_by_context|, recursively breaks down the heap, and
-// returns a traced value with an "entries" array that can be dumped in the
-// trace log, following the format described in https://goo.gl/KY7zVE. The
-// number of entries is kept reasonable because long tails are not included.
-BASE_EXPORT std::unique_ptr<TracedValue> ExportHeapDump(
- const hash_map<AllocationContext, AllocationMetrics>& metrics_by_context,
- const MemoryDumpSessionState& session_state);
-
-namespace internal {
-
-namespace {
-struct Bucket;
-}
-
-// An entry in the "entries" array as described in https://goo.gl/KY7zVE.
-struct BASE_EXPORT Entry {
- size_t size;
- size_t count;
-
- // References a backtrace in the stack frame deduplicator. -1 means empty
- // backtrace (the root of the tree).
- int stack_frame_id;
-
- // References a type name in the type name deduplicator. -1 indicates that
- // the size is the cumulative size for all types (the root of the tree).
- int type_id;
-};
-
-// Comparison operator to enable putting |Entry| in a |std::set|.
-BASE_EXPORT bool operator<(Entry lhs, Entry rhs);
-
-// Serializes entries to an "entries" array in a traced value.
-BASE_EXPORT std::unique_ptr<TracedValue> Serialize(const std::set<Entry>& dump);
-
-// Helper class to dump a snapshot of an |AllocationRegister| or other heap
-// bookkeeping structure into a |TracedValue|. This class is intended to be
-// used as a one-shot local instance on the stack.
-class BASE_EXPORT HeapDumpWriter {
- public:
- // The |stack_frame_deduplicator| and |type_name_deduplicator| are not owned.
- // The heap dump writer assumes exclusive access to them during the lifetime
- // of the dump writer. The heap dumps are broken down for allocations bigger
- // than |breakdown_threshold_bytes|.
- HeapDumpWriter(StackFrameDeduplicator* stack_frame_deduplicator,
- TypeNameDeduplicator* type_name_deduplicator,
- uint32_t breakdown_threshold_bytes);
-
- ~HeapDumpWriter();
-
- // Aggregates allocations to compute the total size of the heap, then breaks
- // down the heap recursively. This produces the values that should be dumped
- // in the "entries" array. The number of entries is kept reasonable because
- // long tails are not included. Use |Serialize| to convert to a traced value.
- const std::set<Entry>& Summarize(
- const hash_map<AllocationContext, AllocationMetrics>& metrics_by_context);
-
- private:
- // Inserts an |Entry| for |Bucket| into |entries_|. Returns false if the
- // entry was present before, true if it was not.
- bool AddEntryForBucket(const Bucket& bucket);
-
- // Recursively breaks down a bucket into smaller buckets and adds entries for
- // the buckets worth dumping to |entries_|.
- void BreakDown(const Bucket& bucket);
-
- // The collection of entries that is filled by |Summarize|.
- std::set<Entry> entries_;
-
- // Helper for generating the |stackFrames| dictionary. Not owned, must outlive
- // this heap dump writer instance.
- StackFrameDeduplicator* const stack_frame_deduplicator_;
-
- // Helper for converting type names to IDs. Not owned, must outlive this heap
- // dump writer instance.
- TypeNameDeduplicator* const type_name_deduplicator_;
-
- // Minimum size of an allocation for which an allocation bucket will be
- // broken down with children.
- uint32_t breakdown_threshold_bytes_;
-
- DISALLOW_COPY_AND_ASSIGN(HeapDumpWriter);
-};
-
-} // namespace internal
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator.cc b/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
deleted file mode 100644
index fc5da0d1dd..0000000000
--- a/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
+++ /dev/null
@@ -1,131 +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/heap_profiler_stack_frame_deduplicator.h"
-
-#include <inttypes.h>
-#include <stddef.h>
-
-#include <string>
-#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"
-
-namespace base {
-namespace trace_event {
-
-StackFrameDeduplicator::FrameNode::FrameNode(StackFrame frame,
- int parent_frame_index)
- : frame(frame), parent_frame_index(parent_frame_index) {}
-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() {}
-
-int StackFrameDeduplicator::Insert(const StackFrame* beginFrame,
- const StackFrame* endFrame) {
- int frame_index = -1;
- std::map<StackFrame, int>* nodes = &roots_;
-
- // Loop through the frames, early out when a frame is null.
- for (const StackFrame* it = beginFrame; it != endFrame; it++) {
- StackFrame frame = *it;
-
- auto node = nodes->find(frame);
- if (node == nodes->end()) {
- // There is no tree node for this frame yet, create it. The parent node
- // is the node associated with the previous frame.
- FrameNode frame_node(frame, frame_index);
-
- // The new frame node will be appended, so its index is the current size
- // of the vector.
- frame_index = static_cast<int>(frames_.size());
-
- // Add the node to the trie so it will be found next time.
- nodes->insert(std::make_pair(frame, frame_index));
-
- // Append the node after modifying |nodes|, because the |frames_| vector
- // might need to resize, and this invalidates the |nodes| pointer.
- frames_.push_back(frame_node);
- } else {
- // A tree node for this frame exists. Look for the next one.
- frame_index = node->second;
- }
-
- nodes = &frames_[frame_index].children;
- }
-
- return frame_index;
-}
-
-void StackFrameDeduplicator::AppendAsTraceFormat(std::string* out) const {
- out->append("{"); // Begin the |stackFrames| dictionary.
-
- int i = 0;
- auto frame_node = begin();
- auto it_end = end();
- std::string stringify_buffer;
-
- while (frame_node != it_end) {
- // The |stackFrames| format is a dictionary, not an array, so the
- // keys are stringified indices. Write the index manually, then use
- // |TracedValue| to format the object. This is to avoid building the
- // entire dictionary as a |TracedValue| in memory.
- SStringPrintf(&stringify_buffer, "\"%d\":", i);
- out->append(stringify_buffer);
-
- std::unique_ptr<TracedValue> frame_node_value(new TracedValue);
- const StackFrame& frame = frame_node->frame;
- switch (frame.type) {
- case StackFrame::Type::TRACE_EVENT_NAME:
- frame_node_value->SetString(
- "name", static_cast<const char*>(frame.value));
- break;
- case StackFrame::Type::THREAD_NAME:
- SStringPrintf(&stringify_buffer,
- "[Thread: %s]",
- static_cast<const char*>(frame.value));
- frame_node_value->SetString("name", stringify_buffer);
- break;
- case StackFrame::Type::PROGRAM_COUNTER:
- SStringPrintf(&stringify_buffer,
- "pc:%" PRIxPTR,
- reinterpret_cast<uintptr_t>(frame.value));
- frame_node_value->SetString("name", stringify_buffer);
- break;
- }
- if (frame_node->parent_frame_index >= 0) {
- SStringPrintf(&stringify_buffer, "%d", frame_node->parent_frame_index);
- frame_node_value->SetString("parent", stringify_buffer);
- }
- frame_node_value->AppendAsTraceFormat(out);
-
- i++;
- frame_node++;
-
- if (frame_node != it_end)
- out->append(",");
- }
-
- out->append("}"); // End the |stackFrames| dictionary.
-}
-
-void StackFrameDeduplicator::EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) {
- size_t memory_usage =
- EstimateMemoryUsage(frames_) + EstimateMemoryUsage(roots_);
- overhead->Add("StackFrameDeduplicator",
- sizeof(StackFrameDeduplicator) + memory_usage);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator.h b/base/trace_event/heap_profiler_stack_frame_deduplicator.h
deleted file mode 100644
index 66d430f2ee..0000000000
--- a/base/trace_event/heap_profiler_stack_frame_deduplicator.h
+++ /dev/null
@@ -1,81 +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.
-
-#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
-#define BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/base_export.h"
-#include "base/macros.h"
-#include "base/trace_event/heap_profiler_allocation_context.h"
-#include "base/trace_event/trace_event_impl.h"
-
-namespace base {
-namespace trace_event {
-
-class TraceEventMemoryOverhead;
-
-// A data structure that allows grouping a set of backtraces in a space-
-// efficient manner by creating a call tree and writing it as a set of (node,
-// parent) pairs. The tree nodes reference both parent and children. The parent
-// is referenced by index into |frames_|. The children are referenced via a map
-// of |StackFrame|s to index into |frames_|. So there is a trie for bottum-up
-// lookup of a backtrace for deduplication, and a tree for compact storage in
-// the trace log.
-class BASE_EXPORT StackFrameDeduplicator : public ConvertableToTraceFormat {
- public:
- // A node in the call tree.
- struct FrameNode {
- FrameNode(StackFrame frame, int parent_frame_index);
- 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
- // parent frame (when it is at the bottom of the call stack).
- int parent_frame_index;
-
- // Indices into |frames_| of frames called from the current frame.
- std::map<StackFrame, int> children;
- };
-
- using ConstIterator = std::vector<FrameNode>::const_iterator;
-
- StackFrameDeduplicator();
- ~StackFrameDeduplicator() override;
-
- // Inserts a backtrace where |beginFrame| is a pointer to the bottom frame
- // (e.g. main) and |endFrame| is a pointer past the top frame (most recently
- // called function), and returns the index of its leaf node in |frames_|.
- // Returns -1 if the backtrace is empty.
- int Insert(const StackFrame* beginFrame, const StackFrame* endFrame);
-
- // Iterators over the frame nodes in the call tree.
- ConstIterator begin() const { return frames_.begin(); }
- ConstIterator end() const { return frames_.end(); }
-
- // Writes the |stackFrames| dictionary as defined in https://goo.gl/GerkV8 to
- // the trace log.
- void AppendAsTraceFormat(std::string* out) const override;
-
- // Estimates memory overhead including |sizeof(StackFrameDeduplicator)|.
- void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
-
- private:
- std::map<StackFrame, int> roots_;
- std::vector<FrameNode> frames_;
-
- DISALLOW_COPY_AND_ASSIGN(StackFrameDeduplicator);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc b/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
deleted file mode 100644
index 2215edebb5..0000000000
--- a/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
+++ /dev/null
@@ -1,152 +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/heap_profiler_stack_frame_deduplicator.h"
-
-#include <iterator>
-#include <memory>
-
-#include "base/macros.h"
-#include "base/trace_event/heap_profiler_allocation_context.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace trace_event {
-
-// Define all strings once, because the deduplicator requires pointer equality,
-// and string interning is unreliable.
-StackFrame kBrowserMain = StackFrame::FromTraceEventName("BrowserMain");
-StackFrame kRendererMain = StackFrame::FromTraceEventName("RendererMain");
-StackFrame kCreateWidget = StackFrame::FromTraceEventName("CreateWidget");
-StackFrame kInitialize = StackFrame::FromTraceEventName("Initialize");
-StackFrame kMalloc = StackFrame::FromTraceEventName("malloc");
-
-TEST(StackFrameDeduplicatorTest, SingleBacktrace) {
- StackFrame bt[] = {kBrowserMain, kCreateWidget, kMalloc};
-
- // The call tree should look like this (index in brackets).
- //
- // BrowserMain [0]
- // CreateWidget [1]
- // malloc [2]
-
- std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
- ASSERT_EQ(2, dedup->Insert(std::begin(bt), std::end(bt)));
-
- auto iter = dedup->begin();
- ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
- ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
-
- ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
- ASSERT_EQ(0, (iter + 1)->parent_frame_index);
-
- ASSERT_EQ(kMalloc, (iter + 2)->frame);
- ASSERT_EQ(1, (iter + 2)->parent_frame_index);
-
- ASSERT_EQ(iter + 3, dedup->end());
-}
-
-TEST(StackFrameDeduplicatorTest, SingleBacktraceWithNull) {
- StackFrame null_frame = StackFrame::FromTraceEventName(nullptr);
- StackFrame bt[] = {kBrowserMain, null_frame, kMalloc};
-
- // Deduplicator doesn't care about what's inside StackFrames,
- // and handles nullptr StackFrame values as any other.
- //
- // So the call tree should look like this (index in brackets).
- //
- // BrowserMain [0]
- // (null) [1]
- // malloc [2]
-
- std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
- ASSERT_EQ(2, dedup->Insert(std::begin(bt), std::end(bt)));
-
- auto iter = dedup->begin();
- ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
- ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
-
- ASSERT_EQ(null_frame, (iter + 1)->frame);
- ASSERT_EQ(0, (iter + 1)->parent_frame_index);
-
- ASSERT_EQ(kMalloc, (iter + 2)->frame);
- ASSERT_EQ(1, (iter + 2)->parent_frame_index);
-
- ASSERT_EQ(iter + 3, dedup->end());
-}
-
-// Test that there can be different call trees (there can be multiple bottom
-// frames). Also verify that frames with the same name but a different caller
-// are represented as distinct nodes.
-TEST(StackFrameDeduplicatorTest, MultipleRoots) {
- StackFrame bt0[] = {kBrowserMain, kCreateWidget};
- StackFrame bt1[] = {kRendererMain, kCreateWidget};
-
- // The call tree should look like this (index in brackets).
- //
- // BrowserMain [0]
- // CreateWidget [1]
- // RendererMain [2]
- // CreateWidget [3]
- //
- // Note that there will be two instances of CreateWidget,
- // with different parents.
-
- std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
- ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
- ASSERT_EQ(3, dedup->Insert(std::begin(bt1), std::end(bt1)));
-
- auto iter = dedup->begin();
- ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
- ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
-
- ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
- ASSERT_EQ(0, (iter + 1)->parent_frame_index);
-
- ASSERT_EQ(kRendererMain, (iter + 2)->frame);
- ASSERT_EQ(-1, (iter + 2)->parent_frame_index);
-
- ASSERT_EQ(kCreateWidget, (iter + 3)->frame);
- ASSERT_EQ(2, (iter + 3)->parent_frame_index);
-
- ASSERT_EQ(iter + 4, dedup->end());
-}
-
-TEST(StackFrameDeduplicatorTest, Deduplication) {
- StackFrame bt0[] = {kBrowserMain, kCreateWidget};
- StackFrame bt1[] = {kBrowserMain, kInitialize};
-
- // The call tree should look like this (index in brackets).
- //
- // BrowserMain [0]
- // CreateWidget [1]
- // Initialize [2]
- //
- // Note that BrowserMain will be re-used.
-
- std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
- ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
- ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
-
- auto iter = dedup->begin();
- ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
- ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
-
- ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
- ASSERT_EQ(0, (iter + 1)->parent_frame_index);
-
- ASSERT_EQ(kInitialize, (iter + 2)->frame);
- ASSERT_EQ(0, (iter + 2)->parent_frame_index);
-
- ASSERT_EQ(iter + 3, dedup->end());
-
- // Inserting the same backtrace again should return the index of the existing
- // node.
- ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
- ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
- ASSERT_EQ(dedup->begin() + 3, dedup->end());
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/heap_profiler_type_name_deduplicator.cc b/base/trace_event/heap_profiler_type_name_deduplicator.cc
deleted file mode 100644
index a6dab51ad2..0000000000
--- a/base/trace_event/heap_profiler_type_name_deduplicator.cc
+++ /dev/null
@@ -1,115 +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/heap_profiler_type_name_deduplicator.h"
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <string>
-#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 {
-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) {
- 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);
- return result;
- }
-
- // Remove the file name from the path.
- result.remove_suffix(result.length() - last_seperator);
-
- // Remove the parent directory references.
- const char kParentDirectory[] = "..";
- const size_t kParentDirectoryLength = 3; // '../' or '..\'.
- while (result.starts_with(kParentDirectory)) {
- result.remove_prefix(kParentDirectoryLength);
- }
- return result;
-}
-
-} // namespace
-
-TypeNameDeduplicator::TypeNameDeduplicator() {
- // A null pointer has type ID 0 ("unknown type");
- type_ids_.insert(std::make_pair(nullptr, 0));
-}
-
-TypeNameDeduplicator::~TypeNameDeduplicator() {}
-
-int TypeNameDeduplicator::Insert(const char* type_name) {
- auto result = type_ids_.insert(std::make_pair(type_name, 0));
- auto& elem = result.first;
- bool did_not_exist_before = result.second;
-
- if (did_not_exist_before) {
- // The type IDs are assigned sequentially and they are zero-based, so
- // |size() - 1| is the ID of the new element.
- elem->second = static_cast<int>(type_ids_.size() - 1);
- }
-
- return elem->second;
-}
-
-void TypeNameDeduplicator::AppendAsTraceFormat(std::string* out) const {
- out->append("{"); // Begin the type names dictionary.
-
- auto it = type_ids_.begin();
- std::string buffer;
-
- // Write the first entry manually; the null pointer must not be dereferenced.
- // (The first entry is the null pointer because a |std::map| is ordered.)
- it++;
- out->append("\"0\":\"[unknown]\"");
-
- for (; it != type_ids_.end(); it++) {
- // Type IDs in the trace are strings, write them as stringified keys of
- // a dictionary.
- SStringPrintf(&buffer, ",\"%d\":", it->second);
-
- // TODO(ssid): crbug.com/594803 the type name is misused for file name in
- // some cases.
- StringPiece type_info = ExtractCategoryFromTypeName(it->first);
-
- // |EscapeJSONString| appends, it does not overwrite |buffer|.
- bool put_in_quotes = true;
- EscapeJSONString(type_info, put_in_quotes, &buffer);
- out->append(buffer);
- }
-
- out->append("}"); // End the type names dictionary.
-}
-
-void TypeNameDeduplicator::EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) {
- size_t memory_usage = EstimateMemoryUsage(type_ids_);
- overhead->Add("TypeNameDeduplicator",
- sizeof(TypeNameDeduplicator) + memory_usage);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/heap_profiler_type_name_deduplicator.h b/base/trace_event/heap_profiler_type_name_deduplicator.h
deleted file mode 100644
index 2d26c73488..0000000000
--- a/base/trace_event/heap_profiler_type_name_deduplicator.h
+++ /dev/null
@@ -1,45 +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.
-
-#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
-#define BASE_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
-
-#include <map>
-#include <string>
-
-#include "base/base_export.h"
-#include "base/macros.h"
-#include "base/trace_event/trace_event_impl.h"
-
-namespace base {
-namespace trace_event {
-
-class TraceEventMemoryOverhead;
-
-// Data structure that assigns a unique numeric ID to |const char*|s.
-class BASE_EXPORT TypeNameDeduplicator : public ConvertableToTraceFormat {
- public:
- TypeNameDeduplicator();
- ~TypeNameDeduplicator() override;
-
- // Inserts a type name and returns its ID.
- int Insert(const char* type_name);
-
- // Writes the type ID -> type name mapping to the trace log.
- void AppendAsTraceFormat(std::string* out) const override;
-
- // Estimates memory overhead including |sizeof(TypeNameDeduplicator)|.
- void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
-
- private:
- // Map from type name to type ID.
- std::map<const char*, int> type_ids_;
-
- DISALLOW_COPY_AND_ASSIGN(TypeNameDeduplicator);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
diff --git a/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc b/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc
deleted file mode 100644
index b2e681ab26..0000000000
--- a/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc
+++ /dev/null
@@ -1,96 +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 <memory>
-#include <string>
-
-#include "base/json/json_reader.h"
-#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
-#include "base/values.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-// Define all strings once, because the deduplicator requires pointer equality,
-// and string interning is unreliable.
-const char kInt[] = "int";
-const char kBool[] = "bool";
-const char kString[] = "string";
-const char kNeedsEscape[] = "\"quotes\"";
-
-#if defined(OS_POSIX)
-const char kTaskFileName[] = "../../base/trace_event/trace_log.cc";
-const char kTaskPath[] = "base/trace_event";
-#else
-const char kTaskFileName[] = "..\\..\\base\\memory\\memory_win.cc";
-const char kTaskPath[] = "base\\memory";
-#endif
-
-std::unique_ptr<Value> DumpAndReadBack(
- const TypeNameDeduplicator& deduplicator) {
- std::string json;
- deduplicator.AppendAsTraceFormat(&json);
- return JSONReader::Read(json);
-}
-
-// Inserts a single type name into a new TypeNameDeduplicator instance and
-// checks if the value gets inserted and the exported value for |type_name| is
-// the same as |expected_value|.
-void TestInsertTypeAndReadback(const char* type_name,
- const char* expected_value) {
- std::unique_ptr<TypeNameDeduplicator> dedup(new TypeNameDeduplicator);
- ASSERT_EQ(1, dedup->Insert(type_name));
-
- std::unique_ptr<Value> type_names = DumpAndReadBack(*dedup);
- ASSERT_NE(nullptr, type_names);
-
- const DictionaryValue* dictionary;
- ASSERT_TRUE(type_names->GetAsDictionary(&dictionary));
-
- // When the type name was inserted, it got ID 1. The exported key "1"
- // should be equal to |expected_value|.
- std::string value;
- ASSERT_TRUE(dictionary->GetString("1", &value));
- ASSERT_EQ(expected_value, value);
-}
-
-} // namespace
-
-TEST(TypeNameDeduplicatorTest, Deduplication) {
- // The type IDs should be like this:
- // 0: [unknown]
- // 1: int
- // 2: bool
- // 3: string
-
- std::unique_ptr<TypeNameDeduplicator> dedup(new TypeNameDeduplicator);
- ASSERT_EQ(1, dedup->Insert(kInt));
- ASSERT_EQ(2, dedup->Insert(kBool));
- ASSERT_EQ(3, dedup->Insert(kString));
-
- // Inserting again should return the same IDs.
- ASSERT_EQ(2, dedup->Insert(kBool));
- ASSERT_EQ(1, dedup->Insert(kInt));
- ASSERT_EQ(3, dedup->Insert(kString));
-
- // A null pointer should yield type ID 0.
- ASSERT_EQ(0, dedup->Insert(nullptr));
-}
-
-TEST(TypeNameDeduplicatorTest, EscapeTypeName) {
- // Reading json should not fail, because the type name should have been
- // escaped properly and exported value should contain quotes.
- TestInsertTypeAndReadback(kNeedsEscape, kNeedsEscape);
-}
-
-TEST(TypeNameDeduplicatorTest, TestExtractFileName) {
- // The exported value for passed file name should be the folders in the path.
- TestInsertTypeAndReadback(kTaskFileName, kTaskPath);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc
deleted file mode 100644
index 7f2706092e..0000000000
--- a/base/trace_event/malloc_dump_provider.cc
+++ /dev/null
@@ -1,378 +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/malloc_dump_provider.h"
-
-#include <stddef.h>
-
-#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"
-#include "base/trace_event/heap_profiler_heap_dump_writer.h"
-#include "base/trace_event/process_memory_dump.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "build/build_config.h"
-
-#if defined(OS_MACOSX)
-#include <malloc/malloc.h>
-#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)
-
-using allocator::AllocatorDispatch;
-
-void* HookAlloc(const AllocatorDispatch* self, size_t size, void* context) {
- const AllocatorDispatch* const next = self->next;
- void* ptr = next->alloc_function(next, size, context);
- if (ptr)
- MallocDumpProvider::GetInstance()->InsertAllocation(ptr, size);
- return ptr;
-}
-
-void* HookZeroInitAlloc(const AllocatorDispatch* self,
- size_t n,
- size_t size,
- void* context) {
- const AllocatorDispatch* const next = self->next;
- void* ptr = next->alloc_zero_initialized_function(next, n, size, context);
- if (ptr)
- MallocDumpProvider::GetInstance()->InsertAllocation(ptr, n * size);
- return ptr;
-}
-
-void* HookAllocAligned(const AllocatorDispatch* self,
- size_t alignment,
- size_t size,
- void* context) {
- const AllocatorDispatch* const next = self->next;
- void* ptr = next->alloc_aligned_function(next, alignment, size, context);
- if (ptr)
- MallocDumpProvider::GetInstance()->InsertAllocation(ptr, size);
- return ptr;
-}
-
-void* HookRealloc(const AllocatorDispatch* self,
- void* address,
- size_t size,
- void* context) {
- const AllocatorDispatch* const next = self->next;
- void* ptr = next->realloc_function(next, address, size, context);
- 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) {
- 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);
-}
-
-AllocatorDispatch g_allocator_hooks = {
- &HookAlloc, /* alloc_function */
- &HookZeroInitAlloc, /* alloc_zero_initialized_function */
- &HookAllocAligned, /* 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 */
-};
-#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
-
-// static
-const char MallocDumpProvider::kAllocatedObjects[] = "malloc/allocated_objects";
-
-// static
-MallocDumpProvider* MallocDumpProvider::GetInstance() {
- return Singleton<MallocDumpProvider,
- LeakySingletonTraits<MallocDumpProvider>>::get();
-}
-
-MallocDumpProvider::MallocDumpProvider()
- : heap_profiler_enabled_(false), tid_dumping_heap_(kInvalidThreadId) {}
-
-MallocDumpProvider::~MallocDumpProvider() {}
-
-// Called at trace dump point time. Creates a snapshot the memory counters for
-// the current process.
-bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
- ProcessMemoryDump* pmd) {
- 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);
- DCHECK(res);
- res = allocator::GetNumericProperty("generic.total_physical_bytes",
- &resident_size);
- DCHECK(res);
- res = allocator::GetNumericProperty("generic.current_allocated_bytes",
- &allocated_objects_size);
- DCHECK(res);
-#elif defined(OS_MACOSX) || defined(OS_IOS)
- malloc_statistics_t stats = {0};
- 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;
-#else
- struct mallinfo info = mallinfo();
- DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
-
- // In case of Android's jemalloc |arena| is 0 and the outer pages size is
- // reported by |hblkhd|. In case of dlmalloc the total is given by
- // |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
-
- MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc");
- outer_dump->AddScalar("virtual_size", MemoryAllocatorDump::kUnitsBytes,
- total_virtual_size);
- outer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
- MemoryAllocatorDump::kUnitsBytes, resident_size);
-
- 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) {
- // 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.
- MemoryAllocatorDump* other_dump =
- pmd->CreateAllocatorDump("malloc/metadata_fragmentation_caches");
- other_dump->AddScalar(MemoryAllocatorDump::kNameSize,
- MemoryAllocatorDump::kUnitsBytes,
- resident_size - allocated_objects_size);
- }
-
- // Heap profiler dumps.
- if (!heap_profiler_enabled_)
- return true;
-
- // The dumps of the heap profiler should be created only when heap profiling
- // was enabled (--enable-heap-profiling) AND a DETAILED dump is requested.
- // However, when enabled, the overhead of the heap profiler should be always
- // reported to avoid oscillations of the malloc total in LIGHT dumps.
-
- tid_dumping_heap_ = PlatformThread::CurrentId();
- // At this point the Insert/RemoveAllocation hooks will ignore this thread.
- // Enclosing all the temporariy data structures in a scope, so that the heap
- // profiler does not see unabalanced malloc/free calls from these containers.
- {
- TraceEventMemoryOverhead overhead;
- hash_map<AllocationContext, AllocationMetrics> metrics_by_context;
- {
- AutoLock lock(allocation_register_lock_);
- if (allocation_register_) {
- if (args.level_of_detail == MemoryDumpLevelOfDetail::DETAILED) {
- for (const auto& alloc_size : *allocation_register_) {
- AllocationMetrics& metrics = metrics_by_context[alloc_size.context];
- metrics.size += alloc_size.size;
- metrics.count++;
- }
- }
- allocation_register_->EstimateTraceMemoryOverhead(&overhead);
- }
- } // lock(allocation_register_lock_)
- pmd->DumpHeapUsage(metrics_by_context, overhead, "malloc");
- }
- tid_dumping_heap_ = kInvalidThreadId;
-
- return true;
-}
-
-void MallocDumpProvider::OnHeapProfilingEnabled(bool enabled) {
-#if BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM)
- if (enabled) {
- {
- AutoLock lock(allocation_register_lock_);
- allocation_register_.reset(new AllocationRegister());
- }
- allocator::InsertAllocatorDispatch(&g_allocator_hooks);
- } else {
- AutoLock lock(allocation_register_lock_);
- allocation_register_.reset();
- // Insert/RemoveAllocation below will no-op if the register is torn down.
- // Once disabled, heap profiling will not re-enabled anymore for the
- // lifetime of the process.
- }
-#endif
- heap_profiler_enabled_ = enabled;
-}
-
-void MallocDumpProvider::InsertAllocation(void* address, size_t size) {
- // CurrentId() can be a slow operation (crbug.com/497226). This apparently
- // redundant condition short circuits the CurrentID() calls when unnecessary.
- if (tid_dumping_heap_ != kInvalidThreadId &&
- tid_dumping_heap_ == PlatformThread::CurrentId())
- return;
-
- // AllocationContextTracker will return nullptr when called re-reentrantly.
- // This is the case of GetInstanceForCurrentThread() being called for the
- // first time, which causes a new() inside the tracker which re-enters the
- // heap profiler, in which case we just want to early out.
- auto* tracker = AllocationContextTracker::GetInstanceForCurrentThread();
- if (!tracker)
- return;
-
- AllocationContext context;
- if (!tracker->GetContextSnapshot(&context))
- return;
-
- AutoLock lock(allocation_register_lock_);
- if (!allocation_register_)
- return;
-
- allocation_register_->Insert(address, size, context);
-}
-
-void MallocDumpProvider::RemoveAllocation(void* address) {
- // No re-entrancy is expected here as none of the calls below should
- // cause a free()-s (|allocation_register_| does its own heap management).
- if (tid_dumping_heap_ != kInvalidThreadId &&
- tid_dumping_heap_ == PlatformThread::CurrentId())
- return;
- AutoLock lock(allocation_register_lock_);
- if (!allocation_register_)
- return;
- allocation_register_->Remove(address);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/malloc_dump_provider.h b/base/trace_event/malloc_dump_provider.h
deleted file mode 100644
index 384033c9b8..0000000000
--- a/base/trace_event/malloc_dump_provider.h
+++ /dev/null
@@ -1,69 +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.
-
-#ifndef BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
-#define BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
-
-#include <istream>
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/platform_thread.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "build/build_config.h"
-
-#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_WIN) || \
- (defined(OS_MACOSX) && !defined(OS_IOS))
-#define MALLOC_MEMORY_TRACING_SUPPORTED
-#endif
-
-namespace base {
-namespace trace_event {
-
-class AllocationRegister;
-
-// Dump provider which collects process-wide memory stats.
-class BASE_EXPORT MallocDumpProvider : public MemoryDumpProvider {
- public:
- // Name of the allocated_objects dump. Use this to declare suballocator dumps
- // from other dump providers.
- static const char kAllocatedObjects[];
-
- static MallocDumpProvider* GetInstance();
-
- // MemoryDumpProvider implementation.
- bool OnMemoryDump(const MemoryDumpArgs& args,
- ProcessMemoryDump* pmd) override;
-
- void OnHeapProfilingEnabled(bool enabled) override;
-
- // For heap profiling.
- void InsertAllocation(void* address, size_t size);
- void RemoveAllocation(void* address);
-
- private:
- friend struct DefaultSingletonTraits<MallocDumpProvider>;
-
- MallocDumpProvider();
- ~MallocDumpProvider() override;
-
- // For heap profiling.
- bool heap_profiler_enabled_;
- std::unique_ptr<AllocationRegister> allocation_register_;
- Lock allocation_register_lock_;
-
- // When in OnMemoryDump(), this contains the current thread ID.
- // This is to prevent re-entrancy in the heap profiler when the heap dump
- // generation is malloc/new-ing for its own bookeeping data structures.
- PlatformThreadId tid_dumping_heap_;
-
- DISALLOW_COPY_AND_ASSIGN(MallocDumpProvider);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
diff --git a/base/trace_event/memory_allocator_dump.cc b/base/trace_event/memory_allocator_dump.cc
deleted file mode 100644
index 2692521c09..0000000000
--- a/base/trace_event/memory_allocator_dump.cc
+++ /dev/null
@@ -1,110 +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/memory_allocator_dump.h"
-
-#include "base/format_macros.h"
-#include "base/strings/stringprintf.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_event_argument.h"
-#include "base/values.h"
-
-namespace base {
-namespace trace_event {
-
-const char MemoryAllocatorDump::kNameSize[] = "size";
-const char MemoryAllocatorDump::kNameObjectCount[] = "object_count";
-const char MemoryAllocatorDump::kTypeScalar[] = "scalar";
-const char MemoryAllocatorDump::kTypeString[] = "string";
-const char MemoryAllocatorDump::kUnitsBytes[] = "bytes";
-const char MemoryAllocatorDump::kUnitsObjects[] = "objects";
-
-MemoryAllocatorDump::MemoryAllocatorDump(const std::string& absolute_name,
- ProcessMemoryDump* process_memory_dump,
- const MemoryAllocatorDumpGuid& guid)
- : absolute_name_(absolute_name),
- process_memory_dump_(process_memory_dump),
- attributes_(new TracedValue),
- guid_(guid),
- flags_(Flags::DEFAULT),
- size_(0) {
- // The |absolute_name| cannot be empty.
- DCHECK(!absolute_name.empty());
-
- // The |absolute_name| can contain slash separator, but not leading or
- // trailing ones.
- DCHECK(absolute_name[0] != '/' && *absolute_name.rbegin() != '/');
-}
-
-// If the caller didn't provide a guid, make one up by hashing the
-// absolute_name with the current PID.
-// Rationale: |absolute_name| is already supposed to be unique within a
-// process, the pid will make it unique among all processes.
-MemoryAllocatorDump::MemoryAllocatorDump(const std::string& absolute_name,
- ProcessMemoryDump* process_memory_dump)
- : MemoryAllocatorDump(absolute_name,
- process_memory_dump,
- MemoryAllocatorDumpGuid(StringPrintf(
- "%d:%s",
- TraceLog::GetInstance()->process_id(),
- absolute_name.c_str()))) {
- string_conversion_buffer_.reserve(16);
-}
-
-MemoryAllocatorDump::~MemoryAllocatorDump() {
-}
-
-void MemoryAllocatorDump::AddScalar(const char* name,
- const char* units,
- uint64_t value) {
- if (strcmp(kNameSize, name) == 0)
- size_ = value;
- SStringPrintf(&string_conversion_buffer_, "%" PRIx64, value);
- attributes_->BeginDictionary(name);
- attributes_->SetString("type", kTypeScalar);
- attributes_->SetString("units", units);
- attributes_->SetString("value", string_conversion_buffer_);
- attributes_->EndDictionary();
-}
-
-void MemoryAllocatorDump::AddScalarF(const char* name,
- const char* units,
- double value) {
- attributes_->BeginDictionary(name);
- attributes_->SetString("type", kTypeScalar);
- attributes_->SetString("units", units);
- attributes_->SetDouble("value", value);
- attributes_->EndDictionary();
-}
-
-void MemoryAllocatorDump::AddString(const char* name,
- const char* units,
- const std::string& value) {
- // String attributes are disabled in background mode.
- if (process_memory_dump_->dump_args().level_of_detail ==
- MemoryDumpLevelOfDetail::BACKGROUND) {
- NOTREACHED();
- return;
- }
-
- attributes_->BeginDictionary(name);
- attributes_->SetString("type", kTypeString);
- attributes_->SetString("units", units);
- attributes_->SetString("value", value);
- attributes_->EndDictionary();
-}
-
-void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
- value->BeginDictionaryWithCopiedName(absolute_name_);
- value->SetString("guid", guid_.ToString());
- value->SetValue("attrs", *attributes_);
- if (flags_)
- value->SetInteger("flags", flags_);
- value->EndDictionary(); // "allocator_name/heap_subheap": { ... }
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_allocator_dump.h b/base/trace_event/memory_allocator_dump.h
deleted file mode 100644
index 99ff114e5c..0000000000
--- a/base/trace_event/memory_allocator_dump.h
+++ /dev/null
@@ -1,115 +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.
-
-#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
-#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/base_export.h"
-#include "base/gtest_prod_util.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/trace_event/memory_allocator_dump_guid.h"
-#include "base/values.h"
-
-namespace base {
-namespace trace_event {
-
-class ProcessMemoryDump;
-class TracedValue;
-
-// Data model for user-land memory allocator dumps.
-class BASE_EXPORT MemoryAllocatorDump {
- public:
- enum Flags {
- DEFAULT = 0,
-
- // A dump marked weak will be discarded by TraceViewer.
- WEAK = 1 << 0,
- };
-
- // MemoryAllocatorDump is owned by ProcessMemoryDump.
- MemoryAllocatorDump(const std::string& absolute_name,
- ProcessMemoryDump* process_memory_dump,
- const MemoryAllocatorDumpGuid& guid);
- MemoryAllocatorDump(const std::string& absolute_name,
- ProcessMemoryDump* process_memory_dump);
- ~MemoryAllocatorDump();
-
- // Standard attribute |name|s for the AddScalar and AddString() methods.
- static const char kNameSize[]; // To represent allocated space.
- static const char kNameObjectCount[]; // To represent number of objects.
-
- // Standard attribute |unit|s for the AddScalar and AddString() methods.
- static const char kUnitsBytes[]; // Unit name to represent bytes.
- static const char kUnitsObjects[]; // Unit name to represent #objects.
-
- // Constants used only internally and by tests.
- static const char kTypeScalar[]; // Type name for scalar attributes.
- static const char kTypeString[]; // Type name for string attributes.
-
- // Setters for scalar attributes. Some examples:
- // - "size" column (all dumps are expected to have at least this one):
- // AddScalar(kNameSize, kUnitsBytes, 1234);
- // - Some extra-column reporting internal details of the subsystem:
- // AddScalar("number_of_freelist_entires", kUnitsObjects, 42)
- // - Other informational column (will not be auto-added in the UI)
- // AddScalarF("kittens_ratio", "ratio", 42.0f)
- void AddScalar(const char* name, const char* units, uint64_t value);
- void AddScalarF(const char* name, const char* units, double value);
- void AddString(const char* name, const char* units, const std::string& value);
-
- // Absolute name, unique within the scope of an entire ProcessMemoryDump.
- const std::string& absolute_name() const { return absolute_name_; }
-
- // Called at trace generation time to populate the TracedValue.
- void AsValueInto(TracedValue* value) const;
-
- // Use enum Flags to set values.
- void set_flags(int flags) { flags_ |= flags; }
- void clear_flags(int flags) { flags_ &= ~flags; }
- int flags() { return flags_; }
-
- // |guid| is an optional global dump identifier, unique across all processes
- // within the scope of a global dump. It is only required when using the
- // graph APIs (see TODO_method_name) to express retention / suballocation or
- // cross process sharing. See crbug.com/492102 for design docs.
- // Subsequent MemoryAllocatorDump(s) with the same |absolute_name| are
- // expected to have the same guid.
- const MemoryAllocatorDumpGuid& guid() const { return guid_; }
-
- TracedValue* attributes_for_testing() const { return attributes_.get(); }
-
- private:
- // TODO(hjd): Transitional until we send the full PMD. See crbug.com/704203
- friend class MemoryDumpManager;
- FRIEND_TEST_ALL_PREFIXES(MemoryAllocatorDumpTest, GetSize);
-
- // Get the size for this dump.
- // The size is the value set with AddScalar(kNameSize, kUnitsBytes, size);
- // TODO(hjd): Transitional until we send the full PMD. See crbug.com/704203
- uint64_t GetSize() const { return size_; };
-
- const std::string absolute_name_;
- ProcessMemoryDump* const process_memory_dump_; // Not owned (PMD owns this).
- std::unique_ptr<TracedValue> attributes_;
- MemoryAllocatorDumpGuid guid_;
- int flags_; // See enum Flags.
- uint64_t size_;
-
- // A local buffer for Sprintf conversion on fastpath. Avoids allocating
- // temporary strings on each AddScalar() call.
- std::string string_conversion_buffer_;
-
- DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorDump);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
diff --git a/base/trace_event/memory_allocator_dump_guid.cc b/base/trace_event/memory_allocator_dump_guid.cc
deleted file mode 100644
index bf4389a4c7..0000000000
--- a/base/trace_event/memory_allocator_dump_guid.cc
+++ /dev/null
@@ -1,38 +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/memory_allocator_dump_guid.h"
-
-#include "base/format_macros.h"
-#include "base/sha1.h"
-#include "base/strings/stringprintf.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-uint64_t HashString(const std::string& str) {
- uint64_t hash[(kSHA1Length + sizeof(uint64_t) - 1) / sizeof(uint64_t)] = {0};
- SHA1HashBytes(reinterpret_cast<const unsigned char*>(str.data()), str.size(),
- reinterpret_cast<unsigned char*>(hash));
- return hash[0];
-}
-} // namespace
-
-MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(uint64_t guid) : guid_(guid) {}
-
-MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid()
- : MemoryAllocatorDumpGuid(0u) {
-}
-
-MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(const std::string& guid_str)
- : MemoryAllocatorDumpGuid(HashString(guid_str)) {
-}
-
-std::string MemoryAllocatorDumpGuid::ToString() const {
- return StringPrintf("%" PRIx64, guid_);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_allocator_dump_guid.h b/base/trace_event/memory_allocator_dump_guid.h
deleted file mode 100644
index b6472c6612..0000000000
--- a/base/trace_event/memory_allocator_dump_guid.h
+++ /dev/null
@@ -1,51 +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.
-
-#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
-#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
-
-#include <stdint.h>
-
-#include <string>
-
-#include "base/base_export.h"
-
-namespace base {
-namespace trace_event {
-
-class BASE_EXPORT MemoryAllocatorDumpGuid {
- public:
- MemoryAllocatorDumpGuid();
- explicit MemoryAllocatorDumpGuid(uint64_t guid);
-
- // Utility ctor to hash a GUID if the caller prefers a string. The caller
- // still has to ensure that |guid_str| is unique, per snapshot, within the
- // global scope of all the traced processes.
- explicit MemoryAllocatorDumpGuid(const std::string& guid_str);
-
- uint64_t ToUint64() const { return guid_; }
-
- // Returns a (hex-encoded) string representation of the guid.
- std::string ToString() const;
-
- bool empty() const { return guid_ == 0u; }
-
- bool operator==(const MemoryAllocatorDumpGuid& other) const {
- return guid_ == other.guid_;
- }
-
- bool operator!=(const MemoryAllocatorDumpGuid& other) const {
- return !(*this == other);
- }
-
- private:
- uint64_t guid_;
-
- // Deliberately copy-able.
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
diff --git a/base/trace_event/memory_allocator_dump_unittest.cc b/base/trace_event/memory_allocator_dump_unittest.cc
deleted file mode 100644
index e1818f6eec..0000000000
--- a/base/trace_event/memory_allocator_dump_unittest.cc
+++ /dev/null
@@ -1,200 +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/memory_allocator_dump.h"
-
-#include <stdint.h>
-
-#include "base/format_macros.h"
-#include "base/strings/stringprintf.h"
-#include "base/trace_event/memory_allocator_dump_guid.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "base/trace_event/memory_dump_session_state.h"
-#include "base/trace_event/process_memory_dump.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
- public:
- bool OnMemoryDump(const MemoryDumpArgs& args,
- ProcessMemoryDump* pmd) override {
- MemoryAllocatorDump* root_heap =
- pmd->CreateAllocatorDump("foobar_allocator");
-
- root_heap->AddScalar(MemoryAllocatorDump::kNameSize,
- MemoryAllocatorDump::kUnitsBytes, 4096);
- root_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount,
- MemoryAllocatorDump::kUnitsObjects, 42);
- root_heap->AddScalar("attr1", "units1", 1234);
- root_heap->AddString("attr2", "units2", "string_value");
- root_heap->AddScalarF("attr3", "units3", 42.5f);
-
- MemoryAllocatorDump* sub_heap =
- pmd->CreateAllocatorDump("foobar_allocator/sub_heap");
- sub_heap->AddScalar(MemoryAllocatorDump::kNameSize,
- MemoryAllocatorDump::kUnitsBytes, 1);
- sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount,
- MemoryAllocatorDump::kUnitsObjects, 3);
-
- pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty");
- // Leave the rest of sub heap deliberately uninitialized, to check that
- // CreateAllocatorDump returns a properly zero-initialized object.
-
- return true;
- }
-};
-
-std::unique_ptr<Value> CheckAttribute(const MemoryAllocatorDump* dump,
- const std::string& name,
- const char* expected_type,
- const char* expected_units) {
- std::unique_ptr<Value> raw_attrs =
- dump->attributes_for_testing()->ToBaseValue();
- DictionaryValue* args = nullptr;
- DictionaryValue* arg = nullptr;
- std::string arg_value;
- const Value* out_value = nullptr;
- EXPECT_TRUE(raw_attrs->GetAsDictionary(&args));
- EXPECT_TRUE(args->GetDictionary(name, &arg));
- EXPECT_TRUE(arg->GetString("type", &arg_value));
- EXPECT_EQ(expected_type, arg_value);
- EXPECT_TRUE(arg->GetString("units", &arg_value));
- EXPECT_EQ(expected_units, arg_value);
- EXPECT_TRUE(arg->Get("value", &out_value));
- return out_value ? out_value->CreateDeepCopy() : std::unique_ptr<Value>();
-}
-
-void CheckString(const MemoryAllocatorDump* dump,
- const std::string& name,
- const char* expected_type,
- const char* expected_units,
- const std::string& expected_value) {
- std::string attr_str_value;
- auto attr_value = CheckAttribute(dump, name, expected_type, expected_units);
- EXPECT_TRUE(attr_value->GetAsString(&attr_str_value));
- EXPECT_EQ(expected_value, attr_str_value);
-}
-
-void CheckScalar(const MemoryAllocatorDump* dump,
- const std::string& name,
- const char* expected_units,
- uint64_t expected_value) {
- CheckString(dump, name, MemoryAllocatorDump::kTypeScalar, expected_units,
- StringPrintf("%" PRIx64, expected_value));
-}
-
-void CheckScalarF(const MemoryAllocatorDump* dump,
- const std::string& name,
- const char* expected_units,
- double expected_value) {
- auto attr_value = CheckAttribute(dump, name, MemoryAllocatorDump::kTypeScalar,
- expected_units);
- double attr_double_value;
- EXPECT_TRUE(attr_value->GetAsDouble(&attr_double_value));
- EXPECT_EQ(expected_value, attr_double_value);
-}
-
-} // namespace
-
-TEST(MemoryAllocatorDumpTest, GuidGeneration) {
- std::unique_ptr<MemoryAllocatorDump> mad(
- new MemoryAllocatorDump("foo", nullptr, MemoryAllocatorDumpGuid(0x42u)));
- ASSERT_EQ("42", mad->guid().ToString());
-
- // If the dumper does not provide a Guid, the MAD will make one up on the
- // flight. Furthermore that Guid will stay stable across across multiple
- // snapshots if the |absolute_name| of the dump doesn't change
- mad.reset(new MemoryAllocatorDump("bar", nullptr));
- const MemoryAllocatorDumpGuid guid_bar = mad->guid();
- ASSERT_FALSE(guid_bar.empty());
- ASSERT_FALSE(guid_bar.ToString().empty());
- ASSERT_EQ(guid_bar, mad->guid());
-
- mad.reset(new MemoryAllocatorDump("bar", nullptr));
- const MemoryAllocatorDumpGuid guid_bar_2 = mad->guid();
- ASSERT_EQ(guid_bar, guid_bar_2);
-
- mad.reset(new MemoryAllocatorDump("baz", nullptr));
- const MemoryAllocatorDumpGuid guid_baz = mad->guid();
- ASSERT_NE(guid_bar, guid_baz);
-}
-
-TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
- FakeMemoryAllocatorDumpProvider fmadp;
- MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
- ProcessMemoryDump pmd(new MemoryDumpSessionState, dump_args);
-
- fmadp.OnMemoryDump(dump_args, &pmd);
-
- ASSERT_EQ(3u, pmd.allocator_dumps().size());
-
- const MemoryAllocatorDump* root_heap =
- pmd.GetAllocatorDump("foobar_allocator");
- ASSERT_NE(nullptr, root_heap);
- EXPECT_EQ("foobar_allocator", root_heap->absolute_name());
- CheckScalar(root_heap, MemoryAllocatorDump::kNameSize,
- MemoryAllocatorDump::kUnitsBytes, 4096);
- CheckScalar(root_heap, MemoryAllocatorDump::kNameObjectCount,
- MemoryAllocatorDump::kUnitsObjects, 42);
- CheckScalar(root_heap, "attr1", "units1", 1234);
- CheckString(root_heap, "attr2", MemoryAllocatorDump::kTypeString, "units2",
- "string_value");
- CheckScalarF(root_heap, "attr3", "units3", 42.5f);
-
- const MemoryAllocatorDump* sub_heap =
- pmd.GetAllocatorDump("foobar_allocator/sub_heap");
- ASSERT_NE(nullptr, sub_heap);
- EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name());
- CheckScalar(sub_heap, MemoryAllocatorDump::kNameSize,
- MemoryAllocatorDump::kUnitsBytes, 1);
- CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectCount,
- MemoryAllocatorDump::kUnitsObjects, 3);
- const MemoryAllocatorDump* empty_sub_heap =
- pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty");
- ASSERT_NE(nullptr, empty_sub_heap);
- EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name());
- auto raw_attrs = empty_sub_heap->attributes_for_testing()->ToBaseValue();
- DictionaryValue* attrs = nullptr;
- ASSERT_TRUE(raw_attrs->GetAsDictionary(&attrs));
- ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameSize));
- ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameObjectCount));
-
- // Check that the AsValueInfo doesn't hit any DCHECK.
- std::unique_ptr<TracedValue> traced_value(new TracedValue);
- pmd.AsValueInto(traced_value.get());
-}
-
-TEST(MemoryAllocatorDumpTest, GetSize) {
- MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
- ProcessMemoryDump pmd(new MemoryDumpSessionState, dump_args);
- MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("allocator_for_size");
- dump->AddScalar(MemoryAllocatorDump::kNameSize,
- MemoryAllocatorDump::kUnitsBytes, 1);
- dump->AddScalar("foo", MemoryAllocatorDump::kUnitsBytes, 2);
- EXPECT_EQ(1u, dump->GetSize());
-}
-
-// DEATH tests are not supported in Android / iOS.
-#if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS)
-TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) {
- FakeMemoryAllocatorDumpProvider fmadp;
- MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
- ProcessMemoryDump pmd(new MemoryDumpSessionState, dump_args);
- pmd.CreateAllocatorDump("foo_allocator");
- pmd.CreateAllocatorDump("bar_allocator/heap");
- ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), "");
- ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator/heap"), "");
- ASSERT_DEATH(pmd.CreateAllocatorDump(""), "");
-}
-#endif
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
deleted file mode 100644
index 6ed1ca8fff..0000000000
--- a/base/trace_event/memory_dump_manager.cc
+++ /dev/null
@@ -1,991 +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/memory_dump_manager.h"
-
-#include <inttypes.h>
-#include <stdio.h>
-
-#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/strings/pattern.h"
-#include "base/strings/string_piece.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"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "build/build_config.h"
-
-#if defined(OS_ANDROID)
-#include "base/trace_event/java_heap_dump_provider_android.h"
-#endif
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-const int kTraceEventNumArgs = 1;
-const char* kTraceEventArgNames[] = {"dumps"};
-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,
- uint64_t dump_guid,
- bool success) {
- char guid_str[20];
- sprintf(guid_str, "0x%" PRIx64, dump_guid);
- TRACE_EVENT_NESTABLE_ASYNC_END2(MemoryDumpManager::kTraceCategory,
- "GlobalMemoryDump", TRACE_ID_LOCAL(dump_guid),
- "dump_guid", TRACE_STR_COPY(guid_str),
- "success", success);
-
- if (!wrapped_callback.is_null()) {
- wrapped_callback.Run(dump_guid, success);
- wrapped_callback.Reset();
- }
-}
-
-// Proxy class which wraps a ConvertableToTraceFormat owned by the
-// |session_state| into a proxy object that can be added to the trace event log.
-// This is to solve the problem that the MemoryDumpSessionState is refcounted
-// but the tracing subsystem wants a std::unique_ptr<ConvertableToTraceFormat>.
-template <typename T>
-struct SessionStateConvertableProxy : public ConvertableToTraceFormat {
- using GetterFunctPtr = T* (MemoryDumpSessionState::*)() const;
-
- SessionStateConvertableProxy(
- scoped_refptr<MemoryDumpSessionState> session_state,
- GetterFunctPtr getter_function)
- : session_state(session_state), getter_function(getter_function) {}
-
- void AppendAsTraceFormat(std::string* out) const override {
- return (session_state.get()->*getter_function)()->AppendAsTraceFormat(out);
- }
-
- void EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) override {
- return (session_state.get()->*getter_function)()
- ->EstimateTraceMemoryOverhead(overhead);
- }
-
- scoped_refptr<MemoryDumpSessionState> session_state;
- GetterFunctPtr const getter_function;
-};
-
-} // namespace
-
-// static
-const char* const MemoryDumpManager::kTraceCategory =
- TRACE_DISABLED_BY_DEFAULT("memory-infra");
-
-// static
-const char* const MemoryDumpManager::kLogPrefix = "Memory-infra dump";
-
-// static
-const int MemoryDumpManager::kMaxConsecutiveFailuresCount = 3;
-
-// static
-const uint64_t MemoryDumpManager::kInvalidTracingProcessId = 0;
-
-// static
-const char* const MemoryDumpManager::kSystemAllocatorPoolName =
-#if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
- MallocDumpProvider::kAllocatedObjects;
-#else
- nullptr;
-#endif
-
-// static
-MemoryDumpManager* MemoryDumpManager::GetInstance() {
- if (g_instance_for_testing)
- return g_instance_for_testing;
-
- return Singleton<MemoryDumpManager,
- LeakySingletonTraits<MemoryDumpManager>>::get();
-}
-
-// static
-void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) {
- g_instance_for_testing = instance;
-}
-
-MemoryDumpManager::MemoryDumpManager()
- : memory_tracing_enabled_(0),
- tracing_process_id_(kInvalidTracingProcessId),
- dumper_registrations_ignored_for_testing_(false),
- heap_profiling_enabled_(false) {
- g_next_guid.GetNext(); // Make sure that first guid is not zero.
-
- // 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() {
- TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
-}
-
-void MemoryDumpManager::EnableHeapProfilingIfNeeded() {
- if (heap_profiling_enabled_)
- return;
-
- if (!CommandLine::InitializedForCurrentProcess() ||
- !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableHeapProfiling))
- return;
-
- std::string profiling_mode = CommandLine::ForCurrentProcess()
- ->GetSwitchValueASCII(switches::kEnableHeapProfiling);
- if (profiling_mode == "") {
- AllocationContextTracker::SetCaptureMode(
- AllocationContextTracker::CaptureMode::PSEUDO_STACK);
-#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();
-#endif
- } else {
- CHECK(false) << "Invalid mode '" << profiling_mode << "' for "
- << switches::kEnableHeapProfiling << " flag.";
- }
-
- for (auto mdp : dump_providers_)
- mdp->dump_provider->OnHeapProfilingEnabled(true);
- heap_profiling_enabled_ = true;
-}
-
-void MemoryDumpManager::Initialize(
- std::unique_ptr<MemoryDumpManagerDelegate> delegate) {
- {
- AutoLock lock(lock_);
- DCHECK(delegate);
- DCHECK(!delegate_);
- delegate_ = std::move(delegate);
- EnableHeapProfilingIfNeeded();
- }
-
-// Enable the core dump providers.
-#if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
- RegisterDumpProvider(MallocDumpProvider::GetInstance(), "Malloc", nullptr);
-#endif
-
-#if defined(OS_ANDROID)
- RegisterDumpProvider(JavaHeapDumpProvider::GetInstance(), "JavaHeap",
- 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.
- std::string filter_string = "*";
- const char* const kFilteredCategories[] = {
- TRACE_DISABLED_BY_DEFAULT("net"), TRACE_DISABLED_BY_DEFAULT("cc"),
- MemoryDumpManager::kTraceCategory};
- for (const char* cat : kFilteredCategories)
- filter_string = filter_string + "," + cat;
- TraceConfigCategoryFilter category_filter;
- category_filter.InitializeFromString(filter_string);
-
- TraceConfig::EventFilterConfig heap_profiler_filter_config(
- HeapProfilerEventFilter::kName);
- heap_profiler_filter_config.SetCategoryFilter(category_filter);
-
- 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 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();
- TraceLog::GetInstance()->AddEnabledStateObserver(this);
- if (is_tracing_already_enabled)
- OnTraceLogEnabled();
-}
-
-void MemoryDumpManager::RegisterDumpProvider(
- MemoryDumpProvider* mdp,
- const char* name,
- scoped_refptr<SingleThreadTaskRunner> task_runner,
- MemoryDumpProvider::Options options) {
- options.dumps_on_single_thread_task_runner = true;
- RegisterDumpProviderInternal(mdp, name, std::move(task_runner), options);
-}
-
-void MemoryDumpManager::RegisterDumpProvider(
- MemoryDumpProvider* mdp,
- const char* name,
- scoped_refptr<SingleThreadTaskRunner> task_runner) {
- // Set |dumps_on_single_thread_task_runner| to true because all providers
- // without task runner are run on dump thread.
- MemoryDumpProvider::Options options;
- options.dumps_on_single_thread_task_runner = true;
- RegisterDumpProviderInternal(mdp, name, std::move(task_runner), options);
-}
-
-void MemoryDumpManager::RegisterDumpProviderWithSequencedTaskRunner(
- MemoryDumpProvider* mdp,
- const char* name,
- scoped_refptr<SequencedTaskRunner> task_runner,
- MemoryDumpProvider::Options options) {
- DCHECK(task_runner);
- options.dumps_on_single_thread_task_runner = false;
- RegisterDumpProviderInternal(mdp, name, std::move(task_runner), options);
-}
-
-void MemoryDumpManager::RegisterDumpProviderInternal(
- MemoryDumpProvider* mdp,
- const char* name,
- scoped_refptr<SequencedTaskRunner> task_runner,
- const MemoryDumpProvider::Options& options) {
- if (dumper_registrations_ignored_for_testing_)
- return;
-
- bool whitelisted_for_background_mode = IsMemoryDumpProviderWhitelisted(name);
- scoped_refptr<MemoryDumpProviderInfo> mdpinfo =
- 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;
- // This actually happens in some tests which don't have a clean tear-down
- // 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_)
- mdp->OnHeapProfilingEnabled(true);
-}
-
-void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
- UnregisterDumpProviderInternal(mdp, false /* delete_async */);
-}
-
-void MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon(
- std::unique_ptr<MemoryDumpProvider> mdp) {
- UnregisterDumpProviderInternal(mdp.release(), true /* delete_async */);
-}
-
-void MemoryDumpManager::UnregisterDumpProviderInternal(
- MemoryDumpProvider* mdp,
- bool take_mdp_ownership_and_delete_async) {
- std::unique_ptr<MemoryDumpProvider> owned_mdp;
- if (take_mdp_ownership_and_delete_async)
- owned_mdp.reset(mdp);
-
- AutoLock lock(lock_);
-
- auto mdp_iter = dump_providers_.begin();
- for (; mdp_iter != dump_providers_.end(); ++mdp_iter) {
- if ((*mdp_iter)->dump_provider == mdp)
- break;
- }
-
- if (mdp_iter == dump_providers_.end())
- return; // Not registered / already unregistered.
-
- if (take_mdp_ownership_and_delete_async) {
- // The MDP will be deleted whenever the MDPInfo struct will, that is either:
- // - 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.
-
- // 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
- // unregistration happens on the same task runner. So that the MDP cannot
- // unregister and be in the middle of a OnMemoryDump() at the same time.
- // - The MDP has NOT specified a task runner affinity and its ownership is
- // transferred via UnregisterAndDeleteDumpProviderSoon().
- // In all the other cases, it is not possible to guarantee that the
- // unregistration will not race with OnMemoryDump() calls.
- DCHECK((*mdp_iter)->task_runner &&
- (*mdp_iter)->task_runner->RunsTasksOnCurrentThread())
- << "MemoryDumpProvider \"" << (*mdp_iter)->name << "\" attempted to "
- << "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()
- // to just skip it, without actually invoking the |mdp|, which might be
- // destroyed by the caller soon after this method returns.
- (*mdp_iter)->disabled = true;
- dump_providers_.erase(mdp_iter);
-}
-
-void MemoryDumpManager::RegisterPollingMDPOnDumpThread(
- scoped_refptr<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)
- MemoryDumpScheduler::GetInstance()->EnablePollingIfNeeded();
-}
-
-void MemoryDumpManager::UnregisterPollingMDPOnDumpThread(
- scoped_refptr<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,
- const MemoryDumpCallback& callback) {
- // Bail out immediately if tracing is not enabled at all or if the dump mode
- // is not allowed.
- if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_)) ||
- !IsDumpModeAllowed(level_of_detail)) {
- VLOG(1) << kLogPrefix << " failed because " << kTraceCategory
- << " tracing category is not enabled or the requested dump mode is "
- "not allowed by trace config.";
- if (!callback.is_null())
- callback.Run(0u /* guid */, false /* success */);
- return;
- }
-
- const uint64_t guid =
- TraceLog::GetInstance()->MangleEventId(g_next_guid.GetNext());
-
- // Creates an async event to keep track of the global dump evolution.
- // The |wrapped_callback| will generate the ASYNC_END event and then invoke
- // the real |callback| provided by the caller.
- TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(
- kTraceCategory, "GlobalMemoryDump", TRACE_ID_LOCAL(guid), "dump_type",
- MemoryDumpTypeToString(dump_type), "level_of_detail",
- MemoryDumpLevelOfDetailToString(level_of_detail));
- MemoryDumpCallback wrapped_callback = Bind(&OnGlobalDumpDone, callback);
-
- // The delegate will coordinate the IPC broadcast and at some point invoke
- // CreateProcessDump() to get a dump for the current process.
- MemoryDumpRequestArgs args = {guid, dump_type, level_of_detail};
- delegate_->RequestGlobalMemoryDump(args, wrapped_callback);
-}
-
-void MemoryDumpManager::RequestGlobalDump(
- MemoryDumpType dump_type,
- MemoryDumpLevelOfDetail level_of_detail) {
- RequestGlobalDump(dump_type, level_of_detail, MemoryDumpCallback());
-}
-
-bool MemoryDumpManager::IsDumpProviderRegisteredForTesting(
- MemoryDumpProvider* provider) {
- AutoLock lock(lock_);
-
- for (const auto& info : dump_providers_) {
- if (info->dump_provider == provider)
- return true;
- }
- return false;
-}
-
-void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args,
- const MemoryDumpCallback& callback) {
- char guid_str[20];
- sprintf(guid_str, "0x%" PRIx64, args.dump_guid);
- TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(kTraceCategory, "ProcessMemoryDump",
- TRACE_ID_LOCAL(args.dump_guid), "dump_guid",
- TRACE_STR_COPY(guid_str));
-
- // If argument filter is enabled then only background mode dumps should be
- // allowed. In case the trace config passed for background tracing session
- // missed the allowed modes argument, it crashes here instead of creating
- // unexpected dumps.
- if (TraceLog::GetInstance()
- ->GetCurrentTraceConfig()
- .IsArgumentFilterEnabled()) {
- CHECK_EQ(MemoryDumpLevelOfDetail::BACKGROUND, args.level_of_detail);
- }
-
- std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state;
- {
- AutoLock lock(lock_);
-
- // |dump_thread_| can be nullptr is tracing was disabled before reaching
- // here. SetupNextMemoryDump() is robust enough to tolerate it and will
- // NACK the dump.
- pmd_async_state.reset(new ProcessMemoryDumpAsyncState(
- args, dump_providers_, session_state_, callback,
- dump_thread_ ? dump_thread_->task_runner() : nullptr));
-
- // Safety check to prevent reaching here without calling RequestGlobalDump,
- // with disallowed modes. If |session_state_| is null then tracing is
- // disabled.
- CHECK(!session_state_ ||
- session_state_->IsDumpModeAllowed(args.level_of_detail));
-
- MemoryDumpScheduler::GetInstance()->NotifyDumpTriggered();
- }
-
- // Start the process dump. This involves task runner hops as specified by the
- // MemoryDumpProvider(s) in RegisterDumpProvider()).
- SetupNextMemoryDump(std::move(pmd_async_state));
-}
-
-// PostTask InvokeOnMemoryDump() to the dump provider's sequenced task runner. A
-// PostTask is always required for a generic SequencedTaskRunner to ensure that
-// no other task is running on it concurrently. SetupNextMemoryDump() and
-// InvokeOnMemoryDump() are called alternatively which linearizes the dump
-// provider's OnMemoryDump invocations.
-// At most one of either SetupNextMemoryDump() or InvokeOnMemoryDump() can be
-// active at any time for a given PMD, regardless of status of the |lock_|.
-// |lock_| is used in these functions purely to ensure consistency w.r.t.
-// (un)registrations of |dump_providers_|.
-void MemoryDumpManager::SetupNextMemoryDump(
- std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
- HEAP_PROFILER_SCOPED_IGNORE;
- // Initalizes the ThreadLocalEventBuffer to guarantee that the TRACE_EVENTs
- // in the PostTask below don't end up registering their own dump providers
- // (for discounting trace memory overhead) while holding the |lock_|.
- TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
-
- // |dump_thread_| might be destroyed before getting this point.
- // It means that tracing was disabled right before starting this dump.
- // Anyway either tracing is stopped or this was the last hop, create a trace
- // event, add it to the trace and finalize process dump invoking the callback.
- if (!pmd_async_state->dump_thread_task_runner.get()) {
- if (pmd_async_state->pending_dump_providers.empty()) {
- VLOG(1) << kLogPrefix << " failed because dump thread was destroyed"
- << " before finalizing the dump";
- } else {
- VLOG(1) << kLogPrefix << " failed because dump thread was destroyed"
- << " before dumping "
- << pmd_async_state->pending_dump_providers.back().get()->name;
- }
- pmd_async_state->dump_successful = false;
- pmd_async_state->pending_dump_providers.clear();
- }
- if (pmd_async_state->pending_dump_providers.empty())
- return FinalizeDumpAndAddToTrace(std::move(pmd_async_state));
-
- // Read MemoryDumpProviderInfo thread safety considerations in
- // memory_dump_manager.h when accessing |mdpinfo| fields.
- MemoryDumpProviderInfo* mdpinfo =
- pmd_async_state->pending_dump_providers.back().get();
-
- // If we are in background tracing, we should invoke only the whitelisted
- // providers. Ignore other providers and continue.
- if (pmd_async_state->req_args.level_of_detail ==
- MemoryDumpLevelOfDetail::BACKGROUND &&
- !mdpinfo->whitelisted_for_background_mode) {
- pmd_async_state->pending_dump_providers.pop_back();
- return SetupNextMemoryDump(std::move(pmd_async_state));
- }
-
- // If the dump provider did not specify a task runner affinity, dump on
- // |dump_thread_| which is already checked above for presence.
- SequencedTaskRunner* task_runner = mdpinfo->task_runner.get();
- if (!task_runner) {
- DCHECK(mdpinfo->options.dumps_on_single_thread_task_runner);
- task_runner = pmd_async_state->dump_thread_task_runner.get();
- DCHECK(task_runner);
- }
-
- if (mdpinfo->options.dumps_on_single_thread_task_runner &&
- task_runner->RunsTasksOnCurrentThread()) {
- // If |dumps_on_single_thread_task_runner| is true then no PostTask is
- // required if we are on the right thread.
- return InvokeOnMemoryDump(pmd_async_state.release());
- }
-
- bool did_post_task = task_runner->PostTask(
- FROM_HERE, Bind(&MemoryDumpManager::InvokeOnMemoryDump, Unretained(this),
- Unretained(pmd_async_state.get())));
-
- if (did_post_task) {
- // Ownership is tranferred to InvokeOnMemoryDump().
- ignore_result(pmd_async_state.release());
- return;
- }
-
- // PostTask usually fails only if the process or thread is shut down. So, the
- // dump provider is disabled here. But, don't disable unbound dump providers.
- // The utility thread is normally shutdown when disabling the trace and
- // getting here in this case is expected.
- if (mdpinfo->task_runner) {
- LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name
- << "\". Failed to post task on the task runner provided.";
-
- // A locked access is required to R/W |disabled| (for the
- // UnregisterAndDeleteDumpProviderSoon() case).
- AutoLock lock(lock_);
- mdpinfo->disabled = true;
- }
-
- // PostTask failed. Ignore the dump provider and continue.
- pmd_async_state->pending_dump_providers.pop_back();
- SetupNextMemoryDump(std::move(pmd_async_state));
-}
-
-// This function is called on the right task runner for current MDP. It is
-// either the task runner specified by MDP or |dump_thread_task_runner| if the
-// MDP did not specify task runner. Invokes the dump provider's OnMemoryDump()
-// (unless disabled).
-void MemoryDumpManager::InvokeOnMemoryDump(
- ProcessMemoryDumpAsyncState* owned_pmd_async_state) {
- HEAP_PROFILER_SCOPED_IGNORE;
- // In theory |owned_pmd_async_state| should be a scoped_ptr. The only reason
- // why it isn't is because of the corner case logic of |did_post_task|
- // above, which needs to take back the ownership of the |pmd_async_state| when
- // the PostTask() fails.
- // Unfortunately, PostTask() destroys the scoped_ptr arguments upon failure
- // to prevent accidental leaks. Using a scoped_ptr would prevent us to to
- // skip the hop and move on. Hence the manual naked -> scoped ptr juggling.
- auto pmd_async_state = WrapUnique(owned_pmd_async_state);
- owned_pmd_async_state = nullptr;
-
- // Read MemoryDumpProviderInfo thread safety considerations in
- // memory_dump_manager.h when accessing |mdpinfo| fields.
- MemoryDumpProviderInfo* mdpinfo =
- pmd_async_state->pending_dump_providers.back().get();
-
- DCHECK(!mdpinfo->task_runner ||
- mdpinfo->task_runner->RunsTasksOnCurrentThread());
-
- bool should_dump;
- {
- // A locked access is required to R/W |disabled| (for the
- // UnregisterAndDeleteDumpProviderSoon() case).
- AutoLock lock(lock_);
-
- // Unregister the dump provider if it failed too many times consecutively.
- if (!mdpinfo->disabled &&
- mdpinfo->consecutive_failures >= kMaxConsecutiveFailuresCount) {
- mdpinfo->disabled = true;
- LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name
- << "\". Dump failed multiple times consecutively.";
- }
- should_dump = !mdpinfo->disabled;
- } // AutoLock lock(lock_);
-
- if (should_dump) {
- // Invoke the dump provider.
- TRACE_EVENT1(kTraceCategory, "MemoryDumpManager::InvokeOnMemoryDump",
- "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).
- ProcessId target_pid = mdpinfo->options.target_pid;
- MemoryDumpArgs args = {pmd_async_state->req_args.level_of_detail};
- ProcessMemoryDump* pmd =
- pmd_async_state->GetOrCreateMemoryDumpContainerForProcess(target_pid,
- args);
- bool dump_successful = mdpinfo->dump_provider->OnMemoryDump(args, pmd);
- mdpinfo->consecutive_failures =
- dump_successful ? 0 : mdpinfo->consecutive_failures + 1;
- }
-
- pmd_async_state->pending_dump_providers.pop_back();
- 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
-uint32_t MemoryDumpManager::GetDumpsSumKb(const std::string& pattern,
- const ProcessMemoryDump* pmd) {
- uint64_t sum = 0;
- for (const auto& kv : pmd->allocator_dumps()) {
- auto name = StringPiece(kv.first);
- if (MatchPattern(name, pattern))
- sum += kv.second->GetSize();
- }
- return sum / 1024;
-}
-
-// static
-void MemoryDumpManager::FinalizeDumpAndAddToTrace(
- std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
- HEAP_PROFILER_SCOPED_IGNORE;
- DCHECK(pmd_async_state->pending_dump_providers.empty());
- const uint64_t dump_guid = pmd_async_state->req_args.dump_guid;
- if (!pmd_async_state->callback_task_runner->BelongsToCurrentThread()) {
- scoped_refptr<SingleThreadTaskRunner> callback_task_runner =
- pmd_async_state->callback_task_runner;
- callback_task_runner->PostTask(
- FROM_HERE, Bind(&MemoryDumpManager::FinalizeDumpAndAddToTrace,
- Passed(&pmd_async_state)));
- return;
- }
-
- TRACE_EVENT0(kTraceCategory, "MemoryDumpManager::FinalizeDumpAndAddToTrace");
-
- // The results struct to fill.
- // TODO(hjd): Transitional until we send the full PMD. See crbug.com/704203
- MemoryDumpCallbackResult result;
-
- for (const auto& kv : pmd_async_state->process_dumps) {
- ProcessId pid = kv.first; // kNullProcessId for the current process.
- ProcessMemoryDump* process_memory_dump = kv.second.get();
- std::unique_ptr<TracedValue> traced_value(new TracedValue);
- process_memory_dump->AsValueInto(traced_value.get());
- traced_value->SetString("level_of_detail",
- MemoryDumpLevelOfDetailToString(
- pmd_async_state->req_args.level_of_detail));
- const char* const event_name =
- MemoryDumpTypeToString(pmd_async_state->req_args.dump_type);
-
- std::unique_ptr<ConvertableToTraceFormat> event_value(
- std::move(traced_value));
- TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
- TRACE_EVENT_PHASE_MEMORY_DUMP,
- TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
- trace_event_internal::kGlobalScope, dump_guid, pid,
- kTraceEventNumArgs, kTraceEventArgNames,
- kTraceEventArgTypes, nullptr /* arg_values */, &event_value,
- TRACE_EVENT_FLAG_HAS_ID);
-
- // TODO(hjd): Transitional until we send the full PMD. See crbug.com/704203
- // Don't try to fill the struct in detailed mode since it is hard to avoid
- // double counting.
- if (pmd_async_state->req_args.level_of_detail ==
- MemoryDumpLevelOfDetail::DETAILED)
- continue;
-
- // TODO(hjd): Transitional until we send the full PMD. See crbug.com/704203
- if (pid == kNullProcessId) {
- result.chrome_dump.malloc_total_kb =
- GetDumpsSumKb("malloc", process_memory_dump);
- result.chrome_dump.v8_total_kb =
- GetDumpsSumKb("v8/*", process_memory_dump);
-
- // partition_alloc reports sizes for both allocated_objects and
- // partitions. The memory allocated_objects uses is a subset of
- // the partitions memory so to avoid double counting we only
- // count partitions memory.
- result.chrome_dump.partition_alloc_total_kb =
- GetDumpsSumKb("partition_alloc/partitions/*", process_memory_dump);
- result.chrome_dump.blink_gc_total_kb =
- GetDumpsSumKb("blink_gc", process_memory_dump);
- }
- }
-
- bool tracing_still_enabled;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &tracing_still_enabled);
- if (!tracing_still_enabled) {
- pmd_async_state->dump_successful = false;
- VLOG(1) << kLogPrefix << " failed because tracing was disabled before"
- << " the dump was completed";
- }
-
- if (!pmd_async_state->callback.is_null()) {
- pmd_async_state->callback.Run(dump_guid, pmd_async_state->dump_successful);
- pmd_async_state->callback.Reset();
- }
-
- TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump",
- TRACE_ID_LOCAL(dump_guid));
-}
-
-void MemoryDumpManager::OnTraceLogEnabled() {
- bool enabled;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
- if (!enabled)
- return;
-
- // Initialize the TraceLog for the current thread. This is to avoid that the
- // TraceLog memory dump provider is registered lazily in the PostTask() below
- // while the |lock_| is taken;
- TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
-
- // Spin-up the thread used to invoke unbound dump providers.
- std::unique_ptr<Thread> dump_thread(new Thread("MemoryInfra"));
- if (!dump_thread->Start()) {
- LOG(ERROR) << "Failed to start the memory-infra thread for tracing";
- return;
- }
-
- 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);
- 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
- // and type IDs.
- session_state->SetStackFrameDeduplicator(
- WrapUnique(new StackFrameDeduplicator));
-
- session_state->SetTypeNameDeduplicator(
- WrapUnique(new TypeNameDeduplicator));
-
- TRACE_EVENT_API_ADD_METADATA_EVENT(
- TraceLog::GetCategoryGroupEnabled("__metadata"), "stackFrames",
- "stackFrames",
- MakeUnique<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));
- }
-
- {
- AutoLock lock(lock_);
-
- DCHECK(delegate_); // At this point we must have a delegate.
- session_state_ = session_state;
-
- DCHECK(!dump_thread_);
- dump_thread_ = std::move(dump_thread);
-
- 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);
- }
-
- MemoryDumpScheduler* dump_scheduler = MemoryDumpScheduler::GetInstance();
- dump_scheduler->Setup(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);
- }
-
- // 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->EnablePollingIfNeeded();
-
- // Only coordinator process triggers periodic global memory dumps.
- if (delegate_->IsCoordinator())
- dump_scheduler->EnablePeriodicTriggerIfNeeded();
- }
-
-}
-
-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;
- {
- AutoLock lock(lock_);
- dump_thread = std::move(dump_thread_);
- session_state_ = nullptr;
- MemoryDumpScheduler::GetInstance()->DisableAllTriggers();
- }
-
- // Thread stops are blocking and must be performed outside of the |lock_|
- // or will deadlock (e.g., if SetupNextMemoryDump() tries to acquire it).
- 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);
-}
-
-MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState(
- MemoryDumpRequestArgs req_args,
- const MemoryDumpProviderInfo::OrderedSet& dump_providers,
- scoped_refptr<MemoryDumpSessionState> session_state,
- MemoryDumpCallback callback,
- scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner)
- : req_args(req_args),
- session_state(std::move(session_state)),
- callback(callback),
- dump_successful(true),
- callback_task_runner(ThreadTaskRunnerHandle::Get()),
- dump_thread_task_runner(std::move(dump_thread_task_runner)) {
- pending_dump_providers.reserve(dump_providers.size());
- pending_dump_providers.assign(dump_providers.rbegin(), dump_providers.rend());
-}
-
-MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() {
-}
-
-ProcessMemoryDump* MemoryDumpManager::ProcessMemoryDumpAsyncState::
- GetOrCreateMemoryDumpContainerForProcess(ProcessId pid,
- const MemoryDumpArgs& dump_args) {
- auto iter = process_dumps.find(pid);
- if (iter == process_dumps.end()) {
- std::unique_ptr<ProcessMemoryDump> new_pmd(
- new ProcessMemoryDump(session_state, dump_args));
- iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first;
- }
- return iter->second.get();
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
deleted file mode 100644
index e7f5194850..0000000000
--- a/base/trace_event/memory_dump_manager.h
+++ /dev/null
@@ -1,354 +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.
-
-#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
-#define BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <unordered_set>
-#include <vector>
-
-#include "base/atomicops.h"
-#include "base/containers/hash_tables.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/singleton.h"
-#include "base/synchronization/lock.h"
-#include "base/trace_event/memory_allocator_dump.h"
-#include "base/trace_event/memory_dump_provider_info.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"
-
-// Forward declare |MemoryDumpManagerDelegateImplTest| so that we can make it a
-// friend of |MemoryDumpManager| and give it access to |SetInstanceForTesting|.
-namespace memory_instrumentation {
-
-class MemoryDumpManagerDelegateImplTest;
-
-} // namespace memory_instrumentation
-
-namespace base {
-
-class SingleThreadTaskRunner;
-class Thread;
-
-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
-// RequestDumpPoint(). The extension by Un(RegisterDumpProvider).
-class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
- public:
- static const char* const kTraceCategory;
- static const char* const kLogPrefix;
-
- // This value is returned as the tracing id of the child processes by
- // GetTracingProcessId() when tracing is not enabled.
- static const uint64_t kInvalidTracingProcessId;
-
- static MemoryDumpManager* GetInstance();
-
- // Invoked once per process to listen to trace begin / end events.
- // Initialization can happen after (Un)RegisterMemoryDumpProvider() calls
- // and the MemoryDumpManager guarantees to support this.
- // On the other side, the MemoryDumpManager will not be fully operational
- // (i.e. will NACK any RequestGlobalMemoryDump()) until initialized.
- // Arguments:
- // delegate: inversion-of-control interface for embedder-specific behaviors
- // (multiprocess handshaking). See the lifetime and thread-safety
- // requirements in the |MemoryDumpManagerDelegate| docstring.
- void Initialize(std::unique_ptr<MemoryDumpManagerDelegate> delegate);
-
- // (Un)Registers a MemoryDumpProvider instance.
- // Args:
- // - mdp: the MemoryDumpProvider instance to be registered. MemoryDumpManager
- // does NOT take memory ownership of |mdp|, which is expected to either
- // be a singleton or unregister itself.
- // - name: a friendly name (duplicates allowed). Used for debugging and
- // run-time profiling of memory-infra internals. Must be a long-lived
- // C string.
- // - task_runner: either a SingleThreadTaskRunner or SequencedTaskRunner. All
- // the calls to |mdp| will be run on the given |task_runner|. If passed
- // null |mdp| should be able to handle calls on arbitrary threads.
- // - options: extra optional arguments. See memory_dump_provider.h.
- void RegisterDumpProvider(MemoryDumpProvider* mdp,
- const char* name,
- scoped_refptr<SingleThreadTaskRunner> task_runner);
- void RegisterDumpProvider(MemoryDumpProvider* mdp,
- const char* name,
- scoped_refptr<SingleThreadTaskRunner> task_runner,
- MemoryDumpProvider::Options options);
- void RegisterDumpProviderWithSequencedTaskRunner(
- MemoryDumpProvider* mdp,
- const char* name,
- scoped_refptr<SequencedTaskRunner> task_runner,
- MemoryDumpProvider::Options options);
- void UnregisterDumpProvider(MemoryDumpProvider* mdp);
-
- // Unregisters an unbound dump provider and takes care about its deletion
- // asynchronously. Can be used only for for dump providers with no
- // task-runner affinity.
- // 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.
- void UnregisterAndDeleteDumpProviderSoon(
- std::unique_ptr<MemoryDumpProvider> mdp);
-
- // Requests a memory dump. The dump might happen or not depending on the
- // filters and categories specified when enabling tracing.
- // The optional |callback| is executed asynchronously, on an arbitrary thread,
- // to notify about the completion of the global dump (i.e. after all the
- // processes have dumped) and its success (true iff all the dumps were
- // successful).
- void RequestGlobalDump(MemoryDumpType dump_type,
- MemoryDumpLevelOfDetail level_of_detail,
- const MemoryDumpCallback& callback);
-
- // Same as above (still asynchronous), but without callback.
- void RequestGlobalDump(MemoryDumpType dump_type,
- MemoryDumpLevelOfDetail level_of_detail);
-
- // TraceLog::EnabledStateObserver implementation.
- 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);
-
- // Lets tests see if a dump provider is registered.
- bool IsDumpProviderRegisteredForTesting(MemoryDumpProvider*);
-
- // Returns the MemoryDumpSessionState object, which is shared by all the
- // ProcessMemoryDump and MemoryAllocatorDump instances through all the tracing
- // session lifetime.
- const scoped_refptr<MemoryDumpSessionState>& session_state_for_testing()
- const {
- return session_state_;
- }
-
- // Returns a unique id for identifying the processes. The id can be
- // retrieved by child processes only when tracing is enabled. This is
- // intended to express cross-process sharing of memory dumps on the
- // child-process side, without having to know its own child process id.
- uint64_t GetTracingProcessId() const { return tracing_process_id_; }
- void set_tracing_process_id(uint64_t tracing_process_id) {
- tracing_process_id_ = tracing_process_id;
- }
-
- // Returns the name for a the allocated_objects dump. Use this to declare
- // suballocator dumps from other dump providers.
- // It will return nullptr if there is no dump provider for the system
- // allocator registered (which is currently the case for Mac OS).
- const char* system_allocator_pool_name() const {
- return kSystemAllocatorPoolName;
- };
-
- // When set to true, calling |RegisterMemoryDumpProvider| is a no-op.
- void set_dumper_registrations_ignored_for_testing(bool ignored) {
- dumper_registrations_ignored_for_testing_ = ignored;
- }
-
- private:
- friend std::default_delete<MemoryDumpManager>; // For the testing instance.
- friend struct DefaultSingletonTraits<MemoryDumpManager>;
- friend class MemoryDumpManagerDelegate;
- friend class MemoryDumpManagerTest;
- friend class MemoryDumpScheduler;
- friend class memory_instrumentation::MemoryDumpManagerDelegateImplTest;
-
- // Holds the state of a process memory dump that needs to be carried over
- // across task runners in order to fulfil an asynchronous CreateProcessDump()
- // request. At any time exactly one task runner owns a
- // ProcessMemoryDumpAsyncState.
- struct ProcessMemoryDumpAsyncState {
- ProcessMemoryDumpAsyncState(
- MemoryDumpRequestArgs req_args,
- const MemoryDumpProviderInfo::OrderedSet& dump_providers,
- scoped_refptr<MemoryDumpSessionState> session_state,
- MemoryDumpCallback callback,
- scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner);
- ~ProcessMemoryDumpAsyncState();
-
- // Gets or creates the memory dump container for the given target process.
- ProcessMemoryDump* GetOrCreateMemoryDumpContainerForProcess(
- ProcessId pid,
- const MemoryDumpArgs& dump_args);
-
- // A map of ProcessId -> ProcessMemoryDump, one for each target process
- // being dumped from the current process. Typically each process dumps only
- // for itself, unless dump providers specify a different |target_process| in
- // MemoryDumpProvider::Options.
- std::map<ProcessId, std::unique_ptr<ProcessMemoryDump>> process_dumps;
-
- // The arguments passed to the initial CreateProcessDump() request.
- const MemoryDumpRequestArgs req_args;
-
- // An ordered sequence of dump providers that have to be invoked to complete
- // the dump. This is a copy of |dump_providers_| at the beginning of a dump
- // and becomes empty at the end, when all dump providers have been invoked.
- std::vector<scoped_refptr<MemoryDumpProviderInfo>> pending_dump_providers;
-
- // The trace-global session state.
- scoped_refptr<MemoryDumpSessionState> session_state;
-
- // Callback passed to the initial call to CreateProcessDump().
- MemoryDumpCallback callback;
-
- // The |success| field that will be passed as argument to the |callback|.
- bool dump_successful;
-
- // The thread on which FinalizeDumpAndAddToTrace() (and hence |callback|)
- // should be invoked. This is the thread on which the initial
- // CreateProcessDump() request was called.
- const scoped_refptr<SingleThreadTaskRunner> callback_task_runner;
-
- // The thread on which unbound dump providers should be invoked.
- // This is essentially |dump_thread_|.task_runner() but needs to be kept
- // as a separate variable as it needs to be accessed by arbitrary dumpers'
- // threads outside of the lock_ to avoid races when disabling tracing.
- // It is immutable for all the duration of a tracing session.
- const scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState);
- };
-
- static const int kMaxConsecutiveFailuresCount;
- static const char* const kSystemAllocatorPoolName;
-
- MemoryDumpManager();
- ~MemoryDumpManager() override;
-
- static void SetInstanceForTesting(MemoryDumpManager* instance);
- static uint32_t GetDumpsSumKb(const std::string&, const ProcessMemoryDump*);
- static void FinalizeDumpAndAddToTrace(
- std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
-
- // 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
- // thread on which CreateProcessDump() was called.
- void CreateProcessDump(const MemoryDumpRequestArgs& args,
- const MemoryDumpCallback& callback);
-
- // Calls InvokeOnMemoryDump() for the next MDP on the task runner specified by
- // the MDP while registration. On failure to do so, skips and continues to
- // next MDP.
- void SetupNextMemoryDump(
- std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
-
- // Invokes OnMemoryDump() of the next MDP and calls SetupNextMemoryDump() at
- // the end to continue the ProcessMemoryDump. Should be called on the MDP task
- // 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,
- const char* name,
- scoped_refptr<SequencedTaskRunner> task_runner,
- const MemoryDumpProvider::Options& options);
-
- // Helper for the public UnregisterDumpProvider* functions.
- 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_;
-
- std::unique_ptr<MemoryDumpManagerDelegate> delegate_;
-
- // Protects from concurrent accesses to the |dump_providers_*| and |delegate_|
- // to guard against disabling logging while dumping on another thread.
- Lock lock_;
-
- // Optimization to avoid attempting any memory dump (i.e. to not walk an empty
- // dump_providers_enabled_ list) when tracing is not enabled.
- subtle::AtomicWord memory_tracing_enabled_;
-
- // Thread used for MemoryDumpProviders which don't specify a task runner
- // affinity.
- std::unique_ptr<Thread> dump_thread_;
-
- // The unique id of the child process. This is created only for tracing and is
- // expected to be valid only when tracing is enabled.
- uint64_t tracing_process_id_;
-
- // When true, calling |RegisterMemoryDumpProvider| is a no-op.
- bool dumper_registrations_ignored_for_testing_;
-
- // Whether new memory dump providers should be told to enable heap profiling.
- bool heap_profiling_enabled_;
-
- DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
-};
-
-// The delegate is supposed to be long lived (read: a Singleton) and thread
-// safe (i.e. should expect calls from any thread and handle thread hopping).
-class BASE_EXPORT MemoryDumpManagerDelegate {
- public:
- MemoryDumpManagerDelegate() {}
- virtual ~MemoryDumpManagerDelegate() {}
-
- virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
- const MemoryDumpCallback& callback) = 0;
-
- virtual bool IsCoordinator() const = 0;
-
- protected:
- void CreateProcessDump(const MemoryDumpRequestArgs& args,
- const MemoryDumpCallback& callback) {
- MemoryDumpManager::GetInstance()->CreateProcessDump(args, callback);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegate);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
deleted file mode 100644
index e126edd397..0000000000
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ /dev/null
@@ -1,1311 +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/memory_dump_manager.h"
-
-#include <stdint.h>
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/message_loop/message_loop.h"
-#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"
-#include "base/trace_event/trace_config_memory_test_util.h"
-#include "build/build_config.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-using testing::AnyNumber;
-using testing::AtMost;
-using testing::Between;
-using testing::Invoke;
-using testing::Return;
-
-namespace base {
-namespace trace_event {
-
-// GTest matchers for MemoryDumpRequestArgs arguments.
-MATCHER(IsDetailedDump, "") {
- return arg.level_of_detail == MemoryDumpLevelOfDetail::DETAILED;
-}
-
-MATCHER(IsLightDump, "") {
- return arg.level_of_detail == MemoryDumpLevelOfDetail::LIGHT;
-}
-
-MATCHER(IsBackgroundDump, "") {
- return arg.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND;
-}
-
-namespace {
-
-const char* kMDPName = "TestDumpProvider";
-const char* kWhitelistedMDPName = "WhitelistedTestDumpProvider";
-const char* const kTestMDPWhitelist[] = {kWhitelistedMDPName, nullptr};
-
-void RegisterDumpProvider(
- MemoryDumpProvider* mdp,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- const MemoryDumpProvider::Options& options,
- const char* name = kMDPName) {
- MemoryDumpManager* mdm = MemoryDumpManager::GetInstance();
- mdm->set_dumper_registrations_ignored_for_testing(false);
- mdm->RegisterDumpProvider(mdp, name, std::move(task_runner), options);
- 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 RegisterDumpProviderWithSequencedTaskRunner(
- MemoryDumpProvider* mdp,
- scoped_refptr<base::SequencedTaskRunner> task_runner,
- const MemoryDumpProvider::Options& options) {
- MemoryDumpManager* mdm = MemoryDumpManager::GetInstance();
- mdm->set_dumper_registrations_ignored_for_testing(false);
- mdm->RegisterDumpProviderWithSequencedTaskRunner(mdp, kMDPName, task_runner,
- options);
- mdm->set_dumper_registrations_ignored_for_testing(true);
-}
-
-void OnTraceDataCollected(Closure quit_closure,
- trace_event::TraceResultBuffer* buffer,
- const scoped_refptr<RefCountedString>& json,
- bool has_more_events) {
- buffer->AddFragment(json->data());
- if (!has_more_events)
- 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,
- base::OnceClosure task) {
- base::WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
- WaitableEvent::InitialState::NOT_SIGNALED);
- task_runner->PostTask(from_here, std::move(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();
-}
-
-// Testing MemoryDumpManagerDelegate which, by default, short-circuits dump
-// requests locally to the MemoryDumpManager instead of performing IPC dances.
-class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
- public:
- MemoryDumpManagerDelegateForTesting(bool is_coordinator)
- : is_coordinator_(is_coordinator) {
- ON_CALL(*this, RequestGlobalMemoryDump(_, _))
- .WillByDefault(Invoke(
- this, &MemoryDumpManagerDelegateForTesting::CreateProcessDump));
- }
-
- MOCK_METHOD2(RequestGlobalMemoryDump,
- void(const MemoryDumpRequestArgs& args,
- const MemoryDumpCallback& callback));
-
- bool IsCoordinator() const override { return is_coordinator_; }
-
- // Promote the CreateProcessDump to public so it can be used by test fixtures.
- using MemoryDumpManagerDelegate::CreateProcessDump;
-
- private:
- bool is_coordinator_;
-};
-
-class MockMemoryDumpProvider : public MemoryDumpProvider {
- public:
- 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(_, _))
- .WillByDefault(Invoke([](const MemoryDumpArgs&,
- ProcessMemoryDump* pmd) -> bool {
- // |session_state| should not be null under any circumstances when
- // invoking a memory dump. The problem might arise in race conditions
- // like crbug.com/600570 .
- 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)
- Destructor();
- }
-
- bool enable_mock_destructor;
-};
-
-class TestSequencedTaskRunner : public SequencedTaskRunner {
- public:
- TestSequencedTaskRunner()
- : worker_pool_(2 /* max_threads */, "Test Task Runner"),
- enabled_(true),
- num_of_post_tasks_(0) {}
-
- void set_enabled(bool value) { enabled_ = value; }
- unsigned no_of_post_tasks() const { return num_of_post_tasks_; }
-
- bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
- OnceClosure task,
- TimeDelta delay) override {
- NOTREACHED();
- return false;
- }
-
- bool PostDelayedTask(const tracked_objects::Location& from_here,
- OnceClosure task,
- TimeDelta delay) override {
- num_of_post_tasks_++;
- if (enabled_) {
- return worker_pool_.pool()->PostSequencedWorkerTask(token_, from_here,
- std::move(task));
- }
- return false;
- }
-
- bool RunsTasksOnCurrentThread() const override {
- return worker_pool_.pool()->RunsTasksOnCurrentThread();
- }
-
- private:
- ~TestSequencedTaskRunner() override {}
-
- SequencedWorkerPoolOwner worker_pool_;
- const SequencedWorkerPool::SequenceToken token_;
- bool enabled_;
- unsigned num_of_post_tasks_;
-};
-
-} // namespace
-
-class MemoryDumpManagerTest : public testing::Test {
- public:
- MemoryDumpManagerTest() : testing::Test(), kDefaultOptions() {}
-
- void SetUp() override {
- last_callback_success_ = false;
- message_loop_.reset(new MessageLoop());
- mdm_.reset(new MemoryDumpManager());
- MemoryDumpManager::SetInstanceForTesting(mdm_.get());
- ASSERT_EQ(mdm_.get(), MemoryDumpManager::GetInstance());
- }
-
- void TearDown() override {
- MemoryDumpManager::SetInstanceForTesting(nullptr);
- delegate_ = nullptr;
- mdm_.reset();
- message_loop_.reset();
- TraceLog::DeleteForTesting();
- }
-
- // Turns a Closure into a MemoryDumpCallback, keeping track of the callback
- // result and taking care of posting the closure on the correct task runner.
- void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner,
- Closure closure,
- uint64_t dump_guid,
- bool success) {
- last_callback_success_ = success;
- 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);
- delegate_ = new MemoryDumpManagerDelegateForTesting(is_coordinator);
- mdm_->Initialize(base::WrapUnique(delegate_));
- }
-
- void RequestGlobalDumpAndWait(MemoryDumpType dump_type,
- MemoryDumpLevelOfDetail level_of_detail) {
- RunLoop run_loop;
- MemoryDumpCallback callback =
- Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
- ThreadTaskRunnerHandle::Get(), run_loop.QuitClosure());
- mdm_->RequestGlobalDump(dump_type, level_of_detail, callback);
- run_loop.Run();
- }
-
- void EnableTracingWithLegacyCategories(const char* category) {
- TraceLog::GetInstance()->SetEnabled(TraceConfig(category, ""),
- TraceLog::RECORDING_MODE);
- }
-
- void EnableTracingWithTraceConfig(const std::string& trace_config) {
- TraceLog::GetInstance()->SetEnabled(TraceConfig(trace_config),
- TraceLog::RECORDING_MODE);
- }
-
- void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
-
- bool IsPeriodicDumpingEnabled() const {
- return MemoryDumpScheduler::GetInstance()
- ->IsPeriodicTimerRunningForTesting();
- }
-
- int GetMaxConsecutiveFailuresCount() const {
- return MemoryDumpManager::kMaxConsecutiveFailuresCount;
- }
-
- const MemoryDumpProvider::Options kDefaultOptions;
- std::unique_ptr<MemoryDumpManager> mdm_;
- MemoryDumpManagerDelegateForTesting* delegate_;
- bool last_callback_success_;
-
- private:
- std::unique_ptr<MessageLoop> message_loop_;
-
- // We want our singleton torn down after each test.
- ShadowingAtExitManager at_exit_manager_;
-};
-
-// Basic sanity checks. Registers a memory dump provider and checks that it is
-// called, but only when memory-infra is enabled.
-TEST_F(MemoryDumpManagerTest, SingleDumper) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- MockMemoryDumpProvider mdp;
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
-
- // Check that the dumper is not called if the memory category is not enabled.
- EnableTracingWithLegacyCategories("foobar-but-not-memory");
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
- EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- DisableTracing();
-
- // Now repeat enabling the memory category and check that the dumper is
- // invoked this time.
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3);
- EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3).WillRepeatedly(Return(true));
- for (int i = 0; i < 3; ++i)
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- DisableTracing();
-
- mdm_->UnregisterDumpProvider(&mdp);
-
- // Finally check the unregister logic: the delegate will be invoked but not
- // the dump provider, as it has been unregistered.
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3);
- EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
-
- for (int i = 0; i < 3; ++i) {
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- }
- DisableTracing();
-}
-
-// Checks that requesting dumps with high level of detail actually propagates
-// the level of the detail properly to OnMemoryDump() call on dump providers.
-TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- MockMemoryDumpProvider mdp;
-
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- EXPECT_CALL(mdp, OnMemoryDump(IsDetailedDump(), _)).WillOnce(Return(true));
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- DisableTracing();
- mdm_->UnregisterDumpProvider(&mdp);
-
- // Check that requesting dumps with low level of detail actually propagates to
- // OnMemoryDump() call on dump providers.
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- EXPECT_CALL(mdp, OnMemoryDump(IsLightDump(), _)).WillOnce(Return(true));
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::LIGHT);
- DisableTracing();
- mdm_->UnregisterDumpProvider(&mdp);
-}
-
-// Checks that the SharedSessionState object is acqually shared over time.
-TEST_F(MemoryDumpManagerTest, SharedSessionState) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- MockMemoryDumpProvider mdp1;
- MockMemoryDumpProvider mdp2;
- RegisterDumpProvider(&mdp1, nullptr);
- RegisterDumpProvider(&mdp2, nullptr);
-
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- const MemoryDumpSessionState* session_state =
- mdm_->session_state_for_testing().get();
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2);
- EXPECT_CALL(mdp1, OnMemoryDump(_, _))
- .Times(2)
- .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&,
- ProcessMemoryDump* pmd) -> bool {
- EXPECT_EQ(session_state, pmd->session_state().get());
- return true;
- }));
- EXPECT_CALL(mdp2, OnMemoryDump(_, _))
- .Times(2)
- .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&,
- ProcessMemoryDump* pmd) -> bool {
- EXPECT_EQ(session_state, pmd->session_state().get());
- return true;
- }));
-
- for (int i = 0; i < 2; ++i) {
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- }
-
- DisableTracing();
-}
-
-// Checks that the (Un)RegisterDumpProvider logic behaves sanely.
-TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- MockMemoryDumpProvider mdp1;
- MockMemoryDumpProvider mdp2;
-
- // Enable only mdp1.
- RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
- EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- DisableTracing();
-
- // Invert: enable mdp1 and disable mdp2.
- mdm_->UnregisterDumpProvider(&mdp1);
- RegisterDumpProvider(&mdp2, nullptr);
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
- EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- DisableTracing();
-
- // Enable both mdp1 and mdp2.
- RegisterDumpProvider(&mdp1, nullptr);
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
- EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- DisableTracing();
-}
-
-// Checks that the dump provider invocations depend only on the current
-// registration state and not on previous registrations and dumps.
-// Flaky on iOS, see crbug.com/706874
-#if defined(OS_IOS)
-#define MAYBE_RegistrationConsistency DISABLED_RegistrationConsistency
-#else
-#define MAYBE_RegistrationConsistency RegistrationConsistency
-#endif
-TEST_F(MemoryDumpManagerTest, MAYBE_RegistrationConsistency) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- MockMemoryDumpProvider mdp;
-
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
-
- {
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- DisableTracing();
- }
-
- mdm_->UnregisterDumpProvider(&mdp);
-
- {
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- DisableTracing();
- }
-
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
- mdm_->UnregisterDumpProvider(&mdp);
-
- {
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- DisableTracing();
- }
-
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
- mdm_->UnregisterDumpProvider(&mdp);
- RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
-
- {
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- DisableTracing();
- }
-}
-
-// Checks that the MemoryDumpManager respects the thread affinity when a
-// MemoryDumpProvider specifies a task_runner(). The test starts creating 8
-// threads and registering a MemoryDumpProvider on each of them. At each
-// iteration, one thread is removed, to check the live unregistration logic.
-TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- const uint32_t kNumInitialThreads = 8;
-
- std::vector<std::unique_ptr<Thread>> threads;
- std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps;
-
- // Create the threads and setup the expectations. Given that at each iteration
- // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be
- // invoked a number of times equal to its index.
- for (uint32_t i = kNumInitialThreads; i > 0; --i) {
- threads.push_back(WrapUnique(new Thread("test thread")));
- auto* thread = threads.back().get();
- thread->Start();
- scoped_refptr<SingleThreadTaskRunner> task_runner = thread->task_runner();
- mdps.push_back(WrapUnique(new MockMemoryDumpProvider()));
- auto* mdp = mdps.back().get();
- RegisterDumpProvider(mdp, task_runner, kDefaultOptions);
- EXPECT_CALL(*mdp, OnMemoryDump(_, _))
- .Times(i)
- .WillRepeatedly(Invoke(
- [task_runner](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
- EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread());
- return true;
- }));
- }
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-
- while (!threads.empty()) {
- last_callback_success_ = false;
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- EXPECT_TRUE(last_callback_success_);
-
- // Unregister a MDP and destroy one thread at each iteration to check the
- // live unregistration logic. The unregistration needs to happen on the same
- // thread the MDP belongs to.
- {
- RunLoop run_loop;
- Closure unregistration =
- Bind(&MemoryDumpManager::UnregisterDumpProvider,
- Unretained(mdm_.get()), Unretained(mdps.back().get()));
- threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration,
- run_loop.QuitClosure());
- run_loop.Run();
- }
- mdps.pop_back();
- threads.back()->Stop();
- threads.pop_back();
- }
-
- DisableTracing();
-}
-
-// Check that the memory dump calls are always posted on task runner for
-// SequencedTaskRunner case and that the dump provider gets disabled when
-// PostTask fails, but the dump still succeeds.
-TEST_F(MemoryDumpManagerTest, PostTaskForSequencedTaskRunner) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- std::vector<MockMemoryDumpProvider> mdps(3);
- scoped_refptr<TestSequencedTaskRunner> task_runner1(
- make_scoped_refptr(new TestSequencedTaskRunner()));
- scoped_refptr<TestSequencedTaskRunner> task_runner2(
- make_scoped_refptr(new TestSequencedTaskRunner()));
- RegisterDumpProviderWithSequencedTaskRunner(&mdps[0], task_runner1,
- kDefaultOptions);
- RegisterDumpProviderWithSequencedTaskRunner(&mdps[1], task_runner2,
- kDefaultOptions);
- RegisterDumpProviderWithSequencedTaskRunner(&mdps[2], task_runner2,
- kDefaultOptions);
- // |mdps[0]| should be disabled permanently after first dump.
- EXPECT_CALL(mdps[0], OnMemoryDump(_, _)).Times(0);
- EXPECT_CALL(mdps[1], OnMemoryDump(_, _)).Times(2);
- EXPECT_CALL(mdps[2], OnMemoryDump(_, _)).Times(2);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2);
-
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-
- task_runner1->set_enabled(false);
- last_callback_success_ = false;
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- // Tasks should be individually posted even if |mdps[1]| and |mdps[2]| belong
- // to same task runner.
- EXPECT_EQ(1u, task_runner1->no_of_post_tasks());
- EXPECT_EQ(2u, task_runner2->no_of_post_tasks());
- EXPECT_TRUE(last_callback_success_);
-
- task_runner1->set_enabled(true);
- last_callback_success_ = false;
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- EXPECT_EQ(2u, task_runner1->no_of_post_tasks());
- EXPECT_EQ(4u, task_runner2->no_of_post_tasks());
- EXPECT_TRUE(last_callback_success_);
- DisableTracing();
-}
-
-// Checks that providers get disabled after 3 consecutive failures, but not
-// otherwise (e.g., if interleaved).
-TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- MockMemoryDumpProvider mdp1;
- MockMemoryDumpProvider mdp2;
-
- RegisterDumpProvider(&mdp1, nullptr);
- RegisterDumpProvider(&mdp2, nullptr);
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-
- const int kNumDumps = 2 * GetMaxConsecutiveFailuresCount();
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(kNumDumps);
-
- EXPECT_CALL(mdp1, OnMemoryDump(_, _))
- .Times(GetMaxConsecutiveFailuresCount())
- .WillRepeatedly(Return(false));
-
- EXPECT_CALL(mdp2, OnMemoryDump(_, _))
- .WillOnce(Return(false))
- .WillOnce(Return(true))
- .WillOnce(Return(false))
- .WillOnce(Return(false))
- .WillOnce(Return(true))
- .WillOnce(Return(false));
-
- for (int i = 0; i < kNumDumps; i++) {
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- }
-
- DisableTracing();
-}
-
-// Sneakily registers an extra memory dump provider while an existing one is
-// dumping and expect it to take part in the already active tracing session.
-TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- MockMemoryDumpProvider mdp1;
- MockMemoryDumpProvider mdp2;
-
- RegisterDumpProvider(&mdp1, nullptr);
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
-
- EXPECT_CALL(mdp1, OnMemoryDump(_, _))
- .Times(4)
- .WillOnce(Return(true))
- .WillOnce(
- Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
- RegisterDumpProvider(&mdp2, nullptr);
- return true;
- }))
- .WillRepeatedly(Return(true));
-
- // Depending on the insertion order (before or after mdp1), mdp2 might be
- // called also immediately after it gets registered.
- EXPECT_CALL(mdp2, OnMemoryDump(_, _))
- .Times(Between(2, 3))
- .WillRepeatedly(Return(true));
-
- for (int i = 0; i < 4; i++) {
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- }
-
- DisableTracing();
-}
-
-// Like RegisterDumperWhileDumping, but unregister the dump provider instead.
-TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- MockMemoryDumpProvider mdp1;
- MockMemoryDumpProvider mdp2;
-
- RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
- RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
-
- EXPECT_CALL(mdp1, OnMemoryDump(_, _))
- .Times(4)
- .WillOnce(Return(true))
- .WillOnce(
- Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
- MemoryDumpManager::GetInstance()->UnregisterDumpProvider(&mdp2);
- return true;
- }))
- .WillRepeatedly(Return(true));
-
- // Depending on the insertion order (before or after mdp1), mdp2 might have
- // been already called when UnregisterDumpProvider happens.
- EXPECT_CALL(mdp2, OnMemoryDump(_, _))
- .Times(Between(1, 2))
- .WillRepeatedly(Return(true));
-
- for (int i = 0; i < 4; i++) {
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- }
-
- DisableTracing();
-}
-
-// Checks that the dump does not abort when unregistering a provider while
-// dumping from a different thread than the dumping thread.
-TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- std::vector<std::unique_ptr<TestIOThread>> threads;
- std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps;
-
- for (int i = 0; i < 2; i++) {
- threads.push_back(
- WrapUnique(new TestIOThread(TestIOThread::kAutoStart)));
- mdps.push_back(WrapUnique(new MockMemoryDumpProvider()));
- RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(),
- kDefaultOptions);
- }
-
- int on_memory_dump_call_count = 0;
-
- // When OnMemoryDump is called on either of the dump providers, it will
- // 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();
- MockMemoryDumpProvider* other_mdp = mdps[other_idx].get();
- auto on_dump = [this, other_runner, 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));
- on_memory_dump_call_count++;
- return true;
- };
-
- // OnMemoryDump is called once for the provider that dumps first, and zero
- // times for the other provider.
- EXPECT_CALL(*mdp, OnMemoryDump(_, _))
- .Times(AtMost(1))
- .WillOnce(Invoke(on_dump));
- }
-
- last_callback_success_ = false;
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- ASSERT_EQ(1, on_memory_dump_call_count);
- ASSERT_TRUE(last_callback_success_);
-
- 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) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- std::vector<std::unique_ptr<TestIOThread>> threads;
- std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps;
-
- for (int i = 0; i < 2; i++) {
- threads.push_back(
- WrapUnique(new TestIOThread(TestIOThread::kAutoStart)));
- mdps.push_back(WrapUnique(new MockMemoryDumpProvider()));
- RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(),
- kDefaultOptions);
- }
-
- int on_memory_dump_call_count = 0;
-
- // When OnMemoryDump is called on either of the dump providers, it will
- // tear down the thread of the other one.
- 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](
- const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
- PostTaskAndWait(
- FROM_HERE, main_runner.get(),
- base::Bind(&TestIOThread::Stop, base::Unretained(other_thread)));
- on_memory_dump_call_count++;
- return true;
- };
-
- // OnMemoryDump is called once for the provider that dumps first, and zero
- // times for the other provider.
- EXPECT_CALL(*mdp, OnMemoryDump(_, _))
- .Times(AtMost(1))
- .WillOnce(Invoke(on_dump));
- }
-
- last_callback_success_ = false;
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- ASSERT_EQ(1, on_memory_dump_call_count);
- ASSERT_TRUE(last_callback_success_);
-
- DisableTracing();
-}
-
-// Checks that a NACK callback is invoked if RequestGlobalDump() is called when
-// tracing is not enabled.
-TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- MockMemoryDumpProvider mdp1;
- RegisterDumpProvider(&mdp1, nullptr);
-
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
- EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
-
- last_callback_success_ = true;
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- EXPECT_FALSE(last_callback_success_);
-}
-
-// Checks that is the MemoryDumpManager is initialized after tracing already
-// began, it will still late-join the party (real use case: startup tracing).
-TEST_F(MemoryDumpManagerTest, InitializedAfterStartOfTracing) {
- MockMemoryDumpProvider mdp;
- RegisterDumpProvider(&mdp, nullptr);
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-
- // First check that a RequestGlobalDump() issued before the MemoryDumpManager
- // initialization gets NACK-ed cleanly.
- {
- EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- EXPECT_FALSE(last_callback_success_);
- }
-
- // Now late-initialize the MemoryDumpManager and check that the
- // RequestGlobalDump completes successfully.
- {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- EXPECT_TRUE(last_callback_success_);
- }
- DisableTracing();
-}
-
-// This test (and the MemoryDumpManagerTestCoordinator below) crystallizes the
-// expectations of the chrome://tracing UI and chrome telemetry w.r.t. periodic
-// dumps in memory-infra, handling gracefully the transition between the legacy
-// and the new-style (JSON-based) TraceConfig.
-TEST_F(MemoryDumpManagerTest, TraceConfigExpectations) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- MemoryDumpManagerDelegateForTesting& delegate = *delegate_;
-
- // Don't trigger the default behavior of the mock delegate in this test,
- // which would short-circuit the dump request to the actual
- // CreateProcessDump().
- // We don't want to create any dump in this test, only check whether the dumps
- // are requested or not.
- ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return());
-
- // Enabling memory-infra in a non-coordinator process should not trigger any
- // periodic dumps.
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_FALSE(IsPeriodicDumpingEnabled());
- DisableTracing();
-
- // Enabling memory-infra with the new (JSON) TraceConfig in a non-coordinator
- // process with a fully defined trigger config should NOT enable any periodic
- // dumps.
- EnableTracingWithTraceConfig(
- TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(1, 5));
- EXPECT_FALSE(IsPeriodicDumpingEnabled());
- DisableTracing();
-}
-
-TEST_F(MemoryDumpManagerTest, TraceConfigExpectationsWhenIsCoordinator) {
- InitializeMemoryDumpManager(true /* is_coordinator */);
- MemoryDumpManagerDelegateForTesting& delegate = *delegate_;
- ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return());
-
- // Enabling memory-infra with the legacy TraceConfig (category filter) in
- // a coordinator process should enable periodic dumps.
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_TRUE(IsPeriodicDumpingEnabled());
- DisableTracing();
-
- // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
- // process without specifying any "memory_dump_config" section should enable
- // periodic dumps. This is to preserve the behavior chrome://tracing UI, that
- // is: ticking memory-infra should dump periodically with the default config.
- EnableTracingWithTraceConfig(
- TraceConfigMemoryTestUtil::GetTraceConfig_NoTriggers());
- EXPECT_TRUE(IsPeriodicDumpingEnabled());
- DisableTracing();
-
- // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
- // process with an empty "memory_dump_config" should NOT enable periodic
- // dumps. This is the way telemetry is supposed to use memory-infra with
- // only explicitly triggered dumps.
- EnableTracingWithTraceConfig(
- TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
- EXPECT_FALSE(IsPeriodicDumpingEnabled());
- DisableTracing();
-
- // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
- // process with a fully defined trigger config should cause periodic dumps to
- // be performed in the correct order.
- RunLoop run_loop;
- auto quit_closure = run_loop.QuitClosure();
-
- const int kHeavyDumpRate = 5;
- const int kLightDumpPeriodMs = 1;
- const int kHeavyDumpPeriodMs = kHeavyDumpRate * kLightDumpPeriodMs;
- // The expected sequence with light=1ms, heavy=5ms is H,L,L,L,L,H,...
- testing::InSequence sequence;
- EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _));
- EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
- .Times(kHeavyDumpRate - 1);
- EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _));
- EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
- .Times(kHeavyDumpRate - 2);
- EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
- .WillOnce(Invoke([quit_closure](const MemoryDumpRequestArgs& args,
- const MemoryDumpCallback& callback) {
- ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure);
- }));
-
- // Swallow all the final spurious calls until tracing gets disabled.
- EXPECT_CALL(delegate, RequestGlobalMemoryDump(_, _)).Times(AnyNumber());
-
- EnableTracingWithTraceConfig(
- TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(
- kLightDumpPeriodMs, kHeavyDumpPeriodMs));
- run_loop.Run();
- DisableTracing();
-}
-
-// Tests against race conditions that might arise when disabling tracing in the
-// middle of a global memory dump.
-// Flaky on iOS, see crbug.com/706961
-#if defined(OS_IOS)
-#define MAYBE_DisableTracingWhileDumping DISABLED_DisableTracingWhileDumping
-#else
-#define MAYBE_DisableTracingWhileDumping DisableTracingWhileDumping
-#endif
-TEST_F(MemoryDumpManagerTest, MAYBE_DisableTracingWhileDumping) {
- base::WaitableEvent tracing_disabled_event(
- WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- InitializeMemoryDumpManager(false /* is_coordinator */);
-
- // Register a bound dump provider.
- std::unique_ptr<Thread> mdp_thread(new Thread("test thread"));
- mdp_thread->Start();
- MockMemoryDumpProvider mdp_with_affinity;
- RegisterDumpProvider(&mdp_with_affinity, mdp_thread->task_runner(),
- kDefaultOptions);
-
- // Register also an unbound dump provider. Unbound dump providers are always
- // invoked after bound ones.
- MockMemoryDumpProvider unbound_mdp;
- RegisterDumpProvider(&unbound_mdp, nullptr, kDefaultOptions);
-
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- EXPECT_CALL(mdp_with_affinity, OnMemoryDump(_, _))
- .Times(1)
- .WillOnce(
- Invoke([&tracing_disabled_event](const MemoryDumpArgs&,
- ProcessMemoryDump* pmd) -> bool {
- tracing_disabled_event.Wait();
-
- // At this point tracing has been disabled and the
- // MemoryDumpManager.dump_thread_ has been shut down.
- return true;
- }));
-
- // |unbound_mdp| should never be invoked because the thread for unbound dump
- // providers has been shutdown in the meanwhile.
- EXPECT_CALL(unbound_mdp, OnMemoryDump(_, _)).Times(0);
-
- last_callback_success_ = true;
- RunLoop run_loop;
- MemoryDumpCallback callback =
- Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
- ThreadTaskRunnerHandle::Get(), run_loop.QuitClosure());
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED, callback);
- DisableTracing();
- tracing_disabled_event.Signal();
- run_loop.Run();
-
- EXPECT_FALSE(last_callback_success_);
-}
-
-// Tests against race conditions that can happen if tracing is disabled before
-// the CreateProcessDump() call. Real-world regression: crbug.com/580295 .
-TEST_F(MemoryDumpManagerTest, DisableTracingRightBeforeStartOfDump) {
- base::WaitableEvent tracing_disabled_event(
- WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- InitializeMemoryDumpManager(false /* is_coordinator */);
-
- std::unique_ptr<Thread> mdp_thread(new Thread("test thread"));
- mdp_thread->Start();
-
- // Create both same-thread MDP and another MDP with dedicated thread
- MockMemoryDumpProvider mdp1;
- RegisterDumpProvider(&mdp1, nullptr);
- MockMemoryDumpProvider mdp2;
- RegisterDumpProvider(&mdp2, mdp_thread->task_runner(), kDefaultOptions);
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _))
- .WillOnce(Invoke([this](const MemoryDumpRequestArgs& args,
- const MemoryDumpCallback& callback) {
- DisableTracing();
- delegate_->CreateProcessDump(args, callback);
- }));
-
- // If tracing is disabled for current session CreateProcessDump() should NOT
- // request dumps from providers. Real-world regression: crbug.com/600570 .
- EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
- EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
-
- last_callback_success_ = true;
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- EXPECT_FALSE(last_callback_success_);
-}
-
-TEST_F(MemoryDumpManagerTest, DumpOnBehalfOfOtherProcess) {
- using trace_analyzer::Query;
-
- InitializeMemoryDumpManager(false /* is_coordinator */);
-
- // Standard provider with default options (create dump for current process).
- MemoryDumpProvider::Options options;
- MockMemoryDumpProvider mdp1;
- RegisterDumpProvider(&mdp1, nullptr, options);
-
- // Provider with out-of-process dumping.
- MockMemoryDumpProvider mdp2;
- options.target_pid = 123;
- RegisterDumpProvider(&mdp2, nullptr, options);
-
- // Another provider with out-of-process dumping.
- MockMemoryDumpProvider mdp3;
- options.target_pid = 456;
- RegisterDumpProvider(&mdp3, nullptr, options);
-
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
- EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
- EXPECT_CALL(mdp3, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- DisableTracing();
-
- // Flush the trace into JSON.
- trace_event::TraceResultBuffer buffer;
- TraceResultBuffer::SimpleOutput trace_output;
- buffer.SetOutputCallback(trace_output.GetCallback());
- RunLoop run_loop;
- buffer.Start();
- trace_event::TraceLog::GetInstance()->Flush(
- Bind(&OnTraceDataCollected, run_loop.QuitClosure(), Unretained(&buffer)));
- run_loop.Run();
- buffer.Finish();
-
- // Analyze the JSON.
- std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer = WrapUnique(
- trace_analyzer::TraceAnalyzer::Create(trace_output.json_output));
- trace_analyzer::TraceEventVector events;
- analyzer->FindEvents(Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP),
- &events);
-
- ASSERT_EQ(3u, events.size());
- ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(123)));
- ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(456)));
- ASSERT_EQ(1u, trace_analyzer::CountMatches(
- events, Query::EventPidIs(GetCurrentProcId())));
- ASSERT_EQ(events[0]->id, events[1]->id);
- ASSERT_EQ(events[0]->id, events[2]->id);
-}
-
-// Tests the basics of the UnregisterAndDeleteDumpProviderSoon(): the
-// unregistration should actually delete the providers and not leak them.
-TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoon) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- static const int kNumProviders = 3;
- int dtor_count = 0;
- std::vector<std::unique_ptr<MemoryDumpProvider>> mdps;
- for (int i = 0; i < kNumProviders; ++i) {
- std::unique_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider);
- mdp->enable_mock_destructor = true;
- EXPECT_CALL(*mdp, Destructor())
- .WillOnce(Invoke([&dtor_count]() { dtor_count++; }));
- RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions);
- mdps.push_back(std::move(mdp));
- }
-
- while (!mdps.empty()) {
- mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdps.back()));
- mdps.pop_back();
- }
-
- ASSERT_EQ(kNumProviders, dtor_count);
-}
-
-// This test checks against races when unregistering an unbound dump provider
-// from another thread while dumping. It registers one MDP and, when
-// OnMemoryDump() is called, it invokes UnregisterAndDeleteDumpProviderSoon()
-// from another thread. The OnMemoryDump() and the dtor call are expected to
-// happen on the same thread (the MemoryDumpManager utility thread).
-TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoonDuringDump) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- std::unique_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider);
- mdp->enable_mock_destructor = true;
- RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions);
-
- base::PlatformThreadRef thread_ref;
- auto self_unregister_from_another_thread = [&mdp, &thread_ref](
- const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
- thread_ref = PlatformThread::CurrentRef();
- TestIOThread thread_for_unregistration(TestIOThread::kAutoStart);
- PostTaskAndWait(
- FROM_HERE, thread_for_unregistration.task_runner().get(),
- base::Bind(
- &MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon,
- base::Unretained(MemoryDumpManager::GetInstance()),
- base::Passed(std::unique_ptr<MemoryDumpProvider>(std::move(mdp)))));
- thread_for_unregistration.Stop();
- return true;
- };
- EXPECT_CALL(*mdp, OnMemoryDump(_, _))
- .Times(1)
- .WillOnce(Invoke(self_unregister_from_another_thread));
- EXPECT_CALL(*mdp, Destructor())
- .Times(1)
- .WillOnce(Invoke([&thread_ref]() {
- EXPECT_EQ(thread_ref, PlatformThread::CurrentRef());
- }));
-
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2);
- for (int i = 0; i < 2; ++i) {
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- }
- DisableTracing();
-}
-
-TEST_F(MemoryDumpManagerTest, TestWhitelistingMDP) {
- InitializeMemoryDumpManager(false /* is_coordinator */);
- SetDumpProviderWhitelistForTesting(kTestMDPWhitelist);
- std::unique_ptr<MockMemoryDumpProvider> mdp1(new MockMemoryDumpProvider);
- RegisterDumpProvider(mdp1.get(), nullptr);
- std::unique_ptr<MockMemoryDumpProvider> mdp2(new MockMemoryDumpProvider);
- RegisterDumpProvider(mdp2.get(), nullptr, kDefaultOptions,
- kWhitelistedMDPName);
-
- EXPECT_CALL(*mdp1, OnMemoryDump(_, _)).Times(0);
- EXPECT_CALL(*mdp2, OnMemoryDump(_, _)).Times(1).WillOnce(Return(true));
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
-
- EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_FALSE(IsPeriodicDumpingEnabled());
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::BACKGROUND);
- DisableTracing();
-}
-
-TEST_F(MemoryDumpManagerTest, TestBackgroundTracingSetup) {
- InitializeMemoryDumpManager(true /* is_coordinator */);
-
- RunLoop run_loop;
- auto quit_closure = run_loop.QuitClosure();
-
- testing::InSequence sequence;
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(IsBackgroundDump(), _))
- .Times(5);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(IsBackgroundDump(), _))
- .WillOnce(Invoke([quit_closure](const MemoryDumpRequestArgs& args,
- const MemoryDumpCallback& callback) {
- ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure);
- }));
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(AnyNumber());
-
- EnableTracingWithTraceConfig(
- TraceConfigMemoryTestUtil::GetTraceConfig_BackgroundTrigger(
- 1 /* period_ms */));
-
- // Only background mode dumps should be allowed with the trace config.
- last_callback_success_ = false;
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::LIGHT);
- EXPECT_FALSE(last_callback_success_);
- last_callback_success_ = false;
- RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- EXPECT_FALSE(last_callback_success_);
-
- ASSERT_TRUE(IsPeriodicDumpingEnabled());
- run_loop.Run();
- 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
deleted file mode 100644
index 244319efa7..0000000000
--- a/base/trace_event/memory_dump_provider.h
+++ /dev/null
@@ -1,82 +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.
-
-#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
-#define BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
-
-#include "base/base_export.h"
-#include "base/macros.h"
-#include "base/process/process_handle.h"
-#include "base/trace_event/memory_dump_request_args.h"
-
-namespace base {
-namespace trace_event {
-
-class ProcessMemoryDump;
-
-// The contract interface that memory dump providers must implement.
-class BASE_EXPORT MemoryDumpProvider {
- public:
- // Optional arguments for MemoryDumpManager::RegisterDumpProvider().
- struct Options {
- Options()
- : target_pid(kNullProcessId),
- dumps_on_single_thread_task_runner(false),
- is_fast_polling_supported(false) {}
-
- // If the dump provider generates dumps on behalf of another process,
- // |target_pid| contains the pid of that process.
- // The default value is kNullProcessId, which means that the dump provider
- // generates dumps for the current process.
- ProcessId target_pid;
-
- // |dumps_on_single_thread_task_runner| is true if the dump provider runs on
- // 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() {}
-
- // Called by the MemoryDumpManager when generating memory dumps.
- // The |args| specify if the embedder should generate light/heavy dumps on
- // dump requests. The embedder should return true if the |pmd| was
- // successfully populated, false if something went wrong and the dump should
- // be considered invalid.
- // (Note, the MemoryDumpManager has a fail-safe logic which will disable the
- // MemoryDumpProvider for the entire trace session if it fails consistently).
- virtual bool OnMemoryDump(const MemoryDumpArgs& args,
- ProcessMemoryDump* pmd) = 0;
-
- // Called by the MemoryDumpManager when an allocator should start or stop
- // collecting extensive allocation data, if supported.
- virtual void OnHeapProfilingEnabled(bool enabled) {}
-
- // 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() {}
-
- DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
diff --git a/base/trace_event/memory_dump_provider_info.cc b/base/trace_event/memory_dump_provider_info.cc
deleted file mode 100644
index 6bb711018b..0000000000
--- a/base/trace_event/memory_dump_provider_info.cc
+++ /dev/null
@@ -1,43 +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_provider_info.h"
-
-#include <tuple>
-
-#include "base/sequenced_task_runner.h"
-
-namespace base {
-namespace trace_event {
-
-MemoryDumpProviderInfo::MemoryDumpProviderInfo(
- MemoryDumpProvider* dump_provider,
- const char* name,
- scoped_refptr<SequencedTaskRunner> task_runner,
- const MemoryDumpProvider::Options& options,
- bool whitelisted_for_background_mode)
- : dump_provider(dump_provider),
- options(options),
- name(name),
- task_runner(std::move(task_runner)),
- whitelisted_for_background_mode(whitelisted_for_background_mode),
- consecutive_failures(0),
- disabled(false) {}
-
-MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {}
-
-bool MemoryDumpProviderInfo::Comparator::operator()(
- const scoped_refptr<MemoryDumpProviderInfo>& a,
- const scoped_refptr<MemoryDumpProviderInfo>& b) const {
- if (!a || !b)
- return a.get() < b.get();
- // Ensure that unbound providers (task_runner == nullptr) always run last.
- // Rationale: some unbound dump providers are known to be slow, keep them last
- // to avoid skewing timings of the other dump providers.
- return std::tie(a->task_runner, a->dump_provider) >
- std::tie(b->task_runner, b->dump_provider);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_dump_provider_info.h b/base/trace_event/memory_dump_provider_info.h
deleted file mode 100644
index ca63a987b2..0000000000
--- a/base/trace_event/memory_dump_provider_info.h
+++ /dev/null
@@ -1,108 +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_PROVIDER_INFO_H_
-#define BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_INFO_H_
-
-#include <memory>
-#include <set>
-
-#include "base/base_export.h"
-#include "base/memory/ref_counted.h"
-#include "base/trace_event/memory_dump_provider.h"
-
-namespace base {
-
-class SequencedTaskRunner;
-
-namespace trace_event {
-
-// Wraps a MemoryDumpProvider (MDP), which is registered via
-// MemoryDumpManager(MDM)::RegisterDumpProvider(), holding the extra information
-// required to deal with it (which task runner it should be invoked onto,
-// whether it has been disabled, etc.)
-// More importantly, having a refptr to this object guarantees that a MDP that
-// is not thread-bound (hence which can only be unregistered via
-// MDM::UnregisterAndDeleteDumpProviderSoon()) will stay alive as long as the
-// refptr is held.
-//
-// Lifetime:
-// At any time, there is at most one instance of this class for each instance
-// of a given MemoryDumpProvider, but there might be several scoped_refptr
-// holding onto each of this. Specifically:
-// - In nominal conditions, there is a refptr for each registerd MDP in the
-// MDM's |dump_providers_| list.
-// - In most cases, the only refptr (in the |dump_providers_| list) is destroyed
-// by MDM::UnregisterDumpProvider().
-// - However, when MDM starts a dump, the list of refptrs is copied into the
-// ProcessMemoryDumpAsyncState. That list is pruned as MDP(s) are invoked.
-// - If UnregisterDumpProvider() is called on a non-thread-bound MDP while a
-// dump is in progress, the extar extra of the handle is destroyed in
-// MDM::SetupNextMemoryDump() or MDM::InvokeOnMemoryDump(), when the copy
-// inside ProcessMemoryDumpAsyncState is erase()-d.
-// - The PeakDetector can keep extra refptrs when enabled.
-struct BASE_EXPORT MemoryDumpProviderInfo
- : public RefCountedThreadSafe<MemoryDumpProviderInfo> {
- public:
- // Define a total order based on the |task_runner| affinity, so that MDPs
- // belonging to the same SequencedTaskRunner are adjacent in the set.
- struct Comparator {
- bool operator()(const scoped_refptr<MemoryDumpProviderInfo>& a,
- const scoped_refptr<MemoryDumpProviderInfo>& b) const;
- };
- using OrderedSet =
- std::set<scoped_refptr<MemoryDumpProviderInfo>, Comparator>;
-
- MemoryDumpProviderInfo(MemoryDumpProvider* dump_provider,
- const char* name,
- scoped_refptr<SequencedTaskRunner> task_runner,
- const MemoryDumpProvider::Options& options,
- bool whitelisted_for_background_mode);
-
- // It is safe to access the const fields below from any thread as they are
- // never mutated.
-
- MemoryDumpProvider* const dump_provider;
-
- // The |options| arg passed to MDM::RegisterDumpProvider().
- const MemoryDumpProvider::Options options;
-
- // Human readable name, not unique (distinct MDP instances might have the same
- // name). Used for debugging, testing and whitelisting for BACKGROUND mode.
- const char* const name;
-
- // The task runner on which the MDP::OnMemoryDump call should be posted onto.
- // Can be nullptr, in which case the MDP will be invoked on a background
- // thread handled by MDM.
- const scoped_refptr<SequencedTaskRunner> task_runner;
-
- // True if the dump provider is whitelisted for background mode.
- const bool whitelisted_for_background_mode;
-
- // These fields below, instead, are not thread safe and can be mutated only:
- // - On the |task_runner|, when not null (i.e. for thread-bound MDPS).
- // - By the MDM's background thread (or in any other way that guarantees
- // sequencing) for non-thread-bound MDPs.
-
- // Used to transfer ownership for UnregisterAndDeleteDumpProviderSoon().
- // nullptr in all other cases.
- std::unique_ptr<MemoryDumpProvider> owned_dump_provider;
-
- // For fail-safe logic (auto-disable failing MDPs).
- int consecutive_failures;
-
- // Flagged either by the auto-disable logic or during unregistration.
- bool disabled;
-
- private:
- friend class base::RefCountedThreadSafe<MemoryDumpProviderInfo>;
- ~MemoryDumpProviderInfo();
-
- DISALLOW_COPY_AND_ASSIGN(MemoryDumpProviderInfo);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_INFO_H_
diff --git a/base/trace_event/memory_dump_request_args.cc b/base/trace_event/memory_dump_request_args.cc
deleted file mode 100644
index f2744007d7..0000000000
--- a/base/trace_event/memory_dump_request_args.cc
+++ /dev/null
@@ -1,68 +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/memory_dump_request_args.h"
-
-#include "base/logging.h"
-
-namespace base {
-namespace trace_event {
-
-// static
-const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type) {
- switch (dump_type) {
- 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) {
- case MemoryDumpLevelOfDetail::BACKGROUND:
- return "background";
- case MemoryDumpLevelOfDetail::LIGHT:
- return "light";
- case MemoryDumpLevelOfDetail::DETAILED:
- return "detailed";
- }
- NOTREACHED();
- return "unknown";
-}
-
-MemoryDumpLevelOfDetail StringToMemoryDumpLevelOfDetail(
- const std::string& str) {
- if (str == "background")
- return MemoryDumpLevelOfDetail::BACKGROUND;
- if (str == "light")
- return MemoryDumpLevelOfDetail::LIGHT;
- if (str == "detailed")
- return MemoryDumpLevelOfDetail::DETAILED;
- NOTREACHED();
- return MemoryDumpLevelOfDetail::LAST;
-}
-
-MemoryDumpCallbackResult::MemoryDumpCallbackResult() {}
-
-MemoryDumpCallbackResult::~MemoryDumpCallbackResult() {}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_dump_request_args.h b/base/trace_event/memory_dump_request_args.h
deleted file mode 100644
index a8b3f423ca..0000000000
--- a/base/trace_event/memory_dump_request_args.h
+++ /dev/null
@@ -1,119 +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.
-
-#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_ARGS_H_
-#define BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_ARGS_H_
-
-// This file defines the types and structs used to issue memory dump requests.
-// These are also used in the IPCs for coordinating inter-process memory dumps.
-
-#include <stdint.h>
-#include <map>
-#include <string>
-
-#include "base/base_export.h"
-#include "base/callback.h"
-#include "base/process/process_handle.h"
-
-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.
-enum class MemoryDumpType {
- 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.
-};
-
-// 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,
-
- // For background tracing mode. The dump time is quick, and typically just the
- // totals are expected. Suballocations need not be specified. Dump name must
- // contain only pre-defined strings and string arguments cannot be added.
- BACKGROUND = FIRST,
-
- // For the levels below, MemoryDumpProvider instances must guarantee that the
- // total size reported in the root node is consistent. Only the granularity of
- // the child MemoryAllocatorDump(s) differs with the levels.
-
- // Few entries, typically a fixed number, per dump.
- LIGHT,
-
- // Unrestricted amount of entries per dump.
- DETAILED,
-
- LAST = DETAILED
-};
-
-// 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.
-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
- // reconstruct the global dump.
- uint64_t dump_guid;
-
- MemoryDumpType dump_type;
- MemoryDumpLevelOfDetail level_of_detail;
-};
-
-// Args for ProcessMemoryDump and passed to OnMemoryDump calls for memory dump
-// providers. Dump providers are expected to read the args for creating dumps.
-struct MemoryDumpArgs {
- // Specifies how detailed the dumps should be.
- MemoryDumpLevelOfDetail level_of_detail;
-};
-
-// TODO(hjd): Not used yet, see crbug.com/703184
-// Summarises information about memory use as seen by a single process.
-// This information will eventually be passed to a service to be colated
-// and reported.
-struct MemoryDumpCallbackResult {
- struct OSMemDump {
- uint32_t resident_set_kb = 0;
- };
- struct ChromeMemDump {
- uint32_t malloc_total_kb = 0;
- uint32_t partition_alloc_total_kb = 0;
- uint32_t blink_gc_total_kb = 0;
- uint32_t v8_total_kb = 0;
- };
-
- // These are for the current process.
- OSMemDump os_dump;
- ChromeMemDump chrome_dump;
-
- // In some cases, OS stats can only be dumped from a privileged process to
- // get around to sandboxing/selinux restrictions (see crbug.com/461788).
- std::map<ProcessId, OSMemDump> extra_processes_dump;
-
- MemoryDumpCallbackResult();
- ~MemoryDumpCallbackResult();
-};
-
-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);
-
-BASE_EXPORT MemoryDumpLevelOfDetail
-StringToMemoryDumpLevelOfDetail(const std::string& str);
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_ARGS_H_
diff --git a/base/trace_event/memory_dump_scheduler.cc b/base/trace_event/memory_dump_scheduler.cc
deleted file mode 100644
index 150feb8e79..0000000000
--- a/base/trace_event/memory_dump_scheduler.cc
+++ /dev/null
@@ -1,328 +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
-
-// static
-MemoryDumpScheduler* MemoryDumpScheduler::GetInstance() {
- static MemoryDumpScheduler* instance = new MemoryDumpScheduler();
- return instance;
-}
-
-MemoryDumpScheduler::MemoryDumpScheduler() : mdm_(nullptr), is_setup_(false) {}
-MemoryDumpScheduler::~MemoryDumpScheduler() {}
-
-void MemoryDumpScheduler::Setup(
- MemoryDumpManager* mdm,
- scoped_refptr<SingleThreadTaskRunner> polling_task_runner) {
- mdm_ = mdm;
- polling_task_runner_ = polling_task_runner;
- periodic_state_.reset(new PeriodicTriggerState);
- polling_state_.reset(new PollingTriggerState);
- is_setup_ = true;
-}
-
-void MemoryDumpScheduler::AddTrigger(MemoryDumpType trigger_type,
- MemoryDumpLevelOfDetail level_of_detail,
- uint32_t min_time_between_dumps_ms) {
- DCHECK(is_setup_);
- 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::EnablePeriodicTriggerIfNeeded() {
- DCHECK(is_setup_);
- 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::EnablePollingIfNeeded() {
- DCHECK(is_setup_);
- if (polling_state_->current_state != PollingTriggerState::CONFIGURED)
- return;
-
- polling_state_->current_state = PollingTriggerState::ENABLED;
- polling_state_->ResetTotals();
-
- polling_task_runner_->PostTask(
- FROM_HERE,
- Bind(&MemoryDumpScheduler::PollMemoryOnPollingThread, Unretained(this)));
-}
-
-void MemoryDumpScheduler::NotifyDumpTriggered() {
- if (polling_task_runner_ &&
- !polling_task_runner_->RunsTasksOnCurrentThread()) {
- polling_task_runner_->PostTask(
- FROM_HERE,
- Bind(&MemoryDumpScheduler::NotifyDumpTriggered, Unretained(this)));
- return;
- }
-
- if (!polling_state_ ||
- polling_state_->current_state != PollingTriggerState::ENABLED) {
- return;
- }
-
- polling_state_->ResetTotals();
-}
-
-void MemoryDumpScheduler::DisableAllTriggers() {
- if (periodic_state_) {
- if (periodic_state_->timer.IsRunning())
- periodic_state_->timer.Stop();
- periodic_state_.reset();
- }
-
- if (polling_task_runner_) {
- DCHECK(polling_state_);
- polling_task_runner_->PostTask(
- FROM_HERE, Bind(&MemoryDumpScheduler::DisablePollingOnPollingThread,
- Unretained(this)));
- polling_task_runner_ = nullptr;
- }
- is_setup_ = false;
-}
-
-void MemoryDumpScheduler::DisablePollingOnPollingThread() {
- polling_state_->current_state = PollingTriggerState::DISABLED;
- polling_state_.reset();
-}
-
-// 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_)
- return;
-
- DCHECK_EQ(PollingTriggerState::ENABLED, polling_state_->current_state);
-
- 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()
- : current_state(DISABLED),
- level_of_detail(MemoryDumpLevelOfDetail::FIRST),
- 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() {}
-
-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 =
- (static_cast<int64_t>(meminfo.total) / 100) * 1024;
- }
- DCHECK_GT(memory_increase_threshold, 0u);
-#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 ab8441bc20..0000000000
--- a/base/trace_event/memory_dump_scheduler.h
+++ /dev/null
@@ -1,163 +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 <memory>
-
-#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. The methods of
-// this class are NOT thread safe and the client has to take care of invoking
-// all the methods of the class safely.
-class BASE_EXPORT MemoryDumpScheduler {
- public:
- static MemoryDumpScheduler* GetInstance();
-
- // Initializes the scheduler. NOT thread safe.
- void Setup(MemoryDumpManager* mdm_,
- scoped_refptr<SingleThreadTaskRunner> polling_task_runner);
-
- // 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. NOT thread safe.
- void AddTrigger(MemoryDumpType trigger_type,
- MemoryDumpLevelOfDetail level_of_detail,
- uint32_t min_time_between_dumps_ms);
-
- // Starts periodic dumps. NOT thread safe and triggers must be added before
- // enabling.
- void EnablePeriodicTriggerIfNeeded();
-
- // Starts polling memory total. NOT thread safe and triggers must be added
- // before enabling.
- void EnablePollingIfNeeded();
-
- // Resets time for triggering dump to account for minimum time between the
- // dumps. NOT thread safe.
- void NotifyDumpTriggered();
-
- // Disables all triggers. NOT thread safe. This should be called before
- // polling thread is stopped to stop polling cleanly.
- void DisableAllTriggers();
-
- private:
- friend class MemoryDumpManagerTest;
- friend class MemoryDumpSchedulerPollingTest;
- FRIEND_TEST_ALL_PREFIXES(MemoryDumpManagerTest, TestPollingOnDumpThread);
- FRIEND_TEST_ALL_PREFIXES(MemoryDumpSchedulerPollingTest, NotifyDumpTriggered);
-
- // Helper class to schdule periodic memory dumps.
- struct BASE_EXPORT 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 BASE_EXPORT PollingTriggerState {
- enum State {
- CONFIGURED, // Polling trigger was added.
- ENABLED, // Polling is running.
- DISABLED // Polling is disabled.
- };
-
- static const uint32_t kMaxNumMemorySamples = 50;
-
- PollingTriggerState();
- ~PollingTriggerState();
-
- // Helper to clear the tracked memory totals and poll count from last dump.
- void ResetTotals();
-
- State current_state;
- MemoryDumpLevelOfDetail level_of_detail;
-
- 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);
- };
-
- MemoryDumpScheduler();
- ~MemoryDumpScheduler();
-
- // Helper to set polling disabled.
- void DisablePollingOnPollingThread();
-
- // 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_;
-
- // Accessed on the thread of the client before enabling and only accessed on
- // the thread that called "EnablePeriodicTriggersIfNeeded()" after enabling.
- std::unique_ptr<PeriodicTriggerState> periodic_state_;
-
- // Accessed on the thread of the client before enabling and only accessed on
- // the polling thread after enabling.
- std::unique_ptr<PollingTriggerState> polling_state_;
-
- // Accessed on the thread of the client only.
- scoped_refptr<SingleThreadTaskRunner> polling_task_runner_;
-
- // True when the scheduler is setup. Accessed on the thread of client only.
- bool is_setup_;
-
- 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_scheduler_unittest.cc b/base/trace_event/memory_dump_scheduler_unittest.cc
deleted file mode 100644
index 9af2a3b430..0000000000
--- a/base/trace_event/memory_dump_scheduler_unittest.cc
+++ /dev/null
@@ -1,101 +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 <memory>
-
-#include "base/single_thread_task_runner.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace trace_event {
-
-class MemoryDumpSchedulerPollingTest : public testing::Test {
- public:
- static const uint32_t kMinPollsToDump = 5;
-
- MemoryDumpSchedulerPollingTest()
- : testing::Test(),
- num_samples_tracked_(
- MemoryDumpScheduler::PollingTriggerState::kMaxNumMemorySamples) {}
-
- void SetUp() override {
- MemoryDumpScheduler::SetPollingIntervalForTesting(1);
- uint32_t kMinPollsToDump = 5;
- mds_ = MemoryDumpScheduler::GetInstance();
- mds_->Setup(nullptr, nullptr);
- mds_->AddTrigger(MemoryDumpType::PEAK_MEMORY_USAGE,
- MemoryDumpLevelOfDetail::LIGHT, kMinPollsToDump);
- mds_->polling_state_->ResetTotals();
- mds_->polling_state_->current_state =
- MemoryDumpScheduler::PollingTriggerState::ENABLED;
- }
-
- void TearDown() override {
- mds_->polling_state_->current_state =
- MemoryDumpScheduler::PollingTriggerState::DISABLED;
- }
-
- protected:
- bool ShouldTriggerDump(uint64_t total) {
- return mds_->ShouldTriggerDump(total);
- }
-
- uint32_t num_samples_tracked_;
- MemoryDumpScheduler* mds_;
-};
-
-TEST_F(MemoryDumpSchedulerPollingTest, PeakDetection) {
- for (uint32_t i = 0; i < num_samples_tracked_ * 6; ++i) {
- // Memory is increased in steps and dumps must be triggered at every step.
- uint64_t total = (2 + (i / (2 * num_samples_tracked_))) * 1024 * 1204;
- bool did_trigger = ShouldTriggerDump(total);
- // Dumps must be triggered only at specific iterations.
- bool should_have_triggered = i == 0;
- should_have_triggered |=
- (i > num_samples_tracked_) && (i % (2 * num_samples_tracked_) == 1);
- if (should_have_triggered) {
- ASSERT_TRUE(did_trigger) << "Dump wasn't triggered at " << i;
- } else {
- ASSERT_FALSE(did_trigger) << "Unexpected dump at " << i;
- }
- }
-}
-
-TEST_F(MemoryDumpSchedulerPollingTest, SlowGrowthDetection) {
- for (uint32_t i = 0; i < 15; ++i) {
- // Record 1GiB of increase in each call. Dumps are triggered with 1% w.r.t
- // system's total memory.
- uint64_t total = static_cast<uint64_t>(i + 1) * 1024 * 1024 * 1024;
- bool did_trigger = ShouldTriggerDump(total);
- bool should_have_triggered = i % kMinPollsToDump == 0;
- if (should_have_triggered) {
- ASSERT_TRUE(did_trigger) << "Dump wasn't triggered at " << i;
- } else {
- ASSERT_FALSE(did_trigger) << "Unexpected dump at " << i;
- }
- }
-}
-
-TEST_F(MemoryDumpSchedulerPollingTest, NotifyDumpTriggered) {
- for (uint32_t i = 0; i < num_samples_tracked_ * 6; ++i) {
- uint64_t total = (2 + (i / (2 * num_samples_tracked_))) * 1024 * 1204;
- if (i % num_samples_tracked_ == 0)
- mds_->NotifyDumpTriggered();
- bool did_trigger = ShouldTriggerDump(total);
- // Dumps should never be triggered since NotifyDumpTriggered() is called
- // frequently.
- EXPECT_NE(0u, mds_->polling_state_->last_dump_memory_total);
- EXPECT_GT(num_samples_tracked_ - 1,
- mds_->polling_state_->last_memory_totals_kb_index);
- EXPECT_LT(static_cast<int64_t>(
- total - mds_->polling_state_->last_dump_memory_total),
- mds_->polling_state_->memory_increase_threshold);
- ASSERT_FALSE(did_trigger && i) << "Unexpected dump at " << i;
- }
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_dump_session_state.cc b/base/trace_event/memory_dump_session_state.cc
deleted file mode 100644
index d26b82a5b7..0000000000
--- a/base/trace_event/memory_dump_session_state.cc
+++ /dev/null
@@ -1,37 +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/memory_dump_session_state.h"
-
-namespace base {
-namespace trace_event {
-
-MemoryDumpSessionState::MemoryDumpSessionState()
- : heap_profiler_breakdown_threshold_bytes_(0) {}
-MemoryDumpSessionState::~MemoryDumpSessionState() {}
-
-void MemoryDumpSessionState::SetStackFrameDeduplicator(
- std::unique_ptr<StackFrameDeduplicator> stack_frame_deduplicator) {
- DCHECK(!stack_frame_deduplicator_);
- stack_frame_deduplicator_ = std::move(stack_frame_deduplicator);
-}
-
-void MemoryDumpSessionState::SetTypeNameDeduplicator(
- std::unique_ptr<TypeNameDeduplicator> type_name_deduplicator) {
- DCHECK(!type_name_deduplicator_);
- 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;
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_dump_session_state.h b/base/trace_event/memory_dump_session_state.h
deleted file mode 100644
index 46092cb483..0000000000
--- a/base/trace_event/memory_dump_session_state.h
+++ /dev/null
@@ -1,77 +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.
-
-#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
-#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"
-
-namespace base {
-namespace trace_event {
-
-// Container for state variables that should be shared across all the memory
-// dumps in a tracing session.
-class BASE_EXPORT MemoryDumpSessionState
- : public RefCountedThreadSafe<MemoryDumpSessionState> {
- public:
- MemoryDumpSessionState();
-
- // Returns the stack frame deduplicator that should be used by memory dump
- // providers when doing a heap dump.
- StackFrameDeduplicator* stack_frame_deduplicator() const {
- return stack_frame_deduplicator_.get();
- }
-
- void SetStackFrameDeduplicator(
- std::unique_ptr<StackFrameDeduplicator> stack_frame_deduplicator);
-
- // Returns the type name deduplicator that should be used by memory dump
- // providers when doing a heap dump.
- TypeNameDeduplicator* type_name_deduplicator() const {
- return type_name_deduplicator_.get();
- }
-
- 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;
- }
-
- uint32_t heap_profiler_breakdown_threshold_bytes() const {
- return heap_profiler_breakdown_threshold_bytes_;
- }
-
- private:
- friend class RefCountedThreadSafe<MemoryDumpSessionState>;
- ~MemoryDumpSessionState();
-
- // Deduplicates backtraces in heap dumps so they can be written once when the
- // trace is finalized.
- std::unique_ptr<StackFrameDeduplicator> stack_frame_deduplicator_;
-
- // Deduplicates type names in heap dumps so they can be written once when the
- // trace is finalized.
- std::unique_ptr<TypeNameDeduplicator> type_name_deduplicator_;
-
- std::set<MemoryDumpLevelOfDetail> allowed_dump_modes_;
-
- uint32_t heap_profiler_breakdown_threshold_bytes_;
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
diff --git a/base/trace_event/memory_infra_background_whitelist.cc b/base/trace_event/memory_infra_background_whitelist.cc
deleted file mode 100644
index 746068a7b1..0000000000
--- a/base/trace_event/memory_infra_background_whitelist.cc
+++ /dev/null
@@ -1,258 +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_infra_background_whitelist.h"
-
-#include <ctype.h>
-#include <string.h>
-
-#include <string>
-
-namespace base {
-namespace trace_event {
-namespace {
-
-// The names of dump providers whitelisted for background tracing. Dump
-// 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",
- "DOMStorage",
- "DiscardableSharedMemoryManager",
- "IndexedDBBackingStore",
- "JavaHeap",
- "LevelDB",
- "LeveldbValueStore",
- "Malloc",
- "MemoryCache",
- "PartitionAlloc",
- "ProcessMemoryMetrics",
- "Skia",
- "Sql",
- "URLRequestContext",
- "V8Isolate",
- "WinHeap",
- "SyncDirectory",
- "TabRestoreServiceHelper",
- nullptr // End of list marker.
-};
-
-// A list of string names that are allowed for the memory allocator dumps in
-// background mode.
-const char* const kAllocatorDumpNameWhitelist[] = {
- "blink_gc",
- "blink_gc/allocated_objects",
- "discardable",
- "discardable/child_0x?",
- "dom_storage/0x?/cache_size",
- "dom_storage/session_storage_0x?",
- "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?",
- "leveldb/value_store/Extensions.Database.Open/0x?",
- "leveldb/value_store/Extensions.Database.Restore/0x?",
- "leveldb/value_store/Extensions.Database.Value.Restore/0x?",
- "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",
- "net/url_request_context/app_request",
- "net/url_request_context/app_request/0x?",
- "net/url_request_context/app_request/0x?/http_cache",
- "net/url_request_context/app_request/0x?/http_cache/memory_backend",
- "net/url_request_context/app_request/0x?/http_cache/simple_backend",
- "net/url_request_context/app_request/0x?/http_network_session",
- "net/url_request_context/app_request/0x?/sdch_manager",
- "net/url_request_context/extensions",
- "net/url_request_context/extensions/0x?",
- "net/url_request_context/extensions/0x?/http_cache",
- "net/url_request_context/extensions/0x?/http_cache/memory_backend",
- "net/url_request_context/extensions/0x?/http_cache/simple_backend",
- "net/url_request_context/extensions/0x?/http_network_session",
- "net/url_request_context/extensions/0x?/sdch_manager",
- "net/url_request_context/isolated_media",
- "net/url_request_context/isolated_media/0x?",
- "net/url_request_context/isolated_media/0x?/http_cache",
- "net/url_request_context/isolated_media/0x?/http_cache/memory_backend",
- "net/url_request_context/isolated_media/0x?/http_cache/simple_backend",
- "net/url_request_context/isolated_media/0x?/http_network_session",
- "net/url_request_context/isolated_media/0x?/sdch_manager",
- "net/url_request_context/main",
- "net/url_request_context/main/0x?",
- "net/url_request_context/main/0x?/http_cache",
- "net/url_request_context/main/0x?/http_cache/memory_backend",
- "net/url_request_context/main/0x?/http_cache/simple_backend",
- "net/url_request_context/main/0x?/http_network_session",
- "net/url_request_context/main/0x?/sdch_manager",
- "net/url_request_context/main_media",
- "net/url_request_context/main_media/0x?",
- "net/url_request_context/main_media/0x?/http_cache",
- "net/url_request_context/main_media/0x?/http_cache/memory_backend",
- "net/url_request_context/main_media/0x?/http_cache/simple_backend",
- "net/url_request_context/main_media/0x?/http_network_session",
- "net/url_request_context/main_media/0x?/sdch_manager",
- "net/url_request_context/proxy",
- "net/url_request_context/proxy/0x?",
- "net/url_request_context/proxy/0x?/http_cache",
- "net/url_request_context/proxy/0x?/http_cache/memory_backend",
- "net/url_request_context/proxy/0x?/http_cache/simple_backend",
- "net/url_request_context/proxy/0x?/http_network_session",
- "net/url_request_context/proxy/0x?/sdch_manager",
- "net/url_request_context/safe_browsing",
- "net/url_request_context/safe_browsing/0x?",
- "net/url_request_context/safe_browsing/0x?/http_cache",
- "net/url_request_context/safe_browsing/0x?/http_cache/memory_backend",
- "net/url_request_context/safe_browsing/0x?/http_cache/simple_backend",
- "net/url_request_context/safe_browsing/0x?/http_network_session",
- "net/url_request_context/safe_browsing/0x?/sdch_manager",
- "net/url_request_context/system",
- "net/url_request_context/system/0x?",
- "net/url_request_context/system/0x?/http_cache",
- "net/url_request_context/system/0x?/http_cache/memory_backend",
- "net/url_request_context/system/0x?/http_cache/simple_backend",
- "net/url_request_context/system/0x?/http_network_session",
- "net/url_request_context/system/0x?/sdch_manager",
- "net/url_request_context/unknown",
- "net/url_request_context/unknown/0x?",
- "net/url_request_context/unknown/0x?/http_cache",
- "net/url_request_context/unknown/0x?/http_cache/memory_backend",
- "net/url_request_context/unknown/0x?/http_cache/simple_backend",
- "net/url_request_context/unknown/0x?/http_network_session",
- "net/url_request_context/unknown/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",
- "v8/isolate_0x?/heap_spaces/map_space",
- "v8/isolate_0x?/heap_spaces/new_space",
- "v8/isolate_0x?/heap_spaces/old_space",
- "v8/isolate_0x?/heap_spaces/other_spaces",
- "v8/isolate_0x?/malloc",
- "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.
-};
-
-const char* const* g_dump_provider_whitelist = kDumpProviderWhitelist;
-const char* const* g_allocator_dump_name_whitelist =
- kAllocatorDumpNameWhitelist;
-
-} // namespace
-
-bool IsMemoryDumpProviderWhitelisted(const char* mdp_name) {
- for (size_t i = 0; g_dump_provider_whitelist[i] != nullptr; ++i) {
- if (strcmp(mdp_name, g_dump_provider_whitelist[i]) == 0)
- return true;
- }
- return false;
-}
-
-bool IsMemoryAllocatorDumpNameWhitelisted(const std::string& name) {
- // Remove special characters, numbers (including hexadecimal which are marked
- // by '0x') from the given string.
- const size_t length = name.size();
- std::string stripped_str;
- stripped_str.reserve(length);
- bool parsing_hex = false;
- for (size_t i = 0; i < length; ++i) {
- if (parsing_hex && isxdigit(name[i]))
- continue;
- parsing_hex = false;
- if (i + 1 < length && name[i] == '0' && name[i + 1] == 'x') {
- parsing_hex = true;
- stripped_str.append("0x?");
- ++i;
- } else {
- stripped_str.push_back(name[i]);
- }
- }
-
- for (size_t i = 0; g_allocator_dump_name_whitelist[i] != nullptr; ++i) {
- if (stripped_str == g_allocator_dump_name_whitelist[i]) {
- return true;
- }
- }
- return false;
-}
-
-void SetDumpProviderWhitelistForTesting(const char* const* list) {
- g_dump_provider_whitelist = list;
-}
-
-void SetAllocatorDumpNameWhitelistForTesting(const char* const* list) {
- g_allocator_dump_name_whitelist = list;
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/memory_infra_background_whitelist.h b/base/trace_event/memory_infra_background_whitelist.h
deleted file mode 100644
index b8d704ae24..0000000000
--- a/base/trace_event/memory_infra_background_whitelist.h
+++ /dev/null
@@ -1,33 +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_INFRA_BACKGROUND_WHITELIST_H_
-#define BASE_TRACE_EVENT_MEMORY_INFRA_BACKGROUND_WHITELIST_H_
-
-// This file contains the whitelists for background mode to limit the tracing
-// overhead and remove sensitive information from traces.
-
-#include <string>
-
-#include "base/base_export.h"
-
-namespace base {
-namespace trace_event {
-
-// Checks if the given |mdp_name| is in the whitelist.
-bool BASE_EXPORT IsMemoryDumpProviderWhitelisted(const char* mdp_name);
-
-// Checks if the given |name| matches any of the whitelisted patterns.
-bool BASE_EXPORT IsMemoryAllocatorDumpNameWhitelisted(const std::string& name);
-
-// The whitelist is replaced with the given list for tests. The last element of
-// the list must be nullptr.
-void BASE_EXPORT SetDumpProviderWhitelistForTesting(const char* const* list);
-void BASE_EXPORT
-SetAllocatorDumpNameWhitelistForTesting(const char* const* list);
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_MEMORY_INFRA_BACKGROUND_WHITELIST_H_
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 6f02bb93bb..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& value) { 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
deleted file mode 100644
index 63d1340e42..0000000000
--- a/base/trace_event/process_memory_dump.cc
+++ /dev/null
@@ -1,367 +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/process_memory_dump.h"
-
-#include <errno.h>
-
-#include <vector>
-
-#include "base/memory/ptr_util.h"
-#include "base/process/process_metrics.h"
-#include "base/strings/stringprintf.h"
-#include "base/trace_event/heap_profiler_heap_dump_writer.h"
-#include "base/trace_event/memory_infra_background_whitelist.h"
-#include "base/trace_event/process_memory_totals.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "build/build_config.h"
-
-#if defined(OS_IOS)
-#include <mach/vm_page_size.h>
-#endif
-
-#if defined(OS_POSIX)
-#include <sys/mman.h>
-#endif
-
-#if defined(OS_WIN)
-#include <Psapi.h>
-#endif
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-const char kEdgeTypeOwnership[] = "ownership";
-
-std::string GetSharedGlobalAllocatorDumpName(
- const MemoryAllocatorDumpGuid& guid) {
- return "global/" + guid.ToString();
-}
-
-#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
-size_t GetSystemPageCount(size_t mapped_size, size_t page_size) {
- return (mapped_size + page_size - 1) / page_size;
-}
-#endif
-
-} // namespace
-
-// static
-bool ProcessMemoryDump::is_black_hole_non_fatal_for_testing_ = false;
-
-#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
-// static
-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();
-#endif // defined(OS_IOS)
-}
-
-// static
-size_t ProcessMemoryDump::CountResidentBytes(void* start_address,
- size_t mapped_size) {
- const size_t page_size = GetSystemPageSize();
- const uintptr_t start_pointer = reinterpret_cast<uintptr_t>(start_address);
- DCHECK_EQ(0u, start_pointer % page_size);
-
- size_t offset = 0;
- size_t total_resident_size = 0;
- bool failure = false;
-
- // An array as large as number of pages in memory segment needs to be passed
- // to the query function. To avoid allocating a large array, the given block
- // of memory is split into chunks of size |kMaxChunkSize|.
- const size_t kMaxChunkSize = 8 * 1024 * 1024;
- size_t max_vec_size =
- GetSystemPageCount(std::min(mapped_size, kMaxChunkSize), page_size);
-#if defined(OS_MACOSX) || defined(OS_IOS)
- std::unique_ptr<char[]> vec(new char[max_vec_size]);
-#elif defined(OS_WIN)
- std::unique_ptr<PSAPI_WORKING_SET_EX_INFORMATION[]> vec(
- new PSAPI_WORKING_SET_EX_INFORMATION[max_vec_size]);
-#elif defined(OS_POSIX)
- std::unique_ptr<unsigned char[]> vec(new unsigned char[max_vec_size]);
-#endif
-
- while (offset < mapped_size) {
- uintptr_t chunk_start = (start_pointer + offset);
- const size_t chunk_size = std::min(mapped_size - offset, kMaxChunkSize);
- const size_t page_count = GetSystemPageCount(chunk_size, page_size);
- size_t resident_page_count = 0;
-
-#if defined(OS_MACOSX) || defined(OS_IOS)
- // mincore in MAC does not fail with EAGAIN.
- failure =
- !!mincore(reinterpret_cast<void*>(chunk_start), chunk_size, vec.get());
- for (size_t i = 0; i < page_count; i++)
- resident_page_count += vec[i] & MINCORE_INCORE ? 1 : 0;
-#elif defined(OS_WIN)
- for (size_t i = 0; i < page_count; i++) {
- vec[i].VirtualAddress =
- reinterpret_cast<void*>(chunk_start + i * page_size);
- }
- DWORD vec_size = static_cast<DWORD>(
- page_count * sizeof(PSAPI_WORKING_SET_EX_INFORMATION));
- failure = !QueryWorkingSetEx(GetCurrentProcess(), vec.get(), vec_size);
-
- for (size_t i = 0; i < page_count; i++)
- resident_page_count += vec[i].VirtualAttributes.Valid;
-#elif defined(OS_POSIX)
- int error_counter = 0;
- int result = 0;
- // HANDLE_EINTR tries for 100 times. So following the same pattern.
- do {
- result =
- mincore(reinterpret_cast<void*>(chunk_start), chunk_size, vec.get());
- } while (result == -1 && errno == EAGAIN && error_counter++ < 100);
- failure = !!result;
-
- for (size_t i = 0; i < page_count; i++)
- resident_page_count += vec[i] & 1;
-#endif
-
- if (failure)
- break;
-
- total_resident_size += resident_page_count * page_size;
- offset += kMaxChunkSize;
- }
-
- DCHECK(!failure);
- if (failure) {
- total_resident_size = 0;
- LOG(ERROR) << "CountResidentBytes failed. The resident size is invalid";
- }
- return total_resident_size;
-}
-#endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
-
-ProcessMemoryDump::ProcessMemoryDump(
- scoped_refptr<MemoryDumpSessionState> session_state,
- const MemoryDumpArgs& dump_args)
- : has_process_totals_(false),
- has_process_mmaps_(false),
- session_state_(std::move(session_state)),
- dump_args_(dump_args) {}
-
-ProcessMemoryDump::~ProcessMemoryDump() {}
-
-MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
- const std::string& absolute_name) {
- return AddAllocatorDumpInternal(
- MakeUnique<MemoryAllocatorDump>(absolute_name, this));
-}
-
-MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
- const std::string& absolute_name,
- const MemoryAllocatorDumpGuid& guid) {
- return AddAllocatorDumpInternal(
- MakeUnique<MemoryAllocatorDump>(absolute_name, this, guid));
-}
-
-MemoryAllocatorDump* ProcessMemoryDump::AddAllocatorDumpInternal(
- std::unique_ptr<MemoryAllocatorDump> mad) {
- // In background mode return the black hole dump, if invalid dump name is
- // given.
- if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND &&
- !IsMemoryAllocatorDumpNameWhitelisted(mad->absolute_name())) {
- return GetBlackHoleMad();
- }
-
- auto insertion_result = allocator_dumps_.insert(
- std::make_pair(mad->absolute_name(), std::move(mad)));
- MemoryAllocatorDump* inserted_mad = insertion_result.first->second.get();
- DCHECK(insertion_result.second) << "Duplicate name: "
- << inserted_mad->absolute_name();
- return inserted_mad;
-}
-
-MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
- const std::string& absolute_name) const {
- auto it = allocator_dumps_.find(absolute_name);
- if (it != allocator_dumps_.end())
- return it->second.get();
- if (black_hole_mad_)
- return black_hole_mad_.get();
- return nullptr;
-}
-
-MemoryAllocatorDump* ProcessMemoryDump::GetOrCreateAllocatorDump(
- const std::string& absolute_name) {
- MemoryAllocatorDump* mad = GetAllocatorDump(absolute_name);
- return mad ? mad : CreateAllocatorDump(absolute_name);
-}
-
-MemoryAllocatorDump* ProcessMemoryDump::CreateSharedGlobalAllocatorDump(
- const MemoryAllocatorDumpGuid& guid) {
- // Global dumps are disabled in background mode.
- if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND)
- return GetBlackHoleMad();
-
- // A shared allocator dump can be shared within a process and the guid could
- // have been created already.
- MemoryAllocatorDump* mad = GetSharedGlobalAllocatorDump(guid);
- if (mad) {
- // The weak flag is cleared because this method should create a non-weak
- // dump.
- mad->clear_flags(MemoryAllocatorDump::Flags::WEAK);
- return mad;
- }
- return CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid);
-}
-
-MemoryAllocatorDump* ProcessMemoryDump::CreateWeakSharedGlobalAllocatorDump(
- const MemoryAllocatorDumpGuid& guid) {
- // Global dumps are disabled in background mode.
- if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND)
- return GetBlackHoleMad();
-
- MemoryAllocatorDump* mad = GetSharedGlobalAllocatorDump(guid);
- if (mad)
- return mad;
- mad = CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid);
- mad->set_flags(MemoryAllocatorDump::Flags::WEAK);
- return mad;
-}
-
-MemoryAllocatorDump* ProcessMemoryDump::GetSharedGlobalAllocatorDump(
- const MemoryAllocatorDumpGuid& guid) const {
- return GetAllocatorDump(GetSharedGlobalAllocatorDumpName(guid));
-}
-
-void ProcessMemoryDump::DumpHeapUsage(
- const base::hash_map<base::trace_event::AllocationContext,
- base::trace_event::AllocationMetrics>& metrics_by_context,
- base::trace_event::TraceEventMemoryOverhead& overhead,
- const char* allocator_name) {
- if (!metrics_by_context.empty()) {
- DCHECK_EQ(0ul, heap_dumps_.count(allocator_name));
- std::unique_ptr<TracedValue> heap_dump = ExportHeapDump(
- metrics_by_context, *session_state());
- heap_dumps_[allocator_name] = std::move(heap_dump);
- }
-
- std::string base_name = base::StringPrintf("tracing/heap_profiler_%s",
- allocator_name);
- overhead.DumpInto(base_name.c_str(), this);
-}
-
-void ProcessMemoryDump::Clear() {
- if (has_process_totals_) {
- process_totals_.Clear();
- has_process_totals_ = false;
- }
-
- if (has_process_mmaps_) {
- process_mmaps_.Clear();
- has_process_mmaps_ = false;
- }
-
- allocator_dumps_.clear();
- allocator_dumps_edges_.clear();
- heap_dumps_.clear();
-}
-
-void ProcessMemoryDump::TakeAllDumpsFrom(ProcessMemoryDump* other) {
- DCHECK(!other->has_process_totals() && !other->has_process_mmaps());
-
- // Moves the ownership of all MemoryAllocatorDump(s) contained in |other|
- // into this ProcessMemoryDump, checking for duplicates.
- for (auto& it : other->allocator_dumps_)
- AddAllocatorDumpInternal(std::move(it.second));
- other->allocator_dumps_.clear();
-
- // Move all the edges.
- allocator_dumps_edges_.insert(allocator_dumps_edges_.end(),
- other->allocator_dumps_edges_.begin(),
- other->allocator_dumps_edges_.end());
- other->allocator_dumps_edges_.clear();
-
- for (auto& it : other->heap_dumps_) {
- DCHECK_EQ(0ul, heap_dumps_.count(it.first));
- heap_dumps_.insert(std::make_pair(it.first, std::move(it.second)));
- }
- other->heap_dumps_.clear();
-}
-
-void ProcessMemoryDump::AsValueInto(TracedValue* value) const {
- if (has_process_totals_) {
- value->BeginDictionary("process_totals");
- process_totals_.AsValueInto(value);
- value->EndDictionary();
- }
-
- if (has_process_mmaps_) {
- value->BeginDictionary("process_mmaps");
- process_mmaps_.AsValueInto(value);
- value->EndDictionary();
- }
-
- if (allocator_dumps_.size() > 0) {
- value->BeginDictionary("allocators");
- for (const auto& allocator_dump_it : allocator_dumps_)
- allocator_dump_it.second->AsValueInto(value);
- value->EndDictionary();
- }
-
- if (heap_dumps_.size() > 0) {
- value->BeginDictionary("heaps");
- for (const auto& name_and_dump : heap_dumps_)
- value->SetValueWithCopiedName(name_and_dump.first, *name_and_dump.second);
- value->EndDictionary(); // "heaps"
- }
-
- value->BeginArray("allocators_graph");
- for (const MemoryAllocatorDumpEdge& edge : allocator_dumps_edges_) {
- value->BeginDictionary();
- value->SetString("source", edge.source.ToString());
- value->SetString("target", edge.target.ToString());
- value->SetInteger("importance", edge.importance);
- value->SetString("type", edge.type);
- value->EndDictionary();
- }
- value->EndArray();
-}
-
-void ProcessMemoryDump::AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
- const MemoryAllocatorDumpGuid& target,
- int importance) {
- allocator_dumps_edges_.push_back(
- {source, target, importance, kEdgeTypeOwnership});
-}
-
-void ProcessMemoryDump::AddOwnershipEdge(
- const MemoryAllocatorDumpGuid& source,
- const MemoryAllocatorDumpGuid& target) {
- AddOwnershipEdge(source, target, 0 /* importance */);
-}
-
-void ProcessMemoryDump::AddSuballocation(const MemoryAllocatorDumpGuid& source,
- const std::string& target_node_name) {
- // Do not create new dumps for suballocations in background mode.
- if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND)
- return;
-
- std::string child_mad_name = target_node_name + "/__" + source.ToString();
- MemoryAllocatorDump* target_child_mad = CreateAllocatorDump(child_mad_name);
- AddOwnershipEdge(source, target_child_mad->guid());
-}
-
-MemoryAllocatorDump* ProcessMemoryDump::GetBlackHoleMad() {
- DCHECK(is_black_hole_non_fatal_for_testing_);
- if (!black_hole_mad_)
- black_hole_mad_.reset(new MemoryAllocatorDump("discarded", this));
- return black_hole_mad_.get();
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
deleted file mode 100644
index 6f8d167273..0000000000
--- a/base/trace_event/process_memory_dump.h
+++ /dev/null
@@ -1,222 +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.
-
-#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
-#define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
-
-#include <stddef.h>
-
-#include <unordered_map>
-#include <vector>
-
-#include "base/base_export.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
-#include "base/trace_event/memory_allocator_dump.h"
-#include "base/trace_event/memory_allocator_dump_guid.h"
-#include "base/trace_event/memory_dump_request_args.h"
-#include "base/trace_event/memory_dump_session_state.h"
-#include "base/trace_event/process_memory_maps.h"
-#include "base/trace_event/process_memory_totals.h"
-#include "build/build_config.h"
-
-// Define COUNT_RESIDENT_BYTES_SUPPORTED if platform supports counting of the
-// resident memory.
-#if (defined(OS_POSIX) && !defined(OS_NACL)) || defined(OS_WIN)
-#define COUNT_RESIDENT_BYTES_SUPPORTED
-#endif
-
-namespace base {
-namespace trace_event {
-
-class MemoryDumpSessionState;
-class TracedValue;
-
-// ProcessMemoryDump is as a strongly typed container which holds the dumps
-// produced by the MemoryDumpProvider(s) for a specific process.
-class BASE_EXPORT ProcessMemoryDump {
- public:
- struct MemoryAllocatorDumpEdge {
- MemoryAllocatorDumpGuid source;
- MemoryAllocatorDumpGuid target;
- int importance;
- const char* type;
- };
-
- // Maps allocator dumps absolute names (allocator_name/heap/subheap) to
- // MemoryAllocatorDump instances.
- using AllocatorDumpsMap =
- std::unordered_map<std::string, std::unique_ptr<MemoryAllocatorDump>>;
-
- using HeapDumpsMap =
- std::unordered_map<std::string, std::unique_ptr<TracedValue>>;
-
-#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
- // Returns the number of bytes in a kernel memory page. Some platforms may
- // have a different value for kernel page sizes from user page sizes. It is
- // important to use kernel memory page sizes for resident bytes calculation.
- // In most cases, the two are the same.
- static size_t GetSystemPageSize();
-
- // Returns the total bytes resident for a virtual address range, with given
- // |start_address| and |mapped_size|. |mapped_size| is specified in bytes. The
- // value returned is valid only if the given range is currently mmapped by the
- // process. The |start_address| must be page-aligned.
- static size_t CountResidentBytes(void* start_address, size_t mapped_size);
-#endif
-
- ProcessMemoryDump(scoped_refptr<MemoryDumpSessionState> session_state,
- const MemoryDumpArgs& dump_args);
- ~ProcessMemoryDump();
-
- // Creates a new MemoryAllocatorDump with the given name and returns the
- // empty object back to the caller.
- // Arguments:
- // absolute_name: a name that uniquely identifies allocator dumps produced
- // by this provider. It is possible to specify nesting by using a
- // path-like string (e.g., v8/isolate1/heap1, v8/isolate1/heap2).
- // Leading or trailing slashes are not allowed.
- // guid: an optional identifier, unique among all processes within the
- // scope of a global dump. This is only relevant when using
- // AddOwnershipEdge() to express memory sharing. If omitted,
- // it will be automatically generated.
- // ProcessMemoryDump handles the memory ownership of its MemoryAllocatorDumps.
- MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name);
- MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name,
- const MemoryAllocatorDumpGuid& guid);
-
- // Looks up a MemoryAllocatorDump given its allocator and heap names, or
- // nullptr if not found.
- MemoryAllocatorDump* GetAllocatorDump(const std::string& absolute_name) const;
-
- MemoryAllocatorDump* GetOrCreateAllocatorDump(
- const std::string& absolute_name);
-
- // Creates a shared MemoryAllocatorDump, to express cross-process sharing.
- // Shared allocator dumps are allowed to have duplicate guids within the
- // global scope, in order to reference the same dump from multiple processes.
- // See the design doc goo.gl/keU6Bf for reference usage patterns.
- MemoryAllocatorDump* CreateSharedGlobalAllocatorDump(
- const MemoryAllocatorDumpGuid& guid);
-
- // Creates a shared MemoryAllocatorDump as CreateSharedGlobalAllocatorDump,
- // but with a WEAK flag. A weak dump will be discarded unless a non-weak dump
- // is created using CreateSharedGlobalAllocatorDump by at least one process.
- // The WEAK flag does not apply if a non-weak dump with the same GUID already
- // exists or is created later. All owners and children of the discarded dump
- // will also be discarded transitively.
- MemoryAllocatorDump* CreateWeakSharedGlobalAllocatorDump(
- const MemoryAllocatorDumpGuid& guid);
-
- // Looks up a shared MemoryAllocatorDump given its guid.
- MemoryAllocatorDump* GetSharedGlobalAllocatorDump(
- const MemoryAllocatorDumpGuid& guid) const;
-
- // Returns the map of the MemoryAllocatorDumps added to this dump.
- const AllocatorDumpsMap& allocator_dumps() const { return allocator_dumps_; }
-
- // Dumps heap usage with |allocator_name|.
- void DumpHeapUsage(const base::hash_map<base::trace_event::AllocationContext,
- base::trace_event::AllocationMetrics>&
- metrics_by_context,
- base::trace_event::TraceEventMemoryOverhead& overhead,
- const char* allocator_name);
-
- // Adds an ownership relationship between two MemoryAllocatorDump(s) with the
- // semantics: |source| owns |target|, and has the effect of attributing
- // the memory usage of |target| to |source|. |importance| is optional and
- // relevant only for the cases of co-ownership, where it acts as a z-index:
- // the owner with the highest importance will be attributed |target|'s memory.
- void AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
- const MemoryAllocatorDumpGuid& target,
- int importance);
- void AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
- const MemoryAllocatorDumpGuid& target);
-
- const std::vector<MemoryAllocatorDumpEdge>& allocator_dumps_edges() const {
- return allocator_dumps_edges_;
- }
-
- // Utility method to add a suballocation relationship with the following
- // semantics: |source| is suballocated from |target_node_name|.
- // This creates a child node of |target_node_name| and adds an ownership edge
- // between |source| and the new child node. As a result, the UI will not
- // account the memory of |source| in the target node.
- void AddSuballocation(const MemoryAllocatorDumpGuid& source,
- const std::string& target_node_name);
-
- const scoped_refptr<MemoryDumpSessionState>& session_state() const {
- return session_state_;
- }
-
- // Removes all the MemoryAllocatorDump(s) contained in this instance. This
- // ProcessMemoryDump can be safely reused as if it was new once this returns.
- void Clear();
-
- // Merges all MemoryAllocatorDump(s) contained in |other| inside this
- // ProcessMemoryDump, transferring their ownership to this instance.
- // |other| will be an empty ProcessMemoryDump after this method returns.
- // This is to allow dump providers to pre-populate ProcessMemoryDump instances
- // and later move their contents into the ProcessMemoryDump passed as argument
- // of the MemoryDumpProvider::OnMemoryDump(ProcessMemoryDump*) callback.
- void TakeAllDumpsFrom(ProcessMemoryDump* other);
-
- // Called at trace generation time to populate the TracedValue.
- void AsValueInto(TracedValue* value) const;
-
- ProcessMemoryTotals* process_totals() { return &process_totals_; }
- bool has_process_totals() const { return has_process_totals_; }
- void set_has_process_totals() { has_process_totals_ = true; }
-
- ProcessMemoryMaps* process_mmaps() { return &process_mmaps_; }
- bool has_process_mmaps() const { return has_process_mmaps_; }
- void set_has_process_mmaps() { has_process_mmaps_ = true; }
-
- const HeapDumpsMap& heap_dumps() const { return heap_dumps_; }
-
- const MemoryDumpArgs& dump_args() const { return dump_args_; }
-
- private:
- FRIEND_TEST_ALL_PREFIXES(ProcessMemoryDumpTest, BackgroundModeTest);
-
- MemoryAllocatorDump* AddAllocatorDumpInternal(
- std::unique_ptr<MemoryAllocatorDump> mad);
-
- MemoryAllocatorDump* GetBlackHoleMad();
-
- ProcessMemoryTotals process_totals_;
- bool has_process_totals_;
-
- ProcessMemoryMaps process_mmaps_;
- bool has_process_mmaps_;
-
- AllocatorDumpsMap allocator_dumps_;
- HeapDumpsMap heap_dumps_;
-
- // State shared among all PMDs instances created in a given trace session.
- scoped_refptr<MemoryDumpSessionState> session_state_;
-
- // Keeps track of relationships between MemoryAllocatorDump(s).
- std::vector<MemoryAllocatorDumpEdge> allocator_dumps_edges_;
-
- // Level of detail of the current dump.
- const MemoryDumpArgs dump_args_;
-
- // This allocator dump is returned when an invalid dump is created in
- // background mode. The attributes of the dump are ignored and not added to
- // the trace.
- std::unique_ptr<MemoryAllocatorDump> black_hole_mad_;
-
- // When set to true, the DCHECK(s) for invalid dump creations on the
- // background mode are disabled for testing.
- static bool is_black_hole_non_fatal_for_testing_;
-
- DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
diff --git a/base/trace_event/process_memory_dump_unittest.cc b/base/trace_event/process_memory_dump_unittest.cc
deleted file mode 100644
index 571774a10c..0000000000
--- a/base/trace_event/process_memory_dump_unittest.cc
+++ /dev/null
@@ -1,306 +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/process_memory_dump.h"
-
-#include <stddef.h>
-
-#include "base/memory/aligned_memory.h"
-#include "base/memory/ptr_util.h"
-#include "base/process/process_metrics.h"
-#include "base/trace_event/memory_allocator_dump_guid.h"
-#include "base/trace_event/memory_infra_background_whitelist.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-const MemoryDumpArgs kDetailedDumpArgs = {MemoryDumpLevelOfDetail::DETAILED};
-const char* const kTestDumpNameWhitelist[] = {
- "Whitelisted/TestName", "Whitelisted/TestName_0x?",
- "Whitelisted/0x?/TestName", nullptr};
-
-TracedValue* GetHeapDump(const ProcessMemoryDump& pmd, const char* name) {
- auto it = pmd.heap_dumps().find(name);
- return it == pmd.heap_dumps().end() ? nullptr : it->second.get();
-}
-
-} // namespace
-
-TEST(ProcessMemoryDumpTest, Clear) {
- std::unique_ptr<ProcessMemoryDump> pmd1(
- new ProcessMemoryDump(nullptr, kDetailedDumpArgs));
- pmd1->CreateAllocatorDump("mad1");
- pmd1->CreateAllocatorDump("mad2");
- ASSERT_FALSE(pmd1->allocator_dumps().empty());
-
- pmd1->process_totals()->set_resident_set_bytes(42);
- pmd1->set_has_process_totals();
-
- pmd1->process_mmaps()->AddVMRegion(ProcessMemoryMaps::VMRegion());
- pmd1->set_has_process_mmaps();
-
- pmd1->AddOwnershipEdge(MemoryAllocatorDumpGuid(42),
- MemoryAllocatorDumpGuid(4242));
-
- MemoryAllocatorDumpGuid shared_mad_guid1(1);
- MemoryAllocatorDumpGuid shared_mad_guid2(2);
- pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid1);
- pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid2);
-
- pmd1->Clear();
- ASSERT_TRUE(pmd1->allocator_dumps().empty());
- ASSERT_TRUE(pmd1->allocator_dumps_edges().empty());
- ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad1"));
- ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad2"));
- ASSERT_FALSE(pmd1->has_process_totals());
- ASSERT_FALSE(pmd1->has_process_mmaps());
- ASSERT_TRUE(pmd1->process_mmaps()->vm_regions().empty());
- ASSERT_EQ(nullptr, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid1));
- ASSERT_EQ(nullptr, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid2));
-
- // Check that calling AsValueInto() doesn't cause a crash.
- std::unique_ptr<TracedValue> traced_value(new TracedValue);
- pmd1->AsValueInto(traced_value.get());
-
- // Check that the pmd can be reused and behaves as expected.
- auto* mad1 = pmd1->CreateAllocatorDump("mad1");
- auto* mad3 = pmd1->CreateAllocatorDump("mad3");
- auto* shared_mad1 = pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid1);
- auto* shared_mad2 =
- pmd1->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid2);
- ASSERT_EQ(4u, pmd1->allocator_dumps().size());
- ASSERT_EQ(mad1, pmd1->GetAllocatorDump("mad1"));
- ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad2"));
- ASSERT_EQ(mad3, pmd1->GetAllocatorDump("mad3"));
- ASSERT_EQ(shared_mad1, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid1));
- ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags());
- ASSERT_EQ(shared_mad2, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid2));
- ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad2->flags());
-
- traced_value.reset(new TracedValue);
- pmd1->AsValueInto(traced_value.get());
-
- pmd1.reset();
-}
-
-TEST(ProcessMemoryDumpTest, TakeAllDumpsFrom) {
- std::unique_ptr<TracedValue> traced_value(new TracedValue);
- hash_map<AllocationContext, AllocationMetrics> metrics_by_context;
- metrics_by_context[AllocationContext()] = { 1, 1 };
- TraceEventMemoryOverhead overhead;
-
- scoped_refptr<MemoryDumpSessionState> session_state =
- new MemoryDumpSessionState;
- session_state->SetStackFrameDeduplicator(
- WrapUnique(new StackFrameDeduplicator));
- session_state->SetTypeNameDeduplicator(
- WrapUnique(new TypeNameDeduplicator));
- std::unique_ptr<ProcessMemoryDump> pmd1(
- new ProcessMemoryDump(session_state.get(), kDetailedDumpArgs));
- auto* mad1_1 = pmd1->CreateAllocatorDump("pmd1/mad1");
- auto* mad1_2 = pmd1->CreateAllocatorDump("pmd1/mad2");
- pmd1->AddOwnershipEdge(mad1_1->guid(), mad1_2->guid());
- pmd1->DumpHeapUsage(metrics_by_context, overhead, "pmd1/heap_dump1");
- pmd1->DumpHeapUsage(metrics_by_context, overhead, "pmd1/heap_dump2");
-
- std::unique_ptr<ProcessMemoryDump> pmd2(
- new ProcessMemoryDump(session_state.get(), kDetailedDumpArgs));
- auto* mad2_1 = pmd2->CreateAllocatorDump("pmd2/mad1");
- auto* mad2_2 = pmd2->CreateAllocatorDump("pmd2/mad2");
- pmd2->AddOwnershipEdge(mad2_1->guid(), mad2_2->guid());
- pmd2->DumpHeapUsage(metrics_by_context, overhead, "pmd2/heap_dump1");
- pmd2->DumpHeapUsage(metrics_by_context, overhead, "pmd2/heap_dump2");
-
- MemoryAllocatorDumpGuid shared_mad_guid1(1);
- MemoryAllocatorDumpGuid shared_mad_guid2(2);
- auto* shared_mad1 = pmd2->CreateSharedGlobalAllocatorDump(shared_mad_guid1);
- auto* shared_mad2 =
- pmd2->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid2);
-
- pmd1->TakeAllDumpsFrom(pmd2.get());
-
- // Make sure that pmd2 is empty but still usable after it has been emptied.
- ASSERT_TRUE(pmd2->allocator_dumps().empty());
- ASSERT_TRUE(pmd2->allocator_dumps_edges().empty());
- ASSERT_TRUE(pmd2->heap_dumps().empty());
- pmd2->CreateAllocatorDump("pmd2/this_mad_stays_with_pmd2");
- ASSERT_EQ(1u, pmd2->allocator_dumps().size());
- ASSERT_EQ(1u, pmd2->allocator_dumps().count("pmd2/this_mad_stays_with_pmd2"));
- pmd2->AddOwnershipEdge(MemoryAllocatorDumpGuid(42),
- MemoryAllocatorDumpGuid(4242));
-
- // Check that calling AsValueInto() doesn't cause a crash.
- pmd2->AsValueInto(traced_value.get());
-
- // Free the |pmd2| to check that the memory ownership of the two MAD(s)
- // has been transferred to |pmd1|.
- pmd2.reset();
-
- // Now check that |pmd1| has been effectively merged.
- ASSERT_EQ(6u, pmd1->allocator_dumps().size());
- ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad1"));
- ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2"));
- ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd2/mad1"));
- ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2"));
- ASSERT_EQ(2u, pmd1->allocator_dumps_edges().size());
- ASSERT_EQ(shared_mad1, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid1));
- ASSERT_EQ(shared_mad2, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid2));
- ASSERT_TRUE(MemoryAllocatorDump::Flags::WEAK & shared_mad2->flags());
- ASSERT_EQ(4u, pmd1->heap_dumps().size());
- ASSERT_TRUE(GetHeapDump(*pmd1, "pmd1/heap_dump1") != nullptr);
- ASSERT_TRUE(GetHeapDump(*pmd1, "pmd1/heap_dump2") != nullptr);
- ASSERT_TRUE(GetHeapDump(*pmd1, "pmd2/heap_dump1") != nullptr);
- ASSERT_TRUE(GetHeapDump(*pmd1, "pmd2/heap_dump2") != nullptr);
-
- // Check that calling AsValueInto() doesn't cause a crash.
- traced_value.reset(new TracedValue);
- pmd1->AsValueInto(traced_value.get());
-
- pmd1.reset();
-}
-
-TEST(ProcessMemoryDumpTest, Suballocations) {
- std::unique_ptr<ProcessMemoryDump> pmd(
- new ProcessMemoryDump(nullptr, kDetailedDumpArgs));
- const std::string allocator_dump_name = "fakealloc/allocated_objects";
- pmd->CreateAllocatorDump(allocator_dump_name);
-
- // Create one allocation with an auto-assigned guid and mark it as a
- // suballocation of "fakealloc/allocated_objects".
- auto* pic1_dump = pmd->CreateAllocatorDump("picturemanager/picture1");
- pmd->AddSuballocation(pic1_dump->guid(), allocator_dump_name);
-
- // Same here, but this time create an allocation with an explicit guid.
- auto* pic2_dump = pmd->CreateAllocatorDump("picturemanager/picture2",
- MemoryAllocatorDumpGuid(0x42));
- pmd->AddSuballocation(pic2_dump->guid(), allocator_dump_name);
-
- // Now check that AddSuballocation() has created anonymous child dumps under
- // "fakealloc/allocated_objects".
- auto anon_node_1_it = pmd->allocator_dumps().find(
- allocator_dump_name + "/__" + pic1_dump->guid().ToString());
- ASSERT_NE(pmd->allocator_dumps().end(), anon_node_1_it);
-
- auto anon_node_2_it =
- pmd->allocator_dumps().find(allocator_dump_name + "/__42");
- ASSERT_NE(pmd->allocator_dumps().end(), anon_node_2_it);
-
- // Finally check that AddSuballocation() has created also the
- // edges between the pictures and the anonymous allocator child dumps.
- bool found_edge[2]{false, false};
- for (const auto& e : pmd->allocator_dumps_edges()) {
- found_edge[0] |= (e.source == pic1_dump->guid() &&
- e.target == anon_node_1_it->second->guid());
- found_edge[1] |= (e.source == pic2_dump->guid() &&
- e.target == anon_node_2_it->second->guid());
- }
- ASSERT_TRUE(found_edge[0]);
- ASSERT_TRUE(found_edge[1]);
-
- // Check that calling AsValueInto() doesn't cause a crash.
- std::unique_ptr<TracedValue> traced_value(new TracedValue);
- pmd->AsValueInto(traced_value.get());
-
- pmd.reset();
-}
-
-TEST(ProcessMemoryDumpTest, GlobalAllocatorDumpTest) {
- std::unique_ptr<ProcessMemoryDump> pmd(
- new ProcessMemoryDump(nullptr, kDetailedDumpArgs));
- MemoryAllocatorDumpGuid shared_mad_guid(1);
- auto* shared_mad1 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid);
- ASSERT_EQ(shared_mad_guid, shared_mad1->guid());
- ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags());
-
- auto* shared_mad2 = pmd->GetSharedGlobalAllocatorDump(shared_mad_guid);
- ASSERT_EQ(shared_mad1, shared_mad2);
- ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags());
-
- auto* shared_mad3 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid);
- ASSERT_EQ(shared_mad1, shared_mad3);
- ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags());
-
- auto* shared_mad4 = pmd->CreateSharedGlobalAllocatorDump(shared_mad_guid);
- ASSERT_EQ(shared_mad1, shared_mad4);
- ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags());
-
- auto* shared_mad5 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid);
- ASSERT_EQ(shared_mad1, shared_mad5);
- ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags());
-}
-
-TEST(ProcessMemoryDumpTest, BackgroundModeTest) {
- MemoryDumpArgs background_args = {MemoryDumpLevelOfDetail::BACKGROUND};
- std::unique_ptr<ProcessMemoryDump> pmd(
- new ProcessMemoryDump(nullptr, background_args));
- ProcessMemoryDump::is_black_hole_non_fatal_for_testing_ = true;
- SetAllocatorDumpNameWhitelistForTesting(kTestDumpNameWhitelist);
- MemoryAllocatorDump* black_hole_mad = pmd->GetBlackHoleMad();
-
- // Invalid dump names.
- EXPECT_EQ(black_hole_mad,
- pmd->CreateAllocatorDump("NotWhitelisted/TestName"));
- EXPECT_EQ(black_hole_mad, pmd->CreateAllocatorDump("TestName"));
- EXPECT_EQ(black_hole_mad, pmd->CreateAllocatorDump("Whitelisted/Test"));
- EXPECT_EQ(black_hole_mad,
- pmd->CreateAllocatorDump("Not/Whitelisted/TestName"));
- EXPECT_EQ(black_hole_mad,
- pmd->CreateAllocatorDump("Whitelisted/TestName/Google"));
- EXPECT_EQ(black_hole_mad,
- pmd->CreateAllocatorDump("Whitelisted/TestName/0x1a2Google"));
- EXPECT_EQ(black_hole_mad,
- pmd->CreateAllocatorDump("Whitelisted/TestName/__12/Google"));
-
- // Global dumps.
- MemoryAllocatorDumpGuid guid(1);
- EXPECT_EQ(black_hole_mad, pmd->CreateSharedGlobalAllocatorDump(guid));
- EXPECT_EQ(black_hole_mad, pmd->CreateWeakSharedGlobalAllocatorDump(guid));
- EXPECT_EQ(black_hole_mad, pmd->GetSharedGlobalAllocatorDump(guid));
-
- // Suballocations.
- pmd->AddSuballocation(guid, "malloc/allocated_objects");
- EXPECT_EQ(0u, pmd->allocator_dumps_edges_.size());
- EXPECT_EQ(0u, pmd->allocator_dumps_.size());
-
- // Valid dump names.
- EXPECT_NE(black_hole_mad, pmd->CreateAllocatorDump("Whitelisted/TestName"));
- EXPECT_NE(black_hole_mad,
- pmd->CreateAllocatorDump("Whitelisted/TestName_0xA1b2"));
- EXPECT_NE(black_hole_mad,
- pmd->CreateAllocatorDump("Whitelisted/0xaB/TestName"));
-
- // GetAllocatorDump is consistent.
- EXPECT_EQ(black_hole_mad, pmd->GetAllocatorDump("NotWhitelisted/TestName"));
- EXPECT_NE(black_hole_mad, pmd->GetAllocatorDump("Whitelisted/TestName"));
-}
-
-#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
-TEST(ProcessMemoryDumpTest, CountResidentBytes) {
- const size_t page_size = ProcessMemoryDump::GetSystemPageSize();
-
- // Allocate few page of dirty memory and check if it is resident.
- const size_t size1 = 5 * page_size;
- std::unique_ptr<char, base::AlignedFreeDeleter> memory1(
- static_cast<char*>(base::AlignedAlloc(size1, page_size)));
- memset(memory1.get(), 0, size1);
- size_t res1 = ProcessMemoryDump::CountResidentBytes(memory1.get(), size1);
- ASSERT_EQ(res1, size1);
-
- // Allocate a large memory segment (> 8Mib).
- const size_t kVeryLargeMemorySize = 15 * 1024 * 1024;
- std::unique_ptr<char, base::AlignedFreeDeleter> memory2(
- static_cast<char*>(base::AlignedAlloc(kVeryLargeMemorySize, page_size)));
- memset(memory2.get(), 0, kVeryLargeMemorySize);
- size_t res2 = ProcessMemoryDump::CountResidentBytes(memory2.get(),
- kVeryLargeMemorySize);
- ASSERT_EQ(res2, kVeryLargeMemorySize);
-}
-#endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/process_memory_maps.cc b/base/trace_event/process_memory_maps.cc
deleted file mode 100644
index a121239604..0000000000
--- a/base/trace_event/process_memory_maps.cc
+++ /dev/null
@@ -1,77 +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/process_memory_maps.h"
-
-#include "base/format_macros.h"
-#include "base/strings/stringprintf.h"
-#include "base/trace_event/trace_event_argument.h"
-
-namespace base {
-namespace trace_event {
-
-// static
-const uint32_t ProcessMemoryMaps::VMRegion::kProtectionFlagsRead = 4;
-const uint32_t ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite = 2;
-const uint32_t ProcessMemoryMaps::VMRegion::kProtectionFlagsExec = 1;
-const uint32_t ProcessMemoryMaps::VMRegion::kProtectionFlagsMayshare = 128;
-
-ProcessMemoryMaps::VMRegion::VMRegion()
- : start_address(0),
- size_in_bytes(0),
- protection_flags(0),
- byte_stats_private_dirty_resident(0),
- byte_stats_private_clean_resident(0),
- byte_stats_shared_dirty_resident(0),
- byte_stats_shared_clean_resident(0),
- byte_stats_swapped(0),
- byte_stats_proportional_resident(0) {
-}
-
-ProcessMemoryMaps::VMRegion::VMRegion(const VMRegion& other) = default;
-
-ProcessMemoryMaps::ProcessMemoryMaps() {
-}
-
-ProcessMemoryMaps::~ProcessMemoryMaps() {
-}
-
-void ProcessMemoryMaps::AsValueInto(TracedValue* value) const {
- static const char kHexFmt[] = "%" PRIx64;
-
- // Refer to the design doc goo.gl/sxfFY8 for the semantic of these fields.
- value->BeginArray("vm_regions");
- for (const auto& region : vm_regions_) {
- value->BeginDictionary();
-
- value->SetString("sa", StringPrintf(kHexFmt, region.start_address));
- value->SetString("sz", StringPrintf(kHexFmt, region.size_in_bytes));
- value->SetInteger("pf", region.protection_flags);
- value->SetString("mf", region.mapped_file);
-
- value->BeginDictionary("bs"); // byte stats
- value->SetString(
- "pss", StringPrintf(kHexFmt, region.byte_stats_proportional_resident));
- value->SetString(
- "pd", StringPrintf(kHexFmt, region.byte_stats_private_dirty_resident));
- value->SetString(
- "pc", StringPrintf(kHexFmt, region.byte_stats_private_clean_resident));
- value->SetString(
- "sd", StringPrintf(kHexFmt, region.byte_stats_shared_dirty_resident));
- value->SetString(
- "sc", StringPrintf(kHexFmt, region.byte_stats_shared_clean_resident));
- value->SetString("sw", StringPrintf(kHexFmt, region.byte_stats_swapped));
- value->EndDictionary();
-
- value->EndDictionary();
- }
- value->EndArray();
-}
-
-void ProcessMemoryMaps::Clear() {
- vm_regions_.clear();
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/process_memory_maps.h b/base/trace_event/process_memory_maps.h
deleted file mode 100644
index 6a7367437e..0000000000
--- a/base/trace_event/process_memory_maps.h
+++ /dev/null
@@ -1,72 +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.
-
-#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
-#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
-
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include "base/base_export.h"
-#include "base/macros.h"
-
-namespace base {
-namespace trace_event {
-
-class TracedValue;
-
-// Data model for process-wide memory stats.
-class BASE_EXPORT ProcessMemoryMaps {
- public:
- struct BASE_EXPORT VMRegion {
- static const uint32_t kProtectionFlagsRead;
- static const uint32_t kProtectionFlagsWrite;
- static const uint32_t kProtectionFlagsExec;
- static const uint32_t kProtectionFlagsMayshare;
-
- VMRegion();
- VMRegion(const VMRegion& other);
-
- uint64_t start_address;
- uint64_t size_in_bytes;
- uint32_t protection_flags;
- std::string mapped_file;
-
- // private_dirty_resident + private_clean_resident + shared_dirty_resident +
- // shared_clean_resident = resident set size.
- uint64_t byte_stats_private_dirty_resident;
- uint64_t byte_stats_private_clean_resident;
- uint64_t byte_stats_shared_dirty_resident;
- uint64_t byte_stats_shared_clean_resident;
-
- uint64_t byte_stats_swapped;
-
- // For multiprocess accounting.
- uint64_t byte_stats_proportional_resident;
- };
-
- ProcessMemoryMaps();
- ~ProcessMemoryMaps();
-
- void AddVMRegion(const VMRegion& region) { vm_regions_.push_back(region); }
- const std::vector<VMRegion>& vm_regions() const { return vm_regions_; }
-
- // Called at trace generation time to populate the TracedValue.
- void AsValueInto(TracedValue* value) const;
-
- // Clears up all the VMRegion(s) stored.
- void Clear();
-
- private:
- std::vector<VMRegion> vm_regions_;
-
- DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMaps);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
diff --git a/base/trace_event/process_memory_totals.cc b/base/trace_event/process_memory_totals.cc
deleted file mode 100644
index de27ab3d9d..0000000000
--- a/base/trace_event/process_memory_totals.cc
+++ /dev/null
@@ -1,47 +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/process_memory_totals.h"
-
-#include "base/format_macros.h"
-#include "base/strings/stringprintf.h"
-#include "base/trace_event/trace_event_argument.h"
-
-namespace base {
-namespace trace_event {
-
-ProcessMemoryTotals::ProcessMemoryTotals()
- : resident_set_bytes_(0),
- peak_resident_set_bytes_(0),
- is_peak_rss_resetable_(false) {
-}
-
-ProcessMemoryTotals::~ProcessMemoryTotals() {}
-
-void ProcessMemoryTotals::AsValueInto(TracedValue* value) const {
- value->SetString("resident_set_bytes",
- StringPrintf("%" PRIx64, resident_set_bytes_));
- if (peak_resident_set_bytes_ > 0) {
- value->SetString("peak_resident_set_bytes",
- StringPrintf("%" PRIx64, peak_resident_set_bytes_));
- value->SetBoolean("is_peak_rss_resetable", is_peak_rss_resetable_);
- }
-
- for (const auto it : extra_fields_) {
- value->SetString(it.first, StringPrintf("%" PRIx64, it.second));
- }
-}
-
-void ProcessMemoryTotals::Clear() {
- resident_set_bytes_ = 0;
-}
-
-void ProcessMemoryTotals::SetExtraFieldInBytes(const char* name,
- uint64_t value) {
- DCHECK_EQ(0u, extra_fields_.count(name));
- extra_fields_[name] = value;
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/process_memory_totals.h b/base/trace_event/process_memory_totals.h
deleted file mode 100644
index 329967a6ee..0000000000
--- a/base/trace_event/process_memory_totals.h
+++ /dev/null
@@ -1,63 +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.
-
-#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
-#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
-
-#include <stdint.h>
-
-#include <map>
-
-#include "base/base_export.h"
-#include "base/macros.h"
-
-namespace base {
-namespace trace_event {
-
-class TracedValue;
-
-// Data model for process-wide memory stats.
-class BASE_EXPORT ProcessMemoryTotals {
- public:
- ProcessMemoryTotals();
- ~ProcessMemoryTotals();
-
- // Called at trace generation time to populate the TracedValue.
- void AsValueInto(TracedValue* value) const;
-
- // Clears up all the data collected.
- void Clear();
-
- uint64_t resident_set_bytes() const { return resident_set_bytes_; }
- void set_resident_set_bytes(uint64_t value) { resident_set_bytes_ = value; }
-
- uint64_t peak_resident_set_bytes() const { return peak_resident_set_bytes_; }
- void set_peak_resident_set_bytes(uint64_t value) {
- peak_resident_set_bytes_ = value;
- }
-
- // On some platforms (recent linux kernels, see goo.gl/sMvAVz) the peak rss
- // can be reset. When is_peak_rss_resettable == true, the peak refers to
- // peak from the previous measurement. When false, it is the absolute peak
- // since the start of the process.
- bool is_peak_rss_resetable() const { return is_peak_rss_resetable_; }
- void set_is_peak_rss_resetable(bool value) { is_peak_rss_resetable_ = value; }
-
- void SetExtraFieldInBytes(const char* name, uint64_t value);
-
- private:
- uint64_t resident_set_bytes_;
- uint64_t peak_resident_set_bytes_;
- bool is_peak_rss_resetable_;
-
- // Extra metrics for OS-specific statistics.
- std::map<const char*, uint64_t> extra_fields_;
-
- DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotals);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
diff --git a/base/trace_event/trace_buffer.cc b/base/trace_event/trace_buffer.cc
deleted file mode 100644
index e26e9fd28f..0000000000
--- a/base/trace_event/trace_buffer.cc
+++ /dev/null
@@ -1,345 +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/trace_buffer.h"
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/trace_event/heap_profiler.h"
-#include "base/trace_event/trace_event_impl.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-class TraceBufferRingBuffer : public TraceBuffer {
- public:
- TraceBufferRingBuffer(size_t max_chunks)
- : max_chunks_(max_chunks),
- recyclable_chunks_queue_(new size_t[queue_capacity()]),
- queue_head_(0),
- queue_tail_(max_chunks),
- current_iteration_index_(0),
- current_chunk_seq_(1) {
- chunks_.reserve(max_chunks);
- for (size_t i = 0; i < max_chunks; ++i)
- recyclable_chunks_queue_[i] = i;
- }
-
- std::unique_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
- HEAP_PROFILER_SCOPED_IGNORE;
-
- // Because the number of threads is much less than the number of chunks,
- // the queue should never be empty.
- DCHECK(!QueueIsEmpty());
-
- *index = recyclable_chunks_queue_[queue_head_];
- queue_head_ = NextQueueIndex(queue_head_);
- current_iteration_index_ = queue_head_;
-
- if (*index >= chunks_.size())
- chunks_.resize(*index + 1);
-
- TraceBufferChunk* chunk = chunks_[*index].release();
- chunks_[*index] = NULL; // Put NULL in the slot of a in-flight chunk.
- if (chunk)
- chunk->Reset(current_chunk_seq_++);
- else
- chunk = new TraceBufferChunk(current_chunk_seq_++);
-
- return std::unique_ptr<TraceBufferChunk>(chunk);
- }
-
- void ReturnChunk(size_t index,
- std::unique_ptr<TraceBufferChunk> chunk) override {
- // When this method is called, the queue should not be full because it
- // can contain all chunks including the one to be returned.
- DCHECK(!QueueIsFull());
- DCHECK(chunk);
- DCHECK_LT(index, chunks_.size());
- DCHECK(!chunks_[index]);
- chunks_[index] = std::move(chunk);
- recyclable_chunks_queue_[queue_tail_] = index;
- queue_tail_ = NextQueueIndex(queue_tail_);
- }
-
- bool IsFull() const override { return false; }
-
- size_t Size() const override {
- // This is approximate because not all of the chunks are full.
- return chunks_.size() * TraceBufferChunk::kTraceBufferChunkSize;
- }
-
- size_t Capacity() const override {
- return max_chunks_ * TraceBufferChunk::kTraceBufferChunkSize;
- }
-
- TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
- if (handle.chunk_index >= chunks_.size())
- return NULL;
- TraceBufferChunk* chunk = chunks_[handle.chunk_index].get();
- if (!chunk || chunk->seq() != handle.chunk_seq)
- return NULL;
- return chunk->GetEventAt(handle.event_index);
- }
-
- const TraceBufferChunk* NextChunk() override {
- if (chunks_.empty())
- return NULL;
-
- while (current_iteration_index_ != queue_tail_) {
- size_t chunk_index = recyclable_chunks_queue_[current_iteration_index_];
- current_iteration_index_ = NextQueueIndex(current_iteration_index_);
- if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
- continue;
- DCHECK(chunks_[chunk_index]);
- return chunks_[chunk_index].get();
- }
- return NULL;
- }
-
- void EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) override {
- overhead->Add("TraceBufferRingBuffer", sizeof(*this));
- for (size_t queue_index = queue_head_; queue_index != queue_tail_;
- queue_index = NextQueueIndex(queue_index)) {
- size_t chunk_index = recyclable_chunks_queue_[queue_index];
- if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
- continue;
- chunks_[chunk_index]->EstimateTraceMemoryOverhead(overhead);
- }
- }
-
- private:
- bool QueueIsEmpty() const { return queue_head_ == queue_tail_; }
-
- size_t QueueSize() const {
- return queue_tail_ > queue_head_
- ? queue_tail_ - queue_head_
- : queue_tail_ + queue_capacity() - queue_head_;
- }
-
- bool QueueIsFull() const { return QueueSize() == queue_capacity() - 1; }
-
- size_t queue_capacity() const {
- // One extra space to help distinguish full state and empty state.
- return max_chunks_ + 1;
- }
-
- size_t NextQueueIndex(size_t index) const {
- index++;
- if (index >= queue_capacity())
- index = 0;
- return index;
- }
-
- size_t max_chunks_;
- std::vector<std::unique_ptr<TraceBufferChunk>> chunks_;
-
- std::unique_ptr<size_t[]> recyclable_chunks_queue_;
- size_t queue_head_;
- size_t queue_tail_;
-
- size_t current_iteration_index_;
- uint32_t current_chunk_seq_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceBufferRingBuffer);
-};
-
-class TraceBufferVector : public TraceBuffer {
- public:
- TraceBufferVector(size_t max_chunks)
- : in_flight_chunk_count_(0),
- current_iteration_index_(0),
- max_chunks_(max_chunks) {
- chunks_.reserve(max_chunks_);
- }
-
- std::unique_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
- HEAP_PROFILER_SCOPED_IGNORE;
-
- // This function may be called when adding normal events or indirectly from
- // AddMetadataEventsWhileLocked(). We can not DECHECK(!IsFull()) because we
- // 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);
- ++in_flight_chunk_count_;
- // + 1 because zero chunk_seq is not allowed.
- return std::unique_ptr<TraceBufferChunk>(
- new TraceBufferChunk(static_cast<uint32_t>(*index) + 1));
- }
-
- void ReturnChunk(size_t index,
- std::unique_ptr<TraceBufferChunk> chunk) override {
- DCHECK_GT(in_flight_chunk_count_, 0u);
- DCHECK_LT(index, chunks_.size());
- DCHECK(!chunks_[index]);
- --in_flight_chunk_count_;
- chunks_[index] = std::move(chunk);
- }
-
- bool IsFull() const override { return chunks_.size() >= max_chunks_; }
-
- size_t Size() const override {
- // This is approximate because not all of the chunks are full.
- return chunks_.size() * TraceBufferChunk::kTraceBufferChunkSize;
- }
-
- size_t Capacity() const override {
- return max_chunks_ * TraceBufferChunk::kTraceBufferChunkSize;
- }
-
- TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
- if (handle.chunk_index >= chunks_.size())
- return NULL;
- TraceBufferChunk* chunk = chunks_[handle.chunk_index].get();
- if (!chunk || chunk->seq() != handle.chunk_seq)
- return NULL;
- return chunk->GetEventAt(handle.event_index);
- }
-
- const TraceBufferChunk* NextChunk() override {
- while (current_iteration_index_ < chunks_.size()) {
- // Skip in-flight chunks.
- const TraceBufferChunk* chunk = chunks_[current_iteration_index_++].get();
- if (chunk)
- return chunk;
- }
- return NULL;
- }
-
- void EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) override {
- const size_t chunks_ptr_vector_allocated_size =
- sizeof(*this) + max_chunks_ * sizeof(decltype(chunks_)::value_type);
- const size_t chunks_ptr_vector_resident_size =
- sizeof(*this) + chunks_.size() * sizeof(decltype(chunks_)::value_type);
- 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();
- // Skip the in-flight (nullptr) chunks. They will be accounted by the
- // per-thread-local dumpers, see ThreadLocalEventBuffer::OnMemoryDump.
- if (chunk)
- chunk->EstimateTraceMemoryOverhead(overhead);
- }
- }
-
- private:
- size_t in_flight_chunk_count_;
- size_t current_iteration_index_;
- size_t max_chunks_;
- std::vector<std::unique_ptr<TraceBufferChunk>> chunks_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceBufferVector);
-};
-
-} // namespace
-
-TraceBufferChunk::TraceBufferChunk(uint32_t seq) : next_free_(0), seq_(seq) {}
-
-TraceBufferChunk::~TraceBufferChunk() {}
-
-void TraceBufferChunk::Reset(uint32_t new_seq) {
- for (size_t i = 0; i < next_free_; ++i)
- chunk_[i].Reset();
- next_free_ = 0;
- seq_ = new_seq;
- cached_overhead_estimate_.reset();
-}
-
-TraceEvent* TraceBufferChunk::AddTraceEvent(size_t* event_index) {
- DCHECK(!IsFull());
- *event_index = next_free_++;
- return &chunk_[*event_index];
-}
-
-void TraceBufferChunk::EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) {
- if (!cached_overhead_estimate_) {
- cached_overhead_estimate_.reset(new TraceEventMemoryOverhead);
-
- // When estimating the size of TraceBufferChunk, exclude the array of trace
- // events, as they are computed individually below.
- cached_overhead_estimate_->Add("TraceBufferChunk",
- sizeof(*this) - sizeof(chunk_));
- }
-
- const size_t num_cached_estimated_events =
- cached_overhead_estimate_->GetCount("TraceEvent");
- DCHECK_LE(num_cached_estimated_events, size());
-
- if (IsFull() && num_cached_estimated_events == size()) {
- overhead->Update(*cached_overhead_estimate_);
- return;
- }
-
- for (size_t i = num_cached_estimated_events; i < size(); ++i)
- chunk_[i].EstimateTraceMemoryOverhead(cached_overhead_estimate_.get());
-
- if (IsFull()) {
- cached_overhead_estimate_->AddSelf();
- } else {
- // The unused TraceEvents in |chunks_| are not cached. They will keep
- // changing as new TraceEvents are added to this chunk, so they are
- // computed on the fly.
- const size_t num_unused_trace_events = capacity() - size();
- overhead->Add("TraceEvent (unused)",
- num_unused_trace_events * sizeof(TraceEvent));
- }
-
- overhead->Update(*cached_overhead_estimate_);
-}
-
-TraceResultBuffer::OutputCallback
-TraceResultBuffer::SimpleOutput::GetCallback() {
- return Bind(&SimpleOutput::Append, Unretained(this));
-}
-
-void TraceResultBuffer::SimpleOutput::Append(
- const std::string& json_trace_output) {
- json_output += json_trace_output;
-}
-
-TraceResultBuffer::TraceResultBuffer() : append_comma_(false) {}
-
-TraceResultBuffer::~TraceResultBuffer() {}
-
-void TraceResultBuffer::SetOutputCallback(
- const OutputCallback& json_chunk_callback) {
- output_callback_ = json_chunk_callback;
-}
-
-void TraceResultBuffer::Start() {
- append_comma_ = false;
- output_callback_.Run("[");
-}
-
-void TraceResultBuffer::AddFragment(const std::string& trace_fragment) {
- if (append_comma_)
- output_callback_.Run(",");
- append_comma_ = true;
- output_callback_.Run(trace_fragment);
-}
-
-void TraceResultBuffer::Finish() {
- output_callback_.Run("]");
-}
-
-TraceBuffer* TraceBuffer::CreateTraceBufferRingBuffer(size_t max_chunks) {
- return new TraceBufferRingBuffer(max_chunks);
-}
-
-TraceBuffer* TraceBuffer::CreateTraceBufferVectorOfSize(size_t max_chunks) {
- return new TraceBufferVector(max_chunks);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/trace_buffer.h b/base/trace_event/trace_buffer.h
deleted file mode 100644
index 4885a3c7c0..0000000000
--- a/base/trace_event/trace_buffer.h
+++ /dev/null
@@ -1,130 +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.
-
-#ifndef BASE_TRACE_EVENT_TRACE_BUFFER_H_
-#define BASE_TRACE_EVENT_TRACE_BUFFER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/base_export.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_impl.h"
-
-namespace base {
-
-namespace trace_event {
-
-// TraceBufferChunk is the basic unit of TraceBuffer.
-class BASE_EXPORT TraceBufferChunk {
- public:
- explicit TraceBufferChunk(uint32_t seq);
- ~TraceBufferChunk();
-
- void Reset(uint32_t new_seq);
- TraceEvent* AddTraceEvent(size_t* event_index);
- bool IsFull() const { return next_free_ == kTraceBufferChunkSize; }
-
- uint32_t seq() const { return seq_; }
- size_t capacity() const { return kTraceBufferChunkSize; }
- size_t size() const { return next_free_; }
-
- TraceEvent* GetEventAt(size_t index) {
- DCHECK(index < size());
- return &chunk_[index];
- }
- const TraceEvent* GetEventAt(size_t index) const {
- DCHECK(index < size());
- return &chunk_[index];
- }
-
- void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
-
- // These values must be kept consistent with the numbers of bits of
- // chunk_index and event_index fields in TraceEventHandle
- // (in trace_event_impl.h).
- static const size_t kMaxChunkIndex = (1u << 26) - 1;
- static const size_t kTraceBufferChunkSize = 64;
-
- private:
- size_t next_free_;
- std::unique_ptr<TraceEventMemoryOverhead> cached_overhead_estimate_;
- TraceEvent chunk_[kTraceBufferChunkSize];
- uint32_t seq_;
-};
-
-// TraceBuffer holds the events as they are collected.
-class BASE_EXPORT TraceBuffer {
- public:
- virtual ~TraceBuffer() {}
-
- virtual std::unique_ptr<TraceBufferChunk> GetChunk(size_t* index) = 0;
- virtual void ReturnChunk(size_t index,
- std::unique_ptr<TraceBufferChunk> chunk) = 0;
-
- virtual bool IsFull() const = 0;
- virtual size_t Size() const = 0;
- virtual size_t Capacity() const = 0;
- virtual TraceEvent* GetEventByHandle(TraceEventHandle handle) = 0;
-
- // For iteration. Each TraceBuffer can only be iterated once.
- virtual const TraceBufferChunk* NextChunk() = 0;
-
-
- // Computes an estimate of the size of the buffer, including all the retained
- // objects.
- virtual void EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) = 0;
-
- static TraceBuffer* CreateTraceBufferRingBuffer(size_t max_chunks);
- static TraceBuffer* CreateTraceBufferVectorOfSize(size_t max_chunks);
-};
-
-// TraceResultBuffer collects and converts trace fragments returned by TraceLog
-// to JSON output.
-class BASE_EXPORT TraceResultBuffer {
- public:
- typedef base::Callback<void(const std::string&)> OutputCallback;
-
- // If you don't need to stream JSON chunks out efficiently, and just want to
- // get a complete JSON string after calling Finish, use this struct to collect
- // JSON trace output.
- struct BASE_EXPORT SimpleOutput {
- OutputCallback GetCallback();
- void Append(const std::string& json_string);
-
- // Do what you want with the json_output_ string after calling
- // TraceResultBuffer::Finish.
- std::string json_output;
- };
-
- TraceResultBuffer();
- ~TraceResultBuffer();
-
- // Set callback. The callback will be called during Start with the initial
- // JSON output and during AddFragment and Finish with following JSON output
- // chunks. The callback target must live past the last calls to
- // TraceResultBuffer::Start/AddFragment/Finish.
- void SetOutputCallback(const OutputCallback& json_chunk_callback);
-
- // Start JSON output. This resets all internal state, so you can reuse
- // the TraceResultBuffer by calling Start.
- void Start();
-
- // Call AddFragment 0 or more times to add trace fragments from TraceLog.
- void AddFragment(const std::string& trace_fragment);
-
- // When all fragments have been added, call Finish to complete the JSON
- // formatted output.
- void Finish();
-
- private:
- OutputCallback output_callback_;
- bool append_comma_;
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_TRACE_BUFFER_H_
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
deleted file mode 100644
index 7ee9a4a101..0000000000
--- a/base/trace_event/trace_config.cc
+++ /dev/null
@@ -1,592 +0,0 @@
-// Copyright (c) 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/trace_config.h"
-
-#include <stddef.h>
-
-#include <utility>
-
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/string_split.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/memory_dump_request_args.h"
-#include "base/trace_event/trace_event.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-// String options that can be used to initialize TraceOptions.
-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 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 kEnableSystraceParam[] = "enable_systrace";
-const char kEnableArgumentFilterParam[] = "enable_argument_filter";
-
-// String parameters that is used to parse memory dump config in trace config
-// string.
-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 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};
-const TraceConfig::MemoryDumpConfig::Trigger kDefaultLightMemoryDumpTrigger = {
- 250, // min_time_between_dumps_ms
- MemoryDumpLevelOfDetail::LIGHT, MemoryDumpType::PERIODIC_INTERVAL};
-
-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 {
- out->append(trace_config_.ToString());
- }
-
- private:
- const TraceConfig trace_config_;
-};
-
-std::set<MemoryDumpLevelOfDetail> GetDefaultAllowedMemoryDumpModes() {
- std::set<MemoryDumpLevelOfDetail> all_modes;
- for (uint32_t mode = static_cast<uint32_t>(MemoryDumpLevelOfDetail::FIRST);
- mode <= static_cast<uint32_t>(MemoryDumpLevelOfDetail::LAST); mode++) {
- all_modes.insert(static_cast<MemoryDumpLevelOfDetail>(mode));
- }
- return all_modes;
-}
-
-} // namespace
-
-TraceConfig::MemoryDumpConfig::HeapProfiler::HeapProfiler()
- : breakdown_threshold_bytes(kDefaultBreakdownThresholdBytes) {}
-
-void TraceConfig::MemoryDumpConfig::HeapProfiler::Clear() {
- breakdown_threshold_bytes = kDefaultBreakdownThresholdBytes;
-}
-
-void TraceConfig::ResetMemoryDumpConfig(
- const TraceConfig::MemoryDumpConfig& memory_dump_config) {
- memory_dump_config_.Clear();
- memory_dump_config_ = memory_dump_config;
-}
-
-TraceConfig::MemoryDumpConfig::MemoryDumpConfig() {}
-
-TraceConfig::MemoryDumpConfig::MemoryDumpConfig(
- const MemoryDumpConfig& other) = default;
-
-TraceConfig::MemoryDumpConfig::~MemoryDumpConfig() {}
-
-void TraceConfig::MemoryDumpConfig::Clear() {
- allowed_dump_modes.clear();
- triggers.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_;
- category_filter_ = rhs.category_filter_;
-
- if (rhs.args_)
- args_ = rhs.args_->CreateDeepCopy();
-
- return *this;
-}
-
-void TraceConfig::EventFilterConfig::InitializeFromConfigDict(
- const base::DictionaryValue* event_filter) {
- category_filter_.InitializeFromConfigDict(*event_filter);
-
- const base::DictionaryValue* args_dict = nullptr;
- if (event_filter->GetDictionary(kFilterArgsParam, &args_dict))
- args_ = args_dict->CreateDeepCopy();
-}
-
-void TraceConfig::EventFilterConfig::SetCategoryFilter(
- const TraceConfigCategoryFilter& category_filter) {
- category_filter_ = category_filter;
-}
-
-void TraceConfig::EventFilterConfig::ToDict(
- DictionaryValue* filter_dict) const {
- filter_dict->SetString(kFilterPredicateParam, predicate_name());
-
- category_filter_.ToDict(filter_dict);
-
- if (args_)
- filter_dict->Set(kFilterArgsParam, args_->CreateDeepCopy());
-}
-
-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 StringPiece& category_group_name) const {
- return category_filter_.IsCategoryGroupEnabled(category_group_name);
-}
-
-TraceConfig::TraceConfig() {
- InitializeDefault();
-}
-
-TraceConfig::TraceConfig(StringPiece category_filter_string,
- StringPiece trace_options_string) {
- InitializeFromStrings(category_filter_string, trace_options_string);
-}
-
-TraceConfig::TraceConfig(StringPiece category_filter_string,
- TraceRecordMode record_mode) {
- std::string trace_options_string;
- switch (record_mode) {
- case RECORD_UNTIL_FULL:
- trace_options_string = kRecordUntilFull;
- break;
- case RECORD_CONTINUOUSLY:
- trace_options_string = kRecordContinuously;
- break;
- case RECORD_AS_MUCH_AS_POSSIBLE:
- trace_options_string = kRecordAsMuchAsPossible;
- break;
- case ECHO_TO_CONSOLE:
- trace_options_string = kTraceToConsole;
- break;
- default:
- NOTREACHED();
- }
- InitializeFromStrings(category_filter_string, trace_options_string);
-}
-
-TraceConfig::TraceConfig(const DictionaryValue& config) {
- InitializeFromConfigDict(config);
-}
-
-TraceConfig::TraceConfig(StringPiece config_string) {
- if (!config_string.empty())
- InitializeFromConfigString(config_string);
- else
- InitializeDefault();
-}
-
-TraceConfig::TraceConfig(const TraceConfig& tc)
- : record_mode_(tc.record_mode_),
- enable_systrace_(tc.enable_systrace_),
- enable_argument_filter_(tc.enable_argument_filter_),
- category_filter_(tc.category_filter_),
- memory_dump_config_(tc.memory_dump_config_),
- event_filters_(tc.event_filters_) {}
-
-TraceConfig::~TraceConfig() {
-}
-
-TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
- if (this == &rhs)
- return *this;
-
- record_mode_ = rhs.record_mode_;
- enable_systrace_ = rhs.enable_systrace_;
- enable_argument_filter_ = rhs.enable_argument_filter_;
- category_filter_ = rhs.category_filter_;
- memory_dump_config_ = rhs.memory_dump_config_;
- event_filters_ = rhs.event_filters_;
- return *this;
-}
-
-const TraceConfig::StringList& TraceConfig::GetSyntheticDelayValues() const {
- return category_filter_.synthetic_delays();
-}
-
-std::string TraceConfig::ToString() const {
- std::unique_ptr<DictionaryValue> dict = ToDict();
- std::string json;
- JSONWriter::Write(*dict, &json);
- return json;
-}
-
-std::unique_ptr<ConvertableToTraceFormat>
-TraceConfig::AsConvertableToTraceFormat() const {
- return MakeUnique<ConvertableTraceConfigToTraceFormat>(*this);
-}
-
-std::string TraceConfig::ToCategoryFilterString() const {
- return category_filter_.ToFilterString();
-}
-
-bool TraceConfig::IsCategoryGroupEnabled(
- const StringPiece& category_group_name) const {
- // TraceLog should call this method only as part of enabling/disabling
- // categories.
- return category_filter_.IsCategoryGroupEnabled(category_group_name);
-}
-
-void TraceConfig::Merge(const TraceConfig& config) {
- if (record_mode_ != config.record_mode_
- || enable_systrace_ != config.enable_systrace_
- || enable_argument_filter_ != config.enable_argument_filter_) {
- DLOG(ERROR) << "Attempting to merge trace config with a different "
- << "set of options.";
- }
-
- category_filter_.Merge(config.category_filter_);
-
- memory_dump_config_.Merge(config.memory_dump_config_);
-
- event_filters_.insert(event_filters_.end(), config.event_filters().begin(),
- config.event_filters().end());
-}
-
-void TraceConfig::Clear() {
- record_mode_ = RECORD_UNTIL_FULL;
- enable_systrace_ = false;
- enable_argument_filter_ = false;
- category_filter_.Clear();
- memory_dump_config_.Clear();
- event_filters_.clear();
-}
-
-void TraceConfig::InitializeDefault() {
- record_mode_ = RECORD_UNTIL_FULL;
- enable_systrace_ = false;
- enable_argument_filter_ = false;
-}
-
-void TraceConfig::InitializeFromConfigDict(const DictionaryValue& dict) {
- record_mode_ = RECORD_UNTIL_FULL;
- std::string record_mode;
- if (dict.GetString(kRecordModeParam, &record_mode)) {
- if (record_mode == kRecordUntilFull) {
- record_mode_ = RECORD_UNTIL_FULL;
- } else if (record_mode == kRecordContinuously) {
- record_mode_ = RECORD_CONTINUOUSLY;
- } else if (record_mode == kTraceToConsole) {
- record_mode_ = ECHO_TO_CONSOLE;
- } else if (record_mode == kRecordAsMuchAsPossible) {
- record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
- }
- }
-
- bool val;
- enable_systrace_ = dict.GetBoolean(kEnableSystraceParam, &val) ? val : false;
- enable_argument_filter_ =
- dict.GetBoolean(kEnableArgumentFilterParam, &val) ? val : false;
-
- category_filter_.InitializeFromConfigDict(dict);
-
- const base::ListValue* category_event_filters = nullptr;
- if (dict.GetList(kEventFiltersParam, &category_event_filters))
- SetEventFiltersFromConfigList(*category_event_filters);
-
- if (category_filter_.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.
- const DictionaryValue* memory_dump_config = nullptr;
- if (dict.GetDictionary(kMemoryDumpConfigParam, &memory_dump_config))
- SetMemoryDumpConfigFromConfigDict(*memory_dump_config);
- else
- SetDefaultMemoryDumpConfig();
- }
-}
-
-void TraceConfig::InitializeFromConfigString(StringPiece config_string) {
- auto dict = DictionaryValue::From(JSONReader::Read(config_string));
- if (dict)
- InitializeFromConfigDict(*dict);
- else
- InitializeDefault();
-}
-
-void TraceConfig::InitializeFromStrings(StringPiece category_filter_string,
- StringPiece trace_options_string) {
- if (!category_filter_string.empty())
- category_filter_.InitializeFromString(category_filter_string);
-
- record_mode_ = RECORD_UNTIL_FULL;
- enable_systrace_ = false;
- enable_argument_filter_ = false;
- if (!trace_options_string.empty()) {
- std::vector<std::string> split =
- SplitString(trace_options_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
- for (const std::string& token : split) {
- if (token == kRecordUntilFull) {
- record_mode_ = RECORD_UNTIL_FULL;
- } else if (token == kRecordContinuously) {
- record_mode_ = RECORD_CONTINUOUSLY;
- } else if (token == kTraceToConsole) {
- record_mode_ = ECHO_TO_CONSOLE;
- } else if (token == kRecordAsMuchAsPossible) {
- record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
- } else if (token == kEnableSystrace) {
- enable_systrace_ = true;
- } else if (token == kEnableArgumentFilter) {
- enable_argument_filter_ = true;
- }
- }
- }
-
- if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
- SetDefaultMemoryDumpConfig();
- }
-}
-
-void TraceConfig::SetMemoryDumpConfigFromConfigDict(
- const DictionaryValue& memory_dump_config) {
- // Set allowed dump modes.
- memory_dump_config_.allowed_dump_modes.clear();
- const ListValue* allowed_modes_list;
- if (memory_dump_config.GetList(kAllowedDumpModesParam, &allowed_modes_list)) {
- for (size_t i = 0; i < allowed_modes_list->GetSize(); ++i) {
- std::string level_of_detail_str;
- allowed_modes_list->GetString(i, &level_of_detail_str);
- memory_dump_config_.allowed_dump_modes.insert(
- StringToMemoryDumpLevelOfDetail(level_of_detail_str));
- }
- } else {
- // If allowed modes param is not given then allow all modes by default.
- memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
- }
-
- // Set triggers
- memory_dump_config_.triggers.clear();
- const ListValue* trigger_list = nullptr;
- if (memory_dump_config.GetList(kTriggersParam, &trigger_list) &&
- trigger_list->GetSize() > 0) {
- for (size_t i = 0; i < trigger_list->GetSize(); ++i) {
- const DictionaryValue* trigger = nullptr;
- 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);
-
- std::string level_of_detail_str;
- trigger->GetString(kTriggerModeParam, &level_of_detail_str);
- dump_config.level_of_detail =
- StringToMemoryDumpLevelOfDetail(level_of_detail_str);
-
- memory_dump_config_.triggers.push_back(dump_config);
- }
- }
-
- // Set heap profiler options
- const DictionaryValue* heap_profiler_options = nullptr;
- if (memory_dump_config.GetDictionary(kHeapProfilerOptions,
- &heap_profiler_options)) {
- int min_size_bytes = 0;
- if (heap_profiler_options->GetInteger(kBreakdownThresholdBytes,
- &min_size_bytes)
- && min_size_bytes >= 0) {
- memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
- static_cast<size_t>(min_size_bytes);
- } else {
- memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
- MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes;
- }
- }
-}
-
-void TraceConfig::SetDefaultMemoryDumpConfig() {
- memory_dump_config_.Clear();
- memory_dump_config_.triggers.push_back(kDefaultHeavyMemoryDumpTrigger);
- memory_dump_config_.triggers.push_back(kDefaultLightMemoryDumpTrigger);
- 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);
- new_config.InitializeFromConfigDict(event_filter);
- event_filters_.push_back(new_config);
- }
-}
-
-std::unique_ptr<DictionaryValue> TraceConfig::ToDict() const {
- auto dict = MakeUnique<DictionaryValue>();
- switch (record_mode_) {
- case RECORD_UNTIL_FULL:
- dict->SetString(kRecordModeParam, kRecordUntilFull);
- break;
- case RECORD_CONTINUOUSLY:
- dict->SetString(kRecordModeParam, kRecordContinuously);
- break;
- case RECORD_AS_MUCH_AS_POSSIBLE:
- dict->SetString(kRecordModeParam, kRecordAsMuchAsPossible);
- break;
- case ECHO_TO_CONSOLE:
- dict->SetString(kRecordModeParam, kTraceToConsole);
- break;
- default:
- NOTREACHED();
- }
-
- dict->SetBoolean(kEnableSystraceParam, enable_systrace_);
- dict->SetBoolean(kEnableArgumentFilterParam, enable_argument_filter_);
-
- category_filter_.ToDict(dict.get());
-
- 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.ToDict(filter_dict.get());
- filter_list->Append(std::move(filter_dict));
- }
- dict->Set(kEventFiltersParam, std::move(filter_list));
- }
-
- if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
- auto allowed_modes = MakeUnique<ListValue>();
- for (auto dump_mode : memory_dump_config_.allowed_dump_modes)
- allowed_modes->AppendString(MemoryDumpLevelOfDetailToString(dump_mode));
-
- auto memory_dump_config = MakeUnique<DictionaryValue>();
- memory_dump_config->Set(kAllowedDumpModesParam, std::move(allowed_modes));
-
- 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->SetString(
- kTriggerModeParam,
- MemoryDumpLevelOfDetailToString(config.level_of_detail));
- triggers_list->Append(std::move(trigger_dict));
- }
-
- // Empty triggers will still be specified explicitly since it means that
- // the periodic dumps are not enabled.
- memory_dump_config->Set(kTriggersParam, std::move(triggers_list));
-
- if (memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes !=
- MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes) {
- auto options = MakeUnique<DictionaryValue>();
- options->SetInteger(
- kBreakdownThresholdBytes,
- memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes);
- memory_dump_config->Set(kHeapProfilerOptions, std::move(options));
- }
- dict->Set(kMemoryDumpConfigParam, std::move(memory_dump_config));
- }
- return dict;
-}
-
-std::string TraceConfig::ToTraceOptionsString() const {
- std::string ret;
- switch (record_mode_) {
- case RECORD_UNTIL_FULL:
- ret = kRecordUntilFull;
- break;
- case RECORD_CONTINUOUSLY:
- ret = kRecordContinuously;
- break;
- case RECORD_AS_MUCH_AS_POSSIBLE:
- ret = kRecordAsMuchAsPossible;
- break;
- case ECHO_TO_CONSOLE:
- ret = kTraceToConsole;
- break;
- default:
- NOTREACHED();
- }
- if (enable_systrace_)
- ret = ret + "," + kEnableSystrace;
- if (enable_argument_filter_)
- ret = ret + "," + kEnableArgumentFilter;
- return ret;
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/trace_config.h b/base/trace_event/trace_config.h
deleted file mode 100644
index 13b2f5f0ee..0000000000
--- a/base/trace_event/trace_config.h
+++ /dev/null
@@ -1,300 +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.
-
-#ifndef BASE_TRACE_EVENT_TRACE_CONFIG_H_
-#define BASE_TRACE_EVENT_TRACE_CONFIG_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <set>
-#include <string>
-#include <unordered_set>
-#include <vector>
-
-#include "base/base_export.h"
-#include "base/gtest_prod_util.h"
-#include "base/strings/string_piece.h"
-#include "base/trace_event/memory_dump_request_args.h"
-#include "base/trace_event/trace_config_category_filter.h"
-#include "base/values.h"
-
-namespace base {
-namespace trace_event {
-
-class ConvertableToTraceFormat;
-
-// Options determines how the trace buffer stores data.
-enum TraceRecordMode {
- // Record until the trace buffer is full.
- RECORD_UNTIL_FULL,
-
- // Record until the user ends the trace. The trace buffer is a fixed size
- // and we use it as a ring buffer during recording.
- RECORD_CONTINUOUSLY,
-
- // Record until the trace buffer is full, but with a huge buffer size.
- RECORD_AS_MUCH_AS_POSSIBLE,
-
- // Echo to console. Events are discarded.
- ECHO_TO_CONSOLE,
-};
-
-class BASE_EXPORT TraceConfig {
- public:
- using StringList = std::vector<std::string>;
-
- // Specifies the memory dump config for tracing.
- // Used only when "memory-infra" category is enabled.
- struct BASE_EXPORT MemoryDumpConfig {
- MemoryDumpConfig();
- MemoryDumpConfig(const MemoryDumpConfig& other);
- ~MemoryDumpConfig();
-
- // Specifies the triggers in the memory dump config.
- struct Trigger {
- uint32_t min_time_between_dumps_ms;
- MemoryDumpLevelOfDetail level_of_detail;
- MemoryDumpType trigger_type;
- };
-
- // Specifies the configuration options for the heap profiler.
- struct HeapProfiler {
- // Default value for |breakdown_threshold_bytes|.
- enum { kDefaultBreakdownThresholdBytes = 1024 };
-
- HeapProfiler();
-
- // Reset the options to default.
- void Clear();
-
- uint32_t breakdown_threshold_bytes;
- };
-
- // 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.
- std::set<MemoryDumpLevelOfDetail> allowed_dump_modes;
-
- std::vector<Trigger> triggers;
- 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 InitializeFromConfigDict(const base::DictionaryValue* event_filter);
-
- void SetCategoryFilter(const TraceConfigCategoryFilter& category_filter);
-
- void ToDict(DictionaryValue* filter_dict) const;
-
- bool GetArgAsSet(const char* key, std::unordered_set<std::string>*) const;
-
- bool IsCategoryGroupEnabled(const StringPiece& category_group_name) const;
-
- const std::string& predicate_name() const { return predicate_name_; }
- base::DictionaryValue* filter_args() const { return args_.get(); }
- const TraceConfigCategoryFilter& category_filter() const {
- return category_filter_;
- }
-
- private:
- std::string predicate_name_;
- TraceConfigCategoryFilter category_filter_;
- std::unique_ptr<base::DictionaryValue> args_;
- };
- typedef std::vector<EventFilterConfig> EventFilters;
-
- TraceConfig();
-
- // Create TraceConfig object from category filter and trace options strings.
- //
- // |category_filter_string| is a comma-delimited list of category wildcards.
- // A category can have an optional '-' prefix to make it an excluded category.
- // All the same rules apply above, so for example, having both included and
- // excluded categories in the same list would not be supported.
- //
- // Category filters can also be used to configure synthetic delays.
- //
- // |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".
- // 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
- // |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");
- // Example: TraceConfig("-excluded_category1,-excluded_category2",
- // "record-until-full, trace-to-console");
- // would set ECHO_TO_CONSOLE as the recording mode.
- // Example: TraceConfig("-*,webkit", "");
- // would disable everything but webkit; and use default options.
- // Example: TraceConfig("-webkit", "");
- // would enable everything but webkit; and use default options.
- // Example: TraceConfig("DELAY(gpu.PresentingFrame;16)", "");
- // would make swap buffers always take at least 16 ms; and use
- // default options.
- // Example: TraceConfig("DELAY(gpu.PresentingFrame;16;oneshot)", "");
- // would make swap buffers take at least 16 ms the first time it is
- // called; and use default options.
- // Example: TraceConfig("DELAY(gpu.PresentingFrame;16;alternating)", "");
- // would make swap buffers take at least 16 ms every other time it
- // is called; and use default options.
- TraceConfig(StringPiece category_filter_string,
- StringPiece trace_options_string);
-
- TraceConfig(StringPiece category_filter_string, TraceRecordMode record_mode);
-
- // Create TraceConfig object from the trace config string.
- //
- // |config_string| is a dictionary formatted as a JSON string, containing both
- // category filters and trace options.
- //
- // Example:
- // {
- // "record_mode": "record-continuously",
- // "enable_systrace": true,
- // "enable_argument_filter": true,
- // "included_categories": ["included",
- // "inc_pattern*",
- // "disabled-by-default-memory-infra"],
- // "excluded_categories": ["excluded", "exc_pattern*"],
- // "synthetic_delays": ["test.Delay1;16", "test.Delay2;32"],
- // "memory_dump_config": {
- // "triggers": [
- // {
- // "mode": "detailed",
- // "periodic_interval_ms": 2000
- // }
- // ]
- // }
- // }
- //
- // Note: memory_dump_config can be specified only if
- // disabled-by-default-memory-infra category is enabled.
- explicit TraceConfig(StringPiece config_string);
-
- // Functionally identical to the above, but takes a parsed dictionary as input
- // instead of its JSON serialization.
- explicit TraceConfig(const DictionaryValue& config);
-
- TraceConfig(const TraceConfig& tc);
-
- ~TraceConfig();
-
- TraceConfig& operator=(const TraceConfig& rhs);
-
- // Return a list of the synthetic delays specified in this category filter.
- const StringList& GetSyntheticDelayValues() const;
-
- TraceRecordMode GetTraceRecordMode() const { return record_mode_; }
- bool IsSystraceEnabled() const { return enable_systrace_; }
- bool IsArgumentFilterEnabled() const { return enable_argument_filter_; }
-
- void SetTraceRecordMode(TraceRecordMode mode) { record_mode_ = mode; }
- void EnableSystrace() { enable_systrace_ = true; }
- void EnableArgumentFilter() { enable_argument_filter_ = true; }
-
- // Writes the string representation of the TraceConfig. The string is JSON
- // formatted.
- std::string ToString() const;
-
- // Returns a copy of the TraceConfig wrapped in a ConvertableToTraceFormat
- std::unique_ptr<ConvertableToTraceFormat> AsConvertableToTraceFormat() const;
-
- // Write the string representation of the CategoryFilter part.
- std::string ToCategoryFilterString() const;
-
- // 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 StringPiece& category_group_name) const;
-
- // Merges config with the current TraceConfig
- void Merge(const TraceConfig& config);
-
- void Clear();
-
- // Clears and resets the memory dump config.
- void ResetMemoryDumpConfig(const MemoryDumpConfig& memory_dump_config);
-
- const TraceConfigCategoryFilter& category_filter() const {
- return category_filter_;
- }
-
- const MemoryDumpConfig& memory_dump_config() const {
- 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,
- TraceConfigFromInvalidLegacyStrings);
-
- // The default trace config, used when none is provided.
- // Allows all non-disabled-by-default categories through, except if they end
- // in the suffix 'Debug' or 'Test'.
- void InitializeDefault();
-
- // Initialize from a config dictionary.
- void InitializeFromConfigDict(const DictionaryValue& dict);
-
- // Initialize from a config string.
- void InitializeFromConfigString(StringPiece config_string);
-
- // Initialize from category filter and trace options strings
- void InitializeFromStrings(StringPiece category_filter_string,
- StringPiece trace_options_string);
-
- void SetMemoryDumpConfigFromConfigDict(
- const DictionaryValue& memory_dump_config);
- void SetDefaultMemoryDumpConfig();
-
- void SetEventFiltersFromConfigList(const base::ListValue& event_filters);
- std::unique_ptr<DictionaryValue> ToDict() const;
-
- std::string ToTraceOptionsString() const;
-
- TraceRecordMode record_mode_;
- bool enable_systrace_ : 1;
- bool enable_argument_filter_ : 1;
-
- TraceConfigCategoryFilter category_filter_;
-
- MemoryDumpConfig memory_dump_config_;
-
- EventFilters event_filters_;
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_TRACE_CONFIG_H_
diff --git a/base/trace_event/trace_config_category_filter.cc b/base/trace_event/trace_config_category_filter.cc
deleted file mode 100644
index 234db18c5c..0000000000
--- a/base/trace_event/trace_config_category_filter.cc
+++ /dev/null
@@ -1,297 +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/trace_config_category_filter.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/strings/pattern.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_tokenizer.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/trace_event/trace_event.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-const char kIncludedCategoriesParam[] = "included_categories";
-const char kExcludedCategoriesParam[] = "excluded_categories";
-const char kSyntheticDelaysParam[] = "synthetic_delays";
-
-const char kSyntheticDelayCategoryFilterPrefix[] = "DELAY(";
-}
-
-TraceConfigCategoryFilter::TraceConfigCategoryFilter() {}
-
-TraceConfigCategoryFilter::TraceConfigCategoryFilter(
- const TraceConfigCategoryFilter& other)
- : included_categories_(other.included_categories_),
- disabled_categories_(other.disabled_categories_),
- excluded_categories_(other.excluded_categories_),
- synthetic_delays_(other.synthetic_delays_) {}
-
-TraceConfigCategoryFilter::~TraceConfigCategoryFilter() {}
-
-TraceConfigCategoryFilter& TraceConfigCategoryFilter::operator=(
- const TraceConfigCategoryFilter& rhs) {
- included_categories_ = rhs.included_categories_;
- disabled_categories_ = rhs.disabled_categories_;
- excluded_categories_ = rhs.excluded_categories_;
- synthetic_delays_ = rhs.synthetic_delays_;
- return *this;
-}
-
-void TraceConfigCategoryFilter::InitializeFromString(
- const StringPiece& category_filter_string) {
- std::vector<StringPiece> split = SplitStringPiece(
- category_filter_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
- for (const StringPiece& category : split) {
- // Ignore empty categories.
- if (category.empty())
- continue;
- // Synthetic delays are of the form 'DELAY(delay;option;option;...)'.
- if (StartsWith(category, kSyntheticDelayCategoryFilterPrefix,
- CompareCase::SENSITIVE) &&
- category.back() == ')') {
- StringPiece synthetic_category = category.substr(
- strlen(kSyntheticDelayCategoryFilterPrefix),
- category.size() - strlen(kSyntheticDelayCategoryFilterPrefix) - 1);
- size_t name_length = synthetic_category.find(';');
- if (name_length != std::string::npos && name_length > 0 &&
- name_length != synthetic_category.size() - 1) {
- synthetic_delays_.push_back(synthetic_category.as_string());
- }
- } else if (category.front() == '-') {
- // Excluded categories start with '-'.
- // Remove '-' from category string.
- excluded_categories_.push_back(category.substr(1).as_string());
- } else if (category.starts_with(TRACE_DISABLED_BY_DEFAULT(""))) {
- disabled_categories_.push_back(category.as_string());
- } else {
- included_categories_.push_back(category.as_string());
- }
- }
-}
-
-void TraceConfigCategoryFilter::InitializeFromConfigDict(
- const DictionaryValue& dict) {
- const ListValue* category_list = nullptr;
- if (dict.GetList(kIncludedCategoriesParam, &category_list))
- SetCategoriesFromIncludedList(*category_list);
- if (dict.GetList(kExcludedCategoriesParam, &category_list))
- SetCategoriesFromExcludedList(*category_list);
- if (dict.GetList(kSyntheticDelaysParam, &category_list))
- SetSyntheticDelaysFromList(*category_list);
-}
-
-bool TraceConfigCategoryFilter::IsCategoryGroupEnabled(
- const StringPiece& category_group_name) const {
- bool had_enabled_by_default = false;
- DCHECK(!category_group_name.empty());
- CStringTokenizer category_group_tokens(category_group_name.begin(),
- category_group_name.end(), ",");
- while (category_group_tokens.GetNext()) {
- StringPiece category_group_token = category_group_tokens.token_piece();
- // Don't allow empty tokens, nor tokens with leading or trailing space.
- DCHECK(IsCategoryNameAllowed(category_group_token))
- << "Disallowed category string";
- if (IsCategoryEnabled(category_group_token))
- return true;
-
- if (!MatchPattern(category_group_token, TRACE_DISABLED_BY_DEFAULT("*")))
- had_enabled_by_default = true;
- }
- // Do a second pass to check for explicitly disabled categories
- // (those explicitly enabled have priority due to first pass).
- category_group_tokens.Reset();
- bool category_group_disabled = false;
- while (category_group_tokens.GetNext()) {
- StringPiece category_group_token = category_group_tokens.token_piece();
- for (const std::string& category : excluded_categories_) {
- if (MatchPattern(category_group_token, category)) {
- // Current token of category_group_name is present in excluded_list.
- // Flag the exclusion and proceed further to check if any of the
- // remaining categories of category_group_name is not present in the
- // excluded_ list.
- category_group_disabled = true;
- break;
- }
- // One of the category of category_group_name is not present in
- // excluded_ list. So, if it's not a disabled-by-default category,
- // it has to be included_ list. Enable the category_group_name
- // for recording.
- if (!MatchPattern(category_group_token, TRACE_DISABLED_BY_DEFAULT("*")))
- category_group_disabled = false;
- }
- // One of the categories present in category_group_name is not present in
- // excluded_ list. Implies this category_group_name group can be enabled
- // for recording, since one of its groups is enabled for recording.
- if (!category_group_disabled)
- break;
- }
- // If the category group is not excluded, and there are no included patterns
- // we consider this category group enabled, as long as it had categories
- // other than disabled-by-default.
- return !category_group_disabled && had_enabled_by_default &&
- included_categories_.empty();
-}
-
-bool TraceConfigCategoryFilter::IsCategoryEnabled(
- const StringPiece& category_name) const {
- // Check the disabled- filters and the disabled-* wildcard first so that a
- // "*" filter does not include the disabled.
- for (const std::string& category : disabled_categories_) {
- if (MatchPattern(category_name, category))
- return true;
- }
-
- if (MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
- return false;
-
- for (const std::string& category : included_categories_) {
- if (MatchPattern(category_name, category))
- return true;
- }
-
- return false;
-}
-
-void TraceConfigCategoryFilter::Merge(const TraceConfigCategoryFilter& config) {
- // Keep included patterns only if both filters have an included entry.
- // Otherwise, one of the filter was specifying "*" and we want to honor the
- // broadest filter.
- if (!included_categories_.empty() && !config.included_categories_.empty()) {
- included_categories_.insert(included_categories_.end(),
- config.included_categories_.begin(),
- config.included_categories_.end());
- } else {
- included_categories_.clear();
- }
-
- disabled_categories_.insert(disabled_categories_.end(),
- config.disabled_categories_.begin(),
- config.disabled_categories_.end());
- excluded_categories_.insert(excluded_categories_.end(),
- config.excluded_categories_.begin(),
- config.excluded_categories_.end());
- synthetic_delays_.insert(synthetic_delays_.end(),
- config.synthetic_delays_.begin(),
- config.synthetic_delays_.end());
-}
-
-void TraceConfigCategoryFilter::Clear() {
- included_categories_.clear();
- disabled_categories_.clear();
- excluded_categories_.clear();
- synthetic_delays_.clear();
-}
-
-void TraceConfigCategoryFilter::ToDict(DictionaryValue* dict) const {
- StringList categories(included_categories_);
- categories.insert(categories.end(), disabled_categories_.begin(),
- disabled_categories_.end());
- AddCategoriesToDict(categories, kIncludedCategoriesParam, dict);
- AddCategoriesToDict(excluded_categories_, kExcludedCategoriesParam, dict);
- AddCategoriesToDict(synthetic_delays_, kSyntheticDelaysParam, dict);
-}
-
-std::string TraceConfigCategoryFilter::ToFilterString() const {
- std::string filter_string;
- WriteCategoryFilterString(included_categories_, &filter_string, true);
- WriteCategoryFilterString(disabled_categories_, &filter_string, true);
- WriteCategoryFilterString(excluded_categories_, &filter_string, false);
- WriteCategoryFilterString(synthetic_delays_, &filter_string);
- return filter_string;
-}
-
-void TraceConfigCategoryFilter::SetCategoriesFromIncludedList(
- const ListValue& included_list) {
- included_categories_.clear();
- for (size_t i = 0; i < included_list.GetSize(); ++i) {
- std::string category;
- if (!included_list.GetString(i, &category))
- continue;
- if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")),
- TRACE_DISABLED_BY_DEFAULT("")) == 0) {
- disabled_categories_.push_back(category);
- } else {
- included_categories_.push_back(category);
- }
- }
-}
-
-void TraceConfigCategoryFilter::SetCategoriesFromExcludedList(
- const ListValue& excluded_list) {
- excluded_categories_.clear();
- for (size_t i = 0; i < excluded_list.GetSize(); ++i) {
- std::string category;
- if (excluded_list.GetString(i, &category))
- excluded_categories_.push_back(category);
- }
-}
-
-void TraceConfigCategoryFilter::SetSyntheticDelaysFromList(
- const ListValue& list) {
- for (size_t i = 0; i < list.GetSize(); ++i) {
- std::string delay;
- if (!list.GetString(i, &delay))
- continue;
- // Synthetic delays are of the form "delay;option;option;...".
- size_t name_length = delay.find(';');
- if (name_length != std::string::npos && name_length > 0 &&
- name_length != delay.size() - 1) {
- synthetic_delays_.push_back(delay);
- }
- }
-}
-
-void TraceConfigCategoryFilter::AddCategoriesToDict(
- const StringList& categories,
- const char* param,
- DictionaryValue* dict) const {
- if (categories.empty())
- return;
-
- auto list = MakeUnique<ListValue>();
- for (const std::string& category : categories)
- list->AppendString(category);
- dict->Set(param, std::move(list));
-}
-
-void TraceConfigCategoryFilter::WriteCategoryFilterString(
- const StringList& values,
- std::string* out,
- bool included) const {
- bool prepend_comma = !out->empty();
- int token_cnt = 0;
- for (const std::string& category : values) {
- if (token_cnt > 0 || prepend_comma)
- StringAppendF(out, ",");
- StringAppendF(out, "%s%s", (included ? "" : "-"), category.c_str());
- ++token_cnt;
- }
-}
-
-void TraceConfigCategoryFilter::WriteCategoryFilterString(
- const StringList& delays,
- std::string* out) const {
- bool prepend_comma = !out->empty();
- int token_cnt = 0;
- for (const std::string& category : delays) {
- if (token_cnt > 0 || prepend_comma)
- StringAppendF(out, ",");
- StringAppendF(out, "%s%s)", kSyntheticDelayCategoryFilterPrefix,
- category.c_str());
- ++token_cnt;
- }
-}
-
-// static
-bool TraceConfigCategoryFilter::IsCategoryNameAllowed(StringPiece str) {
- return !str.empty() && str.front() != ' ' && str.back() != ' ';
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/trace_config_category_filter.h b/base/trace_event/trace_config_category_filter.h
deleted file mode 100644
index 0d7dba0374..0000000000
--- a/base/trace_event/trace_config_category_filter.h
+++ /dev/null
@@ -1,86 +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_TRACE_CONFIG_CATEGORY_FILTER_H_
-#define BASE_TRACE_EVENT_TRACE_CONFIG_CATEGORY_FILTER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/base_export.h"
-#include "base/strings/string_piece.h"
-#include "base/values.h"
-
-namespace base {
-namespace trace_event {
-
-// Configuration of categories enabled and disabled in TraceConfig.
-class BASE_EXPORT TraceConfigCategoryFilter {
- public:
- using StringList = std::vector<std::string>;
-
- TraceConfigCategoryFilter();
- TraceConfigCategoryFilter(const TraceConfigCategoryFilter& other);
- ~TraceConfigCategoryFilter();
-
- TraceConfigCategoryFilter& operator=(const TraceConfigCategoryFilter& rhs);
-
- // Initializes from category filter string. See TraceConfig constructor for
- // description of how to write category filter string.
- void InitializeFromString(const StringPiece& category_filter_string);
-
- // Initializes TraceConfigCategoryFilter object from the config dictionary.
- void InitializeFromConfigDict(const DictionaryValue& dict);
-
- // Merges this with category filter config.
- void Merge(const TraceConfigCategoryFilter& config);
- void Clear();
-
- // 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 StringPiece& category_group_name) const;
-
- // Returns true if the category is enabled according to this trace config.
- // This tells whether a category is enabled from the TraceConfig's
- // perspective. Please refer to IsCategoryGroupEnabled() to determine if a
- // category is enabled from the tracing runtime's perspective.
- bool IsCategoryEnabled(const StringPiece& category_name) const;
-
- void ToDict(DictionaryValue* dict) const;
-
- std::string ToFilterString() const;
-
- // Returns true if category name is a valid string.
- static bool IsCategoryNameAllowed(StringPiece str);
-
- const StringList& included_categories() const { return included_categories_; }
- const StringList& excluded_categories() const { return excluded_categories_; }
- const StringList& synthetic_delays() const { return synthetic_delays_; }
-
- private:
- void SetCategoriesFromIncludedList(const ListValue& included_list);
- void SetCategoriesFromExcludedList(const ListValue& excluded_list);
- void SetSyntheticDelaysFromList(const ListValue& list);
-
- void AddCategoriesToDict(const StringList& categories,
- const char* param,
- DictionaryValue* dict) const;
-
- void WriteCategoryFilterString(const StringList& values,
- std::string* out,
- bool included) const;
- void WriteCategoryFilterString(const StringList& delays,
- std::string* out) const;
-
- StringList included_categories_;
- StringList disabled_categories_;
- StringList excluded_categories_;
- StringList synthetic_delays_;
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_TRACE_CONFIG_CATEGORY_FILTER_H_
diff --git a/base/trace_event/trace_config_memory_test_util.h b/base/trace_event/trace_config_memory_test_util.h
deleted file mode 100644
index 744e8a8acc..0000000000
--- a/base/trace_event/trace_config_memory_test_util.h
+++ /dev/null
@@ -1,160 +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.
-
-#ifndef BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
-#define BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
-
-#include "base/strings/stringprintf.h"
-#include "base/trace_event/memory_dump_manager.h"
-
-namespace base {
-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);
- }
-
- 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);
- }
-
- static std::string GetTraceConfig_NoTriggers() {
- return StringPrintf(
- "{"
- "\"enable_argument_filter\":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);
- }
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
diff --git a/base/trace_event/trace_config_unittest.cc b/base/trace_event/trace_config_unittest.cc
deleted file mode 100644
index a856c27192..0000000000
--- a/base/trace_event/trace_config_unittest.cc
+++ /dev/null
@@ -1,708 +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 <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"
-#include "base/trace_event/trace_config_memory_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-const char kDefaultTraceConfigString[] =
- "{"
- "\"enable_argument_filter\":false,"
- "\"enable_systrace\":false,"
- "\"record_mode\":\"record-until-full\""
- "}";
-
-const char kCustomTraceConfigString[] =
- "{"
- "\"enable_argument_filter\":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\"],"
- "\"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\""
- "}"
- "]"
- "},"
- "\"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.IsSystraceEnabled());
- EXPECT_FALSE(tc.IsArgumentFilterEnabled());
-
- // Default trace config enables every category filter except the
- // disabled-by-default-* ones.
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1"));
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("not-excluded-category"));
- EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
-
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1,not-excluded-category"));
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1,disabled-by-default-cc"));
- EXPECT_FALSE(tc.IsCategoryGroupEnabled(
- "disabled-by-default-cc,disabled-by-default-cc2"));
-}
-
-} // namespace
-
-TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
- // From trace options strings
- TraceConfig config("", "record-until-full");
- EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
- 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.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.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.IsSystraceEnabled());
- EXPECT_FALSE(config.IsArgumentFilterEnabled());
- EXPECT_STREQ("record-as-much-as-possible",
- config.ToTraceOptionsString().c_str());
-
- config = TraceConfig("", "enable-systrace, record-continuously");
- EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
- EXPECT_TRUE(config.IsSystraceEnabled());
- EXPECT_FALSE(config.IsArgumentFilterEnabled());
- EXPECT_STREQ("record-continuously,enable-systrace",
- config.ToTraceOptionsString().c_str());
-
- config = TraceConfig("", "enable-argument-filter,record-as-much-as-possible");
- EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode());
- EXPECT_FALSE(config.IsSystraceEnabled());
- EXPECT_TRUE(config.IsArgumentFilterEnabled());
- EXPECT_STREQ("record-as-much-as-possible,enable-argument-filter",
- config.ToTraceOptionsString().c_str());
-
- config = TraceConfig(
- "",
- "enable-systrace,trace-to-console,enable-argument-filter");
- EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
- EXPECT_TRUE(config.IsSystraceEnabled());
- EXPECT_TRUE(config.IsArgumentFilterEnabled());
- EXPECT_STREQ(
- "trace-to-console,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.IsSystraceEnabled());
- EXPECT_FALSE(config.IsArgumentFilterEnabled());
- EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str());
-
- // From TraceRecordMode
- config = TraceConfig("", RECORD_UNTIL_FULL);
- EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
- 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.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.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.IsSystraceEnabled());
- EXPECT_FALSE(config.IsArgumentFilterEnabled());
- EXPECT_STREQ("record-as-much-as-possible",
- config.ToTraceOptionsString().c_str());
-
- // From category filter strings
- config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*", "");
- EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
- config.ToCategoryFilterString().c_str());
-
- config = TraceConfig("only_inc_cat", "");
- EXPECT_STREQ("only_inc_cat", config.ToCategoryFilterString().c_str());
-
- config = TraceConfig("-only_exc_cat", "");
- EXPECT_STREQ("-only_exc_cat", config.ToCategoryFilterString().c_str());
-
- config = TraceConfig("disabled-by-default-cc,-excluded", "");
- EXPECT_STREQ("disabled-by-default-cc,-excluded",
- config.ToCategoryFilterString().c_str());
-
- config = TraceConfig("disabled-by-default-cc,included", "");
- EXPECT_STREQ("included,disabled-by-default-cc",
- config.ToCategoryFilterString().c_str());
-
- config = TraceConfig("DELAY(test.Delay1;16),included", "");
- EXPECT_STREQ("included,DELAY(test.Delay1;16)",
- config.ToCategoryFilterString().c_str());
-
- // From both trace options and category filter strings
- config = TraceConfig("", "");
- EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
- 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");
- EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
- 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",
- 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 ");
- EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
- 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",
- config.ToTraceOptionsString().c_str());
-
- // From category filter string and TraceRecordMode
- config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*",
- RECORD_CONTINUOUSLY);
- EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
- EXPECT_FALSE(config.IsSystraceEnabled());
- EXPECT_FALSE(config.IsArgumentFilterEnabled());
- EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
- config.ToCategoryFilterString().c_str());
- EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str());
-}
-
-TEST(TraceConfigTest, TraceConfigFromInvalidLegacyStrings) {
- TraceConfig config("", "foo-bar-baz");
- EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
- 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("arbitrary-category", "foo-bar-baz, enable-systrace");
- EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
- EXPECT_TRUE(config.IsSystraceEnabled());
- EXPECT_FALSE(config.IsArgumentFilterEnabled());
- EXPECT_STREQ("arbitrary-category", config.ToCategoryFilterString().c_str());
- EXPECT_STREQ("record-until-full,enable-systrace",
- config.ToTraceOptionsString().c_str());
-
- const char* const configs[] = {
- "",
- "DELAY(",
- "DELAY(;",
- "DELAY(;)",
- "DELAY(test.Delay)",
- "DELAY(test.Delay;)"
- };
- for (size_t i = 0; i < arraysize(configs); i++) {
- TraceConfig tc(configs[i], "");
- EXPECT_EQ(0u, tc.GetSyntheticDelayValues().size());
- }
-}
-
-TEST(TraceConfigTest, ConstructDefaultTraceConfig) {
- TraceConfig tc;
- EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
- EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
- CheckDefaultTraceConfigBehavior(tc);
-
- // Constructors from category filter string and trace option string.
- TraceConfig tc_asterisk("*", "");
- EXPECT_STREQ("*", tc_asterisk.ToCategoryFilterString().c_str());
- CheckDefaultTraceConfigBehavior(tc_asterisk);
-
- TraceConfig tc_empty_category_filter("", "");
- EXPECT_STREQ("", tc_empty_category_filter.ToCategoryFilterString().c_str());
- EXPECT_STREQ(kDefaultTraceConfigString,
- tc_empty_category_filter.ToString().c_str());
- CheckDefaultTraceConfigBehavior(tc_empty_category_filter);
-
- // Constructor from JSON formated config string.
- TraceConfig tc_empty_json_string("");
- EXPECT_STREQ("", tc_empty_json_string.ToCategoryFilterString().c_str());
- EXPECT_STREQ(kDefaultTraceConfigString,
- tc_empty_json_string.ToString().c_str());
- CheckDefaultTraceConfigBehavior(tc_empty_json_string);
-
- // Constructor from dictionary value.
- DictionaryValue dict;
- TraceConfig tc_dict(dict);
- EXPECT_STREQ("", tc_dict.ToCategoryFilterString().c_str());
- EXPECT_STREQ(kDefaultTraceConfigString, tc_dict.ToString().c_str());
- CheckDefaultTraceConfigBehavior(tc_dict);
-}
-
-TEST(TraceConfigTest, EmptyAndAsteriskCategoryFilterString) {
- TraceConfig tc_empty("", "");
- TraceConfig tc_asterisk("*", "");
-
- EXPECT_STREQ("", tc_empty.ToCategoryFilterString().c_str());
- EXPECT_STREQ("*", tc_asterisk.ToCategoryFilterString().c_str());
-
- // Both fall back to default config.
- CheckDefaultTraceConfigBehavior(tc_empty);
- CheckDefaultTraceConfigBehavior(tc_asterisk);
-
- // They differ only for internal checking.
- EXPECT_FALSE(tc_empty.category_filter().IsCategoryEnabled("Category1"));
- EXPECT_FALSE(
- tc_empty.category_filter().IsCategoryEnabled("not-excluded-category"));
- EXPECT_TRUE(tc_asterisk.category_filter().IsCategoryEnabled("Category1"));
- EXPECT_TRUE(
- tc_asterisk.category_filter().IsCategoryEnabled("not-excluded-category"));
-}
-
-TEST(TraceConfigTest, DisabledByDefaultCategoryFilterString) {
- TraceConfig tc("foo,disabled-by-default-foo", "");
- EXPECT_STREQ("foo,disabled-by-default-foo",
- tc.ToCategoryFilterString().c_str());
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("foo"));
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-foo"));
- 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", "");
- EXPECT_STREQ("disabled-by-default-foo", tc.ToCategoryFilterString().c_str());
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-foo"));
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("foo"));
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("bar"));
- EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-bar"));
-}
-
-TEST(TraceConfigTest, TraceConfigFromDict) {
- // Passing in empty dictionary will result in default trace config.
- DictionaryValue dict;
- TraceConfig tc(dict);
- EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
- EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
- EXPECT_FALSE(tc.IsSystraceEnabled());
- EXPECT_FALSE(tc.IsArgumentFilterEnabled());
- EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
-
- std::unique_ptr<Value> default_value(
- JSONReader::Read(kDefaultTraceConfigString));
- DCHECK(default_value);
- const DictionaryValue* default_dict = nullptr;
- bool is_dict = default_value->GetAsDictionary(&default_dict);
- DCHECK(is_dict);
- 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.IsSystraceEnabled());
- EXPECT_FALSE(default_tc.IsArgumentFilterEnabled());
- EXPECT_STREQ("", default_tc.ToCategoryFilterString().c_str());
-
- std::unique_ptr<Value> custom_value(
- JSONReader::Read(kCustomTraceConfigString));
- DCHECK(custom_value);
- const DictionaryValue* custom_dict = nullptr;
- is_dict = custom_value->GetAsDictionary(&custom_dict);
- DCHECK(is_dict);
- TraceConfig custom_tc(*custom_dict);
- EXPECT_STREQ(kCustomTraceConfigString, custom_tc.ToString().c_str());
- EXPECT_EQ(RECORD_CONTINUOUSLY, custom_tc.GetTraceRecordMode());
- EXPECT_TRUE(custom_tc.IsSystraceEnabled());
- EXPECT_TRUE(custom_tc.IsArgumentFilterEnabled());
- EXPECT_STREQ("included,inc_pattern*,"
- "disabled-by-default-cc,disabled-by-default-memory-infra,"
- "-excluded,-exc_pattern*,"
- "DELAY(test.Delay1;16),DELAY(test.Delay2;32)",
- custom_tc.ToCategoryFilterString().c_str());
-}
-
-TEST(TraceConfigTest, TraceConfigFromValidString) {
- // Using some non-empty config string.
- const char config_string[] =
- "{"
- "\"enable_argument_filter\":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\"],"
- "\"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.IsSystraceEnabled());
- EXPECT_TRUE(tc.IsArgumentFilterEnabled());
- EXPECT_STREQ("included,inc_pattern*,disabled-by-default-cc,-excluded,"
- "-exc_pattern*,DELAY(test.Delay1;16),DELAY(test.Delay2;32)",
- tc.ToCategoryFilterString().c_str());
-
- EXPECT_TRUE(tc.category_filter().IsCategoryEnabled("included"));
- EXPECT_TRUE(tc.category_filter().IsCategoryEnabled("inc_pattern_category"));
- EXPECT_TRUE(tc.category_filter().IsCategoryEnabled("disabled-by-default-cc"));
- EXPECT_FALSE(tc.category_filter().IsCategoryEnabled("excluded"));
- EXPECT_FALSE(tc.category_filter().IsCategoryEnabled("exc_pattern_category"));
- EXPECT_FALSE(
- tc.category_filter().IsCategoryEnabled("disabled-by-default-others"));
- EXPECT_FALSE(
- tc.category_filter().IsCategoryEnabled("not-excluded-nor-included"));
-
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("included"));
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("inc_pattern_category"));
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
- EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded"));
- EXPECT_FALSE(tc.IsCategoryGroupEnabled("exc_pattern_category"));
- EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-others"));
- EXPECT_FALSE(tc.IsCategoryGroupEnabled("not-excluded-nor-included"));
-
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("included,excluded"));
- EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded,exc_pattern_category"));
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("included,DELAY(test.Delay1;16)"));
- EXPECT_FALSE(tc.IsCategoryGroupEnabled("DELAY(test.Delay1;16)"));
-
- EXPECT_EQ(2u, tc.GetSyntheticDelayValues().size());
- 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.category_filter().included_categories().size());
- EXPECT_STREQ("*",
- event_filter.category_filter().included_categories()[0].c_str());
- EXPECT_EQ(1u, event_filter.category_filter().excluded_categories().size());
- EXPECT_STREQ("unfiltered_cat",
- event_filter.category_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.category_filter().IsCategoryEnabled(
- "non-disabled-by-default-pattern"));
- EXPECT_FALSE(
- tc2.category_filter().IsCategoryEnabled("disabled-by-default-pattern"));
- EXPECT_TRUE(tc2.IsCategoryGroupEnabled("non-disabled-by-default-pattern"));
- EXPECT_FALSE(tc2.IsCategoryGroupEnabled("disabled-by-default-pattern"));
-
- // Clear
- tc.Clear();
- EXPECT_STREQ(tc.ToString().c_str(),
- "{"
- "\"enable_argument_filter\":false,"
- "\"enable_systrace\":false,"
- "\"record_mode\":\"record-until-full\""
- "}");
-}
-
-TEST(TraceConfigTest, TraceConfigFromInvalidString) {
- // The config string needs to be a dictionary correctly formatted as a JSON
- // string. Otherwise, it will fall back to the default initialization.
- TraceConfig tc("");
- EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
- EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
- EXPECT_FALSE(tc.IsSystraceEnabled());
- EXPECT_FALSE(tc.IsArgumentFilterEnabled());
- EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
- CheckDefaultTraceConfigBehavior(tc);
-
- 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.IsSystraceEnabled());
- EXPECT_FALSE(tc.IsArgumentFilterEnabled());
- EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
- CheckDefaultTraceConfigBehavior(tc);
-
- tc = TraceConfig("[\"This\", \"is\", \"not\", \"a\", \"dictionary\"]");
- EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
- EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
- EXPECT_FALSE(tc.IsSystraceEnabled());
- EXPECT_FALSE(tc.IsArgumentFilterEnabled());
- EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
- CheckDefaultTraceConfigBehavior(tc);
-
- 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.IsSystraceEnabled());
- EXPECT_FALSE(tc.IsArgumentFilterEnabled());
- EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
- CheckDefaultTraceConfigBehavior(tc);
-
- // If the config string a dictionary formatted as a JSON string, it will
- // initialize TraceConfig with best effort.
- tc = TraceConfig("{}");
- EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
- EXPECT_FALSE(tc.IsSystraceEnabled());
- EXPECT_FALSE(tc.IsArgumentFilterEnabled());
- EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
- CheckDefaultTraceConfigBehavior(tc);
-
- tc = TraceConfig("{\"arbitrary-key\":\"arbitrary-value\"}");
- EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
- EXPECT_FALSE(tc.IsSystraceEnabled());
- EXPECT_FALSE(tc.IsArgumentFilterEnabled());
- EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
- CheckDefaultTraceConfigBehavior(tc);
-
- const char invalid_config_string[] =
- "{"
- "\"enable_systrace\":1,"
- "\"excluded_categories\":[\"excluded\"],"
- "\"included_categories\":\"not a list\","
- "\"record_mode\":\"arbitrary-mode\","
- "\"synthetic_delays\":[\"test.Delay1;16\","
- "\"invalid-delay\","
- "\"test.Delay2;32\"]"
- "}";
- tc = TraceConfig(invalid_config_string);
- EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
- EXPECT_FALSE(tc.IsSystraceEnabled());
- EXPECT_FALSE(tc.IsArgumentFilterEnabled());
- EXPECT_STREQ("-excluded,DELAY(test.Delay1;16),DELAY(test.Delay2;32)",
- tc.ToCategoryFilterString().c_str());
-
- const char invalid_config_string_2[] =
- "{"
- "\"included_categories\":[\"category\",\"disabled-by-default-pattern\"],"
- "\"excluded_categories\":[\"category\",\"disabled-by-default-pattern\"]"
- "}";
- tc = TraceConfig(invalid_config_string_2);
- EXPECT_TRUE(tc.category_filter().IsCategoryEnabled("category"));
- EXPECT_TRUE(
- tc.category_filter().IsCategoryEnabled("disabled-by-default-pattern"));
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("category"));
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-pattern"));
-}
-
-TEST(TraceConfigTest, MergingTraceConfigs) {
- // Merge
- TraceConfig tc;
- TraceConfig tc2("included,-excluded,inc_pattern*,-exc_pattern*", "");
- tc.Merge(tc2);
- EXPECT_STREQ("{"
- "\"enable_argument_filter\":false,"
- "\"enable_systrace\":false,"
- "\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
- "\"record_mode\":\"record-until-full\""
- "}",
- tc.ToString().c_str());
-
- tc = TraceConfig("DELAY(test.Delay1;16)", "");
- tc2 = TraceConfig("DELAY(test.Delay2;32)", "");
- tc.Merge(tc2);
- EXPECT_EQ(2u, tc.GetSyntheticDelayValues().size());
- EXPECT_STREQ("test.Delay1;16", tc.GetSyntheticDelayValues()[0].c_str());
- EXPECT_STREQ("test.Delay2;32", tc.GetSyntheticDelayValues()[1].c_str());
-}
-
-TEST(TraceConfigTest, IsCategoryGroupEnabled) {
- // Enabling a disabled- category does not require all categories to be traced
- // to be included.
- TraceConfig tc("disabled-by-default-cc,-excluded", "");
- EXPECT_STREQ("disabled-by-default-cc,-excluded",
- tc.ToCategoryFilterString().c_str());
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("some_other_group"));
- EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded"));
-
- // Enabled a disabled- category and also including makes all categories to
- // be traced require including.
- tc = TraceConfig("disabled-by-default-cc,included", "");
- EXPECT_STREQ("included,disabled-by-default-cc",
- tc.ToCategoryFilterString().c_str());
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
- EXPECT_TRUE(tc.IsCategoryGroupEnabled("included"));
- EXPECT_FALSE(tc.IsCategoryGroupEnabled("other_included"));
-
- // Excluding categories won't enable disabled-by-default ones with the
- // excluded category is also present in the group.
- tc = TraceConfig("-excluded", "");
- EXPECT_STREQ("-excluded", tc.ToCategoryFilterString().c_str());
- EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded,disabled-by-default-cc"));
-}
-
-TEST(TraceConfigTest, IsCategoryNameAllowed) {
- // Test that IsCategoryNameAllowed actually catches categories that are
- // explicitly forbidden. This method is called in a DCHECK to assert that we
- // don't have these types of strings as categories.
- EXPECT_FALSE(
- TraceConfigCategoryFilter::IsCategoryNameAllowed(" bad_category "));
- EXPECT_FALSE(
- TraceConfigCategoryFilter::IsCategoryNameAllowed(" bad_category"));
- EXPECT_FALSE(
- TraceConfigCategoryFilter::IsCategoryNameAllowed("bad_category "));
- EXPECT_FALSE(
- TraceConfigCategoryFilter::IsCategoryNameAllowed(" bad_category"));
- EXPECT_FALSE(
- TraceConfigCategoryFilter::IsCategoryNameAllowed("bad_category "));
- EXPECT_FALSE(
- TraceConfigCategoryFilter::IsCategoryNameAllowed(" bad_category "));
- EXPECT_FALSE(TraceConfigCategoryFilter::IsCategoryNameAllowed(""));
- EXPECT_TRUE(
- TraceConfigCategoryFilter::IsCategoryNameAllowed("good_category"));
-}
-
-TEST(TraceConfigTest, SetTraceOptionValues) {
- TraceConfig tc;
- EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
- EXPECT_FALSE(tc.IsSystraceEnabled());
-
- tc.SetTraceRecordMode(RECORD_AS_MUCH_AS_POSSIBLE);
- EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, tc.GetTraceRecordMode());
-
- tc.EnableSystrace();
- EXPECT_TRUE(tc.IsSystraceEnabled());
-}
-
-TEST(TraceConfigTest, TraceConfigFromMemoryConfigString) {
- std::string tc_str1 =
- 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(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(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 =
- 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);
- 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);
-}
-
-TEST(TraceConfigTest, EmptyMemoryDumpConfigTest) {
- // Empty trigger list should also be specified when converting back to string.
- TraceConfig tc(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
- EXPECT_EQ(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers(),
- tc.ToString());
- EXPECT_EQ(0u, tc.memory_dump_config().triggers.size());
- EXPECT_EQ(
- TraceConfig::MemoryDumpConfig::HeapProfiler ::
- kDefaultBreakdownThresholdBytes,
- tc.memory_dump_config().heap_profiler_options.breakdown_threshold_bytes);
-}
-
-TEST(TraceConfigTest, LegacyStringToMemoryDumpConfig) {
- TraceConfig tc(MemoryDumpManager::kTraceCategory, "");
- EXPECT_TRUE(tc.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
- EXPECT_NE(std::string::npos, tc.ToString().find("memory_dump_config"));
- EXPECT_EQ(2u, tc.memory_dump_config().triggers.size());
- EXPECT_EQ(
- TraceConfig::MemoryDumpConfig::HeapProfiler ::
- kDefaultBreakdownThresholdBytes,
- tc.memory_dump_config().heap_profiler_options.breakdown_threshold_bytes);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index 51e6927cbd..9abb8887b0 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -5,6 +5,43 @@
#ifndef BASE_TRACE_EVENT_TRACE_EVENT_H_
#define BASE_TRACE_EVENT_TRACE_EVENT_H_
+// Replace with stub implementation.
+#if 1
+#include "base/trace_event/common/trace_event_common.h"
+#include "base/trace_event/heap_profiler.h"
+
+// To avoid -Wunused-* errors, eat expression by macro.
+namespace libchrome_internal {
+template <typename... Args> void Ignore(Args&&... args) {}
+}
+#define INTERNAL_IGNORE(...) \
+ (false ? libchrome_internal::Ignore(__VA_ARGS__) : (void) 0)
+
+// Body is effectively empty.
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED(...) INTERNAL_IGNORE(__VA_ARGS__)
+#define INTERNAL_TRACE_TASK_EXECUTION(...)
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(...) \
+ INTERNAL_IGNORE(__VA_ARGS__)
+#define TRACE_ID_MANGLE(val) (val)
+
+namespace base {
+namespace trace_event {
+
+class TraceLog {
+ public:
+ static TraceLog* GetInstance() {
+ static TraceLog instance;
+ return &instance;
+ }
+
+ pid_t process_id() { return 0; }
+ void SetCurrentThreadBlocksMessageLoop() {}
+};
+
+} // namespace trace_event
+} // namespace base
+#else
+
// This header file defines implementation details of how the trace macros in
// trace_event_common.h collect and store trace events. Anything not
// implementation-specific should go in trace_event_common.h instead of here.
@@ -1115,4 +1152,5 @@ template<typename IDType> class TraceScopedTrackableObject {
} // namespace trace_event
} // namespace base
+#endif
#endif // BASE_TRACE_EVENT_TRACE_EVENT_H_
diff --git a/base/trace_event/trace_event_argument.cc b/base/trace_event/trace_event_argument.cc
deleted file mode 100644
index db702b6231..0000000000
--- a/base/trace_event/trace_event_argument.cc
+++ /dev/null
@@ -1,473 +0,0 @@
-// Copyright (c) 2014 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_argument.h"
-
-#include <stdint.h>
-
-#include <utility>
-
-#include "base/bits.h"
-#include "base/json/json_writer.h"
-#include "base/memory/ptr_util.h"
-#include "base/trace_event/trace_event_memory_overhead.h"
-#include "base/values.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-const char kTypeStartDict = '{';
-const char kTypeEndDict = '}';
-const char kTypeStartArray = '[';
-const char kTypeEndArray = ']';
-const char kTypeBool = 'b';
-const char kTypeInt = 'i';
-const char kTypeDouble = 'd';
-const char kTypeString = 's';
-const char kTypeCStr = '*';
-
-#ifndef NDEBUG
-const bool kStackTypeDict = false;
-const bool kStackTypeArray = true;
-#define DCHECK_CURRENT_CONTAINER_IS(x) DCHECK_EQ(x, nesting_stack_.back())
-#define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) DCHECK_EQ(x, nesting_stack_.size())
-#define DEBUG_PUSH_CONTAINER(x) nesting_stack_.push_back(x)
-#define DEBUG_POP_CONTAINER() nesting_stack_.pop_back()
-#else
-#define DCHECK_CURRENT_CONTAINER_IS(x) do {} while (0)
-#define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) do {} while (0)
-#define DEBUG_PUSH_CONTAINER(x) do {} while (0)
-#define DEBUG_POP_CONTAINER() do {} while (0)
-#endif
-
-inline void WriteKeyNameAsRawPtr(Pickle& pickle, const char* ptr) {
- pickle.WriteBytes(&kTypeCStr, 1);
- pickle.WriteUInt64(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(ptr)));
-}
-
-inline void WriteKeyNameWithCopy(Pickle& pickle, base::StringPiece str) {
- pickle.WriteBytes(&kTypeString, 1);
- pickle.WriteString(str);
-}
-
-std::string ReadKeyName(PickleIterator& pickle_iterator) {
- const char* type = nullptr;
- bool res = pickle_iterator.ReadBytes(&type, 1);
- std::string key_name;
- if (res && *type == kTypeCStr) {
- uint64_t ptr_value = 0;
- res = pickle_iterator.ReadUInt64(&ptr_value);
- key_name = reinterpret_cast<const char*>(static_cast<uintptr_t>(ptr_value));
- } else if (res && *type == kTypeString) {
- res = pickle_iterator.ReadString(&key_name);
- }
- DCHECK(res);
- return key_name;
-}
-} // namespace
-
-TracedValue::TracedValue() : TracedValue(0) {
-}
-
-TracedValue::TracedValue(size_t capacity) {
- DEBUG_PUSH_CONTAINER(kStackTypeDict);
- if (capacity)
- pickle_.Reserve(capacity);
-}
-
-TracedValue::~TracedValue() {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- DEBUG_POP_CONTAINER();
- DCHECK_CONTAINER_STACK_DEPTH_EQ(0u);
-}
-
-void TracedValue::SetInteger(const char* name, int value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- pickle_.WriteBytes(&kTypeInt, 1);
- pickle_.WriteInt(value);
- WriteKeyNameAsRawPtr(pickle_, name);
-}
-
-void TracedValue::SetIntegerWithCopiedName(base::StringPiece name, int value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- pickle_.WriteBytes(&kTypeInt, 1);
- pickle_.WriteInt(value);
- WriteKeyNameWithCopy(pickle_, name);
-}
-
-void TracedValue::SetDouble(const char* name, double value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- pickle_.WriteBytes(&kTypeDouble, 1);
- pickle_.WriteDouble(value);
- WriteKeyNameAsRawPtr(pickle_, name);
-}
-
-void TracedValue::SetDoubleWithCopiedName(base::StringPiece name,
- double value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- pickle_.WriteBytes(&kTypeDouble, 1);
- pickle_.WriteDouble(value);
- WriteKeyNameWithCopy(pickle_, name);
-}
-
-void TracedValue::SetBoolean(const char* name, bool value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- pickle_.WriteBytes(&kTypeBool, 1);
- pickle_.WriteBool(value);
- WriteKeyNameAsRawPtr(pickle_, name);
-}
-
-void TracedValue::SetBooleanWithCopiedName(base::StringPiece name,
- bool value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- pickle_.WriteBytes(&kTypeBool, 1);
- pickle_.WriteBool(value);
- WriteKeyNameWithCopy(pickle_, name);
-}
-
-void TracedValue::SetString(const char* name, base::StringPiece value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- pickle_.WriteBytes(&kTypeString, 1);
- pickle_.WriteString(value);
- WriteKeyNameAsRawPtr(pickle_, name);
-}
-
-void TracedValue::SetStringWithCopiedName(base::StringPiece name,
- base::StringPiece value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- pickle_.WriteBytes(&kTypeString, 1);
- pickle_.WriteString(value);
- WriteKeyNameWithCopy(pickle_, name);
-}
-
-void TracedValue::SetValue(const char* name, const TracedValue& value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- BeginDictionary(name);
- pickle_.WriteBytes(value.pickle_.payload(),
- static_cast<int>(value.pickle_.payload_size()));
- EndDictionary();
-}
-
-void TracedValue::SetValueWithCopiedName(base::StringPiece name,
- const TracedValue& value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- BeginDictionaryWithCopiedName(name);
- pickle_.WriteBytes(value.pickle_.payload(),
- static_cast<int>(value.pickle_.payload_size()));
- EndDictionary();
-}
-
-void TracedValue::BeginDictionary(const char* name) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- DEBUG_PUSH_CONTAINER(kStackTypeDict);
- pickle_.WriteBytes(&kTypeStartDict, 1);
- WriteKeyNameAsRawPtr(pickle_, name);
-}
-
-void TracedValue::BeginDictionaryWithCopiedName(base::StringPiece name) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- DEBUG_PUSH_CONTAINER(kStackTypeDict);
- pickle_.WriteBytes(&kTypeStartDict, 1);
- WriteKeyNameWithCopy(pickle_, name);
-}
-
-void TracedValue::BeginArray(const char* name) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- DEBUG_PUSH_CONTAINER(kStackTypeArray);
- pickle_.WriteBytes(&kTypeStartArray, 1);
- WriteKeyNameAsRawPtr(pickle_, name);
-}
-
-void TracedValue::BeginArrayWithCopiedName(base::StringPiece name) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- DEBUG_PUSH_CONTAINER(kStackTypeArray);
- pickle_.WriteBytes(&kTypeStartArray, 1);
- WriteKeyNameWithCopy(pickle_, name);
-}
-
-void TracedValue::EndDictionary() {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- DEBUG_POP_CONTAINER();
- pickle_.WriteBytes(&kTypeEndDict, 1);
-}
-
-void TracedValue::AppendInteger(int value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
- pickle_.WriteBytes(&kTypeInt, 1);
- pickle_.WriteInt(value);
-}
-
-void TracedValue::AppendDouble(double value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
- pickle_.WriteBytes(&kTypeDouble, 1);
- pickle_.WriteDouble(value);
-}
-
-void TracedValue::AppendBoolean(bool value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
- pickle_.WriteBytes(&kTypeBool, 1);
- pickle_.WriteBool(value);
-}
-
-void TracedValue::AppendString(base::StringPiece value) {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
- pickle_.WriteBytes(&kTypeString, 1);
- pickle_.WriteString(value);
-}
-
-void TracedValue::BeginArray() {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
- DEBUG_PUSH_CONTAINER(kStackTypeArray);
- pickle_.WriteBytes(&kTypeStartArray, 1);
-}
-
-void TracedValue::BeginDictionary() {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
- DEBUG_PUSH_CONTAINER(kStackTypeDict);
- pickle_.WriteBytes(&kTypeStartDict, 1);
-}
-
-void TracedValue::EndArray() {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
- DEBUG_POP_CONTAINER();
- pickle_.WriteBytes(&kTypeEndArray, 1);
-}
-
-void TracedValue::SetValue(const char* name,
- std::unique_ptr<base::Value> value) {
- SetBaseValueWithCopiedName(name, *value);
-}
-
-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:
- NOTREACHED();
- break;
-
- case base::Value::Type::BOOLEAN: {
- bool bool_value;
- value.GetAsBoolean(&bool_value);
- SetBooleanWithCopiedName(name, bool_value);
- } break;
-
- case base::Value::Type::INTEGER: {
- int int_value;
- value.GetAsInteger(&int_value);
- SetIntegerWithCopiedName(name, int_value);
- } break;
-
- 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;
- value.GetAsString(&string_value);
- SetStringWithCopiedName(name, string_value->GetString());
- } break;
-
- case base::Value::Type::DICTIONARY: {
- const DictionaryValue* dict_value;
- value.GetAsDictionary(&dict_value);
- BeginDictionaryWithCopiedName(name);
- for (DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
- it.Advance()) {
- SetBaseValueWithCopiedName(it.key(), it.value());
- }
- EndDictionary();
- } break;
-
- case base::Value::Type::LIST: {
- const ListValue* list_value;
- value.GetAsList(&list_value);
- BeginArrayWithCopiedName(name);
- for (const auto& base_value : *list_value)
- AppendBaseValue(*base_value);
- EndArray();
- } break;
- }
-}
-
-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:
- NOTREACHED();
- break;
-
- case base::Value::Type::BOOLEAN: {
- bool bool_value;
- value.GetAsBoolean(&bool_value);
- AppendBoolean(bool_value);
- } break;
-
- case base::Value::Type::INTEGER: {
- int int_value;
- value.GetAsInteger(&int_value);
- AppendInteger(int_value);
- } break;
-
- 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;
- value.GetAsString(&string_value);
- AppendString(string_value->GetString());
- } break;
-
- case base::Value::Type::DICTIONARY: {
- const DictionaryValue* dict_value;
- value.GetAsDictionary(&dict_value);
- BeginDictionary();
- for (DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
- it.Advance()) {
- SetBaseValueWithCopiedName(it.key(), it.value());
- }
- EndDictionary();
- } break;
-
- case base::Value::Type::LIST: {
- const ListValue* list_value;
- value.GetAsList(&list_value);
- BeginArray();
- for (const auto& base_value : *list_value)
- AppendBaseValue(*base_value);
- EndArray();
- } break;
- }
-}
-
-std::unique_ptr<base::Value> TracedValue::ToBaseValue() const {
- std::unique_ptr<DictionaryValue> root(new DictionaryValue);
- DictionaryValue* cur_dict = root.get();
- ListValue* cur_list = nullptr;
- std::vector<Value*> stack;
- PickleIterator it(pickle_);
- const char* type;
-
- while (it.ReadBytes(&type, 1)) {
- DCHECK((cur_dict && !cur_list) || (cur_list && !cur_dict));
- switch (*type) {
- case kTypeStartDict: {
- auto* new_dict = new DictionaryValue();
- if (cur_dict) {
- cur_dict->SetWithoutPathExpansion(ReadKeyName(it),
- WrapUnique(new_dict));
- stack.push_back(cur_dict);
- cur_dict = new_dict;
- } else {
- cur_list->Append(WrapUnique(new_dict));
- stack.push_back(cur_list);
- cur_list = nullptr;
- cur_dict = new_dict;
- }
- } break;
-
- case kTypeEndArray:
- case kTypeEndDict: {
- if (stack.back()->GetAsDictionary(&cur_dict)) {
- cur_list = nullptr;
- } else if (stack.back()->GetAsList(&cur_list)) {
- cur_dict = nullptr;
- }
- stack.pop_back();
- } break;
-
- case kTypeStartArray: {
- auto* new_list = new ListValue();
- if (cur_dict) {
- cur_dict->SetWithoutPathExpansion(ReadKeyName(it),
- WrapUnique(new_list));
- stack.push_back(cur_dict);
- cur_dict = nullptr;
- cur_list = new_list;
- } else {
- cur_list->Append(WrapUnique(new_list));
- stack.push_back(cur_list);
- cur_list = new_list;
- }
- } break;
-
- case kTypeBool: {
- bool value;
- CHECK(it.ReadBool(&value));
- if (cur_dict) {
- cur_dict->SetBooleanWithoutPathExpansion(ReadKeyName(it), value);
- } else {
- cur_list->AppendBoolean(value);
- }
- } break;
-
- case kTypeInt: {
- int value;
- CHECK(it.ReadInt(&value));
- if (cur_dict) {
- cur_dict->SetIntegerWithoutPathExpansion(ReadKeyName(it), value);
- } else {
- cur_list->AppendInteger(value);
- }
- } break;
-
- case kTypeDouble: {
- double value;
- CHECK(it.ReadDouble(&value));
- if (cur_dict) {
- cur_dict->SetDoubleWithoutPathExpansion(ReadKeyName(it), value);
- } else {
- cur_list->AppendDouble(value);
- }
- } break;
-
- case kTypeString: {
- std::string value;
- CHECK(it.ReadString(&value));
- if (cur_dict) {
- cur_dict->SetStringWithoutPathExpansion(ReadKeyName(it), value);
- } else {
- cur_list->AppendString(value);
- }
- } break;
-
- default:
- NOTREACHED();
- }
- }
- DCHECK(stack.empty());
- return std::move(root);
-}
-
-void TracedValue::AppendAsTraceFormat(std::string* out) const {
- DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
- DCHECK_CONTAINER_STACK_DEPTH_EQ(1u);
-
- // TODO(primiano): this could be smarter, skip the ToBaseValue encoding and
- // produce the JSON on its own. This will require refactoring JSONWriter
- // to decouple the base::Value traversal from the JSON writing bits
- std::string tmp;
- JSONWriter::Write(*ToBaseValue(), &tmp);
- *out += tmp;
-}
-
-void TracedValue::EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) {
- overhead->Add("TracedValue",
- /* allocated size */
- pickle_.GetTotalAllocatedSize(),
- /* resident size */
- pickle_.size());
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/trace_event_argument.h b/base/trace_event/trace_event_argument.h
deleted file mode 100644
index 81d8c0172a..0000000000
--- a/base/trace_event/trace_event_argument.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2014 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_ARGUMENT_H_
-#define BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
-
-#include <stddef.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/pickle.h"
-#include "base/strings/string_piece.h"
-#include "base/trace_event/trace_event_impl.h"
-
-namespace base {
-
-class Value;
-
-namespace trace_event {
-
-class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
- public:
- TracedValue();
- explicit TracedValue(size_t capacity);
- ~TracedValue() override;
-
- void EndDictionary();
- void EndArray();
-
- // These methods assume that |name| is a long lived "quoted" string.
- void SetInteger(const char* name, int value);
- void SetDouble(const char* name, double value);
- void SetBoolean(const char* name, bool value);
- void SetString(const char* name, base::StringPiece value);
- void SetValue(const char* name, const TracedValue& value);
- void BeginDictionary(const char* name);
- void BeginArray(const char* name);
-
- // These, instead, can be safely passed a temporary string.
- void SetIntegerWithCopiedName(base::StringPiece name, int value);
- void SetDoubleWithCopiedName(base::StringPiece name, double value);
- void SetBooleanWithCopiedName(base::StringPiece name, bool value);
- void SetStringWithCopiedName(base::StringPiece name,
- base::StringPiece value);
- void SetValueWithCopiedName(base::StringPiece name,
- const TracedValue& value);
- void BeginDictionaryWithCopiedName(base::StringPiece name);
- void BeginArrayWithCopiedName(base::StringPiece name);
-
- void AppendInteger(int);
- void AppendDouble(double);
- void AppendBoolean(bool);
- void AppendString(base::StringPiece);
- void BeginArray();
- void BeginDictionary();
-
- // ConvertableToTraceFormat implementation.
- void AppendAsTraceFormat(std::string* out) const override;
-
- void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
-
- // DEPRECATED: do not use, here only for legacy reasons. These methods causes
- // a copy-and-translation of the base::Value into the equivalent TracedValue.
- // TODO(primiano): migrate the (three) existing clients to the cheaper
- // SetValue(TracedValue) API. crbug.com/495628.
- void SetValue(const char* name, std::unique_ptr<base::Value> value);
- void SetBaseValueWithCopiedName(base::StringPiece name,
- const base::Value& value);
- void AppendBaseValue(const base::Value& value);
-
- // Public for tests only.
- std::unique_ptr<base::Value> ToBaseValue() const;
-
- private:
- Pickle pickle_;
-
-#ifndef NDEBUG
- // In debug builds checks the pairings of {Start,End}{Dictionary,Array}
- std::vector<bool> nesting_stack_;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(TracedValue);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
diff --git a/base/trace_event/trace_event_argument_unittest.cc b/base/trace_event/trace_event_argument_unittest.cc
deleted file mode 100644
index aef8441c8e..0000000000
--- a/base/trace_event/trace_event_argument_unittest.cc
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright (c) 2014 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_argument.h"
-
-#include <stddef.h>
-
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-#include "base/values.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace trace_event {
-
-TEST(TraceEventArgumentTest, FlatDictionary) {
- std::unique_ptr<TracedValue> value(new TracedValue());
- value->SetInteger("int", 2014);
- value->SetDouble("double", 0.0);
- value->SetBoolean("bool", true);
- value->SetString("string", "string");
- std::string json = "PREFIX";
- value->AppendAsTraceFormat(&json);
- EXPECT_EQ(
- "PREFIX{\"bool\":true,\"double\":0.0,\"int\":2014,\"string\":\"string\"}",
- json);
-}
-
-TEST(TraceEventArgumentTest, NoDotPathExpansion) {
- std::unique_ptr<TracedValue> value(new TracedValue());
- value->SetInteger("in.t", 2014);
- value->SetDouble("doub.le", 0.0);
- value->SetBoolean("bo.ol", true);
- value->SetString("str.ing", "str.ing");
- std::string json;
- value->AppendAsTraceFormat(&json);
- EXPECT_EQ(
- "{\"bo.ol\":true,\"doub.le\":0.0,\"in.t\":2014,\"str.ing\":\"str.ing\"}",
- json);
-}
-
-TEST(TraceEventArgumentTest, Hierarchy) {
- std::unique_ptr<TracedValue> value(new TracedValue());
- value->SetInteger("i0", 2014);
- value->BeginDictionary("dict1");
- value->SetInteger("i1", 2014);
- value->BeginDictionary("dict2");
- value->SetBoolean("b2", false);
- value->EndDictionary();
- value->SetString("s1", "foo");
- value->EndDictionary();
- value->SetDouble("d0", 0.0);
- value->SetBoolean("b0", true);
- value->BeginArray("a1");
- value->AppendInteger(1);
- value->AppendBoolean(true);
- value->BeginDictionary();
- value->SetInteger("i2", 3);
- value->EndDictionary();
- value->EndArray();
- value->SetString("s0", "foo");
- std::string json;
- value->AppendAsTraceFormat(&json);
- EXPECT_EQ(
- "{\"a1\":[1,true,{\"i2\":3}],\"b0\":true,\"d0\":0.0,\"dict1\":{\"dict2\":"
- "{\"b2\":false},\"i1\":2014,\"s1\":\"foo\"},\"i0\":2014,\"s0\":"
- "\"foo\"}",
- json);
-}
-
-TEST(TraceEventArgumentTest, LongStrings) {
- std::string kLongString = "supercalifragilisticexpialidocious";
- std::string kLongString2 = "0123456789012345678901234567890123456789";
- char kLongString3[4096];
- for (size_t i = 0; i < sizeof(kLongString3); ++i)
- kLongString3[i] = 'a' + (i % 25);
- kLongString3[sizeof(kLongString3) - 1] = '\0';
-
- std::unique_ptr<TracedValue> value(new TracedValue());
- value->SetString("a", "short");
- value->SetString("b", kLongString);
- value->BeginArray("c");
- value->AppendString(kLongString2);
- value->AppendString("");
- value->BeginDictionary();
- value->SetString("a", kLongString3);
- value->EndDictionary();
- value->EndArray();
-
- std::string json;
- value->AppendAsTraceFormat(&json);
- EXPECT_EQ("{\"a\":\"short\",\"b\":\"" + kLongString + "\",\"c\":[\"" +
- kLongString2 + "\",\"\",{\"a\":\"" + kLongString3 + "\"}]}",
- json);
-}
-
-TEST(TraceEventArgumentTest, PassBaseValue) {
- Value int_value(42);
- Value bool_value(true);
- Value double_value(42.0f);
-
- auto dict_value = WrapUnique(new DictionaryValue);
- dict_value->SetBoolean("bool", true);
- dict_value->SetInteger("int", 42);
- dict_value->SetDouble("double", 42.0f);
- dict_value->SetString("string", std::string("a") + "b");
- dict_value->SetString("string", std::string("a") + "b");
-
- auto list_value = WrapUnique(new ListValue);
- list_value->AppendBoolean(false);
- list_value->AppendInteger(1);
- list_value->AppendString("in_list");
- list_value->Append(std::move(dict_value));
-
- std::unique_ptr<TracedValue> value(new TracedValue());
- value->BeginDictionary("outer_dict");
- value->SetValue("inner_list", std::move(list_value));
- value->EndDictionary();
-
- dict_value.reset();
- list_value.reset();
-
- std::string json;
- value->AppendAsTraceFormat(&json);
- EXPECT_EQ(
- "{\"outer_dict\":{\"inner_list\":[false,1,\"in_list\",{\"bool\":true,"
- "\"double\":42.0,\"int\":42,\"string\":\"ab\"}]}}",
- json);
-}
-
-TEST(TraceEventArgumentTest, PassTracedValue) {
- auto dict_value = MakeUnique<TracedValue>();
- dict_value->SetInteger("a", 1);
-
- auto nested_dict_value = MakeUnique<TracedValue>();
- nested_dict_value->SetInteger("b", 2);
- nested_dict_value->BeginArray("c");
- nested_dict_value->AppendString("foo");
- nested_dict_value->EndArray();
-
- dict_value->SetValue("e", *nested_dict_value);
-
- // Check the merged result.
- std::string json;
- dict_value->AppendAsTraceFormat(&json);
- EXPECT_EQ("{\"a\":1,\"e\":{\"b\":2,\"c\":[\"foo\"]}}", json);
-
- // Check that the passed nestd dict was left unouthced.
- json = "";
- nested_dict_value->AppendAsTraceFormat(&json);
- EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"]}", json);
-
- // And that it is still usable.
- nested_dict_value->SetInteger("f", 3);
- nested_dict_value->BeginDictionary("g");
- nested_dict_value->EndDictionary();
- json = "";
- nested_dict_value->AppendAsTraceFormat(&json);
- EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"],\"f\":3,\"g\":{}}", json);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/trace_event_filter.cc b/base/trace_event/trace_event_filter.cc
deleted file mode 100644
index 6265295864..0000000000
--- a/base/trace_event/trace_event_filter.cc
+++ /dev/null
@@ -1,17 +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.h"
-
-namespace base {
-namespace trace_event {
-
-TraceEventFilter::TraceEventFilter() {}
-TraceEventFilter::~TraceEventFilter() {}
-
-void TraceEventFilter::EndEvent(const char* category_name,
- const char* event_name) const {}
-
-} // 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
deleted file mode 100644
index cb23eb474c..0000000000
--- a/base/trace_event/trace_event_impl.cc
+++ /dev/null
@@ -1,490 +0,0 @@
-// Copyright (c) 2012 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_impl.h"
-
-#include <stddef.h>
-
-#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"
-#include "base/strings/string_util.h"
-#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 {
-namespace trace_event {
-
-namespace {
-
-size_t GetAllocLength(const char* str) { return str ? strlen(str) + 1 : 0; }
-
-// Copies |*member| into |*buffer|, sets |*member| to point to this new
-// location, and then advances |*buffer| by the amount written.
-void CopyTraceEventParameter(char** buffer,
- const char** member,
- const char* end) {
- if (*member) {
- size_t written = strlcpy(*buffer, *member, end - *buffer) + 1;
- DCHECK_LE(static_cast<int>(written), end - *buffer);
- *member = *buffer;
- *buffer += written;
- }
-}
-
-} // namespace
-
-TraceEvent::TraceEvent()
- : duration_(TimeDelta::FromInternalValue(-1)),
- scope_(trace_event_internal::kGlobalScope),
- id_(0u),
- category_group_enabled_(NULL),
- name_(NULL),
- thread_id_(0),
- flags_(0),
- phase_(TRACE_EVENT_PHASE_BEGIN) {
- for (int i = 0; i < kTraceMaxNumArgs; ++i)
- arg_names_[i] = NULL;
- memset(arg_values_, 0, sizeof(arg_values_));
-}
-
-TraceEvent::~TraceEvent() {
-}
-
-void TraceEvent::MoveFrom(std::unique_ptr<TraceEvent> other) {
- timestamp_ = other->timestamp_;
- thread_timestamp_ = other->thread_timestamp_;
- duration_ = other->duration_;
- scope_ = other->scope_;
- id_ = other->id_;
- category_group_enabled_ = other->category_group_enabled_;
- name_ = other->name_;
- if (other->flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID)
- process_id_ = other->process_id_;
- else
- thread_id_ = other->thread_id_;
- phase_ = other->phase_;
- flags_ = other->flags_;
- parameter_copy_storage_ = std::move(other->parameter_copy_storage_);
-
- for (int i = 0; i < kTraceMaxNumArgs; ++i) {
- arg_names_[i] = other->arg_names_[i];
- arg_types_[i] = other->arg_types_[i];
- arg_values_[i] = other->arg_values_[i];
- convertable_values_[i] = std::move(other->convertable_values_[i]);
- }
-}
-
-void TraceEvent::Initialize(
- int thread_id,
- TimeTicks timestamp,
- ThreadTicks thread_timestamp,
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- const char* scope,
- unsigned long long id,
- unsigned long long bind_id,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags) {
- timestamp_ = timestamp;
- thread_timestamp_ = thread_timestamp;
- duration_ = TimeDelta::FromInternalValue(-1);
- scope_ = scope;
- id_ = id;
- category_group_enabled_ = category_group_enabled;
- name_ = name;
- thread_id_ = thread_id;
- phase_ = phase;
- flags_ = flags;
- bind_id_ = bind_id;
-
- // Clamp num_args since it may have been set by a third_party library.
- num_args = (num_args > kTraceMaxNumArgs) ? kTraceMaxNumArgs : num_args;
- int i = 0;
- for (; i < num_args; ++i) {
- arg_names_[i] = arg_names[i];
- arg_types_[i] = arg_types[i];
-
- if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
- convertable_values_[i] = std::move(convertable_values[i]);
- } else {
- arg_values_[i].as_uint = arg_values[i];
- convertable_values_[i].reset();
- }
- }
- for (; i < kTraceMaxNumArgs; ++i) {
- arg_names_[i] = NULL;
- arg_values_[i].as_uint = 0u;
- convertable_values_[i].reset();
- arg_types_[i] = TRACE_VALUE_TYPE_UINT;
- }
-
- bool copy = !!(flags & TRACE_EVENT_FLAG_COPY);
- size_t alloc_size = 0;
- if (copy) {
- alloc_size += GetAllocLength(name) + GetAllocLength(scope);
- for (i = 0; i < num_args; ++i) {
- alloc_size += GetAllocLength(arg_names_[i]);
- if (arg_types_[i] == TRACE_VALUE_TYPE_STRING)
- arg_types_[i] = TRACE_VALUE_TYPE_COPY_STRING;
- }
- }
-
- bool arg_is_copy[kTraceMaxNumArgs];
- for (i = 0; i < num_args; ++i) {
- // No copying of convertable types, we retain ownership.
- if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
- continue;
-
- // We only take a copy of arg_vals if they are of type COPY_STRING.
- arg_is_copy[i] = (arg_types_[i] == TRACE_VALUE_TYPE_COPY_STRING);
- if (arg_is_copy[i])
- alloc_size += GetAllocLength(arg_values_[i].as_string);
- }
-
- if (alloc_size) {
- parameter_copy_storage_.reset(new std::string);
- parameter_copy_storage_->resize(alloc_size);
- char* ptr = string_as_array(parameter_copy_storage_.get());
- const char* end = ptr + alloc_size;
- if (copy) {
- CopyTraceEventParameter(&ptr, &name_, end);
- CopyTraceEventParameter(&ptr, &scope_, end);
- for (i = 0; i < num_args; ++i) {
- CopyTraceEventParameter(&ptr, &arg_names_[i], end);
- }
- }
- for (i = 0; i < num_args; ++i) {
- if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
- continue;
- if (arg_is_copy[i])
- CopyTraceEventParameter(&ptr, &arg_values_[i].as_string, end);
- }
- DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end;
- }
-}
-
-void TraceEvent::Reset() {
- // Only reset fields that won't be initialized in Initialize(), or that may
- // hold references to other objects.
- duration_ = TimeDelta::FromInternalValue(-1);
- parameter_copy_storage_.reset();
- for (int i = 0; i < kTraceMaxNumArgs; ++i)
- convertable_values_[i].reset();
-}
-
-void TraceEvent::UpdateDuration(const TimeTicks& now,
- const ThreadTicks& thread_now) {
- DCHECK_EQ(duration_.ToInternalValue(), -1);
- duration_ = now - timestamp_;
-
- // |thread_timestamp_| can be empty if the thread ticks clock wasn't
- // initialized when it was recorded.
- if (thread_timestamp_ != ThreadTicks())
- thread_duration_ = thread_now - thread_timestamp_;
-}
-
-void TraceEvent::EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) {
- overhead->Add("TraceEvent", sizeof(*this));
-
- if (parameter_copy_storage_)
- overhead->AddString(*parameter_copy_storage_);
-
- for (size_t i = 0; i < kTraceMaxNumArgs; ++i) {
- if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
- convertable_values_[i]->EstimateTraceMemoryOverhead(overhead);
- }
-}
-
-// static
-void TraceEvent::AppendValueAsJSON(unsigned char type,
- TraceEvent::TraceValue value,
- std::string* out) {
- switch (type) {
- case TRACE_VALUE_TYPE_BOOL:
- *out += value.as_bool ? "true" : "false";
- break;
- case TRACE_VALUE_TYPE_UINT:
- StringAppendF(out, "%" PRIu64, static_cast<uint64_t>(value.as_uint));
- break;
- case TRACE_VALUE_TYPE_INT:
- StringAppendF(out, "%" PRId64, static_cast<int64_t>(value.as_int));
- break;
- case TRACE_VALUE_TYPE_DOUBLE: {
- // FIXME: base/json/json_writer.cc is using the same code,
- // should be made into a common method.
- std::string real;
- double val = value.as_double;
- if (std::isfinite(val)) {
- real = DoubleToString(val);
- // Ensure that the number has a .0 if there's no decimal or 'e'. This
- // makes sure that when we read the JSON back, it's interpreted as a
- // real rather than an int.
- if (real.find('.') == std::string::npos &&
- real.find('e') == std::string::npos &&
- real.find('E') == std::string::npos) {
- real.append(".0");
- }
- // The JSON spec requires that non-integer values in the range (-1,1)
- // have a zero before the decimal point - ".52" is not valid, "0.52" is.
- if (real[0] == '.') {
- real.insert(0, "0");
- } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
- // "-.1" bad "-0.1" good
- real.insert(1, "0");
- }
- } else if (std::isnan(val)){
- // The JSON spec doesn't allow NaN and Infinity (since these are
- // objects in EcmaScript). Use strings instead.
- real = "\"NaN\"";
- } else if (val < 0) {
- real = "\"-Infinity\"";
- } else {
- real = "\"Infinity\"";
- }
- StringAppendF(out, "%s", real.c_str());
- break;
- }
- case TRACE_VALUE_TYPE_POINTER:
- // JSON only supports double and int numbers.
- // So as not to lose bits from a 64-bit pointer, output as a hex string.
- StringAppendF(
- out, "\"0x%" PRIx64 "\"",
- static_cast<uint64_t>(reinterpret_cast<uintptr_t>(value.as_pointer)));
- break;
- case TRACE_VALUE_TYPE_STRING:
- case TRACE_VALUE_TYPE_COPY_STRING:
- EscapeJSONString(value.as_string ? value.as_string : "NULL", true, out);
- break;
- default:
- NOTREACHED() << "Don't know how to print this value";
- break;
- }
-}
-
-void TraceEvent::AppendAsJSON(
- std::string* out,
- const ArgumentFilterPredicate& argument_filter_predicate) const {
- int64_t time_int64 = timestamp_.ToInternalValue();
- int process_id;
- int thread_id;
- if ((flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID) &&
- process_id_ != kNullProcessId) {
- process_id = process_id_;
- thread_id = -1;
- } else {
- process_id = TraceLog::GetInstance()->process_id();
- thread_id = thread_id_;
- }
- const char* category_group_name =
- TraceLog::GetCategoryGroupName(category_group_enabled_);
-
- // Category group checked at category creation time.
- DCHECK(!strchr(name_, '"'));
- StringAppendF(out, "{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64
- ",\"ph\":\"%c\",\"cat\":\"%s\",\"name\":",
- process_id, thread_id, time_int64, phase_, category_group_name);
- EscapeJSONString(name_, true, out);
- *out += ",\"args\":";
-
- // Output argument names and values, stop at first NULL argument name.
- // TODO(oysteine): The dual predicates here is a bit ugly; if the filtering
- // capabilities need to grow even more precise we should rethink this
- // approach
- ArgumentNameFilterPredicate argument_name_filter_predicate;
- bool strip_args =
- arg_names_[0] && !argument_filter_predicate.is_null() &&
- !argument_filter_predicate.Run(category_group_name, name_,
- &argument_name_filter_predicate);
-
- if (strip_args) {
- *out += "\"__stripped__\"";
- } else {
- *out += "{";
-
- for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
- if (i > 0)
- *out += ",";
- *out += "\"";
- *out += arg_names_[i];
- *out += "\":";
-
- if (argument_name_filter_predicate.is_null() ||
- argument_name_filter_predicate.Run(arg_names_[i])) {
- if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
- convertable_values_[i]->AppendAsTraceFormat(out);
- else
- AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
- } else {
- *out += "\"__stripped__\"";
- }
- }
-
- *out += "}";
- }
-
- if (phase_ == TRACE_EVENT_PHASE_COMPLETE) {
- int64_t duration = duration_.ToInternalValue();
- if (duration != -1)
- StringAppendF(out, ",\"dur\":%" PRId64, duration);
- if (!thread_timestamp_.is_null()) {
- int64_t thread_duration = thread_duration_.ToInternalValue();
- if (thread_duration != -1)
- StringAppendF(out, ",\"tdur\":%" PRId64, thread_duration);
- }
- }
-
- // Output tts if thread_timestamp is valid.
- if (!thread_timestamp_.is_null()) {
- int64_t thread_time_int64 = thread_timestamp_.ToInternalValue();
- StringAppendF(out, ",\"tts\":%" PRId64, thread_time_int64);
- }
-
- // Output async tts marker field if flag is set.
- if (flags_ & TRACE_EVENT_FLAG_ASYNC_TTS) {
- StringAppendF(out, ", \"use_async_tts\":1");
- }
-
- // 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 (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;
- }
- }
-
- if (flags_ & TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
- StringAppendF(out, ",\"bp\":\"e\"");
-
- if ((flags_ & TRACE_EVENT_FLAG_FLOW_OUT) ||
- (flags_ & TRACE_EVENT_FLAG_FLOW_IN)) {
- StringAppendF(out, ",\"bind_id\":\"0x%" PRIx64 "\"",
- static_cast<uint64_t>(bind_id_));
- }
- if (flags_ & TRACE_EVENT_FLAG_FLOW_IN)
- StringAppendF(out, ",\"flow_in\":true");
- if (flags_ & TRACE_EVENT_FLAG_FLOW_OUT)
- StringAppendF(out, ",\"flow_out\":true");
-
- // Instant events also output their scope.
- if (phase_ == TRACE_EVENT_PHASE_INSTANT) {
- char scope = '?';
- switch (flags_ & TRACE_EVENT_FLAG_SCOPE_MASK) {
- case TRACE_EVENT_SCOPE_GLOBAL:
- scope = TRACE_EVENT_SCOPE_NAME_GLOBAL;
- break;
-
- case TRACE_EVENT_SCOPE_PROCESS:
- scope = TRACE_EVENT_SCOPE_NAME_PROCESS;
- break;
-
- case TRACE_EVENT_SCOPE_THREAD:
- scope = TRACE_EVENT_SCOPE_NAME_THREAD;
- break;
- }
- StringAppendF(out, ",\"s\":\"%c\"", scope);
- }
-
- *out += "}";
-}
-
-void TraceEvent::AppendPrettyPrinted(std::ostringstream* out) const {
- *out << name_ << "[";
- *out << TraceLog::GetCategoryGroupName(category_group_enabled_);
- *out << "]";
- if (arg_names_[0]) {
- *out << ", {";
- for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
- if (i > 0)
- *out << ", ";
- *out << arg_names_[i] << ":";
- std::string value_as_text;
-
- if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
- convertable_values_[i]->AppendAsTraceFormat(&value_as_text);
- else
- AppendValueAsJSON(arg_types_[i], arg_values_[i], &value_as_text);
-
- *out << value_as_text;
- }
- *out << "}";
- }
-}
-
-} // 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
deleted file mode 100644
index 5eef702fb9..0000000000
--- a/base/trace_event/trace_event_impl.h
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright (c) 2012 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_IMPL_H_
-#define BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <stack>
-#include <string>
-#include <vector>
-
-#include "base/atomicops.h"
-#include "base/base_export.h"
-#include "base/callback.h"
-#include "base/containers/hash_tables.h"
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_util.h"
-#include "base/synchronization/condition_variable.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread_local.h"
-#include "base/trace_event/trace_event_memory_overhead.h"
-#include "build/build_config.h"
-
-namespace base {
-namespace trace_event {
-
-typedef base::Callback<bool(const char* arg_name)> ArgumentNameFilterPredicate;
-
-typedef base::Callback<bool(const char* category_group_name,
- const char* event_name,
- ArgumentNameFilterPredicate*)>
- ArgumentFilterPredicate;
-
-// For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
-// class must implement this interface.
-class BASE_EXPORT ConvertableToTraceFormat {
- public:
- ConvertableToTraceFormat() {}
- virtual ~ConvertableToTraceFormat() {}
-
- // Append the class info to the provided |out| string. The appended
- // data must be a valid JSON object. Strings must be properly quoted, and
- // escaped. There is no processing applied to the content after it is
- // appended.
- virtual void AppendAsTraceFormat(std::string* out) const = 0;
-
- virtual void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
-
- std::string ToString() const {
- std::string result;
- AppendAsTraceFormat(&result);
- return result;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ConvertableToTraceFormat);
-};
-
-const int kTraceMaxNumArgs = 2;
-
-struct TraceEventHandle {
- uint32_t chunk_seq;
- // These numbers of bits must be kept consistent with
- // TraceBufferChunk::kMaxTrunkIndex and
- // TraceBufferChunk::kTraceBufferChunkSize (in trace_buffer.h).
- unsigned chunk_index : 26;
- unsigned event_index : 6;
-};
-
-class BASE_EXPORT TraceEvent {
- public:
- union TraceValue {
- bool as_bool;
- unsigned long long as_uint;
- long long as_int;
- double as_double;
- const void* as_pointer;
- const char* as_string;
- };
-
- TraceEvent();
- ~TraceEvent();
-
- void MoveFrom(std::unique_ptr<TraceEvent> other);
-
- void Initialize(int thread_id,
- TimeTicks timestamp,
- ThreadTicks thread_timestamp,
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- const char* scope,
- unsigned long long id,
- unsigned long long bind_id,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags);
-
- void Reset();
-
- void UpdateDuration(const TimeTicks& now, const ThreadTicks& thread_now);
-
- void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
-
- // Serialize event data to JSON
- void AppendAsJSON(
- std::string* out,
- const ArgumentFilterPredicate& argument_filter_predicate) const;
- void AppendPrettyPrinted(std::ostringstream* out) const;
-
- static void AppendValueAsJSON(unsigned char type,
- TraceValue value,
- std::string* out);
-
- TimeTicks timestamp() const { return timestamp_; }
- ThreadTicks thread_timestamp() const { return thread_timestamp_; }
- char phase() const { return phase_; }
- int thread_id() const { return thread_id_; }
- TimeDelta duration() const { return duration_; }
- TimeDelta thread_duration() const { return thread_duration_; }
- const char* scope() const { return scope_; }
- unsigned long long id() const { return id_; }
- unsigned int flags() const { return flags_; }
-
- // Exposed for unittesting:
-
- const std::string* parameter_copy_storage() const {
- return parameter_copy_storage_.get();
- }
-
- const unsigned char* category_group_enabled() const {
- return category_group_enabled_;
- }
-
- const char* name() const { return name_; }
-
-#if defined(OS_ANDROID)
- void SendToATrace();
-#endif
-
- private:
- // Note: these are ordered by size (largest first) for optimal packing.
- TimeTicks timestamp_;
- ThreadTicks thread_timestamp_;
- TimeDelta duration_;
- TimeDelta thread_duration_;
- // scope_ and id_ can be used to store phase-specific data.
- const char* scope_;
- unsigned long long id_;
- TraceValue arg_values_[kTraceMaxNumArgs];
- const char* arg_names_[kTraceMaxNumArgs];
- std::unique_ptr<ConvertableToTraceFormat>
- convertable_values_[kTraceMaxNumArgs];
- const unsigned char* category_group_enabled_;
- const char* name_;
- std::unique_ptr<std::string> parameter_copy_storage_;
- // Depending on TRACE_EVENT_FLAG_HAS_PROCESS_ID the event will have either:
- // tid: thread_id_, pid: current_process_id (default case).
- // tid: -1, pid: process_id_ (when flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID).
- union {
- int thread_id_;
- int process_id_;
- };
- unsigned int flags_;
- unsigned long long bind_id_;
- unsigned char arg_types_[kTraceMaxNumArgs];
- char phase_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceEvent);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
diff --git a/base/trace_event/trace_event_memory_overhead.cc b/base/trace_event/trace_event_memory_overhead.cc
deleted file mode 100644
index 8d56e1d80e..0000000000
--- a/base/trace_event/trace_event_memory_overhead.cc
+++ /dev/null
@@ -1,156 +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/trace_event_memory_overhead.h"
-
-#include <algorithm>
-
-#include "base/bits.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/strings/stringprintf.h"
-#include "base/trace_event/memory_allocator_dump.h"
-#include "base/trace_event/process_memory_dump.h"
-#include "base/values.h"
-
-namespace base {
-namespace trace_event {
-
-TraceEventMemoryOverhead::TraceEventMemoryOverhead() {
-}
-
-TraceEventMemoryOverhead::~TraceEventMemoryOverhead() {
-}
-
-void TraceEventMemoryOverhead::AddOrCreateInternal(
- const char* object_type,
- size_t count,
- size_t allocated_size_in_bytes,
- size_t resident_size_in_bytes) {
- auto it = allocated_objects_.find(object_type);
- if (it == allocated_objects_.end()) {
- allocated_objects_.insert(std::make_pair(
- object_type,
- ObjectCountAndSize(
- {count, allocated_size_in_bytes, resident_size_in_bytes})));
- return;
- }
- it->second.count += count;
- it->second.allocated_size_in_bytes += allocated_size_in_bytes;
- it->second.resident_size_in_bytes += resident_size_in_bytes;
-}
-
-void TraceEventMemoryOverhead::Add(const char* object_type,
- size_t allocated_size_in_bytes) {
- Add(object_type, allocated_size_in_bytes, allocated_size_in_bytes);
-}
-
-void TraceEventMemoryOverhead::Add(const char* object_type,
- size_t allocated_size_in_bytes,
- size_t resident_size_in_bytes) {
- AddOrCreateInternal(object_type, 1, allocated_size_in_bytes,
- resident_size_in_bytes);
-}
-
-void TraceEventMemoryOverhead::AddString(const std::string& str) {
- // The number below are empirical and mainly based on profiling of real-world
- // std::string implementations:
- // - even short string end up malloc()-inc at least 32 bytes.
- // - longer strings seem to malloc() multiples of 16 bytes.
- const size_t capacity = bits::Align(str.capacity(), 16);
- Add("std::string", sizeof(std::string) + std::max<size_t>(capacity, 32u));
-}
-
-void TraceEventMemoryOverhead::AddRefCountedString(
- const RefCountedString& str) {
- Add("RefCountedString", sizeof(RefCountedString));
- AddString(str.data());
-}
-
-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:
- Add("FundamentalValue", sizeof(Value));
- break;
-
- case Value::Type::STRING: {
- const Value* string_value = nullptr;
- value.GetAsString(&string_value);
- Add("StringValue", sizeof(Value));
- AddString(string_value->GetString());
- } break;
-
- 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: {
- const DictionaryValue* dictionary_value = nullptr;
- value.GetAsDictionary(&dictionary_value);
- Add("DictionaryValue", sizeof(DictionaryValue));
- for (DictionaryValue::Iterator it(*dictionary_value); !it.IsAtEnd();
- it.Advance()) {
- AddString(it.key());
- AddValue(it.value());
- }
- } break;
-
- case Value::Type::LIST: {
- const ListValue* list_value = nullptr;
- value.GetAsList(&list_value);
- Add("ListValue", sizeof(ListValue));
- for (const auto& v : *list_value)
- AddValue(*v);
- } break;
-
- default:
- NOTREACHED();
- }
-}
-
-void TraceEventMemoryOverhead::AddSelf() {
- size_t estimated_size = sizeof(*this);
- // If the SmallMap did overflow its static capacity, its elements will be
- // allocated on the heap and have to be accounted separately.
- if (allocated_objects_.UsingFullMap())
- estimated_size += sizeof(map_type::value_type) * allocated_objects_.size();
- Add("TraceEventMemoryOverhead", estimated_size);
-}
-
-size_t TraceEventMemoryOverhead::GetCount(const char* object_type) const {
- const auto& it = allocated_objects_.find(object_type);
- if (it == allocated_objects_.end())
- return 0u;
- return it->second.count;
-}
-
-void TraceEventMemoryOverhead::Update(const TraceEventMemoryOverhead& other) {
- for (const auto& it : other.allocated_objects_) {
- AddOrCreateInternal(it.first, it.second.count,
- it.second.allocated_size_in_bytes,
- it.second.resident_size_in_bytes);
- }
-}
-
-void TraceEventMemoryOverhead::DumpInto(const char* base_name,
- ProcessMemoryDump* pmd) const {
- for (const auto& it : allocated_objects_) {
- std::string dump_name = StringPrintf("%s/%s", base_name, it.first);
- MemoryAllocatorDump* mad = pmd->CreateAllocatorDump(dump_name);
- mad->AddScalar(MemoryAllocatorDump::kNameSize,
- MemoryAllocatorDump::kUnitsBytes,
- it.second.allocated_size_in_bytes);
- mad->AddScalar("resident_size", MemoryAllocatorDump::kUnitsBytes,
- it.second.resident_size_in_bytes);
- mad->AddScalar(MemoryAllocatorDump::kNameObjectCount,
- MemoryAllocatorDump::kUnitsObjects, it.second.count);
- }
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/trace_event_memory_overhead.h b/base/trace_event/trace_event_memory_overhead.h
deleted file mode 100644
index a69c93fed2..0000000000
--- a/base/trace_event/trace_event_memory_overhead.h
+++ /dev/null
@@ -1,77 +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.
-
-#ifndef BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
-#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
-
-#include <stddef.h>
-
-#include "base/base_export.h"
-#include "base/containers/hash_tables.h"
-#include "base/containers/small_map.h"
-#include "base/macros.h"
-
-namespace base {
-
-class RefCountedString;
-class Value;
-
-namespace trace_event {
-
-class ProcessMemoryDump;
-
-// Used to estimate the memory overhead of the tracing infrastructure.
-class BASE_EXPORT TraceEventMemoryOverhead {
- public:
- TraceEventMemoryOverhead();
- ~TraceEventMemoryOverhead();
-
- // Use this method to account the overhead of an object for which an estimate
- // is known for both the allocated and resident memory.
- void Add(const char* object_type,
- size_t allocated_size_in_bytes,
- size_t resident_size_in_bytes);
-
- // Similar to Add() above, but assumes that
- // |resident_size_in_bytes| == |allocated_size_in_bytes|.
- void Add(const char* object_type, size_t allocated_size_in_bytes);
-
- // Specialized profiling functions for commonly used object types.
- void AddString(const std::string& str);
- void AddValue(const Value& value);
- void AddRefCountedString(const RefCountedString& str);
-
- // Call this after all the Add* methods above to account the memory used by
- // this TraceEventMemoryOverhead instance itself.
- void AddSelf();
-
- // Retrieves the count, that is, the count of Add*(|object_type|, ...) calls.
- size_t GetCount(const char* object_type) const;
-
- // Adds up and merges all the values from |other| to this instance.
- void Update(const TraceEventMemoryOverhead& other);
-
- void DumpInto(const char* base_name, ProcessMemoryDump* pmd) const;
-
- private:
- struct ObjectCountAndSize {
- size_t count;
- size_t allocated_size_in_bytes;
- size_t resident_size_in_bytes;
- };
- using map_type = SmallMap<hash_map<const char*, ObjectCountAndSize>, 16>;
- map_type allocated_objects_;
-
- void AddOrCreateInternal(const char* object_type,
- size_t count,
- size_t allocated_size_in_bytes,
- size_t resident_size_in_bytes);
-
- DISALLOW_COPY_AND_ASSIGN(TraceEventMemoryOverhead);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
diff --git a/base/trace_event/trace_event_synthetic_delay.cc b/base/trace_event/trace_event_synthetic_delay.cc
deleted file mode 100644
index cfae7435e9..0000000000
--- a/base/trace_event/trace_event_synthetic_delay.cc
+++ /dev/null
@@ -1,235 +0,0 @@
-// Copyright 2014 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/macros.h"
-#include "base/memory/singleton.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "base/trace_event/trace_event_synthetic_delay.h"
-
-namespace {
-const int kMaxSyntheticDelays = 32;
-} // namespace
-
-namespace base {
-namespace trace_event {
-
-TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {}
-TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {}
-
-class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock {
- public:
- static TraceEventSyntheticDelayRegistry* GetInstance();
-
- TraceEventSyntheticDelay* GetOrCreateDelay(const char* name);
- void ResetAllDelays();
-
- // TraceEventSyntheticDelayClock implementation.
- TimeTicks Now() override;
-
- private:
- TraceEventSyntheticDelayRegistry();
-
- friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>;
-
- Lock lock_;
- TraceEventSyntheticDelay delays_[kMaxSyntheticDelays];
- TraceEventSyntheticDelay dummy_delay_;
- subtle::Atomic32 delay_count_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry);
-};
-
-TraceEventSyntheticDelay::TraceEventSyntheticDelay()
- : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(NULL) {}
-
-TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {}
-
-TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup(
- const std::string& name) {
- return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay(
- name.c_str());
-}
-
-void TraceEventSyntheticDelay::Initialize(
- const std::string& name,
- TraceEventSyntheticDelayClock* clock) {
- name_ = name;
- clock_ = clock;
-}
-
-void TraceEventSyntheticDelay::SetTargetDuration(TimeDelta target_duration) {
- AutoLock lock(lock_);
- target_duration_ = target_duration;
- trigger_count_ = 0;
- begin_count_ = 0;
-}
-
-void TraceEventSyntheticDelay::SetMode(Mode mode) {
- AutoLock lock(lock_);
- mode_ = mode;
-}
-
-void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) {
- AutoLock lock(lock_);
- clock_ = clock;
-}
-
-void TraceEventSyntheticDelay::Begin() {
- // Note that we check for a non-zero target duration without locking to keep
- // things quick for the common case when delays are disabled. Since the delay
- // calculation is done with a lock held, it will always be correct. The only
- // downside of this is that we may fail to apply some delays when the target
- // duration changes.
- ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
- if (!target_duration_.ToInternalValue())
- return;
-
- TimeTicks start_time = clock_->Now();
- {
- AutoLock lock(lock_);
- if (++begin_count_ != 1)
- return;
- end_time_ = CalculateEndTimeLocked(start_time);
- }
-}
-
-void TraceEventSyntheticDelay::BeginParallel(TimeTicks* out_end_time) {
- // See note in Begin().
- ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
- if (!target_duration_.ToInternalValue()) {
- *out_end_time = TimeTicks();
- return;
- }
-
- TimeTicks start_time = clock_->Now();
- {
- AutoLock lock(lock_);
- *out_end_time = CalculateEndTimeLocked(start_time);
- }
-}
-
-void TraceEventSyntheticDelay::End() {
- // See note in Begin().
- ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
- if (!target_duration_.ToInternalValue())
- return;
-
- TimeTicks end_time;
- {
- AutoLock lock(lock_);
- if (!begin_count_ || --begin_count_ != 0)
- return;
- end_time = end_time_;
- }
- if (!end_time.is_null())
- ApplyDelay(end_time);
-}
-
-void TraceEventSyntheticDelay::EndParallel(TimeTicks end_time) {
- if (!end_time.is_null())
- ApplyDelay(end_time);
-}
-
-TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
- TimeTicks start_time) {
- if (mode_ == ONE_SHOT && trigger_count_++)
- return TimeTicks();
- else if (mode_ == ALTERNATING && trigger_count_++ % 2)
- return TimeTicks();
- return start_time + target_duration_;
-}
-
-void TraceEventSyntheticDelay::ApplyDelay(TimeTicks end_time) {
- TRACE_EVENT0("synthetic_delay", name_.c_str());
- while (clock_->Now() < end_time) {
- // Busy loop.
- }
-}
-
-TraceEventSyntheticDelayRegistry*
-TraceEventSyntheticDelayRegistry::GetInstance() {
- return Singleton<
- TraceEventSyntheticDelayRegistry,
- LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get();
-}
-
-TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry()
- : delay_count_(0) {}
-
-TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay(
- const char* name) {
- // Try to find an existing delay first without locking to make the common case
- // fast.
- int delay_count = subtle::Acquire_Load(&delay_count_);
- for (int i = 0; i < delay_count; ++i) {
- if (!strcmp(name, delays_[i].name_.c_str()))
- return &delays_[i];
- }
-
- AutoLock lock(lock_);
- delay_count = subtle::Acquire_Load(&delay_count_);
- for (int i = 0; i < delay_count; ++i) {
- if (!strcmp(name, delays_[i].name_.c_str()))
- return &delays_[i];
- }
-
- DCHECK(delay_count < kMaxSyntheticDelays)
- << "must increase kMaxSyntheticDelays";
- if (delay_count >= kMaxSyntheticDelays)
- return &dummy_delay_;
-
- delays_[delay_count].Initialize(std::string(name), this);
- subtle::Release_Store(&delay_count_, delay_count + 1);
- return &delays_[delay_count];
-}
-
-TimeTicks TraceEventSyntheticDelayRegistry::Now() {
- return TimeTicks::Now();
-}
-
-void TraceEventSyntheticDelayRegistry::ResetAllDelays() {
- AutoLock lock(lock_);
- int delay_count = subtle::Acquire_Load(&delay_count_);
- for (int i = 0; i < delay_count; ++i) {
- delays_[i].SetTargetDuration(TimeDelta());
- delays_[i].SetClock(this);
- }
-}
-
-void ResetTraceEventSyntheticDelays() {
- TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays();
-}
-
-} // namespace trace_event
-} // namespace base
-
-namespace trace_event_internal {
-
-ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name,
- base::subtle::AtomicWord* impl_ptr)
- : delay_impl_(GetOrCreateDelay(name, impl_ptr)) {
- delay_impl_->BeginParallel(&end_time_);
-}
-
-ScopedSyntheticDelay::~ScopedSyntheticDelay() {
- delay_impl_->EndParallel(end_time_);
-}
-
-base::trace_event::TraceEventSyntheticDelay* GetOrCreateDelay(
- const char* name,
- base::subtle::AtomicWord* impl_ptr) {
- base::trace_event::TraceEventSyntheticDelay* delay_impl =
- reinterpret_cast<base::trace_event::TraceEventSyntheticDelay*>(
- base::subtle::Acquire_Load(impl_ptr));
- if (!delay_impl) {
- delay_impl =
- base::trace_event::TraceEventSyntheticDelayRegistry::GetInstance()
- ->GetOrCreateDelay(name);
- base::subtle::Release_Store(
- impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl));
- }
- return delay_impl;
-}
-
-} // namespace trace_event_internal
diff --git a/base/trace_event/trace_event_synthetic_delay.h b/base/trace_event/trace_event_synthetic_delay.h
deleted file mode 100644
index e86f9eee2c..0000000000
--- a/base/trace_event/trace_event_synthetic_delay.h
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright 2014 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.
-
-// The synthetic delay framework makes it possible to dynamically inject
-// arbitrary delays into into different parts of the codebase. This can be used,
-// for instance, for testing various task scheduling algorithms.
-//
-// The delays are specified in terms of a target duration for a given block of
-// code. If the code executes faster than the duration, the thread is made to
-// sleep until the deadline is met.
-//
-// Code can be instrumented for delays with two sets of macros. First, for
-// delays that should apply within a scope, use the following macro:
-//
-// TRACE_EVENT_SYNTHETIC_DELAY("cc.LayerTreeHost.DrawAndSwap");
-//
-// For delaying operations that span multiple scopes, use:
-//
-// TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.Scheduler.BeginMainFrame");
-// ...
-// TRACE_EVENT_SYNTHETIC_DELAY_END("cc.Scheduler.BeginMainFrame");
-//
-// Here BEGIN establishes the start time for the delay and END executes the
-// delay based on the remaining time. If BEGIN is called multiple times in a
-// row, END should be called a corresponding number of times. Only the last
-// call to END will have an effect.
-//
-// Note that a single delay may begin on one thread and end on another. This
-// implies that a single delay cannot not be applied in several threads at once.
-
-#ifndef BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
-#define BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
-
-#include "base/atomicops.h"
-#include "base/macros.h"
-#include "base/synchronization/lock.h"
-#include "base/time/time.h"
-#include "base/trace_event/trace_event.h"
-
-// Apply a named delay in the current scope.
-#define TRACE_EVENT_SYNTHETIC_DELAY(name) \
- static base::subtle::AtomicWord INTERNAL_TRACE_EVENT_UID(impl_ptr) = 0; \
- trace_event_internal::ScopedSyntheticDelay INTERNAL_TRACE_EVENT_UID(delay)( \
- name, &INTERNAL_TRACE_EVENT_UID(impl_ptr));
-
-// Begin a named delay, establishing its timing start point. May be called
-// multiple times as long as the calls to TRACE_EVENT_SYNTHETIC_DELAY_END are
-// balanced. Only the first call records the timing start point.
-#define TRACE_EVENT_SYNTHETIC_DELAY_BEGIN(name) \
- do { \
- static base::subtle::AtomicWord impl_ptr = 0; \
- trace_event_internal::GetOrCreateDelay(name, &impl_ptr)->Begin(); \
- } while (false)
-
-// End a named delay. The delay is applied only if this call matches the
-// first corresponding call to TRACE_EVENT_SYNTHETIC_DELAY_BEGIN with the
-// same delay.
-#define TRACE_EVENT_SYNTHETIC_DELAY_END(name) \
- do { \
- static base::subtle::AtomicWord impl_ptr = 0; \
- trace_event_internal::GetOrCreateDelay(name, &impl_ptr)->End(); \
- } while (false)
-
-namespace base {
-namespace trace_event {
-
-// Time source for computing delay durations. Used for testing.
-class TRACE_EVENT_API_CLASS_EXPORT TraceEventSyntheticDelayClock {
- public:
- TraceEventSyntheticDelayClock();
- virtual ~TraceEventSyntheticDelayClock();
- virtual base::TimeTicks Now() = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayClock);
-};
-
-// Single delay point instance.
-class TRACE_EVENT_API_CLASS_EXPORT TraceEventSyntheticDelay {
- public:
- enum Mode {
- STATIC, // Apply the configured delay every time.
- ONE_SHOT, // Apply the configured delay just once.
- ALTERNATING // Apply the configured delay every other time.
- };
-
- // Returns an existing named delay instance or creates a new one with |name|.
- static TraceEventSyntheticDelay* Lookup(const std::string& name);
-
- void SetTargetDuration(TimeDelta target_duration);
- void SetMode(Mode mode);
- void SetClock(TraceEventSyntheticDelayClock* clock);
-
- // Begin the delay, establishing its timing start point. May be called
- // multiple times as long as the calls to End() are balanced. Only the first
- // call records the timing start point.
- void Begin();
-
- // End the delay. The delay is applied only if this call matches the first
- // corresponding call to Begin() with the same delay.
- void End();
-
- // Begin a parallel instance of the delay. Several parallel instances may be
- // active simultaneously and will complete independently. The computed end
- // time for the delay is stored in |out_end_time|, which should later be
- // passed to EndParallel().
- void BeginParallel(base::TimeTicks* out_end_time);
-
- // End a previously started parallel delay. |end_time| is the delay end point
- // computed by BeginParallel().
- void EndParallel(base::TimeTicks end_time);
-
- private:
- TraceEventSyntheticDelay();
- ~TraceEventSyntheticDelay();
- friend class TraceEventSyntheticDelayRegistry;
-
- void Initialize(const std::string& name,
- TraceEventSyntheticDelayClock* clock);
- base::TimeTicks CalculateEndTimeLocked(base::TimeTicks start_time);
- void ApplyDelay(base::TimeTicks end_time);
-
- Lock lock_;
- Mode mode_;
- std::string name_;
- int begin_count_;
- int trigger_count_;
- base::TimeTicks end_time_;
- base::TimeDelta target_duration_;
- TraceEventSyntheticDelayClock* clock_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelay);
-};
-
-// Set the target durations of all registered synthetic delay points to zero.
-TRACE_EVENT_API_CLASS_EXPORT void ResetTraceEventSyntheticDelays();
-
-} // namespace trace_event
-} // namespace base
-
-namespace trace_event_internal {
-
-// Helper class for scoped delays. Do not use directly.
-class TRACE_EVENT_API_CLASS_EXPORT ScopedSyntheticDelay {
- public:
- explicit ScopedSyntheticDelay(const char* name,
- base::subtle::AtomicWord* impl_ptr);
- ~ScopedSyntheticDelay();
-
- private:
- base::trace_event::TraceEventSyntheticDelay* delay_impl_;
- base::TimeTicks end_time_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedSyntheticDelay);
-};
-
-// Helper for registering delays. Do not use directly.
-TRACE_EVENT_API_CLASS_EXPORT base::trace_event::TraceEventSyntheticDelay*
- GetOrCreateDelay(const char* name, base::subtle::AtomicWord* impl_ptr);
-
-} // namespace trace_event_internal
-
-#endif // BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
diff --git a/base/trace_event/trace_event_synthetic_delay_unittest.cc b/base/trace_event/trace_event_synthetic_delay_unittest.cc
deleted file mode 100644
index 97a4580b3b..0000000000
--- a/base/trace_event/trace_event_synthetic_delay_unittest.cc
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright 2014 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_synthetic_delay.h"
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace trace_event {
-namespace {
-
-const int kTargetDurationMs = 100;
-// Allow some leeway in timings to make it possible to run these tests with a
-// wall clock time source too.
-const int kShortDurationMs = 10;
-
-} // namespace
-
-class TraceEventSyntheticDelayTest : public testing::Test,
- public TraceEventSyntheticDelayClock {
- public:
- TraceEventSyntheticDelayTest() {}
- ~TraceEventSyntheticDelayTest() override { ResetTraceEventSyntheticDelays(); }
-
- // TraceEventSyntheticDelayClock implementation.
- base::TimeTicks Now() override {
- AdvanceTime(base::TimeDelta::FromMilliseconds(kShortDurationMs / 10));
- return now_;
- }
-
- TraceEventSyntheticDelay* ConfigureDelay(const char* name) {
- TraceEventSyntheticDelay* delay = TraceEventSyntheticDelay::Lookup(name);
- delay->SetClock(this);
- delay->SetTargetDuration(
- base::TimeDelta::FromMilliseconds(kTargetDurationMs));
- return delay;
- }
-
- void AdvanceTime(base::TimeDelta delta) { now_ += delta; }
-
- int64_t TestFunction() {
- base::TimeTicks start = Now();
- { TRACE_EVENT_SYNTHETIC_DELAY("test.Delay"); }
- return (Now() - start).InMilliseconds();
- }
-
- int64_t AsyncTestFunctionBegin() {
- base::TimeTicks start = Now();
- { TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("test.AsyncDelay"); }
- return (Now() - start).InMilliseconds();
- }
-
- int64_t AsyncTestFunctionEnd() {
- base::TimeTicks start = Now();
- { TRACE_EVENT_SYNTHETIC_DELAY_END("test.AsyncDelay"); }
- return (Now() - start).InMilliseconds();
- }
-
- private:
- base::TimeTicks now_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayTest);
-};
-
-TEST_F(TraceEventSyntheticDelayTest, StaticDelay) {
- TraceEventSyntheticDelay* delay = ConfigureDelay("test.Delay");
- delay->SetMode(TraceEventSyntheticDelay::STATIC);
- EXPECT_GE(TestFunction(), kTargetDurationMs);
-}
-
-TEST_F(TraceEventSyntheticDelayTest, OneShotDelay) {
- TraceEventSyntheticDelay* delay = ConfigureDelay("test.Delay");
- delay->SetMode(TraceEventSyntheticDelay::ONE_SHOT);
- EXPECT_GE(TestFunction(), kTargetDurationMs);
- EXPECT_LT(TestFunction(), kShortDurationMs);
-
- delay->SetTargetDuration(
- base::TimeDelta::FromMilliseconds(kTargetDurationMs));
- EXPECT_GE(TestFunction(), kTargetDurationMs);
-}
-
-TEST_F(TraceEventSyntheticDelayTest, AlternatingDelay) {
- TraceEventSyntheticDelay* delay = ConfigureDelay("test.Delay");
- delay->SetMode(TraceEventSyntheticDelay::ALTERNATING);
- EXPECT_GE(TestFunction(), kTargetDurationMs);
- EXPECT_LT(TestFunction(), kShortDurationMs);
- EXPECT_GE(TestFunction(), kTargetDurationMs);
- EXPECT_LT(TestFunction(), kShortDurationMs);
-}
-
-TEST_F(TraceEventSyntheticDelayTest, AsyncDelay) {
- ConfigureDelay("test.AsyncDelay");
- EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
- EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
-}
-
-TEST_F(TraceEventSyntheticDelayTest, AsyncDelayExceeded) {
- ConfigureDelay("test.AsyncDelay");
- EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
- AdvanceTime(base::TimeDelta::FromMilliseconds(kTargetDurationMs));
- EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
-}
-
-TEST_F(TraceEventSyntheticDelayTest, AsyncDelayNoActivation) {
- ConfigureDelay("test.AsyncDelay");
- EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
-}
-
-TEST_F(TraceEventSyntheticDelayTest, AsyncDelayNested) {
- ConfigureDelay("test.AsyncDelay");
- EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
- EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
- EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
- EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
-}
-
-TEST_F(TraceEventSyntheticDelayTest, AsyncDelayUnbalanced) {
- ConfigureDelay("test.AsyncDelay");
- EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
- EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
- EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
-
- EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
- EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
-}
-
-TEST_F(TraceEventSyntheticDelayTest, ResetDelays) {
- ConfigureDelay("test.Delay");
- ResetTraceEventSyntheticDelays();
- EXPECT_LT(TestFunction(), kShortDurationMs);
-}
-
-TEST_F(TraceEventSyntheticDelayTest, BeginParallel) {
- TraceEventSyntheticDelay* delay = ConfigureDelay("test.AsyncDelay");
- base::TimeTicks end_times[2];
- base::TimeTicks start_time = Now();
-
- delay->BeginParallel(&end_times[0]);
- EXPECT_FALSE(end_times[0].is_null());
-
- delay->BeginParallel(&end_times[1]);
- EXPECT_FALSE(end_times[1].is_null());
-
- delay->EndParallel(end_times[0]);
- EXPECT_GE((Now() - start_time).InMilliseconds(), kTargetDurationMs);
-
- start_time = Now();
- delay->EndParallel(end_times[1]);
- EXPECT_LT((Now() - start_time).InMilliseconds(), kShortDurationMs);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/trace_event_system_stats_monitor.h b/base/trace_event/trace_event_system_stats_monitor.h
deleted file mode 100644
index 14aa5681fe..0000000000
--- a/base/trace_event/trace_event_system_stats_monitor.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2013 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_SYSTEM_STATS_MONITOR_H_
-#define BASE_TRACE_EVENT_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
-
-#include "base/base_export.h"
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/process/process_metrics.h"
-#include "base/timer/timer.h"
-#include "base/trace_event/trace_log.h"
-
-namespace base {
-
-class SingleThreadTaskRunner;
-
-namespace trace_event {
-
-// Watches for chrome://tracing to be enabled or disabled. When tracing is
-// enabled, also enables system events profiling. This class is the preferred
-// way to turn system tracing on and off.
-class BASE_EXPORT TraceEventSystemStatsMonitor
- : public TraceLog::EnabledStateObserver {
- public:
- // Length of time interval between stat profiles.
- static const int kSamplingIntervalMilliseconds = 2000;
-
- // |task_runner| must be the primary thread for the client
- // process, e.g. the UI thread in a browser.
- explicit TraceEventSystemStatsMonitor(
- scoped_refptr<SingleThreadTaskRunner> task_runner);
-
- ~TraceEventSystemStatsMonitor() override;
-
- // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
- void OnTraceLogEnabled() override;
- void OnTraceLogDisabled() override;
-
- // Retrieves system profiling at the current time.
- void DumpSystemStats();
-
- private:
- FRIEND_TEST_ALL_PREFIXES(TraceSystemStatsMonitorTest,
- TraceEventSystemStatsMonitor);
-
- bool IsTimerRunningForTest() const;
-
- void StartProfiling();
-
- void StopProfiling();
-
- // Ensures the observer starts and stops tracing on the primary thread.
- scoped_refptr<SingleThreadTaskRunner> task_runner_;
-
- // Timer to schedule system profile dumps.
- RepeatingTimer dump_timer_;
-
- WeakPtrFactory<TraceEventSystemStatsMonitor> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceEventSystemStatsMonitor);
-};
-
-// Converts system memory profiling stats in |input| to
-// trace event compatible JSON and appends to |output|. Visible for testing.
-BASE_EXPORT void AppendSystemProfileAsTraceFormat(const SystemMetrics&
- system_stats,
- std::string* output);
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
deleted file mode 100644
index 7a30e4ee57..0000000000
--- a/base/trace_event/trace_event_unittest.cc
+++ /dev/null
@@ -1,3220 +0,0 @@
-// Copyright (c) 2012 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.h"
-
-#include <math.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include <cstdlib>
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/json/json_reader.h"
-#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"
-#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
-#include "base/strings/pattern.h"
-#include "base/strings/stringprintf.h"
-#include "base/synchronization/waitable_event.h"
-#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"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-enum CompareOp {
- IS_EQUAL,
- IS_NOT_EQUAL,
-};
-
-struct JsonKeyValue {
- const char* key;
- const char* value;
- CompareOp op;
-};
-
-const int kThreadId = 42;
-const int kAsyncId = 5;
-const char kAsyncIdStr[] = "0x5";
-const int kAsyncId2 = 6;
-const char kAsyncId2Str[] = "0x6";
-const int kFlowId = 7;
-const char kFlowIdStr[] = "0x7";
-
-const char kRecordAllCategoryFilter[] = "*";
-
-class TraceEventTestFixture : public testing::Test {
- public:
- void OnTraceDataCollected(
- WaitableEvent* flush_complete_event,
- const scoped_refptr<base::RefCountedString>& events_str,
- bool has_more_events);
- DictionaryValue* FindMatchingTraceEntry(const JsonKeyValue* key_values);
- DictionaryValue* FindNamePhase(const char* name, const char* phase);
- DictionaryValue* FindNamePhaseKeyValue(const char* name,
- const char* phase,
- const char* key,
- const char* value);
- void DropTracedMetadataRecords();
- bool FindMatchingValue(const char* key,
- const char* value);
- bool FindNonMatchingValue(const char* key,
- const char* value);
- void Clear() {
- trace_parsed_.Clear();
- json_output_.json_output.clear();
- }
-
- void BeginTrace() {
- BeginSpecificTrace("*");
- }
-
- void BeginSpecificTrace(const std::string& filter) {
- TraceLog::GetInstance()->SetEnabled(TraceConfig(filter, ""),
- TraceLog::RECORDING_MODE);
- }
-
- void CancelTrace() {
- WaitableEvent flush_complete_event(
- WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- CancelTraceAsync(&flush_complete_event);
- flush_complete_event.Wait();
- }
-
- void EndTraceAndFlush() {
- num_flush_callbacks_ = 0;
- WaitableEvent flush_complete_event(
- WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- EndTraceAndFlushAsync(&flush_complete_event);
- flush_complete_event.Wait();
- }
-
- // Used when testing thread-local buffers which requires the thread initiating
- // flush to have a message loop.
- void EndTraceAndFlushInThreadWithMessageLoop() {
- WaitableEvent flush_complete_event(
- WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- Thread flush_thread("flush");
- flush_thread.Start();
- flush_thread.task_runner()->PostTask(
- FROM_HERE, base::Bind(&TraceEventTestFixture::EndTraceAndFlushAsync,
- base::Unretained(this), &flush_complete_event));
- flush_complete_event.Wait();
- }
-
- void CancelTraceAsync(WaitableEvent* flush_complete_event) {
- TraceLog::GetInstance()->CancelTracing(
- base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
- base::Unretained(static_cast<TraceEventTestFixture*>(this)),
- base::Unretained(flush_complete_event)));
- }
-
- void EndTraceAndFlushAsync(WaitableEvent* flush_complete_event) {
- TraceLog::GetInstance()->SetDisabled(TraceLog::RECORDING_MODE |
- TraceLog::FILTERING_MODE);
- TraceLog::GetInstance()->Flush(
- base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
- base::Unretained(static_cast<TraceEventTestFixture*>(this)),
- base::Unretained(flush_complete_event)));
- }
-
- void SetUp() override {
- const char* name = PlatformThread::GetName();
- old_thread_name_ = name ? strdup(name) : NULL;
-
- TraceLog::DeleteForTesting();
- TraceLog* tracelog = TraceLog::GetInstance();
- ASSERT_TRUE(tracelog);
- ASSERT_FALSE(tracelog->IsEnabled());
- trace_buffer_.SetOutputCallback(json_output_.GetCallback());
- num_flush_callbacks_ = 0;
- }
- void TearDown() override {
- if (TraceLog::GetInstance())
- EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
- PlatformThread::SetName(old_thread_name_ ? old_thread_name_ : "");
- free(old_thread_name_);
- old_thread_name_ = NULL;
- // We want our singleton torn down after each test.
- TraceLog::DeleteForTesting();
- }
-
- char* old_thread_name_;
- ListValue trace_parsed_;
- TraceResultBuffer trace_buffer_;
- TraceResultBuffer::SimpleOutput json_output_;
- size_t num_flush_callbacks_;
-
- private:
- // We want our singleton torn down after each test.
- ShadowingAtExitManager at_exit_manager_;
- Lock lock_;
-};
-
-void TraceEventTestFixture::OnTraceDataCollected(
- WaitableEvent* flush_complete_event,
- const scoped_refptr<base::RefCountedString>& events_str,
- bool has_more_events) {
- num_flush_callbacks_++;
- if (num_flush_callbacks_ > 1) {
- EXPECT_FALSE(events_str->data().empty());
- }
- AutoLock lock(lock_);
- json_output_.json_output.clear();
- trace_buffer_.Start();
- trace_buffer_.AddFragment(events_str->data());
- trace_buffer_.Finish();
-
- std::unique_ptr<Value> root = base::JSONReader::Read(
- json_output_.json_output, JSON_PARSE_RFC | JSON_DETACHABLE_CHILDREN);
-
- if (!root.get()) {
- LOG(ERROR) << json_output_.json_output;
- }
-
- ListValue* root_list = NULL;
- ASSERT_TRUE(root.get());
- ASSERT_TRUE(root->GetAsList(&root_list));
-
- // Move items into our aggregate collection
- while (root_list->GetSize()) {
- std::unique_ptr<Value> item;
- root_list->Remove(0, &item);
- trace_parsed_.Append(std::move(item));
- }
-
- if (!has_more_events)
- flush_complete_event->Signal();
-}
-
-static bool CompareJsonValues(const std::string& lhs,
- const std::string& rhs,
- CompareOp op) {
- switch (op) {
- case IS_EQUAL:
- return lhs == rhs;
- case IS_NOT_EQUAL:
- return lhs != rhs;
- default:
- CHECK(0);
- }
- return false;
-}
-
-static bool IsKeyValueInDict(const JsonKeyValue* key_value,
- DictionaryValue* dict) {
- Value* value = NULL;
- std::string value_str;
- if (dict->Get(key_value->key, &value) &&
- value->GetAsString(&value_str) &&
- CompareJsonValues(value_str, key_value->value, key_value->op))
- return true;
-
- // Recurse to test arguments
- DictionaryValue* args_dict = NULL;
- dict->GetDictionary("args", &args_dict);
- if (args_dict)
- return IsKeyValueInDict(key_value, args_dict);
-
- return false;
-}
-
-static bool IsAllKeyValueInDict(const JsonKeyValue* key_values,
- DictionaryValue* dict) {
- // Scan all key_values, they must all be present and equal.
- while (key_values && key_values->key) {
- if (!IsKeyValueInDict(key_values, dict))
- return false;
- ++key_values;
- }
- return true;
-}
-
-DictionaryValue* TraceEventTestFixture::FindMatchingTraceEntry(
- const JsonKeyValue* key_values) {
- // Scan all items
- size_t trace_parsed_count = trace_parsed_.GetSize();
- 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)
- continue;
- DictionaryValue* dict = static_cast<DictionaryValue*>(value);
-
- if (IsAllKeyValueInDict(key_values, dict))
- return dict;
- }
- return NULL;
-}
-
-void TraceEventTestFixture::DropTracedMetadataRecords() {
- std::unique_ptr<ListValue> old_trace_parsed(trace_parsed_.CreateDeepCopy());
- size_t old_trace_parsed_size = old_trace_parsed->GetSize();
- trace_parsed_.Clear();
-
- 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) {
- trace_parsed_.Append(value->CreateDeepCopy());
- continue;
- }
- DictionaryValue* dict = static_cast<DictionaryValue*>(value);
- std::string tmp;
- if (dict->GetString("ph", &tmp) && tmp == "M")
- continue;
-
- trace_parsed_.Append(value->CreateDeepCopy());
- }
-}
-
-DictionaryValue* TraceEventTestFixture::FindNamePhase(const char* name,
- const char* phase) {
- JsonKeyValue key_values[] = {
- {"name", name, IS_EQUAL},
- {"ph", phase, IS_EQUAL},
- {0, 0, IS_EQUAL}
- };
- return FindMatchingTraceEntry(key_values);
-}
-
-DictionaryValue* TraceEventTestFixture::FindNamePhaseKeyValue(
- const char* name,
- const char* phase,
- const char* key,
- const char* value) {
- JsonKeyValue key_values[] = {
- {"name", name, IS_EQUAL},
- {"ph", phase, IS_EQUAL},
- {key, value, IS_EQUAL},
- {0, 0, IS_EQUAL}
- };
- return FindMatchingTraceEntry(key_values);
-}
-
-bool TraceEventTestFixture::FindMatchingValue(const char* key,
- const char* value) {
- JsonKeyValue key_values[] = {
- {key, value, IS_EQUAL},
- {0, 0, IS_EQUAL}
- };
- return FindMatchingTraceEntry(key_values);
-}
-
-bool TraceEventTestFixture::FindNonMatchingValue(const char* key,
- const char* value) {
- JsonKeyValue key_values[] = {
- {key, value, IS_NOT_EQUAL},
- {0, 0, IS_EQUAL}
- };
- return FindMatchingTraceEntry(key_values);
-}
-
-bool IsStringInDict(const char* string_to_match, const DictionaryValue* dict) {
- for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
- if (it.key().find(string_to_match) != std::string::npos)
- return true;
-
- std::string value_str;
- it.value().GetAsString(&value_str);
- if (value_str.find(string_to_match) != std::string::npos)
- return true;
- }
-
- // Recurse to test arguments
- const DictionaryValue* args_dict = NULL;
- dict->GetDictionary("args", &args_dict);
- if (args_dict)
- return IsStringInDict(string_to_match, args_dict);
-
- return false;
-}
-
-const DictionaryValue* FindTraceEntry(
- const ListValue& trace_parsed,
- const char* string_to_match,
- const DictionaryValue* match_after_this_item = NULL) {
- // Scan all items
- size_t trace_parsed_count = trace_parsed.GetSize();
- for (size_t i = 0; i < trace_parsed_count; i++) {
- const Value* value = NULL;
- trace_parsed.Get(i, &value);
- if (match_after_this_item) {
- if (value == match_after_this_item)
- match_after_this_item = NULL;
- continue;
- }
- if (!value || value->GetType() != Value::Type::DICTIONARY)
- continue;
- const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
-
- if (IsStringInDict(string_to_match, dict))
- return dict;
- }
- return NULL;
-}
-
-std::vector<const DictionaryValue*> FindTraceEntries(
- const ListValue& trace_parsed,
- const char* string_to_match) {
- std::vector<const DictionaryValue*> hits;
- size_t trace_parsed_count = trace_parsed.GetSize();
- 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)
- continue;
- const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
-
- if (IsStringInDict(string_to_match, dict))
- hits.push_back(dict);
- }
- return hits;
-}
-
-const char kControlCharacters[] = "\001\002\003\n\r";
-
-void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) {
- {
- TRACE_EVENT0("all", "TRACE_EVENT0 call");
- TRACE_EVENT1("all", "TRACE_EVENT1 call", "name1", "value1");
- TRACE_EVENT2("all", "TRACE_EVENT2 call",
- "name1", "\"value1\"",
- "name2", "value\\2");
-
- TRACE_EVENT_INSTANT0("all", "TRACE_EVENT_INSTANT0 call",
- TRACE_EVENT_SCOPE_GLOBAL);
- TRACE_EVENT_INSTANT1("all", "TRACE_EVENT_INSTANT1 call",
- TRACE_EVENT_SCOPE_PROCESS, "name1", "value1");
- TRACE_EVENT_INSTANT2("all", "TRACE_EVENT_INSTANT2 call",
- TRACE_EVENT_SCOPE_THREAD,
- "name1", "value1",
- "name2", "value2");
-
- TRACE_EVENT_BEGIN0("all", "TRACE_EVENT_BEGIN0 call");
- TRACE_EVENT_BEGIN1("all", "TRACE_EVENT_BEGIN1 call", "name1", "value1");
- TRACE_EVENT_BEGIN2("all", "TRACE_EVENT_BEGIN2 call",
- "name1", "value1",
- "name2", "value2");
-
- TRACE_EVENT_END0("all", "TRACE_EVENT_END0 call");
- TRACE_EVENT_END1("all", "TRACE_EVENT_END1 call", "name1", "value1");
- TRACE_EVENT_END2("all", "TRACE_EVENT_END2 call",
- "name1", "value1",
- "name2", "value2");
-
- TRACE_EVENT_ASYNC_BEGIN0("all", "TRACE_EVENT_ASYNC_BEGIN0 call", kAsyncId);
- TRACE_EVENT_ASYNC_BEGIN1("all", "TRACE_EVENT_ASYNC_BEGIN1 call", kAsyncId,
- "name1", "value1");
- TRACE_EVENT_ASYNC_BEGIN2("all", "TRACE_EVENT_ASYNC_BEGIN2 call", kAsyncId,
- "name1", "value1",
- "name2", "value2");
-
- TRACE_EVENT_ASYNC_STEP_INTO0("all", "TRACE_EVENT_ASYNC_STEP_INTO0 call",
- kAsyncId, "step_begin1");
- TRACE_EVENT_ASYNC_STEP_INTO1("all", "TRACE_EVENT_ASYNC_STEP_INTO1 call",
- kAsyncId, "step_begin2", "name1", "value1");
-
- TRACE_EVENT_ASYNC_END0("all", "TRACE_EVENT_ASYNC_END0 call", kAsyncId);
- TRACE_EVENT_ASYNC_END1("all", "TRACE_EVENT_ASYNC_END1 call", kAsyncId,
- "name1", "value1");
- TRACE_EVENT_ASYNC_END2("all", "TRACE_EVENT_ASYNC_END2 call", kAsyncId,
- "name1", "value1",
- "name2", "value2");
-
- TRACE_EVENT_FLOW_BEGIN0("all", "TRACE_EVENT_FLOW_BEGIN0 call", kFlowId);
- TRACE_EVENT_FLOW_STEP0("all", "TRACE_EVENT_FLOW_STEP0 call",
- kFlowId, "step1");
- TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0("all",
- "TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 call", kFlowId);
-
- TRACE_COUNTER1("all", "TRACE_COUNTER1 call", 31415);
- TRACE_COUNTER2("all", "TRACE_COUNTER2 call",
- "a", 30000,
- "b", 1415);
-
- TRACE_COUNTER_WITH_TIMESTAMP1("all", "TRACE_COUNTER_WITH_TIMESTAMP1 call",
- TimeTicks::FromInternalValue(42), 31415);
- TRACE_COUNTER_WITH_TIMESTAMP2("all", "TRACE_COUNTER_WITH_TIMESTAMP2 call",
- TimeTicks::FromInternalValue(42),
- "a", 30000, "b", 1415);
-
- TRACE_COUNTER_ID1("all", "TRACE_COUNTER_ID1 call", 0x319009, 31415);
- TRACE_COUNTER_ID2("all", "TRACE_COUNTER_ID2 call", 0x319009,
- "a", 30000, "b", 1415);
-
- 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));
- 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));
-
- TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("all",
- "TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call",
- kAsyncId2, kThreadId, TimeTicks::FromInternalValue(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",
- kAsyncId2, "step_end2", "name1", "value1");
-
- TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0("all",
- "TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0 call",
- kAsyncId2, kThreadId, TimeTicks::FromInternalValue(45678));
-
- TRACE_EVENT_OBJECT_CREATED_WITH_ID("all", "tracked object 1", 0x42);
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- "all", "tracked object 1", 0x42, "hello");
- TRACE_EVENT_OBJECT_DELETED_WITH_ID("all", "tracked object 1", 0x42);
-
- TraceScopedTrackableObject<int> trackable("all", "tracked object 2",
- 0x2128506);
- trackable.snapshot("world");
-
- TRACE_EVENT_OBJECT_CREATED_WITH_ID(
- "all", "tracked object 3", TRACE_ID_WITH_SCOPE("scope", 0x42));
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- "all", "tracked object 3", TRACE_ID_WITH_SCOPE("scope", 0x42), "hello");
- TRACE_EVENT_OBJECT_DELETED_WITH_ID(
- "all", "tracked object 3", TRACE_ID_WITH_SCOPE("scope", 0x42));
-
- TRACE_EVENT1(kControlCharacters, kControlCharacters,
- kControlCharacters, kControlCharacters);
-
- uint64_t context_id = 0x20151021;
-
- TRACE_EVENT_ENTER_CONTEXT("all", "TRACE_EVENT_ENTER_CONTEXT call",
- TRACE_ID_WITH_SCOPE("scope", context_id));
- TRACE_EVENT_LEAVE_CONTEXT("all", "TRACE_EVENT_LEAVE_CONTEXT call",
- TRACE_ID_WITH_SCOPE("scope", context_id));
- TRACE_EVENT_SCOPED_CONTEXT("disabled-by-default-cat",
- "TRACE_EVENT_SCOPED_CONTEXT disabled call",
- 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)
- task_complete_event->Signal();
-}
-
-void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed) {
- const DictionaryValue* item = NULL;
-
-#define EXPECT_FIND_(string) \
- item = FindTraceEntry(trace_parsed, string); \
- EXPECT_TRUE(item);
-#define EXPECT_NOT_FIND_(string) \
- item = FindTraceEntry(trace_parsed, string); \
- EXPECT_FALSE(item);
-#define EXPECT_SUB_FIND_(string) \
- if (item) \
- EXPECT_TRUE(IsStringInDict(string, item));
-
- EXPECT_FIND_("TRACE_EVENT0 call");
- {
- std::string ph;
- std::string ph_end;
- EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call")));
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("X", ph);
- item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call", item);
- EXPECT_FALSE(item);
- }
- EXPECT_FIND_("TRACE_EVENT1 call");
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("value1");
- EXPECT_FIND_("TRACE_EVENT2 call");
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("\"value1\"");
- EXPECT_SUB_FIND_("name2");
- EXPECT_SUB_FIND_("value\\2");
-
- EXPECT_FIND_("TRACE_EVENT_INSTANT0 call");
- {
- std::string scope;
- EXPECT_TRUE((item && item->GetString("s", &scope)));
- EXPECT_EQ("g", scope);
- }
- EXPECT_FIND_("TRACE_EVENT_INSTANT1 call");
- {
- std::string scope;
- EXPECT_TRUE((item && item->GetString("s", &scope)));
- EXPECT_EQ("p", scope);
- }
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("value1");
- EXPECT_FIND_("TRACE_EVENT_INSTANT2 call");
- {
- std::string scope;
- EXPECT_TRUE((item && item->GetString("s", &scope)));
- EXPECT_EQ("t", scope);
- }
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("value1");
- EXPECT_SUB_FIND_("name2");
- EXPECT_SUB_FIND_("value2");
-
- EXPECT_FIND_("TRACE_EVENT_BEGIN0 call");
- EXPECT_FIND_("TRACE_EVENT_BEGIN1 call");
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("value1");
- EXPECT_FIND_("TRACE_EVENT_BEGIN2 call");
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("value1");
- EXPECT_SUB_FIND_("name2");
- EXPECT_SUB_FIND_("value2");
-
- EXPECT_FIND_("TRACE_EVENT_END0 call");
- EXPECT_FIND_("TRACE_EVENT_END1 call");
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("value1");
- EXPECT_FIND_("TRACE_EVENT_END2 call");
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("value1");
- EXPECT_SUB_FIND_("name2");
- EXPECT_SUB_FIND_("value2");
-
- EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN0 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN1 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("value1");
- EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN2 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("value1");
- EXPECT_SUB_FIND_("name2");
- EXPECT_SUB_FIND_("value2");
-
- EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_INTO0 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_SUB_FIND_("step_begin1");
- EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_INTO1 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_SUB_FIND_("step_begin2");
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("value1");
-
- EXPECT_FIND_("TRACE_EVENT_ASYNC_END0 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_FIND_("TRACE_EVENT_ASYNC_END1 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("value1");
- EXPECT_FIND_("TRACE_EVENT_ASYNC_END2 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("value1");
- EXPECT_SUB_FIND_("name2");
- EXPECT_SUB_FIND_("value2");
-
- EXPECT_FIND_("TRACE_EVENT_FLOW_BEGIN0 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kFlowIdStr);
- EXPECT_FIND_("TRACE_EVENT_FLOW_STEP0 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kFlowIdStr);
- EXPECT_SUB_FIND_("step1");
- EXPECT_FIND_("TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kFlowIdStr);
-
- EXPECT_FIND_("TRACE_COUNTER1 call");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("C", ph);
-
- int value;
- EXPECT_TRUE((item && item->GetInteger("args.value", &value)));
- EXPECT_EQ(31415, value);
- }
-
- EXPECT_FIND_("TRACE_COUNTER2 call");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("C", ph);
-
- int value;
- EXPECT_TRUE((item && item->GetInteger("args.a", &value)));
- EXPECT_EQ(30000, value);
-
- EXPECT_TRUE((item && item->GetInteger("args.b", &value)));
- EXPECT_EQ(1415, value);
- }
-
- EXPECT_FIND_("TRACE_COUNTER_WITH_TIMESTAMP1 call");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("C", ph);
-
- int value;
- EXPECT_TRUE((item && item->GetInteger("args.value", &value)));
- EXPECT_EQ(31415, value);
-
- int ts;
- EXPECT_TRUE((item && item->GetInteger("ts", &ts)));
- EXPECT_EQ(42, ts);
- }
-
- EXPECT_FIND_("TRACE_COUNTER_WITH_TIMESTAMP2 call");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("C", ph);
-
- int value;
- EXPECT_TRUE((item && item->GetInteger("args.a", &value)));
- EXPECT_EQ(30000, value);
-
- EXPECT_TRUE((item && item->GetInteger("args.b", &value)));
- EXPECT_EQ(1415, value);
-
- int ts;
- EXPECT_TRUE((item && item->GetInteger("ts", &ts)));
- EXPECT_EQ(42, ts);
- }
-
- EXPECT_FIND_("TRACE_COUNTER_ID1 call");
- {
- std::string id;
- EXPECT_TRUE((item && item->GetString("id", &id)));
- EXPECT_EQ("0x319009", id);
-
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("C", ph);
-
- int value;
- EXPECT_TRUE((item && item->GetInteger("args.value", &value)));
- EXPECT_EQ(31415, value);
- }
-
- EXPECT_FIND_("TRACE_COUNTER_ID2 call");
- {
- std::string id;
- EXPECT_TRUE((item && item->GetString("id", &id)));
- EXPECT_EQ("0x319009", id);
-
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("C", ph);
-
- int value;
- EXPECT_TRUE((item && item->GetInteger("args.a", &value)));
- EXPECT_EQ(30000, value);
-
- EXPECT_TRUE((item && item->GetInteger("args.b", &value)));
- EXPECT_EQ(1415, value);
- }
-
- EXPECT_FIND_("TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call");
- {
- int val;
- EXPECT_TRUE((item && item->GetInteger("ts", &val)));
- EXPECT_EQ(12345, val);
- EXPECT_TRUE((item && item->GetInteger("tid", &val)));
- EXPECT_EQ(kThreadId, val);
- std::string id;
- EXPECT_TRUE((item && item->GetString("id", &id)));
- EXPECT_EQ(kAsyncIdStr, id);
- }
-
- EXPECT_FIND_("TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0 call");
- {
- int val;
- EXPECT_TRUE((item && item->GetInteger("ts", &val)));
- EXPECT_EQ(23456, val);
- EXPECT_TRUE((item && item->GetInteger("tid", &val)));
- EXPECT_EQ(kThreadId, val);
- std::string id;
- EXPECT_TRUE((item && item->GetString("id", &id)));
- EXPECT_EQ(kAsyncIdStr, id);
- }
-
- EXPECT_FIND_("TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call");
- {
- int val;
- EXPECT_TRUE((item && item->GetInteger("ts", &val)));
- EXPECT_EQ(34567, val);
- EXPECT_TRUE((item && item->GetInteger("tid", &val)));
- EXPECT_EQ(kThreadId, val);
- std::string id;
- EXPECT_TRUE((item && item->GetString("id", &id)));
- EXPECT_EQ(kAsyncId2Str, id);
- }
-
- EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_PAST0 call");
- {
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncId2Str);
- EXPECT_SUB_FIND_("step_end1");
- EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_PAST1 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncId2Str);
- EXPECT_SUB_FIND_("step_end2");
- EXPECT_SUB_FIND_("name1");
- EXPECT_SUB_FIND_("value1");
- }
-
- EXPECT_FIND_("TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0 call");
- {
- int val;
- EXPECT_TRUE((item && item->GetInteger("ts", &val)));
- EXPECT_EQ(45678, val);
- EXPECT_TRUE((item && item->GetInteger("tid", &val)));
- EXPECT_EQ(kThreadId, val);
- std::string id;
- EXPECT_TRUE((item && item->GetString("id", &id)));
- EXPECT_EQ(kAsyncId2Str, id);
- }
-
- EXPECT_FIND_("tracked object 1");
- {
- std::string phase;
- std::string id;
- std::string snapshot;
-
- EXPECT_TRUE((item && item->GetString("ph", &phase)));
- EXPECT_EQ("N", phase);
- EXPECT_FALSE((item && item->HasKey("scope")));
- EXPECT_TRUE((item && item->GetString("id", &id)));
- EXPECT_EQ("0x42", id);
-
- item = FindTraceEntry(trace_parsed, "tracked object 1", item);
- EXPECT_TRUE(item);
- EXPECT_TRUE(item && item->GetString("ph", &phase));
- EXPECT_EQ("O", phase);
- EXPECT_FALSE((item && item->HasKey("scope")));
- EXPECT_TRUE(item && item->GetString("id", &id));
- EXPECT_EQ("0x42", id);
- EXPECT_TRUE(item && item->GetString("args.snapshot", &snapshot));
- EXPECT_EQ("hello", snapshot);
-
- item = FindTraceEntry(trace_parsed, "tracked object 1", item);
- EXPECT_TRUE(item);
- EXPECT_TRUE(item && item->GetString("ph", &phase));
- EXPECT_EQ("D", phase);
- EXPECT_FALSE((item && item->HasKey("scope")));
- EXPECT_TRUE(item && item->GetString("id", &id));
- EXPECT_EQ("0x42", id);
- }
-
- EXPECT_FIND_("tracked object 2");
- {
- std::string phase;
- std::string id;
- std::string snapshot;
-
- EXPECT_TRUE(item && item->GetString("ph", &phase));
- EXPECT_EQ("N", phase);
- EXPECT_TRUE(item && item->GetString("id", &id));
- EXPECT_EQ("0x2128506", id);
-
- item = FindTraceEntry(trace_parsed, "tracked object 2", item);
- EXPECT_TRUE(item);
- EXPECT_TRUE(item && item->GetString("ph", &phase));
- EXPECT_EQ("O", phase);
- EXPECT_TRUE(item && item->GetString("id", &id));
- EXPECT_EQ("0x2128506", id);
- EXPECT_TRUE(item && item->GetString("args.snapshot", &snapshot));
- EXPECT_EQ("world", snapshot);
-
- item = FindTraceEntry(trace_parsed, "tracked object 2", item);
- EXPECT_TRUE(item);
- EXPECT_TRUE(item && item->GetString("ph", &phase));
- EXPECT_EQ("D", phase);
- EXPECT_TRUE(item && item->GetString("id", &id));
- EXPECT_EQ("0x2128506", id);
- }
-
- EXPECT_FIND_("tracked object 3");
- {
- std::string phase;
- std::string scope;
- std::string id;
- std::string snapshot;
-
- EXPECT_TRUE((item && item->GetString("ph", &phase)));
- EXPECT_EQ("N", phase);
- EXPECT_TRUE((item && item->GetString("scope", &scope)));
- EXPECT_EQ("scope", scope);
- EXPECT_TRUE((item && item->GetString("id", &id)));
- EXPECT_EQ("0x42", id);
-
- item = FindTraceEntry(trace_parsed, "tracked object 3", item);
- EXPECT_TRUE(item);
- EXPECT_TRUE(item && item->GetString("ph", &phase));
- EXPECT_EQ("O", phase);
- EXPECT_TRUE((item && item->GetString("scope", &scope)));
- EXPECT_EQ("scope", scope);
- EXPECT_TRUE(item && item->GetString("id", &id));
- EXPECT_EQ("0x42", id);
- EXPECT_TRUE(item && item->GetString("args.snapshot", &snapshot));
- EXPECT_EQ("hello", snapshot);
-
- item = FindTraceEntry(trace_parsed, "tracked object 3", item);
- EXPECT_TRUE(item);
- EXPECT_TRUE(item && item->GetString("ph", &phase));
- EXPECT_EQ("D", phase);
- EXPECT_TRUE((item && item->GetString("scope", &scope)));
- EXPECT_EQ("scope", scope);
- EXPECT_TRUE(item && item->GetString("id", &id));
- EXPECT_EQ("0x42", id);
- }
-
- EXPECT_FIND_(kControlCharacters);
- EXPECT_SUB_FIND_(kControlCharacters);
-
- EXPECT_FIND_("TRACE_EVENT_ENTER_CONTEXT call");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("(", ph);
-
- std::string scope;
- std::string id;
- EXPECT_TRUE((item && item->GetString("scope", &scope)));
- EXPECT_EQ("scope", scope);
- EXPECT_TRUE((item && item->GetString("id", &id)));
- EXPECT_EQ("0x20151021", id);
- }
-
- EXPECT_FIND_("TRACE_EVENT_LEAVE_CONTEXT call");
- {
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ(")", ph);
-
- std::string scope;
- std::string id;
- EXPECT_TRUE((item && item->GetString("scope", &scope)));
- EXPECT_EQ("scope", scope);
- EXPECT_TRUE((item && item->GetString("id", &id)));
- EXPECT_EQ("0x20151021", id);
- }
-
- std::vector<const DictionaryValue*> scoped_context_calls =
- FindTraceEntries(trace_parsed, "TRACE_EVENT_SCOPED_CONTEXT call");
- EXPECT_EQ(2u, scoped_context_calls.size());
- {
- item = scoped_context_calls[0];
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ("(", ph);
-
- std::string id;
- EXPECT_FALSE((item && item->HasKey("scope")));
- EXPECT_TRUE((item && item->GetString("id", &id)));
- EXPECT_EQ("0x20151021", id);
- }
-
- {
- item = scoped_context_calls[1];
- std::string ph;
- EXPECT_TRUE((item && item->GetString("ph", &ph)));
- EXPECT_EQ(")", ph);
-
- std::string id;
- EXPECT_FALSE((item && item->HasKey("scope")));
- 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,
- WaitableEvent* task_complete_event) {
- for (int i = 0; i < num_events; i++) {
- TRACE_EVENT_INSTANT2("all", "multi thread event",
- TRACE_EVENT_SCOPE_THREAD,
- "thread", thread_id,
- "event", i);
- }
-
- if (task_complete_event)
- task_complete_event->Signal();
-}
-
-void ValidateInstantEventPresentOnEveryThread(const ListValue& trace_parsed,
- int num_threads,
- int num_events) {
- std::map<int, std::map<int, bool> > results;
-
- size_t trace_parsed_count = trace_parsed.GetSize();
- 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)
- continue;
- const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
- std::string name;
- dict->GetString("name", &name);
- if (name != "multi thread event")
- continue;
-
- int thread = 0;
- int event = 0;
- EXPECT_TRUE(dict->GetInteger("args.thread", &thread));
- EXPECT_TRUE(dict->GetInteger("args.event", &event));
- results[thread][event] = true;
- }
-
- EXPECT_FALSE(results[-1][-1]);
- for (int thread = 0; thread < num_threads; thread++) {
- for (int event = 0; event < num_events; event++) {
- EXPECT_TRUE(results[thread][event]);
- }
- }
-}
-
-void CheckTraceDefaultCategoryFilters(const TraceLog& trace_log) {
- // Default enables all category filters except the disabled-by-default-* ones.
- EXPECT_TRUE(*trace_log.GetCategoryGroupEnabled("foo"));
- EXPECT_TRUE(*trace_log.GetCategoryGroupEnabled("bar"));
- EXPECT_TRUE(*trace_log.GetCategoryGroupEnabled("foo,bar"));
- EXPECT_TRUE(*trace_log.GetCategoryGroupEnabled(
- "foo,disabled-by-default-foo"));
- EXPECT_FALSE(*trace_log.GetCategoryGroupEnabled(
- "disabled-by-default-foo,disabled-by-default-bar"));
-}
-
-} // namespace
-
-// Simple Test for emitting data and validating it was received.
-TEST_F(TraceEventTestFixture, DataCaptured) {
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
-
- TraceWithAllMacroVariants(NULL);
-
- EndTraceAndFlush();
-
- ValidateAllTraceMacrosCreatedData(trace_parsed_);
-}
-
-// Emit some events and validate that only empty strings are received
-// if we tell Flush() to discard events.
-TEST_F(TraceEventTestFixture, DataDiscarded) {
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
-
- TraceWithAllMacroVariants(NULL);
-
- CancelTrace();
-
- EXPECT_TRUE(trace_parsed_.empty());
-}
-
-class MockEnabledStateChangedObserver :
- public TraceLog::EnabledStateObserver {
- public:
- MOCK_METHOD0(OnTraceLogEnabled, void());
- MOCK_METHOD0(OnTraceLogDisabled, void());
-};
-
-TEST_F(TraceEventTestFixture, EnabledObserverFiresOnEnable) {
- MockEnabledStateChangedObserver observer;
- TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
-
- EXPECT_CALL(observer, OnTraceLogEnabled())
- .Times(1);
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
- testing::Mock::VerifyAndClear(&observer);
- EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
-
- // Cleanup.
- TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
- TraceLog::GetInstance()->SetDisabled();
-}
-
-TEST_F(TraceEventTestFixture, EnabledObserverDoesntFireOnSecondEnable) {
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
-
- testing::StrictMock<MockEnabledStateChangedObserver> observer;
- TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
-
- EXPECT_CALL(observer, OnTraceLogEnabled())
- .Times(0);
- EXPECT_CALL(observer, OnTraceLogDisabled())
- .Times(0);
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
- testing::Mock::VerifyAndClear(&observer);
- EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
-
- // Cleanup.
- TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
- TraceLog::GetInstance()->SetDisabled();
- TraceLog::GetInstance()->SetDisabled();
-}
-
-TEST_F(TraceEventTestFixture, EnabledObserverFiresOnFirstDisable) {
- TraceConfig tc_inc_all("*", "");
- TraceLog::GetInstance()->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE);
- TraceLog::GetInstance()->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE);
-
- testing::StrictMock<MockEnabledStateChangedObserver> observer;
- TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
-
- EXPECT_CALL(observer, OnTraceLogEnabled())
- .Times(0);
- EXPECT_CALL(observer, OnTraceLogDisabled())
- .Times(1);
- TraceLog::GetInstance()->SetDisabled();
- testing::Mock::VerifyAndClear(&observer);
-
- // Cleanup.
- TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
- TraceLog::GetInstance()->SetDisabled();
-}
-
-TEST_F(TraceEventTestFixture, EnabledObserverFiresOnDisable) {
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
-
- MockEnabledStateChangedObserver observer;
- TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
-
- EXPECT_CALL(observer, OnTraceLogDisabled())
- .Times(1);
- TraceLog::GetInstance()->SetDisabled();
- testing::Mock::VerifyAndClear(&observer);
-
- // Cleanup.
- TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
-}
-
-// Tests the IsEnabled() state of TraceLog changes before callbacks.
-class AfterStateChangeEnabledStateObserver
- : public TraceLog::EnabledStateObserver {
- public:
- AfterStateChangeEnabledStateObserver() {}
- ~AfterStateChangeEnabledStateObserver() override {}
-
- // TraceLog::EnabledStateObserver overrides:
- void OnTraceLogEnabled() override {
- EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
- }
-
- void OnTraceLogDisabled() override {
- EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
- }
-};
-
-TEST_F(TraceEventTestFixture, ObserversFireAfterStateChange) {
- AfterStateChangeEnabledStateObserver observer;
- TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
-
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
- EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
-
- TraceLog::GetInstance()->SetDisabled();
- EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
-
- TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
-}
-
-// Tests that a state observer can remove itself during a callback.
-class SelfRemovingEnabledStateObserver
- : public TraceLog::EnabledStateObserver {
- public:
- SelfRemovingEnabledStateObserver() {}
- ~SelfRemovingEnabledStateObserver() override {}
-
- // TraceLog::EnabledStateObserver overrides:
- void OnTraceLogEnabled() override {}
-
- void OnTraceLogDisabled() override {
- TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
- }
-};
-
-TEST_F(TraceEventTestFixture, SelfRemovingObserver) {
- ASSERT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
-
- SelfRemovingEnabledStateObserver observer;
- TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
- EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
-
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
- TraceLog::GetInstance()->SetDisabled();
- // The observer removed itself on disable.
- EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
-}
-
-bool IsNewTrace() {
- bool is_new_trace;
- TRACE_EVENT_IS_NEW_TRACE(&is_new_trace);
- return is_new_trace;
-}
-
-TEST_F(TraceEventTestFixture, NewTraceRecording) {
- ASSERT_FALSE(IsNewTrace());
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
- // First call to IsNewTrace() should succeed. But, the second shouldn't.
- ASSERT_TRUE(IsNewTrace());
- ASSERT_FALSE(IsNewTrace());
- EndTraceAndFlush();
-
- // IsNewTrace() should definitely be false now.
- ASSERT_FALSE(IsNewTrace());
-
- // Start another trace. IsNewTrace() should become true again, briefly, as
- // before.
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
- ASSERT_TRUE(IsNewTrace());
- ASSERT_FALSE(IsNewTrace());
-
- // Cleanup.
- EndTraceAndFlush();
-}
-
-TEST_F(TraceEventTestFixture, TestTraceFlush) {
- size_t min_traces = 1;
- size_t max_traces = 1;
- do {
- max_traces *= 2;
- TraceLog::GetInstance()->SetEnabled(TraceConfig(),
- TraceLog::RECORDING_MODE);
- for (size_t i = 0; i < max_traces; i++) {
- TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
- }
- EndTraceAndFlush();
- } while (num_flush_callbacks_ < 2);
-
- while (min_traces + 50 < max_traces) {
- size_t traces = (min_traces + max_traces) / 2;
- TraceLog::GetInstance()->SetEnabled(TraceConfig(),
- TraceLog::RECORDING_MODE);
- for (size_t i = 0; i < traces; i++) {
- TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
- }
- EndTraceAndFlush();
- if (num_flush_callbacks_ < 2) {
- min_traces = traces - 10;
- } else {
- max_traces = traces + 10;
- }
- }
-
- for (size_t traces = min_traces; traces < max_traces; traces++) {
- TraceLog::GetInstance()->SetEnabled(TraceConfig(),
- TraceLog::RECORDING_MODE);
- for (size_t i = 0; i < traces; i++) {
- TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
- }
- EndTraceAndFlush();
- }
-}
-
-TEST_F(TraceEventTestFixture, AddMetadataEvent) {
- int num_calls = 0;
-
- class Convertable : public ConvertableToTraceFormat {
- public:
- explicit Convertable(int* num_calls) : num_calls_(num_calls) {}
- ~Convertable() override {}
- void AppendAsTraceFormat(std::string* out) const override {
- (*num_calls_)++;
- out->append("\"metadata_value\"");
- }
-
- private:
- int* num_calls_;
- };
-
- std::unique_ptr<ConvertableToTraceFormat> conv1(new Convertable(&num_calls));
- std::unique_ptr<Convertable> conv2(new Convertable(&num_calls));
-
- BeginTrace();
- TRACE_EVENT_API_ADD_METADATA_EVENT(
- TraceLog::GetCategoryGroupEnabled("__metadata"), "metadata_event_1",
- "metadata_arg_name", std::move(conv1));
- TRACE_EVENT_API_ADD_METADATA_EVENT(
- TraceLog::GetCategoryGroupEnabled("__metadata"), "metadata_event_2",
- "metadata_arg_name", std::move(conv2));
- // |AppendAsTraceFormat| should only be called on flush, not when the event
- // is added.
- ASSERT_EQ(0, num_calls);
- EndTraceAndFlush();
- ASSERT_EQ(2, num_calls);
- EXPECT_TRUE(FindNamePhaseKeyValue("metadata_event_1", "M",
- "metadata_arg_name", "metadata_value"));
- EXPECT_TRUE(FindNamePhaseKeyValue("metadata_event_2", "M",
- "metadata_arg_name", "metadata_value"));
-
- // The metadata event should only be adde to the current trace. In this new
- // trace, the event should not appear.
- BeginTrace();
- EndTraceAndFlush();
- ASSERT_EQ(2, num_calls);
-}
-
-// Test that categories work.
-TEST_F(TraceEventTestFixture, Categories) {
- // Test that categories that are used can be retrieved whether trace was
- // enabled or disabled when the trace event was encountered.
- TRACE_EVENT_INSTANT0("c1", "name", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("c2", "name", TRACE_EVENT_SCOPE_THREAD);
- BeginTrace();
- TRACE_EVENT_INSTANT0("c3", "name", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("c4", "name", TRACE_EVENT_SCOPE_THREAD);
- // Category groups containing more than one category.
- TRACE_EVENT_INSTANT0("c5,c6", "name", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("c7,c8", "name", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("c9"), "name",
- TRACE_EVENT_SCOPE_THREAD);
-
- EndTraceAndFlush();
- std::vector<std::string> cat_groups;
- TraceLog::GetInstance()->GetKnownCategoryGroups(&cat_groups);
- EXPECT_TRUE(ContainsValue(cat_groups, "c1"));
- EXPECT_TRUE(ContainsValue(cat_groups, "c2"));
- EXPECT_TRUE(ContainsValue(cat_groups, "c3"));
- EXPECT_TRUE(ContainsValue(cat_groups, "c4"));
- EXPECT_TRUE(ContainsValue(cat_groups, "c5,c6"));
- EXPECT_TRUE(ContainsValue(cat_groups, "c7,c8"));
- EXPECT_TRUE(ContainsValue(cat_groups, "disabled-by-default-c9"));
- // Make sure metadata isn't returned.
- EXPECT_FALSE(ContainsValue(cat_groups, "__metadata"));
-
- const std::vector<std::string> empty_categories;
- std::vector<std::string> included_categories;
- std::vector<std::string> excluded_categories;
-
- // Test that category filtering works.
-
- // Include nonexistent category -> no events
- Clear();
- included_categories.clear();
- TraceLog::GetInstance()->SetEnabled(TraceConfig("not_found823564786", ""),
- TraceLog::RECORDING_MODE);
- TRACE_EVENT_INSTANT0("cat1", "name", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("cat2", "name", TRACE_EVENT_SCOPE_THREAD);
- EndTraceAndFlush();
- DropTracedMetadataRecords();
- EXPECT_TRUE(trace_parsed_.empty());
-
- // Include existent category -> only events of that category
- Clear();
- included_categories.clear();
- TraceLog::GetInstance()->SetEnabled(TraceConfig("inc", ""),
- TraceLog::RECORDING_MODE);
- TRACE_EVENT_INSTANT0("inc", "name", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("inc2", "name", TRACE_EVENT_SCOPE_THREAD);
- EndTraceAndFlush();
- DropTracedMetadataRecords();
- EXPECT_TRUE(FindMatchingValue("cat", "inc"));
- EXPECT_FALSE(FindNonMatchingValue("cat", "inc"));
-
- // Include existent wildcard -> all categories matching wildcard
- Clear();
- included_categories.clear();
- TraceLog::GetInstance()->SetEnabled(
- TraceConfig("inc_wildcard_*,inc_wildchar_?_end", ""),
- TraceLog::RECORDING_MODE);
- TRACE_EVENT_INSTANT0("inc_wildcard_abc", "included",
- TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("inc_wildcard_", "included", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "included",
- TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "not_inc",
- TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("cat1", "not_inc", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("cat2", "not_inc", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("inc_wildcard_category,other_category", "included",
- TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0(
- "non_included_category,inc_wildcard_category", "included",
- TRACE_EVENT_SCOPE_THREAD);
- EndTraceAndFlush();
- EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_abc"));
- EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_"));
- EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_x_end"));
- EXPECT_FALSE(FindMatchingValue("name", "not_inc"));
- EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_category,other_category"));
- EXPECT_TRUE(FindMatchingValue("cat",
- "non_included_category,inc_wildcard_category"));
-
- included_categories.clear();
-
- // Exclude nonexistent category -> all events
- Clear();
- TraceLog::GetInstance()->SetEnabled(TraceConfig("-not_found823564786", ""),
- TraceLog::RECORDING_MODE);
- TRACE_EVENT_INSTANT0("cat1", "name", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("cat2", "name", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("category1,category2", "name", TRACE_EVENT_SCOPE_THREAD);
- EndTraceAndFlush();
- EXPECT_TRUE(FindMatchingValue("cat", "cat1"));
- EXPECT_TRUE(FindMatchingValue("cat", "cat2"));
- EXPECT_TRUE(FindMatchingValue("cat", "category1,category2"));
-
- // Exclude existent category -> only events of other categories
- Clear();
- TraceLog::GetInstance()->SetEnabled(TraceConfig("-inc", ""),
- TraceLog::RECORDING_MODE);
- TRACE_EVENT_INSTANT0("inc", "name", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("inc2", "name", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("inc2,inc", "name", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("inc,inc2", "name", TRACE_EVENT_SCOPE_THREAD);
- EndTraceAndFlush();
- EXPECT_TRUE(FindMatchingValue("cat", "inc2"));
- EXPECT_FALSE(FindMatchingValue("cat", "inc"));
- EXPECT_TRUE(FindMatchingValue("cat", "inc2,inc"));
- EXPECT_TRUE(FindMatchingValue("cat", "inc,inc2"));
-
- // Exclude existent wildcard -> all categories not matching wildcard
- Clear();
- TraceLog::GetInstance()->SetEnabled(
- TraceConfig("-inc_wildcard_*,-inc_wildchar_?_end", ""),
- TraceLog::RECORDING_MODE);
- TRACE_EVENT_INSTANT0("inc_wildcard_abc", "not_inc",
- TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("inc_wildcard_", "not_inc",
- TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "not_inc",
- TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "included",
- TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("cat1", "included", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("cat2", "included", TRACE_EVENT_SCOPE_THREAD);
- EndTraceAndFlush();
- EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_bla_end"));
- EXPECT_TRUE(FindMatchingValue("cat", "cat1"));
- EXPECT_TRUE(FindMatchingValue("cat", "cat2"));
- EXPECT_FALSE(FindMatchingValue("name", "not_inc"));
-}
-
-
-// Test ASYNC_BEGIN/END events
-TEST_F(TraceEventTestFixture, AsyncBeginEndEvents) {
- BeginTrace();
-
- unsigned long long id = 0xfeedbeeffeedbeefull;
- TRACE_EVENT_ASYNC_BEGIN0("cat", "name1", id);
- TRACE_EVENT_ASYNC_STEP_INTO0("cat", "name1", id, "step1");
- TRACE_EVENT_ASYNC_END0("cat", "name1", id);
- TRACE_EVENT_BEGIN0("cat", "name2");
- TRACE_EVENT_ASYNC_BEGIN0("cat", "name3", 0);
- TRACE_EVENT_ASYNC_STEP_PAST0("cat", "name3", 0, "step2");
-
- EndTraceAndFlush();
-
- EXPECT_TRUE(FindNamePhase("name1", "S"));
- EXPECT_TRUE(FindNamePhase("name1", "T"));
- EXPECT_TRUE(FindNamePhase("name1", "F"));
-
- std::string id_str;
- StringAppendF(&id_str, "0x%llx", id);
-
- EXPECT_TRUE(FindNamePhaseKeyValue("name1", "S", "id", id_str.c_str()));
- EXPECT_TRUE(FindNamePhaseKeyValue("name1", "T", "id", id_str.c_str()));
- EXPECT_TRUE(FindNamePhaseKeyValue("name1", "F", "id", id_str.c_str()));
- EXPECT_TRUE(FindNamePhaseKeyValue("name3", "S", "id", "0x0"));
- EXPECT_TRUE(FindNamePhaseKeyValue("name3", "p", "id", "0x0"));
-
- // BEGIN events should not have id
- EXPECT_FALSE(FindNamePhaseKeyValue("name2", "B", "id", "0"));
-}
-
-// Test ASYNC_BEGIN/END events
-TEST_F(TraceEventTestFixture, AsyncBeginEndPointerMangling) {
- void* ptr = this;
-
- TraceLog::GetInstance()->SetProcessID(100);
- BeginTrace();
- TRACE_EVENT_ASYNC_BEGIN0("cat", "name1", ptr);
- TRACE_EVENT_ASYNC_BEGIN0("cat", "name2", ptr);
- EndTraceAndFlush();
-
- TraceLog::GetInstance()->SetProcessID(200);
- BeginTrace();
- TRACE_EVENT_ASYNC_END0("cat", "name1", ptr);
- EndTraceAndFlush();
-
- DictionaryValue* async_begin = FindNamePhase("name1", "S");
- DictionaryValue* async_begin2 = FindNamePhase("name2", "S");
- DictionaryValue* async_end = FindNamePhase("name1", "F");
- EXPECT_TRUE(async_begin);
- EXPECT_TRUE(async_begin2);
- EXPECT_TRUE(async_end);
-
- Value* value = NULL;
- std::string async_begin_id_str;
- std::string async_begin2_id_str;
- std::string async_end_id_str;
- ASSERT_TRUE(async_begin->Get("id", &value));
- ASSERT_TRUE(value->GetAsString(&async_begin_id_str));
- ASSERT_TRUE(async_begin2->Get("id", &value));
- ASSERT_TRUE(value->GetAsString(&async_begin2_id_str));
- ASSERT_TRUE(async_end->Get("id", &value));
- ASSERT_TRUE(value->GetAsString(&async_end_id_str));
-
- EXPECT_STREQ(async_begin_id_str.c_str(), async_begin2_id_str.c_str());
- EXPECT_STRNE(async_begin_id_str.c_str(), async_end_id_str.c_str());
-}
-
-// Test that static strings are not copied.
-TEST_F(TraceEventTestFixture, StaticStringVsString) {
- TraceLog* tracer = TraceLog::GetInstance();
- // Make sure old events are flushed:
- EXPECT_EQ(0u, tracer->GetStatus().event_count);
- const unsigned char* category_group_enabled =
- TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("cat");
-
- {
- BeginTrace();
- // Test that string arguments are copied.
- TraceEventHandle handle1 =
- trace_event_internal::AddTraceEvent(
- TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name1",
- trace_event_internal::kGlobalScope, trace_event_internal::kNoId,
- 0, trace_event_internal::kNoId,
- "arg1", std::string("argval"), "arg2", std::string("argval"));
- // Test that static TRACE_STR_COPY string arguments are copied.
- TraceEventHandle handle2 =
- trace_event_internal::AddTraceEvent(
- TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2",
- trace_event_internal::kGlobalScope, trace_event_internal::kNoId,
- 0, trace_event_internal::kNoId,
- "arg1", TRACE_STR_COPY("argval"),
- "arg2", TRACE_STR_COPY("argval"));
- EXPECT_GT(tracer->GetStatus().event_count, 1u);
- const TraceEvent* event1 = tracer->GetEventByHandle(handle1);
- const TraceEvent* event2 = tracer->GetEventByHandle(handle2);
- ASSERT_TRUE(event1);
- ASSERT_TRUE(event2);
- EXPECT_STREQ("name1", event1->name());
- EXPECT_STREQ("name2", event2->name());
- EXPECT_TRUE(event1->parameter_copy_storage() != NULL);
- EXPECT_TRUE(event2->parameter_copy_storage() != NULL);
- EXPECT_GT(event1->parameter_copy_storage()->size(), 0u);
- EXPECT_GT(event2->parameter_copy_storage()->size(), 0u);
- EndTraceAndFlush();
- }
-
- {
- BeginTrace();
- // Test that static literal string arguments are not copied.
- TraceEventHandle handle1 =
- trace_event_internal::AddTraceEvent(
- TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name1",
- trace_event_internal::kGlobalScope, trace_event_internal::kNoId,
- 0, trace_event_internal::kNoId,
- "arg1", "argval", "arg2", "argval");
- // Test that static TRACE_STR_COPY NULL string arguments are not copied.
- const char* str1 = NULL;
- const char* str2 = NULL;
- TraceEventHandle handle2 =
- trace_event_internal::AddTraceEvent(
- TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2",
- trace_event_internal::kGlobalScope, trace_event_internal::kNoId,
- 0, trace_event_internal::kNoId,
- "arg1", TRACE_STR_COPY(str1),
- "arg2", TRACE_STR_COPY(str2));
- EXPECT_GT(tracer->GetStatus().event_count, 1u);
- const TraceEvent* event1 = tracer->GetEventByHandle(handle1);
- const TraceEvent* event2 = tracer->GetEventByHandle(handle2);
- ASSERT_TRUE(event1);
- ASSERT_TRUE(event2);
- EXPECT_STREQ("name1", event1->name());
- EXPECT_STREQ("name2", event2->name());
- EXPECT_TRUE(event1->parameter_copy_storage() == NULL);
- EXPECT_TRUE(event2->parameter_copy_storage() == NULL);
- EndTraceAndFlush();
- }
-}
-
-// Test that data sent from other threads is gathered
-TEST_F(TraceEventTestFixture, DataCapturedOnThread) {
- BeginTrace();
-
- Thread thread("1");
- WaitableEvent task_complete_event(WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- thread.Start();
-
- thread.task_runner()->PostTask(
- FROM_HERE, base::Bind(&TraceWithAllMacroVariants, &task_complete_event));
- task_complete_event.Wait();
- thread.Stop();
-
- EndTraceAndFlush();
- ValidateAllTraceMacrosCreatedData(trace_parsed_);
-}
-
-// Test that data sent from multiple threads is gathered
-TEST_F(TraceEventTestFixture, DataCapturedManyThreads) {
- BeginTrace();
-
- const int num_threads = 4;
- const int num_events = 4000;
- Thread* threads[num_threads];
- WaitableEvent* task_complete_events[num_threads];
- for (int i = 0; i < num_threads; i++) {
- threads[i] = new Thread(StringPrintf("Thread %d", i));
- task_complete_events[i] =
- new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- threads[i]->Start();
- threads[i]->task_runner()->PostTask(
- FROM_HERE, base::Bind(&TraceManyInstantEvents, i, num_events,
- task_complete_events[i]));
- }
-
- for (int i = 0; i < num_threads; i++) {
- task_complete_events[i]->Wait();
- }
-
- // Let half of the threads end before flush.
- for (int i = 0; i < num_threads / 2; i++) {
- threads[i]->Stop();
- delete threads[i];
- delete task_complete_events[i];
- }
-
- EndTraceAndFlushInThreadWithMessageLoop();
- ValidateInstantEventPresentOnEveryThread(trace_parsed_,
- num_threads, num_events);
-
- // Let the other half of the threads end after flush.
- for (int i = num_threads / 2; i < num_threads; i++) {
- threads[i]->Stop();
- delete threads[i];
- delete task_complete_events[i];
- }
-}
-
-// Test that thread and process names show up in the trace
-TEST_F(TraceEventTestFixture, ThreadNames) {
- // Create threads before we enable tracing to make sure
- // that tracelog still captures them.
- const int kNumThreads = 4;
- const int kNumEvents = 10;
- Thread* threads[kNumThreads];
- PlatformThreadId thread_ids[kNumThreads];
- for (int i = 0; i < kNumThreads; i++)
- threads[i] = new Thread(StringPrintf("Thread %d", i));
-
- // Enable tracing.
- BeginTrace();
-
- // Now run some trace code on these threads.
- WaitableEvent* task_complete_events[kNumThreads];
- for (int i = 0; i < kNumThreads; i++) {
- task_complete_events[i] =
- new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- threads[i]->Start();
- thread_ids[i] = threads[i]->GetThreadId();
- threads[i]->task_runner()->PostTask(
- FROM_HERE, base::Bind(&TraceManyInstantEvents, i, kNumEvents,
- task_complete_events[i]));
- }
- for (int i = 0; i < kNumThreads; i++) {
- task_complete_events[i]->Wait();
- }
-
- // Shut things down.
- for (int i = 0; i < kNumThreads; i++) {
- threads[i]->Stop();
- delete threads[i];
- delete task_complete_events[i];
- }
-
- EndTraceAndFlush();
-
- std::string tmp;
- int tmp_int;
- const DictionaryValue* item;
-
- // Make sure we get thread name metadata.
- // Note, the test suite may have created a ton of threads.
- // So, we'll have thread names for threads we didn't create.
- std::vector<const DictionaryValue*> items =
- FindTraceEntries(trace_parsed_, "thread_name");
- for (int i = 0; i < static_cast<int>(items.size()); i++) {
- item = items[i];
- ASSERT_TRUE(item);
- EXPECT_TRUE(item->GetInteger("tid", &tmp_int));
-
- // See if this thread name is one of the threads we just created
- for (int j = 0; j < kNumThreads; j++) {
- if (static_cast<int>(thread_ids[j]) != tmp_int)
- continue;
-
- std::string expected_name = StringPrintf("Thread %d", j);
- EXPECT_TRUE(item->GetString("ph", &tmp) && tmp == "M");
- EXPECT_TRUE(item->GetInteger("pid", &tmp_int) &&
- tmp_int == static_cast<int>(base::GetCurrentProcId()));
- // If the thread name changes or the tid gets reused, the name will be
- // a comma-separated list of thread names, so look for a substring.
- EXPECT_TRUE(item->GetString("args.name", &tmp) &&
- tmp.find(expected_name) != std::string::npos);
- }
- }
-}
-
-TEST_F(TraceEventTestFixture, ThreadNameChanges) {
- BeginTrace();
-
- PlatformThread::SetName("");
- TRACE_EVENT_INSTANT0("drink", "water", TRACE_EVENT_SCOPE_THREAD);
-
- PlatformThread::SetName("cafe");
- TRACE_EVENT_INSTANT0("drink", "coffee", TRACE_EVENT_SCOPE_THREAD);
-
- PlatformThread::SetName("shop");
- // No event here, so won't appear in combined name.
-
- PlatformThread::SetName("pub");
- TRACE_EVENT_INSTANT0("drink", "beer", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("drink", "wine", TRACE_EVENT_SCOPE_THREAD);
-
- PlatformThread::SetName(" bar");
- TRACE_EVENT_INSTANT0("drink", "whisky", TRACE_EVENT_SCOPE_THREAD);
-
- EndTraceAndFlush();
-
- std::vector<const DictionaryValue*> items =
- FindTraceEntries(trace_parsed_, "thread_name");
- EXPECT_EQ(1u, items.size());
- ASSERT_GT(items.size(), 0u);
- const DictionaryValue* item = items[0];
- ASSERT_TRUE(item);
- int tid;
- EXPECT_TRUE(item->GetInteger("tid", &tid));
- EXPECT_EQ(PlatformThread::CurrentId(), static_cast<PlatformThreadId>(tid));
-
- std::string expected_name = "cafe,pub, bar";
- std::string tmp;
- EXPECT_TRUE(item->GetString("args.name", &tmp));
- EXPECT_EQ(expected_name, tmp);
-}
-
-// Test that the disabled trace categories are included/excluded from the
-// trace output correctly.
-TEST_F(TraceEventTestFixture, DisabledCategories) {
- BeginTrace();
- TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc"), "first",
- TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("included", "first", TRACE_EVENT_SCOPE_THREAD);
- EndTraceAndFlush();
- {
- const DictionaryValue* item = NULL;
- ListValue& trace_parsed = trace_parsed_;
- EXPECT_NOT_FIND_("disabled-by-default-cc");
- EXPECT_FIND_("included");
- }
- Clear();
-
- BeginSpecificTrace("disabled-by-default-cc");
- TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc"), "second",
- TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("other_included", "second", TRACE_EVENT_SCOPE_THREAD);
- EndTraceAndFlush();
-
- {
- const DictionaryValue* item = NULL;
- ListValue& trace_parsed = trace_parsed_;
- EXPECT_FIND_("disabled-by-default-cc");
- EXPECT_FIND_("other_included");
- }
-
- Clear();
-
- BeginSpecificTrace("other_included");
- TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc") ",other_included",
- "first", TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_INSTANT0("other_included," TRACE_DISABLED_BY_DEFAULT("cc"),
- "second", TRACE_EVENT_SCOPE_THREAD);
- EndTraceAndFlush();
-
- {
- const DictionaryValue* item = NULL;
- ListValue& trace_parsed = trace_parsed_;
- EXPECT_FIND_("disabled-by-default-cc,other_included");
- EXPECT_FIND_("other_included,disabled-by-default-cc");
- }
-}
-
-TEST_F(TraceEventTestFixture, NormallyNoDeepCopy) {
- // Test that the TRACE_EVENT macros do not deep-copy their string. If they
- // do so it may indicate a performance regression, but more-over it would
- // make the DEEP_COPY overloads redundant.
- std::string name_string("event name");
-
- BeginTrace();
- TRACE_EVENT_INSTANT0("category", name_string.c_str(),
- TRACE_EVENT_SCOPE_THREAD);
-
- // Modify the string in place (a wholesale reassignment may leave the old
- // string intact on the heap).
- name_string[0] = '@';
-
- EndTraceAndFlush();
-
- EXPECT_FALSE(FindTraceEntry(trace_parsed_, "event name"));
- EXPECT_TRUE(FindTraceEntry(trace_parsed_, name_string.c_str()));
-}
-
-TEST_F(TraceEventTestFixture, DeepCopy) {
- static const char kOriginalName1[] = "name1";
- static const char kOriginalName2[] = "name2";
- static const char kOriginalName3[] = "name3";
- std::string name1(kOriginalName1);
- std::string name2(kOriginalName2);
- std::string name3(kOriginalName3);
- std::string arg1("arg1");
- std::string arg2("arg2");
- std::string val1("val1");
- std::string val2("val2");
-
- BeginTrace();
- TRACE_EVENT_COPY_INSTANT0("category", name1.c_str(),
- TRACE_EVENT_SCOPE_THREAD);
- TRACE_EVENT_COPY_BEGIN1("category", name2.c_str(),
- arg1.c_str(), 5);
- TRACE_EVENT_COPY_END2("category", name3.c_str(),
- arg1.c_str(), val1,
- arg2.c_str(), val2);
-
- // As per NormallyNoDeepCopy, modify the strings in place.
- name1[0] = name2[0] = name3[0] = arg1[0] = arg2[0] = val1[0] = val2[0] = '@';
-
- EndTraceAndFlush();
-
- EXPECT_FALSE(FindTraceEntry(trace_parsed_, name1.c_str()));
- EXPECT_FALSE(FindTraceEntry(trace_parsed_, name2.c_str()));
- EXPECT_FALSE(FindTraceEntry(trace_parsed_, name3.c_str()));
-
- const DictionaryValue* entry1 = FindTraceEntry(trace_parsed_, kOriginalName1);
- const DictionaryValue* entry2 = FindTraceEntry(trace_parsed_, kOriginalName2);
- const DictionaryValue* entry3 = FindTraceEntry(trace_parsed_, kOriginalName3);
- ASSERT_TRUE(entry1);
- ASSERT_TRUE(entry2);
- ASSERT_TRUE(entry3);
-
- int i;
- EXPECT_FALSE(entry2->GetInteger("args.@rg1", &i));
- EXPECT_TRUE(entry2->GetInteger("args.arg1", &i));
- EXPECT_EQ(5, i);
-
- std::string s;
- EXPECT_TRUE(entry3->GetString("args.arg1", &s));
- EXPECT_EQ("val1", s);
- EXPECT_TRUE(entry3->GetString("args.arg2", &s));
- EXPECT_EQ("val2", s);
-}
-
-// Test that TraceResultBuffer outputs the correct result whether it is added
-// in chunks or added all at once.
-TEST_F(TraceEventTestFixture, TraceResultBuffer) {
- Clear();
-
- trace_buffer_.Start();
- trace_buffer_.AddFragment("bla1");
- trace_buffer_.AddFragment("bla2");
- trace_buffer_.AddFragment("bla3,bla4");
- trace_buffer_.Finish();
- EXPECT_STREQ(json_output_.json_output.c_str(), "[bla1,bla2,bla3,bla4]");
-
- Clear();
-
- trace_buffer_.Start();
- trace_buffer_.AddFragment("bla1,bla2,bla3,bla4");
- trace_buffer_.Finish();
- EXPECT_STREQ(json_output_.json_output.c_str(), "[bla1,bla2,bla3,bla4]");
-}
-
-// Test that trace_event parameters are not evaluated if the tracing
-// system is disabled.
-TEST_F(TraceEventTestFixture, TracingIsLazy) {
- BeginTrace();
-
- int a = 0;
- TRACE_EVENT_INSTANT1("category", "test", TRACE_EVENT_SCOPE_THREAD, "a", a++);
- EXPECT_EQ(1, a);
-
- TraceLog::GetInstance()->SetDisabled();
-
- TRACE_EVENT_INSTANT1("category", "test", TRACE_EVENT_SCOPE_THREAD, "a", a++);
- EXPECT_EQ(1, a);
-
- EndTraceAndFlush();
-}
-
-TEST_F(TraceEventTestFixture, TraceEnableDisable) {
- TraceLog* trace_log = TraceLog::GetInstance();
- TraceConfig tc_inc_all("*", "");
- trace_log->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE);
- EXPECT_TRUE(trace_log->IsEnabled());
- trace_log->SetDisabled();
- EXPECT_FALSE(trace_log->IsEnabled());
-
- trace_log->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE);
- EXPECT_TRUE(trace_log->IsEnabled());
- const std::vector<std::string> empty;
- trace_log->SetEnabled(TraceConfig(), TraceLog::RECORDING_MODE);
- EXPECT_TRUE(trace_log->IsEnabled());
- trace_log->SetDisabled();
- EXPECT_FALSE(trace_log->IsEnabled());
- trace_log->SetDisabled();
- EXPECT_FALSE(trace_log->IsEnabled());
-}
-
-TEST_F(TraceEventTestFixture, TraceCategoriesAfterNestedEnable) {
- TraceLog* trace_log = TraceLog::GetInstance();
- trace_log->SetEnabled(TraceConfig("foo,bar", ""), TraceLog::RECORDING_MODE);
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo"));
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar"));
- EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz"));
- trace_log->SetEnabled(TraceConfig("foo2", ""), TraceLog::RECORDING_MODE);
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo2"));
- EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz"));
- // The "" becomes the default catergory set when applied.
- trace_log->SetEnabled(TraceConfig(), TraceLog::RECORDING_MODE);
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo"));
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz"));
- EXPECT_STREQ(
- "",
- trace_log->GetCurrentTraceConfig().ToCategoryFilterString().c_str());
- trace_log->SetDisabled();
- trace_log->SetDisabled();
- trace_log->SetDisabled();
- EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo"));
- EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz"));
-
- trace_log->SetEnabled(TraceConfig("-foo,-bar", ""), TraceLog::RECORDING_MODE);
- EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo"));
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz"));
- trace_log->SetEnabled(TraceConfig("moo", ""), TraceLog::RECORDING_MODE);
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz"));
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("moo"));
- EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo"));
- EXPECT_STREQ(
- "-foo,-bar",
- trace_log->GetCurrentTraceConfig().ToCategoryFilterString().c_str());
- trace_log->SetDisabled();
- trace_log->SetDisabled();
-
- // Make sure disabled categories aren't cleared if we set in the second.
- trace_log->SetEnabled(TraceConfig("disabled-by-default-cc,foo", ""),
- TraceLog::RECORDING_MODE);
- EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("bar"));
- trace_log->SetEnabled(TraceConfig("disabled-by-default-gpu", ""),
- TraceLog::RECORDING_MODE);
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-cc"));
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-gpu"));
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar"));
- EXPECT_STREQ(
- "disabled-by-default-cc,disabled-by-default-gpu",
- trace_log->GetCurrentTraceConfig().ToCategoryFilterString().c_str());
- trace_log->SetDisabled();
- trace_log->SetDisabled();
-}
-
-TEST_F(TraceEventTestFixture, TraceWithDefaultCategoryFilters) {
- TraceLog* trace_log = TraceLog::GetInstance();
-
- trace_log->SetEnabled(TraceConfig(), TraceLog::RECORDING_MODE);
- CheckTraceDefaultCategoryFilters(*trace_log);
- trace_log->SetDisabled();
-
- trace_log->SetEnabled(TraceConfig("", ""), TraceLog::RECORDING_MODE);
- CheckTraceDefaultCategoryFilters(*trace_log);
- trace_log->SetDisabled();
-
- trace_log->SetEnabled(TraceConfig("*", ""), TraceLog::RECORDING_MODE);
- CheckTraceDefaultCategoryFilters(*trace_log);
- trace_log->SetDisabled();
-
- trace_log->SetEnabled(TraceConfig(""), TraceLog::RECORDING_MODE);
- CheckTraceDefaultCategoryFilters(*trace_log);
- trace_log->SetDisabled();
-}
-
-TEST_F(TraceEventTestFixture, TraceWithDisabledByDefaultCategoryFilters) {
- TraceLog* trace_log = TraceLog::GetInstance();
-
- trace_log->SetEnabled(TraceConfig("foo,disabled-by-default-foo", ""),
- TraceLog::RECORDING_MODE);
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo"));
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-foo"));
- EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("bar"));
- EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-bar"));
- trace_log->SetDisabled();
-
- // Enabling only the disabled-by-default-* category means the default ones
- // are also enabled.
- trace_log->SetEnabled(TraceConfig("disabled-by-default-foo", ""),
- TraceLog::RECORDING_MODE);
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-foo"));
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo"));
- EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar"));
- EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-bar"));
- trace_log->SetDisabled();
-}
-
-class MyData : public ConvertableToTraceFormat {
- public:
- MyData() {}
- ~MyData() override {}
-
- void AppendAsTraceFormat(std::string* out) const override {
- out->append("{\"foo\":1}");
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MyData);
-};
-
-TEST_F(TraceEventTestFixture, ConvertableTypes) {
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
-
- std::unique_ptr<ConvertableToTraceFormat> data(new MyData());
- std::unique_ptr<ConvertableToTraceFormat> data1(new MyData());
- std::unique_ptr<ConvertableToTraceFormat> data2(new MyData());
- TRACE_EVENT1("foo", "bar", "data", std::move(data));
- TRACE_EVENT2("foo", "baz", "data1", std::move(data1), "data2",
- std::move(data2));
-
- // Check that std::unique_ptr<DerivedClassOfConvertable> are properly treated
- // as
- // convertable and not accidentally casted to bool.
- std::unique_ptr<MyData> convertData1(new MyData());
- std::unique_ptr<MyData> convertData2(new MyData());
- std::unique_ptr<MyData> convertData3(new MyData());
- std::unique_ptr<MyData> convertData4(new MyData());
- TRACE_EVENT2("foo", "string_first", "str", "string value 1", "convert",
- std::move(convertData1));
- TRACE_EVENT2("foo", "string_second", "convert", std::move(convertData2),
- "str", "string value 2");
- TRACE_EVENT2("foo", "both_conv", "convert1", std::move(convertData3),
- "convert2", std::move(convertData4));
- EndTraceAndFlush();
-
- // One arg version.
- DictionaryValue* dict = FindNamePhase("bar", "X");
- ASSERT_TRUE(dict);
-
- const DictionaryValue* args_dict = NULL;
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
-
- const Value* value = NULL;
- const DictionaryValue* convertable_dict = NULL;
- EXPECT_TRUE(args_dict->Get("data", &value));
- ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
-
- int foo_val;
- EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val));
- EXPECT_EQ(1, foo_val);
-
- // Two arg version.
- dict = FindNamePhase("baz", "X");
- ASSERT_TRUE(dict);
-
- args_dict = NULL;
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
-
- value = NULL;
- convertable_dict = NULL;
- EXPECT_TRUE(args_dict->Get("data1", &value));
- ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
-
- value = NULL;
- convertable_dict = NULL;
- EXPECT_TRUE(args_dict->Get("data2", &value));
- ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
-
- // Convertable with other types.
- dict = FindNamePhase("string_first", "X");
- ASSERT_TRUE(dict);
-
- args_dict = NULL;
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
-
- std::string str_value;
- EXPECT_TRUE(args_dict->GetString("str", &str_value));
- EXPECT_STREQ("string value 1", str_value.c_str());
-
- value = NULL;
- convertable_dict = NULL;
- foo_val = 0;
- EXPECT_TRUE(args_dict->Get("convert", &value));
- ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
- EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val));
- EXPECT_EQ(1, foo_val);
-
- dict = FindNamePhase("string_second", "X");
- ASSERT_TRUE(dict);
-
- args_dict = NULL;
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
-
- EXPECT_TRUE(args_dict->GetString("str", &str_value));
- EXPECT_STREQ("string value 2", str_value.c_str());
-
- value = NULL;
- convertable_dict = NULL;
- foo_val = 0;
- EXPECT_TRUE(args_dict->Get("convert", &value));
- ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
- EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val));
- EXPECT_EQ(1, foo_val);
-
- dict = FindNamePhase("both_conv", "X");
- ASSERT_TRUE(dict);
-
- args_dict = NULL;
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
-
- value = NULL;
- convertable_dict = NULL;
- foo_val = 0;
- EXPECT_TRUE(args_dict->Get("convert1", &value));
- ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
- EXPECT_TRUE(args_dict->Get("convert2", &value));
- ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
-}
-
-TEST_F(TraceEventTestFixture, PrimitiveArgs) {
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
-
- TRACE_EVENT1("foo", "event1", "int_one", 1);
- TRACE_EVENT1("foo", "event2", "int_neg_ten", -10);
- TRACE_EVENT1("foo", "event3", "float_one", 1.0f);
- TRACE_EVENT1("foo", "event4", "float_half", .5f);
- TRACE_EVENT1("foo", "event5", "float_neghalf", -.5f);
- TRACE_EVENT1("foo", "event6", "float_infinity",
- std::numeric_limits<float>::infinity());
- TRACE_EVENT1("foo", "event6b", "float_neg_infinity",
- -std::numeric_limits<float>::infinity());
- TRACE_EVENT1("foo", "event7", "double_nan",
- std::numeric_limits<double>::quiet_NaN());
- void* p = 0;
- TRACE_EVENT1("foo", "event8", "pointer_null", p);
- p = reinterpret_cast<void*>(0xbadf00d);
- TRACE_EVENT1("foo", "event9", "pointer_badf00d", p);
- TRACE_EVENT1("foo", "event10", "bool_true", true);
- TRACE_EVENT1("foo", "event11", "bool_false", false);
- TRACE_EVENT1("foo", "event12", "time_null",
- base::Time());
- TRACE_EVENT1("foo", "event13", "time_one",
- base::Time::FromInternalValue(1));
- TRACE_EVENT1("foo", "event14", "timeticks_null",
- base::TimeTicks());
- TRACE_EVENT1("foo", "event15", "timeticks_one",
- base::TimeTicks::FromInternalValue(1));
- EndTraceAndFlush();
-
- const DictionaryValue* args_dict = NULL;
- DictionaryValue* dict = NULL;
- const Value* value = NULL;
- std::string str_value;
- int int_value;
- double double_value;
- bool bool_value;
-
- dict = FindNamePhase("event1", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetInteger("int_one", &int_value));
- EXPECT_EQ(1, int_value);
-
- dict = FindNamePhase("event2", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetInteger("int_neg_ten", &int_value));
- EXPECT_EQ(-10, int_value);
-
- // 1f must be serlized to JSON as "1.0" in order to be a double, not an int.
- dict = FindNamePhase("event3", "X");
- ASSERT_TRUE(dict);
- 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->GetAsDouble(&double_value));
- EXPECT_EQ(1, double_value);
-
- // .5f must be serlized to JSON as "0.5".
- dict = FindNamePhase("event4", "X");
- ASSERT_TRUE(dict);
- 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->GetAsDouble(&double_value));
- EXPECT_EQ(0.5, double_value);
-
- // -.5f must be serlized to JSON as "-0.5".
- dict = FindNamePhase("event5", "X");
- ASSERT_TRUE(dict);
- 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->GetAsDouble(&double_value));
- EXPECT_EQ(-0.5, double_value);
-
- // Infinity is serialized to JSON as a string.
- dict = FindNamePhase("event6", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetString("float_infinity", &str_value));
- EXPECT_STREQ("Infinity", str_value.c_str());
- dict = FindNamePhase("event6b", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetString("float_neg_infinity", &str_value));
- EXPECT_STREQ("-Infinity", str_value.c_str());
-
- // NaN is serialized to JSON as a string.
- dict = FindNamePhase("event7", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetString("double_nan", &str_value));
- EXPECT_STREQ("NaN", str_value.c_str());
-
- // NULL pointers should be serialized as "0x0".
- dict = FindNamePhase("event8", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetString("pointer_null", &str_value));
- EXPECT_STREQ("0x0", str_value.c_str());
-
- // Other pointers should be serlized as a hex string.
- dict = FindNamePhase("event9", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetString("pointer_badf00d", &str_value));
- EXPECT_STREQ("0xbadf00d", str_value.c_str());
-
- dict = FindNamePhase("event10", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetBoolean("bool_true", &bool_value));
- EXPECT_TRUE(bool_value);
-
- dict = FindNamePhase("event11", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetBoolean("bool_false", &bool_value));
- EXPECT_FALSE(bool_value);
-
- dict = FindNamePhase("event12", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetInteger("time_null", &int_value));
- EXPECT_EQ(0, int_value);
-
- dict = FindNamePhase("event13", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetInteger("time_one", &int_value));
- EXPECT_EQ(1, int_value);
-
- dict = FindNamePhase("event14", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetInteger("timeticks_null", &int_value));
- EXPECT_EQ(0, int_value);
-
- dict = FindNamePhase("event15", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetInteger("timeticks_one", &int_value));
- EXPECT_EQ(1, int_value);
-}
-
-TEST_F(TraceEventTestFixture, NameIsEscaped) {
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
- TRACE_EVENT0("category", "name\\with\\backspaces");
- EndTraceAndFlush();
-
- EXPECT_TRUE(FindMatchingValue("cat", "category"));
- EXPECT_TRUE(FindMatchingValue("name", "name\\with\\backspaces"));
-}
-
-namespace {
-
-bool IsArgNameWhitelisted(const char* arg_name) {
- return base::MatchPattern(arg_name, "granular_arg_whitelisted");
-}
-
-bool IsTraceEventArgsWhitelisted(const char* category_group_name,
- const char* event_name,
- ArgumentNameFilterPredicate* arg_filter) {
- if (base::MatchPattern(category_group_name, "toplevel") &&
- base::MatchPattern(event_name, "*")) {
- return true;
- }
-
- if (base::MatchPattern(category_group_name, "benchmark") &&
- base::MatchPattern(event_name, "granularly_whitelisted")) {
- *arg_filter = base::Bind(&IsArgNameWhitelisted);
- return true;
- }
-
- return false;
-}
-
-} // namespace
-
-TEST_F(TraceEventTestFixture, ArgsWhitelisting) {
- TraceLog::GetInstance()->SetArgumentFilterPredicate(
- base::Bind(&IsTraceEventArgsWhitelisted));
-
- TraceLog::GetInstance()->SetEnabled(
- TraceConfig(kRecordAllCategoryFilter, "enable-argument-filter"),
- TraceLog::RECORDING_MODE);
-
- TRACE_EVENT1("toplevel", "event1", "int_one", 1);
- TRACE_EVENT1("whitewashed", "event2", "int_two", 1);
-
- TRACE_EVENT2("benchmark", "granularly_whitelisted",
- "granular_arg_whitelisted", "whitelisted_value",
- "granular_arg_blacklisted", "blacklisted_value");
-
- EndTraceAndFlush();
-
- const DictionaryValue* args_dict = NULL;
- DictionaryValue* dict = NULL;
- int int_value;
-
- dict = FindNamePhase("event1", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_TRUE(args_dict->GetInteger("int_one", &int_value));
- EXPECT_EQ(1, int_value);
-
- dict = FindNamePhase("event2", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
- EXPECT_FALSE(args_dict->GetInteger("int_two", &int_value));
-
- std::string args_string;
- EXPECT_TRUE(dict->GetString("args", &args_string));
- EXPECT_EQ(args_string, "__stripped__");
-
- dict = FindNamePhase("granularly_whitelisted", "X");
- ASSERT_TRUE(dict);
- dict->GetDictionary("args", &args_dict);
- ASSERT_TRUE(args_dict);
-
- EXPECT_TRUE(args_dict->GetString("granular_arg_whitelisted", &args_string));
- EXPECT_EQ(args_string, "whitelisted_value");
-
- EXPECT_TRUE(args_dict->GetString("granular_arg_blacklisted", &args_string));
- EXPECT_EQ(args_string, "__stripped__");
-}
-
-TEST_F(TraceEventTestFixture, TraceBufferVectorReportFull) {
- TraceLog* trace_log = TraceLog::GetInstance();
- trace_log->SetEnabled(
- TraceConfig(kRecordAllCategoryFilter, ""), TraceLog::RECORDING_MODE);
- trace_log->logged_events_.reset(
- TraceBuffer::CreateTraceBufferVectorOfSize(100));
- do {
- TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TimeTicks::Now());
- TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TimeTicks::Now());
- } while (!trace_log->BufferIsFull());
-
- EndTraceAndFlush();
-
- const DictionaryValue* trace_full_metadata = NULL;
-
- trace_full_metadata = FindTraceEntry(trace_parsed_,
- "overflowed_at_ts");
- std::string phase;
- double buffer_limit_reached_timestamp = 0;
-
- EXPECT_TRUE(trace_full_metadata);
- EXPECT_TRUE(trace_full_metadata->GetString("ph", &phase));
- EXPECT_EQ("M", phase);
- EXPECT_TRUE(trace_full_metadata->GetDouble(
- "args.overflowed_at_ts", &buffer_limit_reached_timestamp));
- EXPECT_DOUBLE_EQ(
- static_cast<double>(
- trace_log->buffer_limit_reached_timestamp_.ToInternalValue()),
- buffer_limit_reached_timestamp);
-
- // Test that buffer_limit_reached_timestamp's value is between the timestamp
- // of the last trace event and current time.
- DropTracedMetadataRecords();
- const DictionaryValue* last_trace_event = NULL;
- double last_trace_event_timestamp = 0;
- EXPECT_TRUE(trace_parsed_.GetDictionary(trace_parsed_.GetSize() - 1,
- &last_trace_event));
- EXPECT_TRUE(last_trace_event->GetDouble("ts", &last_trace_event_timestamp));
- EXPECT_LE(last_trace_event_timestamp, buffer_limit_reached_timestamp);
- EXPECT_LE(buffer_limit_reached_timestamp,
- trace_log->OffsetNow().ToInternalValue());
-}
-
-TEST_F(TraceEventTestFixture, TraceBufferRingBufferGetReturnChunk) {
- TraceLog::GetInstance()->SetEnabled(
- TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY),
- TraceLog::RECORDING_MODE);
- TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
- size_t capacity = buffer->Capacity();
- size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
- uint32_t last_seq = 0;
- size_t chunk_index;
- EXPECT_EQ(0u, buffer->Size());
-
- std::unique_ptr<TraceBufferChunk* []> chunks(
- new TraceBufferChunk*[num_chunks]);
- for (size_t i = 0; i < num_chunks; ++i) {
- chunks[i] = buffer->GetChunk(&chunk_index).release();
- EXPECT_TRUE(chunks[i]);
- EXPECT_EQ(i, chunk_index);
- EXPECT_GT(chunks[i]->seq(), last_seq);
- EXPECT_EQ((i + 1) * TraceBufferChunk::kTraceBufferChunkSize,
- buffer->Size());
- last_seq = chunks[i]->seq();
- }
-
- // Ring buffer is never full.
- EXPECT_FALSE(buffer->IsFull());
-
- // Return all chunks in original order.
- for (size_t i = 0; i < num_chunks; ++i)
- buffer->ReturnChunk(i, std::unique_ptr<TraceBufferChunk>(chunks[i]));
-
- // Should recycle the chunks in the returned order.
- for (size_t i = 0; i < num_chunks; ++i) {
- chunks[i] = buffer->GetChunk(&chunk_index).release();
- EXPECT_TRUE(chunks[i]);
- EXPECT_EQ(i, chunk_index);
- EXPECT_GT(chunks[i]->seq(), last_seq);
- last_seq = chunks[i]->seq();
- }
-
- // Return all chunks in reverse order.
- for (size_t i = 0; i < num_chunks; ++i) {
- buffer->ReturnChunk(num_chunks - i - 1, std::unique_ptr<TraceBufferChunk>(
- chunks[num_chunks - i - 1]));
- }
-
- // Should recycle the chunks in the returned order.
- for (size_t i = 0; i < num_chunks; ++i) {
- chunks[i] = buffer->GetChunk(&chunk_index).release();
- EXPECT_TRUE(chunks[i]);
- EXPECT_EQ(num_chunks - i - 1, chunk_index);
- EXPECT_GT(chunks[i]->seq(), last_seq);
- last_seq = chunks[i]->seq();
- }
-
- for (size_t i = 0; i < num_chunks; ++i)
- buffer->ReturnChunk(i, std::unique_ptr<TraceBufferChunk>(chunks[i]));
-
- TraceLog::GetInstance()->SetDisabled();
-}
-
-TEST_F(TraceEventTestFixture, TraceBufferRingBufferHalfIteration) {
- TraceLog::GetInstance()->SetEnabled(
- TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY),
- TraceLog::RECORDING_MODE);
- TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
- size_t capacity = buffer->Capacity();
- size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
- size_t chunk_index;
- EXPECT_EQ(0u, buffer->Size());
- EXPECT_FALSE(buffer->NextChunk());
-
- size_t half_chunks = num_chunks / 2;
- std::unique_ptr<TraceBufferChunk* []> chunks(
- new TraceBufferChunk*[half_chunks]);
-
- for (size_t i = 0; i < half_chunks; ++i) {
- chunks[i] = buffer->GetChunk(&chunk_index).release();
- EXPECT_TRUE(chunks[i]);
- EXPECT_EQ(i, chunk_index);
- }
- for (size_t i = 0; i < half_chunks; ++i)
- buffer->ReturnChunk(i, std::unique_ptr<TraceBufferChunk>(chunks[i]));
-
- for (size_t i = 0; i < half_chunks; ++i)
- EXPECT_EQ(chunks[i], buffer->NextChunk());
- EXPECT_FALSE(buffer->NextChunk());
- TraceLog::GetInstance()->SetDisabled();
-}
-
-TEST_F(TraceEventTestFixture, TraceBufferRingBufferFullIteration) {
- TraceLog::GetInstance()->SetEnabled(
- TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY),
- TraceLog::RECORDING_MODE);
- TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
- size_t capacity = buffer->Capacity();
- size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
- size_t chunk_index;
- EXPECT_EQ(0u, buffer->Size());
- EXPECT_FALSE(buffer->NextChunk());
-
- std::unique_ptr<TraceBufferChunk* []> chunks(
- new TraceBufferChunk*[num_chunks]);
-
- for (size_t i = 0; i < num_chunks; ++i) {
- chunks[i] = buffer->GetChunk(&chunk_index).release();
- EXPECT_TRUE(chunks[i]);
- EXPECT_EQ(i, chunk_index);
- }
- for (size_t i = 0; i < num_chunks; ++i)
- buffer->ReturnChunk(i, std::unique_ptr<TraceBufferChunk>(chunks[i]));
-
- for (size_t i = 0; i < num_chunks; ++i)
- EXPECT_TRUE(chunks[i] == buffer->NextChunk());
- EXPECT_FALSE(buffer->NextChunk());
- TraceLog::GetInstance()->SetDisabled();
-}
-
-TEST_F(TraceEventTestFixture, TraceRecordAsMuchAsPossibleMode) {
- TraceLog::GetInstance()->SetEnabled(
- TraceConfig(kRecordAllCategoryFilter, RECORD_AS_MUCH_AS_POSSIBLE),
- TraceLog::RECORDING_MODE);
- TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
- EXPECT_EQ(512000000UL, buffer->Capacity());
- TraceLog::GetInstance()->SetDisabled();
-}
-
-void BlockUntilStopped(WaitableEvent* task_start_event,
- WaitableEvent* task_stop_event) {
- task_start_event->Signal();
- task_stop_event->Wait();
-}
-
-TEST_F(TraceEventTestFixture, SetCurrentThreadBlocksMessageLoopBeforeTracing) {
- BeginTrace();
-
- Thread thread("1");
- WaitableEvent task_complete_event(WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- thread.Start();
- thread.task_runner()->PostTask(
- FROM_HERE, Bind(&TraceLog::SetCurrentThreadBlocksMessageLoop,
- Unretained(TraceLog::GetInstance())));
-
- thread.task_runner()->PostTask(
- FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
- task_complete_event.Wait();
-
- WaitableEvent task_start_event(WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- WaitableEvent task_stop_event(WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- thread.task_runner()->PostTask(
- FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
- task_start_event.Wait();
-
- EndTraceAndFlush();
- ValidateAllTraceMacrosCreatedData(trace_parsed_);
-
- task_stop_event.Signal();
- thread.Stop();
-}
-
-TEST_F(TraceEventTestFixture, ConvertTraceConfigToInternalOptions) {
- TraceLog* trace_log = TraceLog::GetInstance();
- EXPECT_EQ(TraceLog::kInternalRecordUntilFull,
- trace_log->GetInternalOptionsFromTraceConfig(
- TraceConfig(kRecordAllCategoryFilter, RECORD_UNTIL_FULL)));
-
- EXPECT_EQ(TraceLog::kInternalRecordContinuously,
- trace_log->GetInternalOptionsFromTraceConfig(
- TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY)));
-
- EXPECT_EQ(TraceLog::kInternalEchoToConsole,
- trace_log->GetInternalOptionsFromTraceConfig(
- TraceConfig(kRecordAllCategoryFilter, ECHO_TO_CONSOLE)));
-
- EXPECT_EQ(TraceLog::kInternalEchoToConsole,
- trace_log->GetInternalOptionsFromTraceConfig(
- TraceConfig("*", "trace-to-console,enable-systrace")));
-}
-
-void SetBlockingFlagAndBlockUntilStopped(WaitableEvent* task_start_event,
- WaitableEvent* task_stop_event) {
- TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop();
- BlockUntilStopped(task_start_event, task_stop_event);
-}
-
-TEST_F(TraceEventTestFixture, SetCurrentThreadBlocksMessageLoopAfterTracing) {
- BeginTrace();
-
- Thread thread("1");
- WaitableEvent task_complete_event(WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- thread.Start();
-
- thread.task_runner()->PostTask(
- FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
- task_complete_event.Wait();
-
- WaitableEvent task_start_event(WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- WaitableEvent task_stop_event(WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- thread.task_runner()->PostTask(
- FROM_HERE, Bind(&SetBlockingFlagAndBlockUntilStopped, &task_start_event,
- &task_stop_event));
- task_start_event.Wait();
-
- EndTraceAndFlush();
- ValidateAllTraceMacrosCreatedData(trace_parsed_);
-
- task_stop_event.Signal();
- thread.Stop();
-}
-
-TEST_F(TraceEventTestFixture, ThreadOnceBlocking) {
- BeginTrace();
-
- Thread thread("1");
- WaitableEvent task_complete_event(WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- thread.Start();
-
- thread.task_runner()->PostTask(
- FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
- task_complete_event.Wait();
- task_complete_event.Reset();
-
- WaitableEvent task_start_event(WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- WaitableEvent task_stop_event(WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- thread.task_runner()->PostTask(
- FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
- task_start_event.Wait();
-
- // The thread will timeout in this flush.
- EndTraceAndFlushInThreadWithMessageLoop();
- Clear();
-
- // Let the thread's message loop continue to spin.
- task_stop_event.Signal();
-
- // The following sequence ensures that the FlushCurrentThread task has been
- // executed in the thread before continuing.
- task_start_event.Reset();
- task_stop_event.Reset();
- thread.task_runner()->PostTask(
- FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
- task_start_event.Wait();
- task_stop_event.Signal();
- Clear();
-
- // TraceLog should discover the generation mismatch and recover the thread
- // local buffer for the thread without any error.
- BeginTrace();
- thread.task_runner()->PostTask(
- FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
- task_complete_event.Wait();
- task_complete_event.Reset();
- EndTraceAndFlushInThreadWithMessageLoop();
- ValidateAllTraceMacrosCreatedData(trace_parsed_);
-}
-
-std::string* g_log_buffer = NULL;
-bool MockLogMessageHandler(int, const char*, int, size_t,
- const std::string& str) {
- if (!g_log_buffer)
- g_log_buffer = new std::string();
- g_log_buffer->append(str);
- return false;
-}
-
-TEST_F(TraceEventTestFixture, EchoToConsole) {
- logging::LogMessageHandlerFunction old_log_message_handler =
- logging::GetLogMessageHandler();
- logging::SetLogMessageHandler(MockLogMessageHandler);
-
- TraceLog::GetInstance()->SetEnabled(
- TraceConfig(kRecordAllCategoryFilter, ECHO_TO_CONSOLE),
- TraceLog::RECORDING_MODE);
- TRACE_EVENT_BEGIN0("a", "begin_end");
- {
- TRACE_EVENT0("b", "duration");
- TRACE_EVENT0("b1", "duration1");
- }
- TRACE_EVENT_INSTANT0("c", "instant", TRACE_EVENT_SCOPE_GLOBAL);
- TRACE_EVENT_END0("a", "begin_end");
-
- EXPECT_NE(std::string::npos, g_log_buffer->find("begin_end[a]\x1b"));
- EXPECT_NE(std::string::npos, g_log_buffer->find("| duration[b]\x1b"));
- EXPECT_NE(std::string::npos, g_log_buffer->find("| | duration1[b1]\x1b"));
- EXPECT_NE(std::string::npos, g_log_buffer->find("| | duration1[b1] ("));
- EXPECT_NE(std::string::npos, g_log_buffer->find("| duration[b] ("));
- EXPECT_NE(std::string::npos, g_log_buffer->find("| instant[c]\x1b"));
- EXPECT_NE(std::string::npos, g_log_buffer->find("begin_end[a] ("));
-
- EndTraceAndFlush();
- delete g_log_buffer;
- logging::SetLogMessageHandler(old_log_message_handler);
- g_log_buffer = NULL;
-}
-
-bool LogMessageHandlerWithTraceEvent(int, const char*, int, size_t,
- const std::string&) {
- TRACE_EVENT0("log", "trace_event");
- return false;
-}
-
-TEST_F(TraceEventTestFixture, EchoToConsoleTraceEventRecursion) {
- logging::LogMessageHandlerFunction old_log_message_handler =
- logging::GetLogMessageHandler();
- logging::SetLogMessageHandler(LogMessageHandlerWithTraceEvent);
-
- TraceLog::GetInstance()->SetEnabled(
- TraceConfig(kRecordAllCategoryFilter, ECHO_TO_CONSOLE),
- TraceLog::RECORDING_MODE);
- {
- // This should not cause deadlock or infinite recursion.
- TRACE_EVENT0("b", "duration");
- }
-
- EndTraceAndFlush();
- logging::SetLogMessageHandler(old_log_message_handler);
-}
-
-TEST_F(TraceEventTestFixture, TimeOffset) {
- BeginTrace();
- // Let TraceLog timer start from 0.
- TimeDelta time_offset = TimeTicks::Now() - TimeTicks();
- TraceLog::GetInstance()->SetTimeOffset(time_offset);
-
- {
- TRACE_EVENT0("all", "duration1");
- TRACE_EVENT0("all", "duration2");
- }
- TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TimeTicks::Now());
- TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TimeTicks::Now());
-
- EndTraceAndFlush();
- DropTracedMetadataRecords();
-
- double end_time = static_cast<double>(
- (TimeTicks::Now() - time_offset).ToInternalValue());
- double last_timestamp = 0;
- for (size_t i = 0; i < trace_parsed_.GetSize(); ++i) {
- const DictionaryValue* item;
- EXPECT_TRUE(trace_parsed_.GetDictionary(i, &item));
- double timestamp;
- EXPECT_TRUE(item->GetDouble("ts", &timestamp));
- EXPECT_GE(timestamp, last_timestamp);
- EXPECT_LE(timestamp, end_time);
- last_timestamp = timestamp;
- }
-}
-
-TEST_F(TraceEventTestFixture, ConfigureSyntheticDelays) {
- BeginSpecificTrace("DELAY(test.Delay;0.05)");
-
- base::TimeTicks start = base::TimeTicks::Now();
- {
- TRACE_EVENT_SYNTHETIC_DELAY("test.Delay");
- }
- base::TimeDelta duration = base::TimeTicks::Now() - start;
- EXPECT_GE(duration.InMilliseconds(), 50);
-
- EndTraceAndFlush();
-}
-
-TEST_F(TraceEventTestFixture, BadSyntheticDelayConfigurations) {
- const char* const filters[] = {
- "",
- "DELAY(",
- "DELAY(;",
- "DELAY(;)",
- "DELAY(test.Delay)",
- "DELAY(test.Delay;)"
- };
- for (size_t i = 0; i < arraysize(filters); i++) {
- BeginSpecificTrace(filters[i]);
- EndTraceAndFlush();
- TraceConfig trace_config = TraceLog::GetInstance()->GetCurrentTraceConfig();
- EXPECT_EQ(0u, trace_config.GetSyntheticDelayValues().size());
- }
-}
-
-TEST_F(TraceEventTestFixture, SyntheticDelayConfigurationMerging) {
- TraceConfig config1("DELAY(test.Delay1;16)", "");
- TraceConfig config2("DELAY(test.Delay2;32)", "");
- config1.Merge(config2);
- EXPECT_EQ(2u, config1.GetSyntheticDelayValues().size());
-}
-
-TEST_F(TraceEventTestFixture, SyntheticDelayConfigurationToString) {
- const char filter[] = "DELAY(test.Delay;16;oneshot)";
- TraceConfig config(filter, "");
- 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\","
- " \"" TRACE_DISABLED_BY_DEFAULT("filtered_cat") "\","
- " \"" TRACE_DISABLED_BY_DEFAULT("unfiltered_cat") "\"],"
- " \"event_filters\": ["
- " {"
- " \"filter_predicate\": \"testing_predicate\", "
- " \"included_categories\": ["
- " \"filtered_cat\","
- " \"" TRACE_DISABLED_BY_DEFAULT("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");
-
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("filtered_cat"), "a dog");
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("unfiltered_cat"), "a pony");
-
- // This is scoped so we can test the end event being filtered.
- { TRACE_EVENT0("filtered_cat", "another cat whoa"); }
-
- EndTraceAndFlush();
-
- EXPECT_EQ(4u, 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\","
- " \"" TRACE_DISABLED_BY_DEFAULT("filtered_cat") "\"],"
- " \"event_filters\": ["
- " {"
- " \"filter_predicate\": \"%s\", "
- " \"included_categories\": ["
- " \"filtered_cat\","
- " \"" TRACE_DISABLED_BY_DEFAULT("*") "\"], "
- " \"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");
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("filtered_cat"), "a dog");
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("filtered_cat"), "a pony");
-
- EndTraceAndFlush();
-
- EXPECT_TRUE(FindMatchingValue("name", "a snake"));
- EXPECT_FALSE(FindMatchingValue("name", "a mushroom"));
- EXPECT_TRUE(FindMatchingValue("name", "a cat"));
- EXPECT_TRUE(FindMatchingValue("name", "a dog"));
- EXPECT_FALSE(FindMatchingValue("name", "a pony"));
-}
-
-TEST_F(TraceEventTestFixture, HeapProfilerFiltering) {
- std::string config_json = StringPrintf(
- "{"
- " \"included_categories\": ["
- " \"filtered_cat\","
- " \"unfiltered_cat\","
- " \"" TRACE_DISABLED_BY_DEFAULT("filtered_cat") "\","
- " \"" TRACE_DISABLED_BY_DEFAULT("unfiltered_cat") "\"],"
- " \"excluded_categories\": [\"excluded_cat\"],"
- " \"event_filters\": ["
- " {"
- " \"filter_predicate\": \"%s\", "
- " \"included_categories\": ["
- " \"*\","
- " \"" TRACE_DISABLED_BY_DEFAULT("filtered_cat") "\"]"
- " }"
- " ]"
- "}",
- 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");
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("filtered_cat"), "a dog");
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("unfiltered_cat"), "a pony");
-
- 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"));
- EXPECT_TRUE(FindMatchingValue("name", "a dog"));
- EXPECT_TRUE(FindMatchingValue("name", "a pony"));
-}
-
-TEST_F(TraceEventTestFixture, ClockSyncEventsAreAlwaysAddedToTrace) {
- BeginSpecificTrace("-*");
- TRACE_EVENT_CLOCK_SYNC_RECEIVER(1);
- EndTraceAndFlush();
- EXPECT_TRUE(FindNamePhase("clock_sync", "c"));
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc
deleted file mode 100644
index d08030e709..0000000000
--- a/base/trace_event/trace_log.cc
+++ /dev/null
@@ -1,1749 +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/trace_log.h"
-
-#include <algorithm>
-#include <cmath>
-#include <memory>
-#include <utility>
-
-#include "base/base_switches.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/debug/leak_annotations.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_info.h"
-#include "base/process/process_metrics.h"
-#include "base/stl_util.h"
-#include "base/strings/string_piece.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/threading/platform_thread.h"
-#include "base/threading/thread_id_name_manager.h"
-#include "base/threading/thread_task_runner_handle.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 "build/build_config.h"
-
-#if defined(OS_WIN)
-#include "base/trace_event/trace_event_etw_export_win.h"
-#endif
-
-namespace base {
-namespace internal {
-
-class DeleteTraceLogForTesting {
- public:
- static void Delete() {
- Singleton<trace_event::TraceLog,
- LeakySingletonTraits<trace_event::TraceLog>>::OnExit(0);
- }
-};
-
-} // namespace internal
-
-namespace trace_event {
-
-namespace {
-
-// Controls the number of trace events we will buffer in-memory
-// before throwing them away.
-const size_t kTraceBufferChunkSize = TraceBufferChunk::kTraceBufferChunkSize;
-
-const size_t kTraceEventVectorBigBufferChunks =
- 512000000 / kTraceBufferChunkSize;
-static_assert(
- kTraceEventVectorBigBufferChunks <= TraceBufferChunk::kMaxChunkIndex,
- "Too many big buffer chunks");
-const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize;
-static_assert(
- kTraceEventVectorBufferChunks <= TraceBufferChunk::kMaxChunkIndex,
- "Too many vector buffer chunks");
-const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4;
-
-// ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events.
-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;
-}
-
-ThreadTicks ThreadNow() {
- return ThreadTicks::IsSupported() ? ThreadTicks::Now() : ThreadTicks();
-}
-
-template <typename T>
-void InitializeMetadataEvent(TraceEvent* trace_event,
- int thread_id,
- const char* metadata_name,
- const char* arg_name,
- const T& value) {
- if (!trace_event)
- return;
-
- int num_args = 1;
- unsigned char arg_type;
- unsigned long long arg_value;
- ::trace_event_internal::SetTraceValue(value, &arg_type, &arg_value);
- trace_event->Initialize(
- thread_id,
- TimeTicks(),
- ThreadTicks(),
- TRACE_EVENT_PHASE_METADATA,
- CategoryRegistry::kCategoryMetadata->state_ptr(),
- metadata_name,
- trace_event_internal::kGlobalScope, // scope
- trace_event_internal::kNoId, // id
- trace_event_internal::kNoId, // bind_id
- num_args,
- &arg_name,
- &arg_type,
- &arg_value,
- nullptr,
- TRACE_EVENT_FLAG_NONE);
-}
-
-class AutoThreadLocalBoolean {
- public:
- explicit AutoThreadLocalBoolean(ThreadLocalBoolean* thread_local_boolean)
- : thread_local_boolean_(thread_local_boolean) {
- DCHECK(!thread_local_boolean_->Get());
- thread_local_boolean_->Set(true);
- }
- ~AutoThreadLocalBoolean() { thread_local_boolean_->Set(false); }
-
- private:
- ThreadLocalBoolean* thread_local_boolean_;
- DISALLOW_COPY_AND_ASSIGN(AutoThreadLocalBoolean);
-};
-
-// Use this function instead of TraceEventHandle constructor to keep the
-// overhead of ScopedTracer (trace_event.h) constructor minimum.
-void MakeHandle(uint32_t chunk_seq,
- size_t chunk_index,
- size_t event_index,
- TraceEventHandle* handle) {
- 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
-// and unlocks at the end of scope if locked.
-class TraceLog::OptionalAutoLock {
- public:
- explicit OptionalAutoLock(Lock* lock) : lock_(lock), locked_(false) {}
-
- ~OptionalAutoLock() {
- if (locked_)
- lock_->Release();
- }
-
- void EnsureAcquired() {
- if (!locked_) {
- lock_->Acquire();
- locked_ = true;
- }
- }
-
- private:
- Lock* lock_;
- bool locked_;
- DISALLOW_COPY_AND_ASSIGN(OptionalAutoLock);
-};
-
-class TraceLog::ThreadLocalEventBuffer
- : public MessageLoop::DestructionObserver,
- public MemoryDumpProvider {
- public:
- explicit ThreadLocalEventBuffer(TraceLog* trace_log);
- ~ThreadLocalEventBuffer() override;
-
- TraceEvent* AddTraceEvent(TraceEventHandle* handle);
-
- TraceEvent* GetEventByHandle(TraceEventHandle handle) {
- if (!chunk_ || handle.chunk_seq != chunk_->seq() ||
- handle.chunk_index != chunk_index_) {
- return nullptr;
- }
-
- return chunk_->GetEventAt(handle.event_index);
- }
-
- int generation() const { return generation_; }
-
- private:
- // MessageLoop::DestructionObserver
- void WillDestroyCurrentMessageLoop() override;
-
- // MemoryDumpProvider implementation.
- bool OnMemoryDump(const MemoryDumpArgs& args,
- ProcessMemoryDump* pmd) override;
-
- void FlushWhileLocked();
-
- void CheckThisIsCurrentBuffer() const {
- DCHECK(trace_log_->thread_local_event_buffer_.Get() == this);
- }
-
- // Since TraceLog is a leaky singleton, trace_log_ will always be valid
- // as long as the thread exists.
- TraceLog* trace_log_;
- std::unique_ptr<TraceBufferChunk> chunk_;
- size_t chunk_index_;
- int generation_;
-
- DISALLOW_COPY_AND_ASSIGN(ThreadLocalEventBuffer);
-};
-
-TraceLog::ThreadLocalEventBuffer::ThreadLocalEventBuffer(TraceLog* trace_log)
- : trace_log_(trace_log),
- chunk_index_(0),
- generation_(trace_log->generation()) {
- // ThreadLocalEventBuffer is created only if the thread has a message loop, so
- // the following message_loop won't be NULL.
- MessageLoop* message_loop = MessageLoop::current();
- message_loop->AddDestructionObserver(this);
-
- // This is to report the local memory usage when memory-infra is enabled.
- MemoryDumpManager::GetInstance()->RegisterDumpProvider(
- this, "ThreadLocalEventBuffer", ThreadTaskRunnerHandle::Get());
-
- AutoLock lock(trace_log->lock_);
- trace_log->thread_message_loops_.insert(message_loop);
-}
-
-TraceLog::ThreadLocalEventBuffer::~ThreadLocalEventBuffer() {
- CheckThisIsCurrentBuffer();
- MessageLoop::current()->RemoveDestructionObserver(this);
- MemoryDumpManager::GetInstance()->UnregisterDumpProvider(this);
-
- {
- AutoLock lock(trace_log_->lock_);
- FlushWhileLocked();
- trace_log_->thread_message_loops_.erase(MessageLoop::current());
- }
- trace_log_->thread_local_event_buffer_.Set(NULL);
-}
-
-TraceEvent* TraceLog::ThreadLocalEventBuffer::AddTraceEvent(
- TraceEventHandle* handle) {
- CheckThisIsCurrentBuffer();
-
- if (chunk_ && chunk_->IsFull()) {
- AutoLock lock(trace_log_->lock_);
- FlushWhileLocked();
- chunk_.reset();
- }
- if (!chunk_) {
- AutoLock lock(trace_log_->lock_);
- chunk_ = trace_log_->logged_events_->GetChunk(&chunk_index_);
- trace_log_->CheckIfBufferIsFullWhileLocked();
- }
- if (!chunk_)
- return NULL;
-
- size_t event_index;
- TraceEvent* trace_event = chunk_->AddTraceEvent(&event_index);
- if (trace_event && handle)
- MakeHandle(chunk_->seq(), chunk_index_, event_index, handle);
-
- return trace_event;
-}
-
-void TraceLog::ThreadLocalEventBuffer::WillDestroyCurrentMessageLoop() {
- delete this;
-}
-
-bool TraceLog::ThreadLocalEventBuffer::OnMemoryDump(const MemoryDumpArgs& args,
- ProcessMemoryDump* pmd) {
- if (!chunk_)
- return true;
- std::string dump_base_name = StringPrintf(
- "tracing/thread_%d", static_cast<int>(PlatformThread::CurrentId()));
- TraceEventMemoryOverhead overhead;
- chunk_->EstimateTraceMemoryOverhead(&overhead);
- overhead.DumpInto(dump_base_name.c_str(), pmd);
- return true;
-}
-
-void TraceLog::ThreadLocalEventBuffer::FlushWhileLocked() {
- if (!chunk_)
- return;
-
- trace_log_->lock_.AssertAcquired();
- if (trace_log_->CheckGeneration(generation_)) {
- // Return the chunk to the buffer only if the generation matches.
- trace_log_->logged_events_->ReturnChunk(chunk_index_, std::move(chunk_));
- }
- // Otherwise this method may be called from the destructor, or TraceLog will
- // find the generation mismatch and delete this buffer soon.
-}
-
-struct TraceLog::RegisteredAsyncObserver {
- explicit RegisteredAsyncObserver(WeakPtr<AsyncEnabledStateObserver> observer)
- : observer(observer), task_runner(ThreadTaskRunnerHandle::Get()) {}
- ~RegisteredAsyncObserver() {}
-
- WeakPtr<AsyncEnabledStateObserver> observer;
- scoped_refptr<SequencedTaskRunner> task_runner;
-};
-
-TraceLogStatus::TraceLogStatus() : event_capacity(0), event_count(0) {}
-
-TraceLogStatus::~TraceLogStatus() {}
-
-// static
-TraceLog* TraceLog::GetInstance() {
- return Singleton<TraceLog, LeakySingletonTraits<TraceLog>>::get();
-}
-
-TraceLog::TraceLog()
- : enabled_modes_(0),
- num_traces_recorded_(0),
- dispatching_to_observer_list_(false),
- process_sort_index_(0),
- process_id_hash_(0),
- process_id_(0),
- trace_options_(kInternalRecordUntilFull),
- trace_config_(TraceConfig()),
- thread_shared_chunk_index_(0),
- generation_(0),
- use_worker_thread_(false),
- filter_factory_for_testing_(nullptr) {
- CategoryRegistry::Initialize();
-
-#if defined(OS_NACL) // NaCl shouldn't expose the process id.
- SetProcessID(0);
-#else
- SetProcessID(static_cast<int>(GetCurrentProcId()));
-#endif
-
- logged_events_.reset(CreateTraceBuffer());
-
- MemoryDumpManager::GetInstance()->RegisterDumpProvider(this, "TraceLog",
- nullptr);
-}
-
-TraceLog::~TraceLog() {}
-
-void TraceLog::InitializeThreadLocalEventBufferIfSupported() {
- // A ThreadLocalEventBuffer needs the message loop
- // - to know when the thread exits;
- // - to handle the final flush.
- // For a thread without a message loop or the message loop may be blocked, the
- // trace events will be added into the main buffer directly.
- if (thread_blocks_message_loop_.Get() || !MessageLoop::current())
- return;
- HEAP_PROFILER_SCOPED_IGNORE;
- auto* thread_local_event_buffer = thread_local_event_buffer_.Get();
- if (thread_local_event_buffer &&
- !CheckGeneration(thread_local_event_buffer->generation())) {
- delete thread_local_event_buffer;
- thread_local_event_buffer = NULL;
- }
- if (!thread_local_event_buffer) {
- thread_local_event_buffer = new ThreadLocalEventBuffer(this);
- thread_local_event_buffer_.Set(thread_local_event_buffer);
- }
-}
-
-bool TraceLog::OnMemoryDump(const MemoryDumpArgs& args,
- ProcessMemoryDump* pmd) {
- // TODO(ssid): Use MemoryDumpArgs to create light dumps when requested
- // (crbug.com/499731).
- TraceEventMemoryOverhead overhead;
- overhead.Add("TraceLog", sizeof(*this));
- {
- AutoLock lock(lock_);
- if (logged_events_)
- logged_events_->EstimateTraceMemoryOverhead(&overhead);
-
- for (auto& metadata_event : metadata_events_)
- metadata_event->EstimateTraceMemoryOverhead(&overhead);
- }
- overhead.AddSelf();
- overhead.DumpInto("tracing/main_trace_log", pmd);
- return true;
-}
-
-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(category->state_ptr());
- return category->state_ptr();
-}
-
-const char* TraceLog::GetCategoryGroupName(
- const unsigned char* category_group_enabled) {
- return CategoryRegistry::GetCategoryByStatePtr(category_group_enabled)
- ->name();
-}
-
-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;
- }
-
- // TODO(primiano): this is a temporary workaround for catapult:#2341,
- // to guarantee that metadata events are always added even if the category
- // filter is "-*". See crbug.com/618054 for more details and long-term fix.
- if (enabled_modes_ & RECORDING_MODE &&
- category == CategoryRegistry::kCategoryMetadata) {
- state_flags |= TraceCategory::ENABLED_FOR_RECORDING;
- }
-
-#if defined(OS_WIN)
- if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled(
- category->name())) {
- state_flags |= TraceCategory::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);
-}
-
-void TraceLog::UpdateCategoryRegistry() {
- lock_.AssertAcquired();
- CreateFiltersForTraceConfig();
- for (TraceCategory& category : CategoryRegistry::GetAllCategories()) {
- UpdateCategoryState(&category);
- }
-}
-
-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::UpdateSyntheticDelaysFromTraceConfig() {
- ResetTraceEventSyntheticDelays();
- const TraceConfig::StringList& delays =
- trace_config_.GetSyntheticDelayValues();
- TraceConfig::StringList::const_iterator ci;
- for (ci = delays.begin(); ci != delays.end(); ++ci) {
- StringTokenizer tokens(*ci, ";");
- if (!tokens.GetNext())
- continue;
- TraceEventSyntheticDelay* delay =
- TraceEventSyntheticDelay::Lookup(tokens.token());
- while (tokens.GetNext()) {
- std::string token = tokens.token();
- char* duration_end;
- double target_duration = strtod(token.c_str(), &duration_end);
- if (duration_end != token.c_str()) {
- delay->SetTargetDuration(TimeDelta::FromMicroseconds(
- static_cast<int64_t>(target_duration * 1e6)));
- } else if (token == "static") {
- delay->SetMode(TraceEventSyntheticDelay::STATIC);
- } else if (token == "oneshot") {
- delay->SetMode(TraceEventSyntheticDelay::ONE_SHOT);
- } else if (token == "alternating") {
- delay->SetMode(TraceEventSyntheticDelay::ALTERNATING);
- }
- }
- }
-}
-
-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());
- }
-}
-
-void TraceLog::SetEnabled(const TraceConfig& trace_config,
- uint8_t modes_to_enable) {
- std::vector<EnabledStateObserver*> observer_list;
- std::map<AsyncEnabledStateObserver*, RegisteredAsyncObserver> observer_map;
- {
- AutoLock lock(lock_);
-
- // Can't enable tracing when Flush() is in progress.
- DCHECK(!flush_task_runner_);
-
- InternalTraceOptions new_options =
- GetInternalOptionsFromTraceConfig(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;
- }
-
- // 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;
- }
- }
-
- // 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();
- }
- // 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)
- return;
-
- if (new_options != old_options) {
- subtle::NoBarrier_Store(&trace_options_, new_options);
- UseNextTraceBuffer();
- }
-
- num_traces_recorded_++;
-
- UpdateCategoryRegistry();
- UpdateSyntheticDelaysFromTraceConfig();
-
- 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 (const auto& it : observer_map) {
- it.second.task_runner->PostTask(
- FROM_HERE, Bind(&AsyncEnabledStateObserver::OnTraceLogEnabled,
- it.second.observer));
- }
-
- {
- AutoLock lock(lock_);
- dispatching_to_observer_list_ = false;
- }
-}
-
-void TraceLog::SetArgumentFilterPredicate(
- const ArgumentFilterPredicate& argument_filter_predicate) {
- AutoLock lock(lock_);
- DCHECK(!argument_filter_predicate.is_null());
- DCHECK(argument_filter_predicate_.is_null());
- argument_filter_predicate_ = argument_filter_predicate;
-}
-
-TraceLog::InternalTraceOptions TraceLog::GetInternalOptionsFromTraceConfig(
- const TraceConfig& config) {
- InternalTraceOptions ret = config.IsArgumentFilterEnabled()
- ? kInternalEnableArgumentFilter
- : kInternalNone;
- switch (config.GetTraceRecordMode()) {
- case RECORD_UNTIL_FULL:
- return ret | kInternalRecordUntilFull;
- case RECORD_CONTINUOUSLY:
- return ret | kInternalRecordContinuously;
- case ECHO_TO_CONSOLE:
- return ret | kInternalEchoToConsole;
- case RECORD_AS_MUCH_AS_POSSIBLE:
- return ret | kInternalRecordAsMuchAsPossible;
- }
- NOTREACHED();
- return kInternalNone;
-}
-
-TraceConfig TraceLog::GetCurrentTraceConfig() const {
- AutoLock lock(lock_);
- return trace_config_;
-}
-
-void TraceLog::SetDisabled() {
- AutoLock lock(lock_);
- SetDisabledWhileLocked(RECORDING_MODE);
-}
-
-void TraceLog::SetDisabled(uint8_t modes_to_disable) {
- AutoLock lock(lock_);
- SetDisabledWhileLocked(modes_to_disable);
-}
-
-void TraceLog::SetDisabledWhileLocked(uint8_t modes_to_disable) {
- lock_.AssertAcquired();
-
- if (!(enabled_modes_ & modes_to_disable))
- 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();
-
- UpdateCategoryRegistry();
-
- // Add metadata events and notify observers only if recording mode was
- // disabled now.
- if (!is_recording_mode_disabled)
- return;
-
- AddMetadataEventsWhileLocked();
-
- // Remove metadata events so they will not get added to a subsequent trace.
- metadata_events_.clear();
-
- dispatching_to_observer_list_ = true;
- std::vector<EnabledStateObserver*> observer_list =
- enabled_state_observer_list_;
- std::map<AsyncEnabledStateObserver*, RegisteredAsyncObserver> observer_map =
- async_observers_;
-
- {
- // 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 (const auto& it : observer_map) {
- it.second.task_runner->PostTask(
- FROM_HERE, Bind(&AsyncEnabledStateObserver::OnTraceLogDisabled,
- it.second.observer));
- }
- }
- dispatching_to_observer_list_ = false;
-}
-
-int TraceLog::GetNumTracesRecorded() {
- AutoLock lock(lock_);
- if (!IsEnabled())
- return -1;
- return num_traces_recorded_;
-}
-
-void TraceLog::AddEnabledStateObserver(EnabledStateObserver* listener) {
- AutoLock lock(lock_);
- enabled_state_observer_list_.push_back(listener);
-}
-
-void TraceLog::RemoveEnabledStateObserver(EnabledStateObserver* listener) {
- AutoLock lock(lock_);
- std::vector<EnabledStateObserver*>::iterator it =
- std::find(enabled_state_observer_list_.begin(),
- enabled_state_observer_list_.end(), listener);
- if (it != enabled_state_observer_list_.end())
- enabled_state_observer_list_.erase(it);
-}
-
-bool TraceLog::HasEnabledStateObserver(EnabledStateObserver* listener) const {
- AutoLock lock(lock_);
- return ContainsValue(enabled_state_observer_list_, listener);
-}
-
-TraceLogStatus TraceLog::GetStatus() const {
- AutoLock lock(lock_);
- TraceLogStatus result;
- result.event_capacity = static_cast<uint32_t>(logged_events_->Capacity());
- result.event_count = static_cast<uint32_t>(logged_events_->Size());
- return result;
-}
-
-bool TraceLog::BufferIsFull() const {
- AutoLock lock(lock_);
- return logged_events_->IsFull();
-}
-
-TraceEvent* TraceLog::AddEventToThreadSharedChunkWhileLocked(
- TraceEventHandle* handle,
- bool check_buffer_is_full) {
- lock_.AssertAcquired();
-
- if (thread_shared_chunk_ && thread_shared_chunk_->IsFull()) {
- logged_events_->ReturnChunk(thread_shared_chunk_index_,
- std::move(thread_shared_chunk_));
- }
-
- if (!thread_shared_chunk_) {
- thread_shared_chunk_ =
- logged_events_->GetChunk(&thread_shared_chunk_index_);
- if (check_buffer_is_full)
- CheckIfBufferIsFullWhileLocked();
- }
- if (!thread_shared_chunk_)
- return NULL;
-
- size_t event_index;
- TraceEvent* trace_event = thread_shared_chunk_->AddTraceEvent(&event_index);
- if (trace_event && handle) {
- MakeHandle(thread_shared_chunk_->seq(), thread_shared_chunk_index_,
- event_index, handle);
- }
- return trace_event;
-}
-
-void TraceLog::CheckIfBufferIsFullWhileLocked() {
- lock_.AssertAcquired();
- if (logged_events_->IsFull()) {
- if (buffer_limit_reached_timestamp_.is_null()) {
- buffer_limit_reached_timestamp_ = OffsetNow();
- }
- SetDisabledWhileLocked(RECORDING_MODE);
- }
-}
-
-// Flush() works as the following:
-// 1. Flush() is called in thread A whose task runner is saved in
-// flush_task_runner_;
-// 2. If thread_message_loops_ is not empty, thread A posts task to each message
-// loop to flush the thread local buffers; otherwise finish the flush;
-// 3. FlushCurrentThread() deletes the thread local event buffer:
-// - The last batch of events of the thread are flushed into the main buffer;
-// - The message loop will be removed from thread_message_loops_;
-// If this is the last message loop, finish the flush;
-// 4. If any thread hasn't finish its flush in time, finish the flush.
-void TraceLog::Flush(const TraceLog::OutputCallback& cb,
- bool use_worker_thread) {
- FlushInternal(cb, use_worker_thread, false);
-}
-
-void TraceLog::CancelTracing(const OutputCallback& cb) {
- SetDisabled();
- FlushInternal(cb, false, true);
-}
-
-void TraceLog::FlushInternal(const TraceLog::OutputCallback& cb,
- bool use_worker_thread,
- bool discard_events) {
- use_worker_thread_ = use_worker_thread;
- if (IsEnabled()) {
- // Can't flush when tracing is enabled because otherwise PostTask would
- // - generate more trace events;
- // - deschedule the calling thread on some platforms causing inaccurate
- // timing of the trace events.
- scoped_refptr<RefCountedString> empty_result = new RefCountedString;
- if (!cb.is_null())
- cb.Run(empty_result, false);
- LOG(WARNING) << "Ignored TraceLog::Flush called when tracing is enabled";
- return;
- }
-
- int gen = generation();
- // Copy of thread_message_loops_ to be used without locking.
- std::vector<scoped_refptr<SingleThreadTaskRunner>>
- thread_message_loop_task_runners;
- {
- AutoLock lock(lock_);
- DCHECK(!flush_task_runner_);
- flush_task_runner_ = ThreadTaskRunnerHandle::IsSet()
- ? ThreadTaskRunnerHandle::Get()
- : nullptr;
- DCHECK(thread_message_loops_.empty() || flush_task_runner_);
- flush_output_callback_ = cb;
-
- if (thread_shared_chunk_) {
- logged_events_->ReturnChunk(thread_shared_chunk_index_,
- std::move(thread_shared_chunk_));
- }
-
- for (MessageLoop* loop : thread_message_loops_)
- thread_message_loop_task_runners.push_back(loop->task_runner());
- }
-
- if (!thread_message_loop_task_runners.empty()) {
- for (auto& task_runner : thread_message_loop_task_runners) {
- task_runner->PostTask(
- FROM_HERE, Bind(&TraceLog::FlushCurrentThread, Unretained(this),
- gen, discard_events));
- }
- flush_task_runner_->PostDelayedTask(
- FROM_HERE, Bind(&TraceLog::OnFlushTimeout, Unretained(this), gen,
- discard_events),
- TimeDelta::FromMilliseconds(kThreadFlushTimeoutMs));
- return;
- }
-
- FinishFlush(gen, discard_events);
-}
-
-// Usually it runs on a different thread.
-void TraceLog::ConvertTraceEventsToTraceFormat(
- std::unique_ptr<TraceBuffer> logged_events,
- const OutputCallback& flush_output_callback,
- const ArgumentFilterPredicate& argument_filter_predicate) {
- if (flush_output_callback.is_null())
- return;
-
- HEAP_PROFILER_SCOPED_IGNORE;
- // The callback need to be called at least once even if there is no events
- // to let the caller know the completion of flush.
- scoped_refptr<RefCountedString> json_events_str_ptr = new RefCountedString();
- while (const TraceBufferChunk* chunk = logged_events->NextChunk()) {
- for (size_t j = 0; j < chunk->size(); ++j) {
- size_t size = json_events_str_ptr->size();
- if (size > kTraceEventBufferSizeInBytes) {
- flush_output_callback.Run(json_events_str_ptr, true);
- json_events_str_ptr = new RefCountedString();
- } else if (size) {
- json_events_str_ptr->data().append(",\n");
- }
- chunk->GetEventAt(j)->AppendAsJSON(&(json_events_str_ptr->data()),
- argument_filter_predicate);
- }
- }
- flush_output_callback.Run(json_events_str_ptr, false);
-}
-
-void TraceLog::FinishFlush(int generation, bool discard_events) {
- std::unique_ptr<TraceBuffer> previous_logged_events;
- OutputCallback flush_output_callback;
- ArgumentFilterPredicate argument_filter_predicate;
-
- if (!CheckGeneration(generation))
- return;
-
- {
- AutoLock lock(lock_);
-
- previous_logged_events.swap(logged_events_);
- UseNextTraceBuffer();
- thread_message_loops_.clear();
-
- flush_task_runner_ = NULL;
- flush_output_callback = flush_output_callback_;
- flush_output_callback_.Reset();
-
- if (trace_options() & kInternalEnableArgumentFilter) {
- CHECK(!argument_filter_predicate_.is_null());
- argument_filter_predicate = argument_filter_predicate_;
- }
- }
-
- if (discard_events) {
- if (!flush_output_callback.is_null()) {
- scoped_refptr<RefCountedString> empty_result = new RefCountedString;
- flush_output_callback.Run(empty_result, false);
- }
- 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));
- return;
-#else
- NOTREACHED();
-#endif
- }
-
- ConvertTraceEventsToTraceFormat(std::move(previous_logged_events),
- flush_output_callback,
- argument_filter_predicate);
-}
-
-// Run in each thread holding a local event buffer.
-void TraceLog::FlushCurrentThread(int generation, bool discard_events) {
- {
- AutoLock lock(lock_);
- if (!CheckGeneration(generation) || !flush_task_runner_) {
- // This is late. The corresponding flush has finished.
- return;
- }
- }
-
- // This will flush the thread local buffer.
- delete thread_local_event_buffer_.Get();
-
- AutoLock lock(lock_);
- if (!CheckGeneration(generation) || !flush_task_runner_ ||
- !thread_message_loops_.empty())
- return;
-
- flush_task_runner_->PostTask(
- FROM_HERE, Bind(&TraceLog::FinishFlush, Unretained(this), generation,
- discard_events));
-}
-
-void TraceLog::OnFlushTimeout(int generation, bool discard_events) {
- {
- AutoLock lock(lock_);
- if (!CheckGeneration(generation) || !flush_task_runner_) {
- // Flush has finished before timeout.
- return;
- }
-
- LOG(WARNING)
- << "The following threads haven't finished flush in time. "
- "If this happens stably for some thread, please call "
- "TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop() from "
- "the thread to avoid its trace events from being lost.";
- for (hash_set<MessageLoop*>::const_iterator it =
- thread_message_loops_.begin();
- it != thread_message_loops_.end(); ++it) {
- LOG(WARNING) << "Thread: " << (*it)->GetThreadName();
- }
- }
- FinishFlush(generation, discard_events);
-}
-
-void TraceLog::UseNextTraceBuffer() {
- logged_events_.reset(CreateTraceBuffer());
- subtle::NoBarrier_AtomicIncrement(&generation_, 1);
- thread_shared_chunk_.reset();
- thread_shared_chunk_index_ = 0;
-}
-
-TraceEventHandle TraceLog::AddTraceEvent(
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- const char* scope,
- unsigned long long id,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags) {
- int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- base::TimeTicks now = base::TimeTicks::Now();
- return AddTraceEventWithThreadIdAndTimestamp(
- phase,
- category_group_enabled,
- name,
- scope,
- id,
- trace_event_internal::kNoId, // bind_id
- thread_id,
- now,
- num_args,
- arg_names,
- arg_types,
- arg_values,
- convertable_values,
- flags);
-}
-
-TraceEventHandle TraceLog::AddTraceEventWithBindId(
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- const char* scope,
- unsigned long long id,
- unsigned long long bind_id,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags) {
- int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- base::TimeTicks now = base::TimeTicks::Now();
- return AddTraceEventWithThreadIdAndTimestamp(
- phase,
- category_group_enabled,
- name,
- scope,
- id,
- bind_id,
- thread_id,
- now,
- num_args,
- arg_names,
- arg_types,
- arg_values,
- convertable_values,
- flags | TRACE_EVENT_FLAG_HAS_CONTEXT_ID);
-}
-
-TraceEventHandle TraceLog::AddTraceEventWithProcessId(
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- const char* scope,
- unsigned long long id,
- int process_id,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags) {
- base::TimeTicks now = base::TimeTicks::Now();
- return AddTraceEventWithThreadIdAndTimestamp(
- phase,
- category_group_enabled,
- name,
- scope,
- id,
- trace_event_internal::kNoId, // bind_id
- process_id,
- now,
- num_args,
- arg_names,
- arg_types,
- arg_values,
- convertable_values,
- flags | TRACE_EVENT_FLAG_HAS_PROCESS_ID);
-}
-
-// Handle legacy calls to AddTraceEventWithThreadIdAndTimestamp
-// with kNoId as bind_id
-TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- const char* scope,
- unsigned long long id,
- int thread_id,
- const TimeTicks& timestamp,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags) {
- return AddTraceEventWithThreadIdAndTimestamp(
- phase,
- category_group_enabled,
- name,
- scope,
- id,
- trace_event_internal::kNoId, // bind_id
- thread_id,
- timestamp,
- num_args,
- arg_names,
- arg_types,
- arg_values,
- convertable_values,
- flags);
-}
-
-TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- const char* scope,
- unsigned long long id,
- unsigned long long bind_id,
- int thread_id,
- const TimeTicks& timestamp,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags) {
- TraceEventHandle handle = {0, 0, 0};
- if (!*category_group_enabled)
- return handle;
-
- // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when
- // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) ->
- // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ...
- if (thread_is_in_trace_event_.Get())
- return handle;
-
- AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
-
- DCHECK(name);
- DCHECK(!timestamp.is_null());
-
- if (flags & TRACE_EVENT_FLAG_MANGLE_ID) {
- if ((flags & TRACE_EVENT_FLAG_FLOW_IN) ||
- (flags & TRACE_EVENT_FLAG_FLOW_OUT))
- bind_id = MangleEventId(bind_id);
- id = MangleEventId(id);
- }
-
- 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();
- }
-
- // Check and update the current thread name only if the event is for the
- // current thread to avoid locks in most cases.
- if (thread_id == static_cast<int>(PlatformThread::CurrentId())) {
- const char* new_name =
- ThreadIdNameManager::GetInstance()->GetName(thread_id);
- // Check if the thread name has been set or changed since the previous
- // 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);
-
- AutoLock thread_info_lock(thread_info_lock_);
-
- hash_map<int, std::string>::iterator existing_name =
- thread_names_.find(thread_id);
- if (existing_name == thread_names_.end()) {
- // This is a new thread id, and a new name.
- thread_names_[thread_id] = new_name;
- } else {
- // This is a thread id that we've seen before, but potentially with a
- // new name.
- std::vector<StringPiece> existing_names = base::SplitStringPiece(
- existing_name->second, ",", base::KEEP_WHITESPACE,
- base::SPLIT_WANT_NONEMPTY);
- bool found = std::find(existing_names.begin(), existing_names.end(),
- new_name) != existing_names.end();
- if (!found) {
- if (!existing_names.empty())
- existing_name->second.push_back(',');
- existing_name->second.append(new_name);
- }
- }
- }
- }
-
-#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)
- 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) {
- OptionalAutoLock lock(&lock_);
-
- TraceEvent* trace_event = NULL;
- if (thread_local_event_buffer) {
- trace_event = thread_local_event_buffer->AddTraceEvent(&handle);
- } else {
- lock.EnsureAcquired();
- trace_event = AddEventToThreadSharedChunkWhileLocked(&handle, true);
- }
-
- 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);
- }
-
-#if defined(OS_ANDROID)
- trace_event->SendToATrace();
-#endif
- }
-
- if (trace_options() & kInternalEchoToConsole) {
- console_message = EventToConsoleMessage(
- phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase,
- timestamp, trace_event);
- }
- }
-
- if (!console_message.empty())
- LOG(ERROR) << console_message;
-
- return handle;
-}
-
-void TraceLog::AddMetadataEvent(
- const unsigned char* category_group_enabled,
- const char* name,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags) {
- HEAP_PROFILER_SCOPED_IGNORE;
- std::unique_ptr<TraceEvent> trace_event(new TraceEvent);
- int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- ThreadTicks thread_now = ThreadNow();
- TimeTicks now = OffsetNow();
- AutoLock lock(lock_);
- trace_event->Initialize(
- thread_id, now, thread_now, TRACE_EVENT_PHASE_METADATA,
- category_group_enabled, name,
- trace_event_internal::kGlobalScope, // scope
- trace_event_internal::kNoId, // id
- trace_event_internal::kNoId, // bind_id
- num_args, arg_names, arg_types, arg_values, convertable_values, flags);
- metadata_events_.push_back(std::move(trace_event));
-}
-
-// May be called when a COMPELETE event ends and the unfinished event has been
-// recycled (phase == TRACE_EVENT_PHASE_END and trace_event == NULL).
-std::string TraceLog::EventToConsoleMessage(unsigned char phase,
- const TimeTicks& timestamp,
- TraceEvent* trace_event) {
- HEAP_PROFILER_SCOPED_IGNORE;
- AutoLock thread_info_lock(thread_info_lock_);
-
- // The caller should translate TRACE_EVENT_PHASE_COMPLETE to
- // TRACE_EVENT_PHASE_BEGIN or TRACE_EVENT_END.
- DCHECK(phase != TRACE_EVENT_PHASE_COMPLETE);
-
- TimeDelta duration;
- int thread_id =
- trace_event ? trace_event->thread_id() : PlatformThread::CurrentId();
- if (phase == TRACE_EVENT_PHASE_END) {
- duration = timestamp - thread_event_start_times_[thread_id].top();
- thread_event_start_times_[thread_id].pop();
- }
-
- std::string thread_name = thread_names_[thread_id];
- if (thread_colors_.find(thread_name) == thread_colors_.end())
- thread_colors_[thread_name] = (thread_colors_.size() % 6) + 1;
-
- std::ostringstream log;
- log << base::StringPrintf("%s: \x1b[0;3%dm", thread_name.c_str(),
- 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();
-
- for (size_t i = 0; i < depth; ++i)
- log << "| ";
-
- if (trace_event)
- trace_event->AppendPrettyPrinted(&log);
- if (phase == TRACE_EVENT_PHASE_END)
- log << base::StringPrintf(" (%.3f ms)", duration.InMillisecondsF());
-
- log << "\x1b[0;m";
-
- if (phase == TRACE_EVENT_PHASE_BEGIN)
- thread_event_start_times_[thread_id].push(timestamp);
-
- return log.str();
-}
-
-void TraceLog::EndFilteredEvent(const unsigned char* category_group_enabled,
- const char* name,
- TraceEventHandle 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,
- TraceEventHandle handle) {
- char category_group_enabled_local = *category_group_enabled;
- if (!category_group_enabled_local)
- return;
-
- // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when
- // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) ->
- // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ...
- if (thread_is_in_trace_event_.Get())
- return;
-
- AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
-
- ThreadTicks thread_now = ThreadNow();
- TimeTicks now = OffsetNow();
-
-#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)
- TraceEventETWExport::AddCompleteEndEvent(name);
-#endif // OS_WIN
-
- std::string console_message;
- if (category_group_enabled_local & TraceCategory::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();
-#endif
- }
-
- if (trace_options() & kInternalEchoToConsole) {
- console_message =
- EventToConsoleMessage(TRACE_EVENT_PHASE_END, now, trace_event);
- }
- }
-
- if (!console_message.empty())
- LOG(ERROR) << console_message;
-
- if (category_group_enabled_local & TraceCategory::ENABLED_FOR_FILTERING)
- EndFilteredEvent(category_group_enabled, name, handle);
-}
-
-uint64_t TraceLog::MangleEventId(uint64_t id) {
- return id ^ process_id_hash_;
-}
-
-void TraceLog::AddMetadataEventsWhileLocked() {
- lock_.AssertAcquired();
-
- // Move metadata added by |AddMetadataEvent| into the trace log.
- while (!metadata_events_.empty()) {
- TraceEvent* event = AddEventToThreadSharedChunkWhileLocked(nullptr, false);
- event->MoveFrom(std::move(metadata_events_.back()));
- metadata_events_.pop_back();
- }
-
-#if !defined(OS_NACL) // NaCl shouldn't expose the process id.
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- 0, "num_cpus", "number",
- base::SysInfo::NumberOfProcessors());
-#endif
-
- int current_thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- if (process_sort_index_ != 0) {
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- current_thread_id, "process_sort_index",
- "sort_index", process_sort_index_);
- }
-
- if (!process_name_.empty()) {
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- current_thread_id, "process_name", "name",
- process_name_);
- }
-
-#if !defined(OS_NACL) && !defined(OS_IOS)
- Time process_creation_time = CurrentProcessInfo::CreationTime();
- if (!process_creation_time.is_null()) {
- TimeDelta process_uptime = Time::Now() - process_creation_time;
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- current_thread_id, "process_uptime_seconds",
- "uptime", process_uptime.InSeconds());
- }
-#endif // !defined(OS_NACL) && !defined(OS_IOS)
-
- if (!process_labels_.empty()) {
- std::vector<base::StringPiece> labels;
- for (const auto& it : process_labels_)
- 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)
- continue;
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- 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())
- continue;
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- it.first, "thread_name", "name", it.second);
- }
-
- // If buffer is full, add a metadata record to report this.
- if (!buffer_limit_reached_timestamp_.is_null()) {
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- current_thread_id, "trace_buffer_overflowed",
- "overflowed_at_ts",
- buffer_limit_reached_timestamp_);
- }
-}
-
-void TraceLog::DeleteForTesting() {
- internal::DeleteTraceLogForTesting::Delete();
- CategoryRegistry::ResetForTesting();
-}
-
-TraceEvent* TraceLog::GetEventByHandle(TraceEventHandle handle) {
- return GetEventByHandleInternal(handle, NULL);
-}
-
-TraceEvent* TraceLog::GetEventByHandleInternal(TraceEventHandle handle,
- OptionalAutoLock* lock) {
- 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);
- if (trace_event)
- return trace_event;
- }
-
- // The event has been out-of-control of the thread local buffer.
- // Try to get the event from the main buffer with a lock.
- if (lock)
- lock->EnsureAcquired();
-
- if (thread_shared_chunk_ &&
- handle.chunk_index == thread_shared_chunk_index_) {
- return handle.chunk_seq == thread_shared_chunk_->seq()
- ? thread_shared_chunk_->GetEventAt(handle.event_index)
- : NULL;
- }
-
- return logged_events_->GetEventByHandle(handle);
-}
-
-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;
-}
-
-void TraceLog::SetProcessSortIndex(int sort_index) {
- AutoLock lock(lock_);
- process_sort_index_ = sort_index;
-}
-
-void TraceLog::SetProcessName(const char* process_name) {
- AutoLock lock(lock_);
- process_name_ = process_name;
-}
-
-void TraceLog::UpdateProcessLabel(int label_id,
- const std::string& current_label) {
- if (!current_label.length())
- return RemoveProcessLabel(label_id);
-
- AutoLock lock(lock_);
- process_labels_[label_id] = current_label;
-}
-
-void TraceLog::RemoveProcessLabel(int label_id) {
- AutoLock lock(lock_);
- process_labels_.erase(label_id);
-}
-
-void TraceLog::SetThreadSortIndex(PlatformThreadId thread_id, int sort_index) {
- AutoLock lock(lock_);
- thread_sort_indices_[static_cast<int>(thread_id)] = sort_index;
-}
-
-void TraceLog::SetTimeOffset(TimeDelta offset) {
- time_offset_ = offset;
-}
-
-size_t TraceLog::GetObserverCountForTest() const {
- return enabled_state_observer_list_.size();
-}
-
-void TraceLog::SetCurrentThreadBlocksMessageLoop() {
- thread_blocks_message_loop_.Set(true);
- // 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) {
- return TraceBuffer::CreateTraceBufferRingBuffer(
- kTraceEventRingBufferChunks);
- }
- if (options & kInternalEchoToConsole) {
- return TraceBuffer::CreateTraceBufferRingBuffer(
- kEchoToConsoleTraceEventBufferChunks);
- }
- if (options & kInternalRecordAsMuchAsPossible) {
- return TraceBuffer::CreateTraceBufferVectorOfSize(
- kTraceEventVectorBigBufferChunks);
- }
- return TraceBuffer::CreateTraceBufferVectorOfSize(
- kTraceEventVectorBufferChunks);
-}
-
-#if defined(OS_WIN)
-void TraceLog::UpdateETWCategoryGroupEnabledFlags() {
- // Go through each category and set/clear the ETW bit depending on whether the
- // category is enabled.
- for (TraceCategory& category : CategoryRegistry::GetAllCategories()) {
- if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled(
- category.name())) {
- category.set_state_flag(TraceCategory::ENABLED_FOR_ETW_EXPORT);
- } else {
- category.clear_state_flag(TraceCategory::ENABLED_FOR_ETW_EXPORT);
- }
- }
-}
-#endif // defined(OS_WIN)
-
-void ConvertableToTraceFormat::EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) {
- overhead->Add("ConvertableToTraceFormat(Unknown)", sizeof(*this));
-}
-
-void TraceLog::AddAsyncEnabledStateObserver(
- WeakPtr<AsyncEnabledStateObserver> listener) {
- AutoLock lock(lock_);
- async_observers_.insert(
- std::make_pair(listener.get(), RegisteredAsyncObserver(listener)));
-}
-
-void TraceLog::RemoveAsyncEnabledStateObserver(
- AsyncEnabledStateObserver* listener) {
- AutoLock lock(lock_);
- async_observers_.erase(listener);
-}
-
-bool TraceLog::HasAsyncEnabledStateObserver(
- AsyncEnabledStateObserver* listener) const {
- AutoLock lock(lock_);
- return ContainsKey(async_observers_, listener);
-}
-
-} // namespace trace_event
-} // namespace base
-
-namespace trace_event_internal {
-
-ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient(
- const char* category_group,
- const char* name) {
- // The single atom works because for now the category_group can only be "gpu".
- DCHECK_EQ(strcmp(category_group, "gpu"), 0);
- static TRACE_EVENT_API_ATOMIC_WORD atomic = 0;
- INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(
- category_group, atomic, category_group_enabled_);
- name_ = name;
- if (*category_group_enabled_) {
- event_handle_ =
- TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- TRACE_EVENT_PHASE_COMPLETE,
- category_group_enabled_,
- name,
- trace_event_internal::kGlobalScope, // scope
- trace_event_internal::kNoId, // id
- static_cast<int>(base::PlatformThread::CurrentId()), // thread_id
- base::TimeTicks::Now(),
- trace_event_internal::kZeroNumArgs,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- TRACE_EVENT_FLAG_NONE);
- }
-}
-
-ScopedTraceBinaryEfficient::~ScopedTraceBinaryEfficient() {
- if (*category_group_enabled_) {
- TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled_, name_,
- event_handle_);
- }
-}
-
-} // namespace trace_event_internal
diff --git a/base/trace_event/trace_log.h b/base/trace_event/trace_log.h
deleted file mode 100644
index 88b6e588e4..0000000000
--- a/base/trace_event/trace_log.h
+++ /dev/null
@@ -1,507 +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.
-
-#ifndef BASE_TRACE_EVENT_TRACE_LOG_H_
-#define BASE_TRACE_EVENT_TRACE_LOG_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/atomicops.h"
-#include "base/containers/hash_tables.h"
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/memory/scoped_vector.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "base/trace_event/trace_config.h"
-#include "base/trace_event/trace_event_impl.h"
-#include "build/build_config.h"
-
-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;
-
-struct BASE_EXPORT TraceLogStatus {
- TraceLogStatus();
- ~TraceLogStatus();
- uint32_t event_capacity;
- uint32_t event_count;
-};
-
-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
- };
-
- static TraceLog* GetInstance();
-
- // Get set of known category groups. This can change as new code paths are
- // reached. The known category groups are inserted into |category_groups|.
- void GetKnownCategoryGroups(std::vector<std::string>* category_groups);
-
- // Retrieves a copy (for thread-safety) of the current TraceConfig.
- TraceConfig GetCurrentTraceConfig() const;
-
- // Initializes the thread-local event buffer, if not already initialized and
- // 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);
-
- // 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; }
-
- // Returns a bitmap of enabled modes from TraceLog::Mode.
- uint8_t enabled_modes() { return enabled_modes_; }
-
- // 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
- // recorded a trace. By watching for this number to increment, you can
- // passively discover when a new trace has begun. This is then used to
- // implement the TRACE_EVENT_IS_NEW_TRACE() primitive.
- int GetNumTracesRecorded();
-
-#if defined(OS_ANDROID)
- void StartATrace();
- void StopATrace();
- void AddClockSyncMetadataEvent();
-#endif
-
- // Enabled state listeners give a callback when tracing is enabled or
- // disabled. This can be used to tie into other library's tracing systems
- // on-demand.
- class BASE_EXPORT EnabledStateObserver {
- public:
- virtual ~EnabledStateObserver() = default;
-
- // Called just after the tracing system becomes enabled, outside of the
- // |lock_|. TraceLog::IsEnabled() is true at this point.
- virtual void OnTraceLogEnabled() = 0;
-
- // Called just after the tracing system disables, outside of the |lock_|.
- // TraceLog::IsEnabled() is false at this point.
- virtual void OnTraceLogDisabled() = 0;
- };
- void AddEnabledStateObserver(EnabledStateObserver* listener);
- void RemoveEnabledStateObserver(EnabledStateObserver* listener);
- bool HasEnabledStateObserver(EnabledStateObserver* listener) const;
-
- // Asynchronous enabled state listeners. When tracing is enabled or disabled,
- // for each observer, a task for invoking its appropriate callback is posted
- // to the thread from which AddAsyncEnabledStateObserver() was called. This
- // allows the observer to be safely destroyed, provided that it happens on the
- // same thread that invoked AddAsyncEnabledStateObserver().
- class BASE_EXPORT AsyncEnabledStateObserver {
- public:
- virtual ~AsyncEnabledStateObserver() = default;
-
- // Posted just after the tracing system becomes enabled, outside |lock_|.
- // TraceLog::IsEnabled() is true at this point.
- virtual void OnTraceLogEnabled() = 0;
-
- // Posted just after the tracing system becomes disabled, outside |lock_|.
- // TraceLog::IsEnabled() is false at this point.
- virtual void OnTraceLogDisabled() = 0;
- };
- void AddAsyncEnabledStateObserver(
- WeakPtr<AsyncEnabledStateObserver> listener);
- void RemoveAsyncEnabledStateObserver(AsyncEnabledStateObserver* listener);
- bool HasAsyncEnabledStateObserver(AsyncEnabledStateObserver* listener) const;
-
- TraceLogStatus GetStatus() const;
- bool BufferIsFull() const;
-
- // Computes an estimate of the size of the TraceLog including all the retained
- // objects.
- void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
-
- void SetArgumentFilterPredicate(
- const ArgumentFilterPredicate& argument_filter_predicate);
-
- // Flush all collected events to the given output callback. The callback will
- // be called one or more times either synchronously or asynchronously from
- // the current thread with IPC-bite-size chunks. The string format is
- // undefined. Use TraceResultBuffer to convert one or more trace strings to
- // JSON. The callback can be null if the caller doesn't want any data.
- // Due to the implementation of thread-local buffers, flush can't be
- // done when tracing is enabled. If called when tracing is enabled, the
- // callback will be called directly with (empty_string, false) to indicate
- // the end of this unsuccessful flush. Flush does the serialization
- // on the same thread if the caller doesn't set use_worker_thread explicitly.
- typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&,
- bool has_more_events)> OutputCallback;
- void Flush(const OutputCallback& cb, bool use_worker_thread = false);
-
- // Cancels tracing and discards collected data.
- void CancelTracing(const OutputCallback& cb);
-
- // Called by TRACE_EVENT* macros, don't call this directly.
- // The name parameter is a category group for example:
- // TRACE_EVENT0("renderer,webkit", "WebViewImpl::HandleInputEvent")
- static const unsigned char* GetCategoryGroupEnabled(const char* name);
- static const char* GetCategoryGroupName(
- const unsigned char* category_group_enabled);
-
- // Called by TRACE_EVENT* macros, don't call this directly.
- // If |copy| is set, |name|, |arg_name1| and |arg_name2| will be deep copied
- // into the event; see "Memory scoping note" and TRACE_EVENT_COPY_XXX above.
- TraceEventHandle AddTraceEvent(
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- const char* scope,
- unsigned long long id,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags);
- TraceEventHandle AddTraceEventWithBindId(
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- const char* scope,
- unsigned long long id,
- unsigned long long bind_id,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags);
- TraceEventHandle AddTraceEventWithProcessId(
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- const char* scope,
- unsigned long long id,
- int process_id,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags);
- TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- const char* scope,
- unsigned long long id,
- int thread_id,
- const TimeTicks& timestamp,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags);
- TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- const char* scope,
- unsigned long long id,
- unsigned long long bind_id,
- int thread_id,
- const TimeTicks& timestamp,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags);
-
- // Adds a metadata event that will be written when the trace log is flushed.
- void AddMetadataEvent(
- const unsigned char* category_group_enabled,
- const char* name,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
- unsigned int flags);
-
- void UpdateTraceEventDuration(const unsigned char* category_group_enabled,
- const char* name,
- TraceEventHandle handle);
-
- void EndFilteredEvent(const unsigned char* category_group_enabled,
- const char* name,
- TraceEventHandle handle);
-
- int process_id() const { return process_id_; }
-
- uint64_t MangleEventId(uint64_t id);
-
- // 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;
- }
-
- // Allows deleting our singleton instance.
- static void DeleteForTesting();
-
- // Allow tests to inspect TraceEvents.
- TraceEvent* GetEventByHandle(TraceEventHandle handle);
-
- void SetProcessID(int process_id);
-
- // Process sort indices, if set, override the order of a process will appear
- // relative to other processes in the trace viewer. Processes are sorted first
- // 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);
-
- // 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.
- void UpdateProcessLabel(int label_id, const std::string& current_label);
- void RemoveProcessLabel(int label_id);
-
- // Thread sort indices, if set, override the order of a thread will appear
- // within its process in the trace viewer. Threads are sorted first on their
- // sort index, ascending, then by their name, and then tid.
- void SetThreadSortIndex(PlatformThreadId thread_id, int sort_index);
-
- // Allow setting an offset between the current TimeTicks time and the time
- // that should be reported.
- void SetTimeOffset(TimeDelta offset);
-
- size_t GetObserverCountForTest() const;
-
- // Call this method if the current thread may block the message loop to
- // prevent the thread from using the thread-local buffer because the thread
- // may not handle the flush request in time causing lost of unflushed events.
- void SetCurrentThreadBlocksMessageLoop();
-
-#if defined(OS_WIN)
- // This function is called by the ETW exporting module whenever the ETW
- // keyword (flags) changes. This keyword indicates which categories should be
- // exported, so whenever it changes, we adjust accordingly.
- void UpdateETWCategoryGroupEnabledFlags();
-#endif
-
- private:
- typedef unsigned int InternalTraceOptions;
-
- FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
- TraceBufferRingBufferGetReturnChunk);
- FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
- TraceBufferRingBufferHalfIteration);
- FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
- TraceBufferRingBufferFullIteration);
- FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture, TraceBufferVectorReportFull);
- FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
- ConvertTraceConfigToInternalOptions);
- FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
- TraceRecordAsMuchAsPossibleMode);
-
- // This allows constructor and destructor to be private and usable only
- // by the Singleton class.
- friend struct DefaultSingletonTraits<TraceLog>;
-
- // MemoryDumpProvider implementation.
- bool OnMemoryDump(const MemoryDumpArgs& args,
- 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();
-
- // Configure synthetic delays based on the values set in the current
- // trace config.
- void UpdateSyntheticDelaysFromTraceConfig();
-
- InternalTraceOptions GetInternalOptionsFromTraceConfig(
- const TraceConfig& config);
-
- class ThreadLocalEventBuffer;
- class OptionalAutoLock;
- struct RegisteredAsyncObserver;
-
- TraceLog();
- ~TraceLog() override;
- void AddMetadataEventsWhileLocked();
-
- InternalTraceOptions trace_options() const {
- return static_cast<InternalTraceOptions>(
- subtle::NoBarrier_Load(&trace_options_));
- }
-
- TraceBuffer* trace_buffer() const { return logged_events_.get(); }
- TraceBuffer* CreateTraceBuffer();
-
- std::string EventToConsoleMessage(unsigned char phase,
- const TimeTicks& timestamp,
- TraceEvent* trace_event);
-
- TraceEvent* AddEventToThreadSharedChunkWhileLocked(TraceEventHandle* handle,
- bool check_buffer_is_full);
- void CheckIfBufferIsFullWhileLocked();
- void SetDisabledWhileLocked(uint8_t modes);
-
- TraceEvent* GetEventByHandleInternal(TraceEventHandle handle,
- OptionalAutoLock* lock);
-
- void FlushInternal(const OutputCallback& cb,
- bool use_worker_thread,
- bool discard_events);
-
- // |generation| is used in the following callbacks to check if the callback
- // is called for the flush of the current |logged_events_|.
- void FlushCurrentThread(int generation, bool discard_events);
- // Usually it runs on a different thread.
- static void ConvertTraceEventsToTraceFormat(
- std::unique_ptr<TraceBuffer> logged_events,
- const TraceLog::OutputCallback& flush_output_callback,
- const ArgumentFilterPredicate& argument_filter_predicate);
- void FinishFlush(int generation, bool discard_events);
- void OnFlushTimeout(int generation, bool discard_events);
-
- int generation() const {
- return static_cast<int>(subtle::NoBarrier_Load(&generation_));
- }
- bool CheckGeneration(int generation) const {
- return generation == this->generation();
- }
- void UseNextTraceBuffer();
-
- TimeTicks OffsetNow() const { return OffsetTimestamp(TimeTicks::Now()); }
- TimeTicks OffsetTimestamp(const TimeTicks& timestamp) const {
- return timestamp - time_offset_;
- }
-
- // Internal representation of trace options since we store the currently used
- // trace option as an AtomicWord.
- static const InternalTraceOptions kInternalNone;
- static const InternalTraceOptions kInternalRecordUntilFull;
- static const InternalTraceOptions kInternalRecordContinuously;
- static const InternalTraceOptions kInternalEchoToConsole;
- static const InternalTraceOptions kInternalRecordAsMuchAsPossible;
- static const InternalTraceOptions kInternalEnableArgumentFilter;
-
- // This lock protects TraceLog member accesses (except for members protected
- // by thread_info_lock_) from arbitrary threads.
- mutable Lock lock_;
- // 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.
- int num_traces_recorded_;
- std::unique_ptr<TraceBuffer> logged_events_;
- std::vector<std::unique_ptr<TraceEvent>> metadata_events_;
- bool dispatching_to_observer_list_;
- std::vector<EnabledStateObserver*> enabled_state_observer_list_;
- std::map<AsyncEnabledStateObserver*, RegisteredAsyncObserver>
- async_observers_;
-
- std::string process_name_;
- base::hash_map<int, std::string> process_labels_;
- int process_sort_index_;
- base::hash_map<int, int> thread_sort_indices_;
- base::hash_map<int, std::string> thread_names_;
-
- // The following two maps are used only when ECHO_TO_CONSOLE.
- base::hash_map<int, std::stack<TimeTicks>> thread_event_start_times_;
- base::hash_map<std::string, int> thread_colors_;
-
- TimeTicks buffer_limit_reached_timestamp_;
-
- // XORed with TraceID to make it unlikely to collide with other processes.
- unsigned long long process_id_hash_;
-
- int process_id_;
-
- TimeDelta time_offset_;
-
- subtle::AtomicWord /* Options */ trace_options_;
-
- TraceConfig trace_config_;
- TraceConfig::EventFilters enabled_event_filters_;
-
- ThreadLocalPointer<ThreadLocalEventBuffer> thread_local_event_buffer_;
- ThreadLocalBoolean thread_blocks_message_loop_;
- ThreadLocalBoolean thread_is_in_trace_event_;
-
- // Contains the message loops of threads that have had at least one event
- // added into the local event buffer. Not using SingleThreadTaskRunner
- // because we need to know the life time of the message loops.
- hash_set<MessageLoop*> thread_message_loops_;
-
- // For events which can't be added into the thread local buffer, e.g. events
- // from threads without a message loop.
- std::unique_ptr<TraceBufferChunk> thread_shared_chunk_;
- size_t thread_shared_chunk_index_;
-
- // Set when asynchronous Flush is in progress.
- OutputCallback flush_output_callback_;
- scoped_refptr<SingleThreadTaskRunner> flush_task_runner_;
- ArgumentFilterPredicate argument_filter_predicate_;
- subtle::AtomicWord generation_;
- bool use_worker_thread_;
-
- FilterFactoryForTesting filter_factory_for_testing_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceLog);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_TRACE_LOG_H_
diff --git a/base/trace_event/trace_log_constants.cc b/base/trace_event/trace_log_constants.cc
deleted file mode 100644
index 65dca2e4d6..0000000000
--- a/base/trace_event/trace_log_constants.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2013 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_log.h"
-
-namespace base {
-namespace trace_event {
-
-// Constant used by TraceLog's internal implementation of trace_option.
-const TraceLog::InternalTraceOptions
- TraceLog::kInternalNone = 0;
-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::kInternalEchoToConsole = 1 << 3;
-const TraceLog::InternalTraceOptions
- TraceLog::kInternalRecordAsMuchAsPossible = 1 << 4;
-const TraceLog::InternalTraceOptions
- TraceLog::kInternalEnableArgumentFilter = 1 << 5;
-
-} // namespace trace_event
-} // namespace base
diff --git a/libchrome_tools/patch/task_scheduler.patch b/libchrome_tools/patch/task_scheduler.patch
index c32520ba41..39a4ead16d 100644
--- a/libchrome_tools/patch/task_scheduler.patch
+++ b/libchrome_tools/patch/task_scheduler.patch
@@ -119,34 +119,3 @@
} else {
inner_->CleanupForTesting();
}
---- a/base/trace_event/trace_log.cc
-+++ b/base/trace_event/trace_log.cc
-@@ -27,7 +27,10 @@
- #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/threading/platform_thread.h"
- #include "base/threading/thread_id_name_manager.h"
- #include "base/threading/thread_task_runner_handle.h"
-@@ -968,6 +971,7 @@ void TraceLog::FinishFlush(int generatio
- }
-
- if (use_worker_thread_) {
-+#if 0
- base::PostTaskWithTraits(
- FROM_HERE, base::TaskTraits()
- .MayBlock()
-@@ -978,6 +982,9 @@ void TraceLog::FinishFlush(int generatio
- Passed(&previous_logged_events), flush_output_callback,
- argument_filter_predicate));
- return;
-+#else
-+ NOTREACHED();
-+#endif
- }
-
- ConvertTraceEventsToTraceFormat(std::move(previous_logged_events),
diff --git a/libchrome_tools/patch/trace_event.patch b/libchrome_tools/patch/trace_event.patch
new file mode 100644
index 0000000000..514ef53bbc
--- /dev/null
+++ b/libchrome_tools/patch/trace_event.patch
@@ -0,0 +1,191 @@
+--- a/base/trace_event/trace_event.h
++++ b/base/trace_event/trace_event.h
+@@ -5,6 +5,43 @@
+ #ifndef BASE_TRACE_EVENT_TRACE_EVENT_H_
+ #define BASE_TRACE_EVENT_TRACE_EVENT_H_
+
++// Replace with stub implementation.
++#if 1
++#include "base/trace_event/common/trace_event_common.h"
++#include "base/trace_event/heap_profiler.h"
++
++// To avoid -Wunused-* errors, eat expression by macro.
++namespace libchrome_internal {
++template <typename... Args> void Ignore(Args&&... args) {}
++}
++#define INTERNAL_IGNORE(...) \
++ (false ? libchrome_internal::Ignore(__VA_ARGS__) : (void) 0)
++
++// Body is effectively empty.
++#define INTERNAL_TRACE_EVENT_ADD_SCOPED(...) INTERNAL_IGNORE(__VA_ARGS__)
++#define INTERNAL_TRACE_TASK_EXECUTION(...)
++#define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(...) \
++ INTERNAL_IGNORE(__VA_ARGS__)
++#define TRACE_ID_MANGLE(val) (val)
++
++namespace base {
++namespace trace_event {
++
++class TraceLog {
++ public:
++ static TraceLog* GetInstance() {
++ static TraceLog instance;
++ return &instance;
++ }
++
++ pid_t process_id() { return 0; }
++ void SetCurrentThreadBlocksMessageLoop() {}
++};
++
++} // namespace trace_event
++} // namespace base
++#else
++
+ // This header file defines implementation details of how the trace macros in
+ // trace_event_common.h collect and store trace events. Anything not
+ // implementation-specific should go in trace_event_common.h instead of here.
+@@ -1115,4 +1152,5 @@ template<typename IDType> class TraceSco
+ } // namespace trace_event
+ } // namespace base
+
++#endif
+ #endif // BASE_TRACE_EVENT_TRACE_EVENT_H_
+--- a/base/trace_event/heap_profiler.h
++++ b/base/trace_event/heap_profiler.h
+@@ -5,6 +5,22 @@
+ #ifndef BASE_TRACE_EVENT_HEAP_PROFILER_H
+ #define BASE_TRACE_EVENT_HEAP_PROFILER_H
+
++// Replace with stub implementation.
++#if 1
++#define TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION \
++ trace_event_internal::HeapProfilerScopedTaskExecutionTracker
++
++namespace trace_event_internal {
++
++class HeapProfilerScopedTaskExecutionTracker {
++ public:
++ explicit HeapProfilerScopedTaskExecutionTracker(const char*) {}
++};
++
++} // namespace trace_event_internal
++
++#else
++
+ #include "base/compiler_specific.h"
+ #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+
+@@ -86,4 +102,5 @@ class BASE_EXPORT HeapProfilerScopedIgno
+
+ } // namespace trace_event_internal
+
++#endif
+ #endif // BASE_TRACE_EVENT_HEAP_PROFILER_H
+--- a/base/test/test_pending_task.h
++++ b/base/test/test_pending_task.h
+@@ -10,7 +10,8 @@
+ #include "base/callback.h"
+ #include "base/location.h"
+ #include "base/time/time.h"
+-#include "base/trace_event/trace_event_argument.h"
++// Unsupported in libchrome.
++// #include "base/trace_event/trace_event_argument.h"
+
+ namespace base {
+
+@@ -58,10 +59,13 @@ struct TestPendingTask {
+ TimeDelta delay;
+ TestNestability nestability;
+
++// Unsupported in libchrome.
++#if 0
+ // Functions for using test pending task with tracing, useful in unit
+ // testing.
+ void AsValueInto(base::trace_event::TracedValue* state) const;
+ std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
++#endif
+ std::string ToString() const;
+
+ private:
+--- a/base/test/test_pending_task.cc
++++ b/base/test/test_pending_task.cc
+@@ -38,6 +38,8 @@ bool TestPendingTask::ShouldRunBefore(co
+
+ TestPendingTask::~TestPendingTask() {}
+
++// Unsupported in libchrome.
++#if 0
+ void TestPendingTask::AsValueInto(base::trace_event::TracedValue* state) const {
+ state->SetInteger("run_at", GetTimeToRun().ToInternalValue());
+ state->SetString("posting_function", location.ToString());
+@@ -61,10 +63,14 @@ TestPendingTask::AsValue() const {
+ AsValueInto(state.get());
+ return std::move(state);
+ }
++#endif
+
+ std::string TestPendingTask::ToString() const {
+ std::string output("TestPendingTask(");
++// Unsupported in libchrome.
++#if 0
+ AsValue()->AppendAsTraceFormat(&output);
++#endif
+ output += ")";
+ return output;
+ }
+--- a/base/threading/thread_id_name_manager.cc
++++ b/base/threading/thread_id_name_manager.cc
+@@ -10,7 +10,8 @@
+ #include "base/logging.h"
+ #include "base/memory/singleton.h"
+ #include "base/strings/string_util.h"
+-#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
++// Unsupported in libchrome.
++// #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+
+ namespace base {
+ namespace {
+@@ -80,8 +81,9 @@ void ThreadIdNameManager::SetName(Platfo
+ // call GetName(which holds a lock) during the first allocation because it can
+ // cause a deadlock when the first allocation happens in the
+ // ThreadIdNameManager itself when holding the lock.
+- trace_event::AllocationContextTracker::SetCurrentThreadName(
+- leaked_str->c_str());
++ // Unsupported in libchrome.
++ // trace_event::AllocationContextTracker::SetCurrentThreadName(
++ // leaked_str->c_str());
+ }
+
+ const char* ThreadIdNameManager::GetName(PlatformThreadId id) {
+--- a/base/memory/shared_memory_posix.cc
++++ b/base/memory/shared_memory_posix.cc
+@@ -15,7 +15,8 @@
+ #include "base/files/scoped_file.h"
+ #include "base/logging.h"
+ #include "base/memory/shared_memory_helper.h"
+-#include "base/memory/shared_memory_tracker.h"
++// Unsupported in libchrome.
++// #include "base/memory/shared_memory_tracker.h"
+ #include "base/posix/eintr_wrapper.h"
+ #include "base/posix/safe_strerror.h"
+ #include "base/process/process_metrics.h"
+@@ -288,7 +291,8 @@ bool SharedMemory::MapAt(off_t offset, s
+ DCHECK_EQ(0U,
+ reinterpret_cast<uintptr_t>(memory_) &
+ (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+- SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
++ // Unsupported in libchrome.
++ // SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
+ } else {
+ memory_ = NULL;
+ }
+@@ -301,7 +305,8 @@ bool SharedMemory::Unmap() {
+ return false;
+
+ munmap(memory_, mapped_size_);
+- SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
++ // Unsupported in libchrome.
++ // SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
+ memory_ = NULL;
+ mapped_size_ = 0;
+ return true;