diff options
-rw-r--r-- | base/base.gyp | 1 | ||||
-rw-r--r-- | base/base.gypi | 1 | ||||
-rw-r--r-- | base/debug/trace_event.h | 1 | ||||
-rw-r--r-- | base/debug/trace_event_system_stats_monitor.cc | 132 | ||||
-rw-r--r-- | base/debug/trace_event_system_stats_monitor.h | 75 | ||||
-rw-r--r-- | base/debug/trace_event_system_stats_monitor_unittest.cc | 66 | ||||
-rw-r--r-- | content/browser/browser_main_loop.cc | 7 | ||||
-rw-r--r-- | content/browser/browser_main_loop.h | 2 |
8 files changed, 285 insertions, 0 deletions
diff --git a/base/base.gyp b/base/base.gyp index 7c988f3..39f6015 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -476,6 +476,7 @@ 'debug/proc_maps_linux_unittest.cc', 'debug/stack_trace_unittest.cc', 'debug/trace_event_memory_unittest.cc', + 'debug/trace_event_system_stats_monitor_unittest.cc', 'debug/trace_event_unittest.cc', 'debug/trace_event_unittest.h', 'debug/trace_event_win_unittest.cc', diff --git a/base/base.gypi b/base/base.gypi index d8be2bb..8caee68 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -155,6 +155,7 @@ 'debug/trace_event_impl.cc', 'debug/trace_event_impl.h', 'debug/trace_event_impl_constants.cc', + 'debug/trace_event_system_stats_monitor.cc', 'debug/trace_event_memory.cc', 'debug/trace_event_memory.h', 'debug/trace_event_win.cc', diff --git a/base/debug/trace_event.h b/base/debug/trace_event.h index b025160..6b45652 100644 --- a/base/debug/trace_event.h +++ b/base/debug/trace_event.h @@ -195,6 +195,7 @@ #include "base/atomicops.h" #include "base/debug/trace_event_impl.h" #include "base/debug/trace_event_memory.h" +#include "base/debug/trace_event_system_stats_monitor.h" #include "build/build_config.h" // By default, const char* argument values are assumed to have long-lived scope diff --git a/base/debug/trace_event_system_stats_monitor.cc b/base/debug/trace_event_system_stats_monitor.cc new file mode 100644 index 0000000..b95e712 --- /dev/null +++ b/base/debug/trace_event_system_stats_monitor.cc @@ -0,0 +1,132 @@ +// 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. + +#include "base/debug/trace_event_system_stats_monitor.h" + +#include "base/debug/leak_annotations.h" +#include "base/debug/trace_event.h" +#include "base/json/json_writer.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/thread_task_runner_handle.h" +#include "base/threading/thread_local_storage.h" + +namespace base { +namespace debug { + +namespace { + +///////////////////////////////////////////////////////////////////////////// +// Holds profiled system stats until the tracing system needs to serialize it. +class SystemStatsHolder : public base::debug::ConvertableToTraceFormat { + public: + SystemStatsHolder() { } + virtual ~SystemStatsHolder() { } + + // Fills system_metrics_ with profiled system memory and disk stats. + // Uses the previous stats to compute rates if this is not the first profile. + void GetSystemProfilingStats(); + + // base::debug::ConvertableToTraceFormat overrides: + virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE { + AppendSystemProfileAsTraceFormat(system_stats_, out); + } + + private: + SystemMetrics system_stats_; + + DISALLOW_COPY_AND_ASSIGN(SystemStatsHolder); +}; + +void SystemStatsHolder::GetSystemProfilingStats() { + system_stats_ = SystemMetrics::Sample(); +} + +} // namespace + +////////////////////////////////////////////////////////////////////////////// + +TraceEventSystemStatsMonitor::TraceEventSystemStatsMonitor( + scoped_refptr<SingleThreadTaskRunner> task_runner) + : task_runner_(task_runner), + weak_factory_(this) { + // Force the "system_stats" category to show up in the trace viewer. + TraceLog::GetCategoryGroupEnabled(TRACE_DISABLED_BY_DEFAULT("system_stats")); + + // Allow this to be instantiated on unsupported platforms, but don't run. + TraceLog::GetInstance()->AddEnabledStateObserver(this); +} + +TraceEventSystemStatsMonitor::~TraceEventSystemStatsMonitor() { + if (dump_timer_.IsRunning()) + StopProfiling(); + TraceLog::GetInstance()->RemoveEnabledStateObserver(this); +} + +void TraceEventSystemStatsMonitor::OnTraceLogEnabled() { + // Check to see if system tracing is enabled. + bool enabled; + + TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT( + "system_stats"), &enabled); + if (!enabled) + return; + task_runner_->PostTask( + FROM_HERE, + base::Bind(&TraceEventSystemStatsMonitor::StartProfiling, + weak_factory_.GetWeakPtr())); +} + +void TraceEventSystemStatsMonitor::OnTraceLogDisabled() { + task_runner_->PostTask( + FROM_HERE, + base::Bind(&TraceEventSystemStatsMonitor::StopProfiling, + weak_factory_.GetWeakPtr())); +} + +void TraceEventSystemStatsMonitor::StartProfiling() { + // Watch for the tracing framework sending enabling more than once. + if (dump_timer_.IsRunning()) + return; + + dump_timer_.Start(FROM_HERE, + TimeDelta::FromMilliseconds(TraceEventSystemStatsMonitor:: + kSamplingIntervalMilliseconds), + base::Bind(&TraceEventSystemStatsMonitor:: + DumpSystemStats, + weak_factory_.GetWeakPtr())); +} + +// If system tracing is enabled, dumps a profile to the tracing system. +void TraceEventSystemStatsMonitor::DumpSystemStats() { + scoped_ptr<SystemStatsHolder> dump_holder(new SystemStatsHolder()); + dump_holder->GetSystemProfilingStats(); + + TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("system_stats"), + "base::TraceEventSystemStatsMonitor::SystemStats", + this, + dump_holder.PassAs<base::debug::ConvertableToTraceFormat>()); +} + +void TraceEventSystemStatsMonitor::StopProfiling() { + dump_timer_.Stop(); +} + +bool TraceEventSystemStatsMonitor::IsTimerRunningForTest() const { + return dump_timer_.IsRunning(); +} + +void AppendSystemProfileAsTraceFormat(const SystemMetrics& system_metrics, + std::string* output) { + std::string tmp; + base::JSONWriter::Write(system_metrics.ToValue().get(), &tmp); + *output += tmp; +} + +} // namespace debug +} // namespace base diff --git a/base/debug/trace_event_system_stats_monitor.h b/base/debug/trace_event_system_stats_monitor.h new file mode 100644 index 0000000..1a8b328 --- /dev/null +++ b/base/debug/trace_event_system_stats_monitor.h @@ -0,0 +1,75 @@ +// 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_DEBUG_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_ +#define BASE_DEBUG_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_ + +#include "base/base_export.h" +#include "base/debug/trace_event_impl.h" +#include "base/gtest_prod_util.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/process/process_metrics.h" +#include "base/timer/timer.h" + +namespace base { + +class SingleThreadTaskRunner; + +namespace debug { + +// 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); + + virtual ~TraceEventSystemStatsMonitor(); + + // base::debug::TraceLog::EnabledStateChangedObserver overrides: + virtual void OnTraceLogEnabled() OVERRIDE; + virtual 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<TraceEventSystemStatsMonitor> 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 debug +} // namespace base + +#endif // BASE_DEBUG_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_ diff --git a/base/debug/trace_event_system_stats_monitor_unittest.cc b/base/debug/trace_event_system_stats_monitor_unittest.cc new file mode 100644 index 0000000..5cc2a0f --- /dev/null +++ b/base/debug/trace_event_system_stats_monitor_unittest.cc @@ -0,0 +1,66 @@ +// 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. + +#include "base/debug/trace_event_system_stats_monitor.h" + +#include <sstream> +#include <string> + +#include "base/debug/trace_event_impl.h" +#include "base/message_loop/message_loop.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace base { +namespace debug { + +#if !defined(OS_IOS) +// Tests for the system stats monitor. +// Exists as a class so it can be a friend of TraceEventSystemStatsMonitor. +class TraceSystemStatsMonitorTest : public testing::Test { + public: + TraceSystemStatsMonitorTest() {} + virtual ~TraceSystemStatsMonitorTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(TraceSystemStatsMonitorTest); +}; + +////////////////////////////////////////////////////////////////////////////// + +TEST_F(TraceSystemStatsMonitorTest, TraceEventSystemStatsMonitor) { + MessageLoop message_loop; + + // Start with no observers of the TraceLog. + EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); + + // Creating a system stats monitor adds it to the TraceLog observer list. + scoped_ptr<TraceEventSystemStatsMonitor> system_stats_monitor( + new TraceEventSystemStatsMonitor( + message_loop.message_loop_proxy())); + EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest()); + EXPECT_TRUE( + TraceLog::GetInstance()->HasEnabledStateObserver( + system_stats_monitor.get())); + + // By default the observer isn't dumping memory profiles. + EXPECT_FALSE(system_stats_monitor->IsTimerRunningForTest()); + + // Simulate enabling tracing. + system_stats_monitor->StartProfiling(); + message_loop.RunUntilIdle(); + EXPECT_TRUE(system_stats_monitor->IsTimerRunningForTest()); + + // Simulate disabling tracing. + system_stats_monitor->StopProfiling(); + message_loop.RunUntilIdle(); + EXPECT_FALSE(system_stats_monitor->IsTimerRunningForTest()); + + // Deleting the observer removes it from the TraceLog observer list. + system_stats_monitor.reset(); + EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); +} +#endif // !defined(OS_IOS) + +} // namespace debug +} // namespace base diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 429da81..d543703 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc @@ -20,6 +20,7 @@ #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/system_monitor/system_monitor.h" +#include "base/thread_task_runner_handle.h" #include "base/threading/thread_restrictions.h" #include "base/timer/hi_res_timer_manager.h" #include "content/browser/browser_thread_impl.h" @@ -455,6 +456,11 @@ void BrowserMainLoop::MainMessageLoopStart() { TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:OnlineStateObserver") online_state_observer_.reset(new BrowserOnlineStateObserver); } + + { + system_stats_monitor_.reset(new base::debug::TraceEventSystemStatsMonitor( + base::ThreadTaskRunnerHandle::Get())); + } #endif // !defined(OS_IOS) #if defined(OS_WIN) @@ -715,6 +721,7 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() { } trace_memory_controller_.reset(); + system_stats_monitor_.reset(); #if !defined(OS_IOS) // Destroying the GpuProcessHostUIShims on the UI thread posts a task to diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h index b3ec73c..821da87 100644 --- a/content/browser/browser_main_loop.h +++ b/content/browser/browser_main_loop.h @@ -20,6 +20,7 @@ class PowerMonitor; class SystemMonitor; namespace debug { class TraceMemoryController; +class TraceEventSystemStatsMonitor; } // namespace debug } // namespace base @@ -170,6 +171,7 @@ class CONTENT_EXPORT BrowserMainLoop { scoped_ptr<base::Thread> indexed_db_thread_; scoped_ptr<MemoryObserver> memory_observer_; scoped_ptr<base::debug::TraceMemoryController> trace_memory_controller_; + scoped_ptr<base::debug::TraceEventSystemStatsMonitor> system_stats_monitor_; DISALLOW_COPY_AND_ASSIGN(BrowserMainLoop); }; |