Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / performance_monitor / performance_monitor.cc
blob3e2cfdbe31230c82673565221d8a31db1fa1eaac
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/performance_monitor/performance_monitor.h"
7 #include "base/memory/singleton.h"
8 #include "base/process/process_iterator.h"
9 #include "base/time/time.h"
10 #include "content/public/browser/browser_child_process_host.h"
11 #include "content/public/browser/browser_child_process_host_iterator.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/child_process_data.h"
14 #include "content/public/browser/render_process_host.h"
16 using content::BrowserThread;
18 namespace {
20 // The default interval at which PerformanceMonitor performs its timed
21 // collections.
22 const int kGatherIntervalInSeconds = 120;
25 namespace performance_monitor {
27 PerformanceMonitor::PerformanceMonitor() {
30 PerformanceMonitor::~PerformanceMonitor() {
33 // static
34 PerformanceMonitor* PerformanceMonitor::GetInstance() {
35 return Singleton<PerformanceMonitor>::get();
38 void PerformanceMonitor::StartGatherCycle() {
39 DCHECK_CURRENTLY_ON(BrowserThread::UI);
40 repeating_timer_.Start(FROM_HERE,
41 base::TimeDelta::FromSeconds(kGatherIntervalInSeconds),
42 this,
43 &PerformanceMonitor::GatherMetricsMapOnUIThread);
46 void PerformanceMonitor::GatherMetricsMapOnUIThread() {
47 DCHECK_CURRENTLY_ON(BrowserThread::UI);
49 static int current_update_sequence = 0;
50 // Even in the "somewhat" unlikely event this wraps around,
51 // it doesn't matter. We just check it for inequality.
52 current_update_sequence++;
54 // Find all render child processes; has to be done on the UI thread.
55 for (content::RenderProcessHost::iterator rph_iter =
56 content::RenderProcessHost::AllHostsIterator();
57 !rph_iter.IsAtEnd(); rph_iter.Advance()) {
58 base::ProcessHandle handle = rph_iter.GetCurrentValue()->GetHandle();
59 MarkProcessAsAlive(handle, content::PROCESS_TYPE_RENDERER,
60 current_update_sequence);
63 BrowserThread::PostTask(
64 BrowserThread::IO,
65 FROM_HERE,
66 base::Bind(&PerformanceMonitor::GatherMetricsMapOnIOThread,
67 base::Unretained(this),
68 current_update_sequence));
71 void PerformanceMonitor::MarkProcessAsAlive(const base::ProcessHandle& handle,
72 int process_type,
73 int current_update_sequence) {
74 if (handle == 0) {
75 // Process may not be valid yet.
76 return;
79 MetricsMap::iterator process_metrics_iter = metrics_map_.find(handle);
80 if (process_metrics_iter == metrics_map_.end()) {
81 // If we're not already watching the process, let's initialize it.
82 metrics_map_[handle]
83 .Initialize(handle, process_type, current_update_sequence);
84 } else {
85 // If we are watching the process, touch it to keep it alive.
86 ProcessMetricsHistory& process_metrics = process_metrics_iter->second;
87 process_metrics.set_last_update_sequence(current_update_sequence);
91 void PerformanceMonitor::GatherMetricsMapOnIOThread(
92 int current_update_sequence) {
93 DCHECK_CURRENTLY_ON(BrowserThread::IO);
95 // Find all child processes (does not include renderers), which has to be
96 // done on the IO thread.
97 for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
98 const content::ChildProcessData& child_process_data = iter.GetData();
99 base::ProcessHandle handle = child_process_data.handle;
100 MarkProcessAsAlive(handle, child_process_data.process_type,
101 current_update_sequence);
104 // Add the current (browser) process.
105 MarkProcessAsAlive(base::GetCurrentProcessHandle(),
106 content::PROCESS_TYPE_BROWSER, current_update_sequence);
108 double cpu_usage = 0.0;
109 size_t private_memory_sum = 0;
110 size_t shared_memory_sum = 0;
112 // Update metrics for all watched processes; remove dead entries from the map.
113 MetricsMap::iterator iter = metrics_map_.begin();
114 while (iter != metrics_map_.end()) {
115 ProcessMetricsHistory& process_metrics = iter->second;
116 if (process_metrics.last_update_sequence() != current_update_sequence) {
117 // Not touched this iteration; let's get rid of it.
118 metrics_map_.erase(iter++);
119 } else {
120 process_metrics.SampleMetrics();
122 // Gather averages of previously sampled metrics.
123 cpu_usage += process_metrics.GetAverageCPUUsage();
125 size_t private_memory = 0;
126 size_t shared_memory = 0;
127 process_metrics.GetAverageMemoryBytes(&private_memory, &shared_memory);
128 private_memory_sum += private_memory;
129 shared_memory_sum += shared_memory;
131 process_metrics.EndOfCycle();
133 ++iter;
138 } // namespace performance_monitor