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. 4 5 #include "chrome/browser/performance_monitor/performance_monitor.h" 6 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" 15 16 using content::BrowserThread; 17 18 namespace { 19 20 // The default interval at which PerformanceMonitor performs its timed 21 // collections. 22 const int kGatherIntervalInSeconds = 120; 23 } 24 25 namespace performance_monitor { 26 27 PerformanceMonitor::PerformanceMonitor() { 28 } 29 30 PerformanceMonitor::~PerformanceMonitor() { 31 } 32 33 // static 34 PerformanceMonitor* PerformanceMonitor::GetInstance() { 35 return Singleton<PerformanceMonitor>::get(); 36 } 37 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); 44 } 45 46 void PerformanceMonitor::GatherMetricsMapOnUIThread() { 47 DCHECK_CURRENTLY_ON(BrowserThread::UI); 48 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++; 53 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); 61 } 62 63 BrowserThread::PostTask( 64 BrowserThread::IO, 65 FROM_HERE, 66 base::Bind(&PerformanceMonitor::GatherMetricsMapOnIOThread, 67 base::Unretained(this), 68 current_update_sequence)); 69 } 70 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; 77 } 78 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); 88 } 89 } 90 91 void PerformanceMonitor::GatherMetricsMapOnIOThread( 92 int current_update_sequence) { 93 DCHECK_CURRENTLY_ON(BrowserThread::IO); 94 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); 102 } 103 104 // Add the current (browser) process. 105 MarkProcessAsAlive(base::GetCurrentProcessHandle(), 106 content::PROCESS_TYPE_BROWSER, current_update_sequence); 107 108 double cpu_usage = 0.0; 109 size_t private_memory_sum = 0; 110 size_t shared_memory_sum = 0; 111 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(); 121 122 // Gather averages of previously sampled metrics. 123 cpu_usage += process_metrics.GetAverageCPUUsage(); 124 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; 130 131 process_metrics.EndOfCycle(); 132 133 ++iter; 134 } 135 } 136 } 137 138 } // namespace performance_monitor 139