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.
7 from telemetry
.value
import scalar
9 from metrics
import Metric
12 class CpuMetric(Metric
):
13 """Calulates CPU load over a span of time."""
15 def __init__(self
, browser
):
16 super(CpuMetric
, self
).__init
__()
17 self
._browser
= browser
18 self
._start
_cpu
= None
21 def DidStartBrowser(self
, browser
):
22 # Save the browser object so that cpu_stats can be accessed later.
23 self
._browser
= browser
25 def Start(self
, page
, tab
):
26 if not self
._browser
.supports_cpu_metrics
:
27 logging
.warning('CPU metrics not supported.')
30 self
._start
_cpu
= self
._browser
.cpu_stats
32 def Stop(self
, page
, tab
):
33 if not self
._browser
.supports_cpu_metrics
:
36 assert self
._start
_cpu
, 'Must call Start() first'
37 self
._stop
_cpu
= self
._browser
.cpu_stats
39 # Optional argument trace_name is not in base class Metric.
40 # pylint: disable=W0221
41 def AddResults(self
, tab
, results
, trace_name
='cpu_utilization'):
42 if not self
._browser
.supports_cpu_metrics
:
45 assert self
._stop
_cpu
, 'Must call Stop() first'
46 cpu_stats
= _SubtractCpuStats(self
._stop
_cpu
, self
._start
_cpu
)
48 # FIXME: Renderer process CPU times are impossible to compare correctly.
49 # http://crbug.com/419786#c11
50 if 'Renderer' in cpu_stats
:
51 del cpu_stats
['Renderer']
53 # Add a result for each process type.
54 for process_type
in cpu_stats
:
55 trace_name_for_process
= '%s_%s' % (trace_name
, process_type
.lower())
56 cpu_percent
= 100 * cpu_stats
[process_type
]
57 results
.AddValue(scalar
.ScalarValue(
58 results
.current_page
, 'cpu_utilization.%s' % trace_name_for_process
,
59 '%', cpu_percent
, important
=False))
62 def _SubtractCpuStats(cpu_stats
, start_cpu_stats
):
63 """Computes average cpu usage over a time period for different process types.
65 Each of the two cpu_stats arguments is a dict with the following format:
66 {'Browser': {'CpuProcessTime': ..., 'TotalTime': ...},
67 'Renderer': {'CpuProcessTime': ..., 'TotalTime': ...}
68 'Gpu': {'CpuProcessTime': ..., 'TotalTime': ...}}
70 The 'CpuProcessTime' fields represent the number of seconds of CPU time
71 spent in each process, and total time is the number of real seconds
72 that have passed (this may be a Unix timestamp).
75 A dict of process type names (Browser, Renderer, etc.) to ratios of cpu
76 time used to total time elapsed.
79 for process_type
in cpu_stats
:
80 assert process_type
in start_cpu_stats
, 'Mismatching process types'
81 # Skip any process_types that are empty.
82 if (not cpu_stats
[process_type
]) or (not start_cpu_stats
[process_type
]):
84 cpu_process_time
= (cpu_stats
[process_type
]['CpuProcessTime'] -
85 start_cpu_stats
[process_type
]['CpuProcessTime'])
86 total_time
= (cpu_stats
[process_type
]['TotalTime'] -
87 start_cpu_stats
[process_type
]['TotalTime'])
88 # Fix overflow for 32-bit jiffie counter, 64-bit counter will not overflow.
89 # Linux kernel starts with a value close to an overflow, so correction is
93 # Assert that the arguments were given in the correct order.
94 assert total_time
> 0 and total_time
< 2**31, (
95 'Expected total_time > 0, was: %d' % total_time
)
96 cpu_usage
[process_type
] = float(cpu_process_time
) / total_time