summaryrefslogtreecommitdiffstats
path: root/base/trace_event
diff options
context:
space:
mode:
authorprimiano <primiano@chromium.org>2015-02-17 15:21:19 -0800
committerCommit bot <commit-bot@chromium.org>2015-02-17 23:22:26 +0000
commitf11ccf580631ee65a5143baff55f704b1a41e591 (patch)
tree789d8ac8385ee023cead811b7ace98a3cdcd147c /base/trace_event
parent48ed6c69108ac710f778a151bfc35b3bfb77fb09 (diff)
downloadchromium_src-f11ccf580631ee65a5143baff55f704b1a41e591.zip
chromium_src-f11ccf580631ee65a5143baff55f704b1a41e591.tar.gz
chromium_src-f11ccf580631ee65a5143baff55f704b1a41e591.tar.bz2
[tracing] Introduce memory tracing skeleton.
This is the first step towards the introduction of memory as a metric in chromium tracing. This change introduces the core memory dump manager which will coordinate the memory dumps. Specifically, the following concepts are introduced by this CL: - memory_dump_manager: the front-end interface exposed to the rest of the codebase to create memory dump points. - memory_dump_provider: the contract interface that memory dumpers need to expose in order to coordinate with the manager. This CL does NOT expose any user-visible tracing functionality. BUG=458295 Review URL: https://codereview.chromium.org/933613002 Cr-Commit-Position: refs/heads/master@{#316700}
Diffstat (limited to 'base/trace_event')
-rw-r--r--base/trace_event/memory_dump_manager.cc135
-rw-r--r--base/trace_event/memory_dump_manager.h87
-rw-r--r--base/trace_event/memory_dump_manager_unittest.cc125
-rw-r--r--base/trace_event/memory_dump_provider.h33
-rw-r--r--base/trace_event/process_memory_dump.cc29
-rw-r--r--base/trace_event/process_memory_dump.h37
6 files changed, 446 insertions, 0 deletions
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
new file mode 100644
index 0000000..bf631b3
--- /dev/null
+++ b/base/trace_event/memory_dump_manager.cc
@@ -0,0 +1,135 @@
+// 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 <algorithm>
+
+#include "base/compiler_specific.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
+
+// TODO(primiano): in a separate CL rename DeleteTraceLogForTesting into
+// something like base::internal::TeardownSingletonForTesting so we don't have
+// to add a new friend to singleton each time.
+class DeleteTraceLogForTesting {
+ public:
+ static void Delete() {
+ Singleton<
+ base::trace_event::MemoryDumpManager,
+ LeakySingletonTraits<base::trace_event::MemoryDumpManager>>::OnExit(0);
+ }
+};
+
+namespace base {
+namespace trace_event {
+
+// TODO(primiano): this should be smarter and should do something similar to
+// trace event synthetic delays.
+const char MemoryDumpManager::kTraceCategory[] =
+ TRACE_DISABLED_BY_DEFAULT("memory-dumps");
+
+// static
+MemoryDumpManager* MemoryDumpManager::GetInstance() {
+ return Singleton<MemoryDumpManager,
+ LeakySingletonTraits<MemoryDumpManager>>::get();
+}
+
+// static
+void MemoryDumpManager::DeleteForTesting() {
+ DeleteTraceLogForTesting::Delete();
+}
+
+MemoryDumpManager::MemoryDumpManager() : memory_tracing_enabled_(0) {
+}
+
+MemoryDumpManager::~MemoryDumpManager() {
+ base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+}
+
+void MemoryDumpManager::Initialize() {
+ TRACE_EVENT0(kTraceCategory, "init"); // Add to trace-viewer category list.
+ trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
+}
+
+void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
+ AutoLock lock(lock_);
+ if (std::find(dump_providers_registered_.begin(),
+ dump_providers_registered_.end(),
+ mdp) != dump_providers_registered_.end()) {
+ return;
+ }
+ dump_providers_registered_.push_back(mdp);
+}
+
+void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
+ AutoLock lock(lock_);
+
+ // Remove from the registered providers list.
+ auto it = std::find(dump_providers_registered_.begin(),
+ dump_providers_registered_.end(), mdp);
+ if (it != dump_providers_registered_.end())
+ dump_providers_registered_.erase(it);
+
+ // Remove from the enabled providers list. This is to deal with the case that
+ // UnregisterDumpProvider is called while the trace is enabled.
+ it = std::find(dump_providers_enabled_.begin(), dump_providers_enabled_.end(),
+ mdp);
+ if (it != dump_providers_enabled_.end())
+ dump_providers_enabled_.erase(it);
+}
+
+void MemoryDumpManager::RequestDumpPoint(DumpPointType type) {
+ // TODO(primiano): this will have more logic, IPC broadcast & co.
+ // Bail out immediately if tracing is not enabled at all.
+ if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_)))
+ return;
+
+ CreateLocalDumpPoint();
+}
+
+void MemoryDumpManager::BroadcastDumpRequest() {
+ NOTREACHED(); // TODO(primiano): implement IPC synchronization.
+}
+
+// Creates a dump point for the current process and appends it to the trace.
+void MemoryDumpManager::CreateLocalDumpPoint() {
+ AutoLock lock(lock_);
+ // TRACE_EVENT_* macros don't induce scoped_refptr type inference, hence we
+ // need the base ConvertableToTraceFormat and the upcast below. The
+ // alternative would be unnecessarily expensive (double Acquire/Release).
+ scoped_refptr<ConvertableToTraceFormat> pmd(new ProcessMemoryDump());
+
+ for (MemoryDumpProvider* dump_provider : dump_providers_enabled_) {
+ dump_provider->DumpInto(static_cast<ProcessMemoryDump*>(pmd.get()));
+ }
+
+ // TODO(primiano): add the dump point to the trace at this point.
+}
+
+void MemoryDumpManager::OnTraceLogEnabled() {
+ // TODO(primiano): at this point we query TraceLog::GetCurrentCategoryFilter
+ // to figure out (and cache) which dumpers should be enabled or not.
+ // For the moment piggy back everything on the generic "memory" category.
+ bool enabled;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
+
+ AutoLock lock(lock_);
+ if (enabled) {
+ dump_providers_enabled_.assign(dump_providers_registered_.begin(),
+ dump_providers_registered_.end());
+ } else {
+ dump_providers_enabled_.clear();
+ }
+ subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
+}
+
+void MemoryDumpManager::OnTraceLogDisabled() {
+ AutoLock lock(lock_);
+ dump_providers_enabled_.clear();
+ subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
new file mode 100644
index 0000000..fbc71d5
--- /dev/null
+++ b/base/trace_event/memory_dump_manager.h
@@ -0,0 +1,87 @@
+// 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 <vector>
+
+#include "base/atomicops.h"
+#include "base/memory/singleton.h"
+#include "base/synchronization/lock.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace trace_event {
+
+class MemoryDumpProvider;
+
+// Captures the reason why a dump point is being requested. This is to allow
+// selective enabling of dump points, filtering and post-processing.
+enum class DumpPointType {
+ TASK_BEGIN, // Dumping memory at the beginning of a message-loop task.
+ TASK_END, // Dumping memory at the ending of a message-loop task.
+ PERIODIC_INTERVAL, // Dumping memory at periodic intervals.
+ EXPLICITLY_TRIGGERED, // Non maskable dump request.
+};
+
+// 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 MemoryDumpManager* GetInstance();
+
+ // Invoked once per process to register the TraceLog observer.
+ void Initialize();
+
+ // MemoryDumpManager does NOT take memory ownership of |mdp|, which is
+ // expected to be a singleton.
+ void RegisterDumpProvider(MemoryDumpProvider* mdp);
+ void UnregisterDumpProvider(MemoryDumpProvider* mdp);
+
+ // Requests a memory dump. The dump might happen or not depending on the
+ // filters and categories specified when enabling tracing.
+ void RequestDumpPoint(DumpPointType type);
+
+ // TraceLog::EnabledStateObserver implementation.
+ void OnTraceLogEnabled() override;
+ void OnTraceLogDisabled() override;
+
+ private:
+ friend struct DefaultSingletonTraits<MemoryDumpManager>;
+ friend class MemoryDumpManagerTest;
+
+ static const char kTraceCategory[];
+
+ MemoryDumpManager();
+ virtual ~MemoryDumpManager();
+
+ // Tears down the singleton instance.
+ static void DeleteForTesting();
+
+ // Broadcasts the dump requests to the other processes.
+ void BroadcastDumpRequest();
+
+ // Creates a dump point for the current process and appends it to the trace.
+ void CreateLocalDumpPoint();
+
+ std::vector<MemoryDumpProvider*> dump_providers_registered_; // Not owned.
+ std::vector<MemoryDumpProvider*> dump_providers_enabled_; // Not owned.
+
+ // Protects from concurrent accesses to the |dump_providers_*|, e.g., tearing
+ // down logging while creating a dump point on another thread.
+ Lock lock_;
+
+ // Optimization to avoid attempting any dump point (i.e. to not walk an empty
+ // dump_providers_enabled_ list) when tracing is not enabled.
+ subtle::AtomicWord memory_tracing_enabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
+};
+
+} // 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
new file mode 100644
index 0000000..b5337e9
--- /dev/null
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -0,0 +1,125 @@
+// 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 "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+
+namespace base {
+namespace trace_event {
+
+class MemoryDumpManagerTest : public testing::Test {
+ public:
+ void SetUp() override {
+ MemoryDumpManager::GetInstance()->Initialize();
+ mdm_ = MemoryDumpManager::GetInstance();
+ }
+
+ void TearDown() override {
+ MemoryDumpManager::DeleteForTesting();
+ TraceLog::DeleteForTesting();
+ mdm_ = NULL;
+ }
+
+ protected:
+ const char* const kTraceCategory = MemoryDumpManager::kTraceCategory;
+
+ void EnableTracing(const char* category) {
+ TraceLog::GetInstance()->SetEnabled(
+ CategoryFilter(category), TraceLog::RECORDING_MODE, TraceOptions());
+ }
+
+ void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
+
+ MemoryDumpManager* mdm_;
+
+ private:
+ // We want our singleton torn down after each test.
+ ShadowingAtExitManager at_exit_manager_;
+};
+
+class MockDumpProvider : public MemoryDumpProvider {
+ public:
+ MOCK_METHOD1(DumpInto, void(ProcessMemoryDump* pmd));
+};
+
+TEST_F(MemoryDumpManagerTest, SingleDumper) {
+ MockDumpProvider mdp;
+ mdm_->RegisterDumpProvider(&mdp);
+
+ // Check that the dumper is not called if the memory category is not enabled.
+ EnableTracing("foo-and-bar-but-not-memory");
+ EXPECT_CALL(mdp, DumpInto(_)).Times(0);
+ mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+ DisableTracing();
+
+ // Now repeat enabling the memory category and check that the dumper is
+ // invoked this time.
+ EnableTracing(kTraceCategory);
+ EXPECT_CALL(mdp, DumpInto(_)).Times(3);
+ for (int i = 0; i < 3; ++i)
+ mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+ DisableTracing();
+
+ mdm_->UnregisterDumpProvider(&mdp);
+
+ // Finally check the unregister logic (no calls to the mdp after unregister).
+ EnableTracing(kTraceCategory);
+ EXPECT_CALL(mdp, DumpInto(_)).Times(0);
+ mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+ TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileTracing) {
+ MockDumpProvider mdp;
+ mdm_->RegisterDumpProvider(&mdp);
+
+ EnableTracing(kTraceCategory);
+ EXPECT_CALL(mdp, DumpInto(_)).Times(1);
+ mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+
+ mdm_->UnregisterDumpProvider(&mdp);
+ EXPECT_CALL(mdp, DumpInto(_)).Times(0);
+ mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+
+ DisableTracing();
+}
+
+TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
+ MockDumpProvider mdp1;
+ MockDumpProvider mdp2;
+
+ // Enable only mdp1.
+ mdm_->RegisterDumpProvider(&mdp1);
+ EnableTracing(kTraceCategory);
+ EXPECT_CALL(mdp1, DumpInto(_)).Times(1);
+ EXPECT_CALL(mdp2, DumpInto(_)).Times(0);
+ mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+ DisableTracing();
+
+ // Invert: enable mdp1 and disable mdp2.
+ mdm_->UnregisterDumpProvider(&mdp1);
+ mdm_->RegisterDumpProvider(&mdp2);
+ EnableTracing(kTraceCategory);
+ EXPECT_CALL(mdp1, DumpInto(_)).Times(0);
+ EXPECT_CALL(mdp2, DumpInto(_)).Times(1);
+ mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+ DisableTracing();
+
+ // Enable both mdp1 and mdp2.
+ mdm_->RegisterDumpProvider(&mdp1);
+ EnableTracing(kTraceCategory);
+ EXPECT_CALL(mdp1, DumpInto(_)).Times(1);
+ EXPECT_CALL(mdp2, DumpInto(_)).Times(1);
+ mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+ DisableTracing();
+}
+
+} // namespace trace_Event
+} // namespace base
diff --git a/base/trace_event/memory_dump_provider.h b/base/trace_event/memory_dump_provider.h
new file mode 100644
index 0000000..18363c5
--- /dev/null
+++ b/base/trace_event/memory_dump_provider.h
@@ -0,0 +1,33 @@
+// 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"
+
+namespace base {
+namespace trace_event {
+
+class ProcessMemoryDump;
+
+// The contract interface that memory dump providers must implement.
+class BASE_EXPORT MemoryDumpProvider {
+ public:
+ // Called by the MemoryDumpManager when generating dump points.
+ virtual void DumpInto(ProcessMemoryDump* pmd) = 0;
+
+ protected:
+ MemoryDumpProvider() {}
+ virtual ~MemoryDumpProvider() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
new file mode 100644
index 0000000..0a3e096
--- /dev/null
+++ b/base/trace_event/process_memory_dump.cc
@@ -0,0 +1,29 @@
+// 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 "base/json/json_writer.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+ProcessMemoryDump::ProcessMemoryDump() {
+}
+
+ProcessMemoryDump::~ProcessMemoryDump() {
+}
+
+void ProcessMemoryDump::AppendAsTraceFormat(std::string* out) const {
+ // Build up the [dumper name] -> [serialized snapshot] JSON dictionary.
+ DictionaryValue dict;
+ std::string json_dict;
+ // TODO(primiano): this will append here the actual dumps from the dumpers.
+ base::JSONWriter::Write(&dict, &json_dict);
+ *out += json_dict;
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
new file mode 100644
index 0000000..ae42987
--- /dev/null
+++ b/base/trace_event/process_memory_dump.h
@@ -0,0 +1,37 @@
+// 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 "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+// A container which holds the dumps produced by the MemoryDumpProvider(s)
+// for a specific process. ProcessMemoryDump is as a strongly typed container
+// which enforces the data model for each memory dump point.
+// At trace generation time (i.e. when AppendAsTraceFormat is called) the
+// ProcessMemoryDump will compose a key-value dictionary of the various dumps
+// obtained during at trace dump point time.
+class BASE_EXPORT ProcessMemoryDump : public ConvertableToTraceFormat {
+ public:
+ ProcessMemoryDump();
+
+ // ConvertableToTraceFormat implementation.
+ void AppendAsTraceFormat(std::string* out) const override;
+
+ private:
+ ~ProcessMemoryDump() override;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_