Commit 040db4f4 authored by jdduke's avatar jdduke Committed by Commit bot

Add key_idle_power_cases for ensuring idle activity on Android

Add a key_idle_power_cases pageset for monitoring activity for static
pages in the foreground and dynamic pages in the background. All such
cases should incur minimal recurring activity, monitored using a
new thread_times.key_power_cases benchmark.

BUG=466213,470147
CQ_EXTRA_TRYBOTS=tryserver.chromium.perf:linux_perf_bisect;tryserver.chromium.perf:mac_perf_bisect;tryserver.chromium.perf:win_perf_bisect;tryserver.chromium.perf:android_nexus5_perf_bisect

Review URL: https://codereview.chromium.org/1097463004

Cr-Commit-Position: refs/heads/master@{#330132}
parent 8959c37c
......@@ -94,3 +94,17 @@ class ThreadTimesPolymer(_ThreadTimes):
def Name(cls):
return 'thread_times.polymer'
@benchmark.Enabled('android')
class ThreadTimesKeyIdlePowerCases(_ThreadTimes):
"""Measures timeline metrics for sites that should be idle in foreground
and background scenarios. The metrics are per-second rather than per-frame."""
page_set = page_sets.KeyIdlePowerCasesPageSet
@classmethod
def Name(cls):
return 'thread_times.key_idle_power_cases'
@classmethod
def ValueCanBeAddedPredicate(cls, value, _):
# Only report per-second metrics.
return 'per_frame' not in value.name and 'mean_frame' not in value.name
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
from telemetry.page import shared_page_state
class AndroidScreenRestorationSharedState(shared_page_state.SharedPageState):
""" Ensures the screen is on before and after each user story is run. """
def WillRunUserStory(self, page):
super(AndroidScreenRestorationSharedState, self).WillRunUserStory(page)
self._EnsureScreenOn()
def DidRunUserStory(self, results):
try:
super(AndroidScreenRestorationSharedState, self).DidRunUserStory(results)
finally:
self._EnsureScreenOn()
def CanRunOnBrowser(self, browser_info):
if not browser_info.browser_type.startswith('android'):
logging.warning('Browser is non-Android, skipping test')
return False
return True
def _EnsureScreenOn(self):
self.platform.android_action_runner.EnsureScreenOn()
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from page_sets import android_screen_restoration_shared_state
from telemetry.page import page as page_module
from telemetry.page import page_set as page_set_module
class KeyIdlePowerPage(page_module.Page):
def __init__(self, url, page_set, turn_screen_off):
super(KeyIdlePowerPage, self).__init__(
url=url,
page_set=page_set,
shared_page_state_class=(android_screen_restoration_shared_state
.AndroidScreenRestorationSharedState))
self.user_agent_type = 'mobile'
self._turn_screen_off = turn_screen_off
def RunNavigateSteps(self, action_runner):
super(KeyIdlePowerPage, self).RunNavigateSteps(action_runner)
action_runner.Wait(2)
if self._turn_screen_off:
# TODO(jdduke): Remove this API violation after the shared page state is
# exposed here, crbug.com/470147.
# pylint: disable=protected-access
action_runner._tab.browser.platform.android_action_runner.TurnScreenOff()
# We're not interested in tracking activity that occurs immediately after
# the screen is turned off. Several seconds should be enough time for the
# browser to "settle down" into an idle state.
action_runner.Wait(2)
def RunPageInteractions(self, action_runner):
# The page interaction is simply waiting in an idle state.
action_runner.Wait(20)
class KeyIdlePowerCasesPageSet(page_set_module.PageSet):
""" Key idle power cases """
def __init__(self):
super(KeyIdlePowerCasesPageSet, self).__init__(user_agent_type='mobile')
foreground_urls_list = [
# Why: Ensure minimal activity for static, empty pages in the foreground.
'file://key_idle_power_cases/blank.html',
]
for url in foreground_urls_list:
self.AddUserStory(KeyIdlePowerPage(url, self, False))
background_urls_list = [
# Why: Ensure animated GIFs aren't processed when Chrome is backgrounded.
'file://key_idle_power_cases/animated-gif.html',
# Why: Ensure CSS animations aren't processed when Chrome is backgrounded.
'file://key_idle_power_cases/css-animation.html',
# Why: Ensure rAF is suppressed when Chrome is backgrounded.
'file://key_idle_power_cases/request-animation-frame.html',
# Why: Ensure setTimeout is throttled when Chrome is backgrounded.
'file://key_idle_power_cases/set-timeout.html',
]
for url in background_urls_list:
self.AddUserStory(KeyIdlePowerPage(url, self, True))
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Animated GIF Test</title>
</head>
<body>
<img src="animated-10color.gif">
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Blank Test</title>
</head>
<body>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>CSS Animation Test</title>
<meta name="viewport" content="initial-scale=0.60, minimum-scale=0.60, maximum-scale=0.60">
<style type="text/css">
#stage {
margin: 150px auto;
width: 600px;
height: 400px;
/*
Setting the perspective of the contents of the stage
but not the stage itself
*/
-webkit-perspective: 800;
}
#rotate {
margin: 0 auto;
width: 600px;
height: 400px;
/* Ensure that we're in 3D space */
-webkit-transform-style: preserve-3d;
/*
Make the whole set of rows use the x-axis spin animation
for a duration of 7 seconds, running infinitely and linearly
*/
-webkit-animation-name: x-spin;
-webkit-animation-duration: 7s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
.ring {
margin: 0 auto;
height: 110px;
width: 600px;
-webkit-transform-style: preserve-3d;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
.ring > :nth-child(odd) {
background-color: #995C7F;
}
.ring > :nth-child(even) {
background-color: #835A99;
}
.poster {
position: absolute;
left: 250px;
width: 100px;
height: 100px;
opacity: 0.7;
color: rgba(0,0,0,0.9);
-webkit-border-radius: 10px;
}
.poster > p {
font-family: 'Georgia', serif;
font-size: 36px;
font-weight: bold;
text-align: center;
margin-top: 28px;
}
/*
Set up each row to have a different animation duration
and alternating y-axis rotation directions.
*/
#ring-1 {
-webkit-animation-name: y-spin;
-webkit-animation-duration: 5s;
}
#ring-2 {
-webkit-animation-name: back-y-spin;
-webkit-animation-duration: 4s;
}
#ring-3 {
-webkit-animation-name: y-spin;
-webkit-animation-duration: 3s;
}
/*
Here we define each of the three individual animations that
we will be using to have our 3D rotation effect. The first
animation will perform a full rotation on the x-axis, we'll
use that on the whole set of objects. The second and third
animations will perform a full rotation on the y-axis in
opposite directions, alternating directions between rows.
Note that you currently have to specify an intermediate step
for rotations even when you are using individual transformation
constructs.
*/
@-webkit-keyframes x-spin {
0% { -webkit-transform: rotateX(0deg); }
50% { -webkit-transform: rotateX(180deg); }
100% { -webkit-transform: rotateX(360deg); }
}
@-webkit-keyframes y-spin {
0% { -webkit-transform: rotateY(0deg); }
50% { -webkit-transform: rotateY(180deg); }
100% { -webkit-transform: rotateY(360deg); }
}
@-webkit-keyframes back-y-spin {
0% { -webkit-transform: rotateY(360deg); }
50% { -webkit-transform: rotateY(180deg); }
100% { -webkit-transform: rotateY(0deg); }
}
</style>
<script type="text/javascript">
const POSTERS_PER_ROW = 12;
const RING_RADIUS = 200;
function setup_posters (row)
{
var posterAngle = 360 / POSTERS_PER_ROW;
for (var i = 0; i < POSTERS_PER_ROW; i ++) {
var poster = document.createElement('div');
poster.className = 'poster';
// compute and assign the transform for this poster
var transform = 'rotateY(' + (posterAngle * i) + 'deg) translateZ(' + RING_RADIUS + 'px)';
poster.style.webkitTransform = transform;
// setup the number to show inside the poster
var content = poster.appendChild(document.createElement('p'));
content.textContent = i;
// add the poster to the row
row.appendChild(poster);
}
}
function init ()
{
setup_posters(document.getElementById('ring-1'));
setup_posters(document.getElementById('ring-2'));
setup_posters(document.getElementById('ring-3'));
}
// call init once the document is fully loaded
window.addEventListener('load', init, false);
</script>
</head>
<body>
<div id="stage">
<div id="rotate">
<div id="ring-1" class="ring"></div>
<div id="ring-2" class="ring"></div>
<div id="ring-3" class="ring"></div>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
<title>requestAnimationFrame Test</title>
<style type="text/css">
html, body {
height: 100%;
padding: 0px;
margin: 0px;
}
#container {
width: 100%;
height: 100%;
background: rgb(128, 128, 128);
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/javascript">
var container = document.getElementById('container');
var c = 128;
tick();
function tick() {
++c;
c %= 256;
container.style.backgroundColor = "rgb("+c+","+c+","+c+")";
requestAnimationFrame(tick);
};
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
<title>setTimeout Test</title>
<style type="text/css">
html, body {
height: 100%;
padding: 0px;
margin: 0px;
}
#container {
width: 100%;
height: 100%;
background: rgb(128, 128, 128);
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/javascript">
var container = document.getElementById('container');
var c = 128;
tick();
function tick() {
++c;
c %= 256;
container.style.backgroundColor = "rgb("+c+","+c+","+c+")";
setTimeout(tick, 16.66666);
};
</script>
</body>
</html>
......@@ -53,3 +53,7 @@ class BrowserInfo(object):
branch_num = (
self._browser._browser_backend.devtools_client.GetChromeBranchNumber())
return branch_num >= 2332
@property
def browser_type(self):
return self._browser.browser_type
......@@ -116,15 +116,28 @@ class AndroidActionRunner(object):
"""
self._platform_backend.adb.RunShellCommand('input roll %s %s' % (dx, dy))
def EnsureScreenOn(self):
"""If device screen is off, turn screen on.
If the screen is already on, return immediately.
Raises:
Timeout: If the screen is off and device fails to turn screen on.
"""
if self._platform_backend.IsScreenOn():
return
self._ToggleScreenOn()
util.WaitFor(self._platform_backend.IsScreenOn, 5)
def TurnScreenOn(self):
"""If device screen is off, turn screen on.
If the screen is already on, this method returns immediately.
If the screen is already on, log a warning and return immediately.
Raises:
Timeout: If the screen is off and device fails to turn screen on.
"""
if not self._platform_backend.IsScreenOn():
self._platform_backend.adb.RunShellCommand('input keyevent 26')
self._ToggleScreenOn()
else:
logging.warning('Screen on when expected off.')
return
......@@ -133,7 +146,7 @@ class AndroidActionRunner(object):
def TurnScreenOff(self):
"""If device screen is on, turn screen off.
If the screen is already off, this method returns immediately.
If the screen is already off, log a warning and return immediately.
Raises:
Timeout: If the screen is on and device fails to turn screen off.
......@@ -142,8 +155,7 @@ class AndroidActionRunner(object):
return not self._platform_backend.IsScreenOn()
if self._platform_backend.IsScreenOn():
self._platform_backend.adb.RunShellCommand(
'input keyevent 26')
self._ToggleScreenOn()
else:
logging.warning('Screen off when expected on.')
return
......@@ -152,7 +164,7 @@ class AndroidActionRunner(object):
def UnlockScreen(self):
"""If device screen is locked, unlocks it.
If the device is not locked, this method returns immediately.
If the device is not locked, log a warning and return immediately.
Raises:
Timeout: If device fails to unlock screen.
......@@ -167,3 +179,6 @@ class AndroidActionRunner(object):
return
util.WaitFor(is_screen_unlocked, 5)
def _ToggleScreenOn(self):
self._platform_backend.adb.RunShellCommand('input keyevent 26')
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment