1# Copyright 2013 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 5from metrics import Metric 6from telemetry.value import scalar 7 8 9class CpuMetric(Metric): 10 """Calulates CPU load over a span of time.""" 11 12 def __init__(self, browser): 13 super(CpuMetric, self).__init__() 14 self._browser = browser 15 self._start_cpu = None 16 self._stop_cpu = None 17 18 def DidStartBrowser(self, browser): 19 # Save the browser object so that cpu_stats can be accessed later. 20 self._browser = browser 21 22 def Start(self, page, tab): 23 self._start_cpu = self._browser.cpu_stats 24 25 def Stop(self, page, tab): 26 assert self._start_cpu, 'Must call Start() first' 27 self._stop_cpu = self._browser.cpu_stats 28 29 # Optional argument trace_name is not in base class Metric. 30 # pylint: disable=W0221 31 def AddResults(self, tab, results, trace_name='cpu_utilization'): 32 assert self._stop_cpu, 'Must call Stop() first' 33 cpu_stats = _SubtractCpuStats(self._stop_cpu, self._start_cpu) 34 # Add a result for each process type. 35 for process_type in cpu_stats: 36 trace_name_for_process = '%s_%s' % (trace_name, process_type.lower()) 37 cpu_percent = 100 * cpu_stats[process_type] 38 results.AddValue(scalar.ScalarValue( 39 results.current_page, 'cpu_utilization.%s' % trace_name_for_process, 40 '%', cpu_percent, important=False)) 41 42 43def _SubtractCpuStats(cpu_stats, start_cpu_stats): 44 """Computes average cpu usage over a time period for different process types. 45 46 Each of the two cpu_stats arguments is a dict with the following format: 47 {'Browser': {'CpuProcessTime': ..., 'TotalTime': ...}, 48 'Renderer': {'CpuProcessTime': ..., 'TotalTime': ...} 49 'Gpu': {'CpuProcessTime': ..., 'TotalTime': ...}} 50 51 The 'CpuProcessTime' fields represent the number of seconds of CPU time 52 spent in each process, and total time is the number of real seconds 53 that have passed (this may be a Unix timestamp). 54 55 Returns: 56 A dict of process type names (Browser, Renderer, etc.) to ratios of cpu 57 time used to total time elapsed. 58 """ 59 cpu_usage = {} 60 for process_type in cpu_stats: 61 assert process_type in start_cpu_stats, 'Mismatching process types' 62 # Skip any process_types that are empty. 63 if (not cpu_stats[process_type]) or (not start_cpu_stats[process_type]): 64 continue 65 cpu_process_time = (cpu_stats[process_type]['CpuProcessTime'] - 66 start_cpu_stats[process_type]['CpuProcessTime']) 67 total_time = (cpu_stats[process_type]['TotalTime'] - 68 start_cpu_stats[process_type]['TotalTime']) 69 # Fix overflow for 32-bit jiffie counter, 64-bit counter will not overflow. 70 # Linux kernel starts with a value close to an overflow, so correction is 71 # necessary. 72 if total_time < 0: 73 total_time += 2**32 74 # Assert that the arguments were given in the correct order. 75 assert total_time > 0 and total_time < 2**31, ( 76 'Expected total_time > 0, was: %d' % total_time) 77 cpu_usage[process_type] = float(cpu_process_time) / total_time 78 return cpu_usage 79 80