cpu.py revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)# found in the LICENSE file.
458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)from metrics import Metric
658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)class CpuMetric(Metric):
858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  """Calulates CPU load over a span of time."""
958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def __init__(self, browser):
1168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    super(CpuMetric, self).__init__()
1258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    self._results = None
1358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    self._browser = browser
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self._start_cpu = None
1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def DidStartBrowser(self, browser):
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # Save the browser object so that cpu_stats can be accessed later.
1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    self._browser = browser
1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def Start(self, page, tab):
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self._start_cpu = self._browser.cpu_stats
2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def Stop(self, page, tab):
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    assert self._start_cpu, 'Must call Start() first'
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self._results = _SubtractCpuStats(self._browser.cpu_stats, self._start_cpu)
2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  # Optional argument trace_name is not in base class Metric.
2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  # pylint: disable=W0221
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def AddResults(self, tab, results, trace_name='cpu_utilization'):
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    assert self._results, 'Must call Stop() first'
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # Add a result for each process type.
3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    for process_type in self._results:
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      trace_name = '%s_%s' % (trace_name, process_type.lower())
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      cpu_percent = 100 * self._results[process_type]
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      results.Add(trace_name, '%', cpu_percent, chart_name='cpu_utilization',
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                  data_type='unimportant')
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def _SubtractCpuStats(cpu_stats, start_cpu_stats):
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  """Computes average cpu usage over a time period for different process types.
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Each of the two cpu_stats arguments is a dict with the following format:
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      {'Browser': {'CpuProcessTime': ..., 'TotalTime': ...},
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       'Renderer': {'CpuProcessTime': ..., 'TotalTime': ...}
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       'Gpu': {'CpuProcessTime': ..., 'TotalTime': ...}}
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  The 'CpuProcessTime' fields represent the number of seconds of CPU time
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  spent in each process, and total time is the number of real seconds
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  that have passed (this may be a Unix timestamp).
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Returns:
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    A dict of process type names (Browser, Renderer, etc.) to ratios of cpu
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    time used to total time elapsed.
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  """
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  cpu_usage = {}
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for process_type in cpu_stats:
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    assert process_type in start_cpu_stats, 'Mismatching process types'
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # Skip any process_types that are empty.
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (not cpu_stats[process_type]) or (not start_cpu_stats[process_type]):
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      continue
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    cpu_process_time = (cpu_stats[process_type]['CpuProcessTime'] -
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                        start_cpu_stats[process_type]['CpuProcessTime'])
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    total_time = (cpu_stats[process_type]['TotalTime'] -
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                  start_cpu_stats[process_type]['TotalTime'])
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    assert total_time > 0, 'Expected total_time > 0, was: %d' % total_time
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    cpu_usage[process_type] = float(cpu_process_time) / total_time
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return cpu_usage
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
69