Home | History | Annotate | Download | only in performance_monitor
      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