Add video_WebRtcPower and video_PowerConsumption test.
The video_WebRtcPower measures the power consumption of WebRTC loopback.
The video_PowerConsumption test turns off the AC power and runs the
video_WebRtcPower test.
BUG=chromium:391396
TEST=Run the test on peach_pit
CQ-DEPEND=CL:206995
Change-Id: I8749b73a4097dcad354e9de1ab919414f5e20043
Reviewed-on: https://chromium-review.googlesource.com/206963
Reviewed-by: Wu-Cheng Li <wuchengli@chromium.org>
Commit-Queue: Wen-Ding Li <wending@google.com>
Tested-by: Wen-Ding Li <wending@google.com>
diff --git a/client/site_tests/video_WebRtcPower/control b/client/site_tests/video_WebRtcPower/control
new file mode 100644
index 0000000..0b46d30
--- /dev/null
+++ b/client/site_tests/video_WebRtcPower/control
@@ -0,0 +1,25 @@
+# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+AUTHOR = "Chrome OS Project, chromeos-video@google.com"
+NAME = "video_WebRtcPower"
+PURPOSE = "Test the power consumption of video encode/decode in a WebRTC call"
+CRITERIA = """
+The test outputs the video power consumption.
+"""
+TIME = "MEDIUM"
+TEST_CATEGORY = "Performance"
+TEST_CLASS = "video"
+TEST_TYPE = "client"
+DEPENDENCIES = "hw_video_acc_vp8"
+BUG_TEMPLATE = {
+ 'labels': ['OS-Chrome', 'Cr-OS-Kernel-Video'],
+}
+
+DOC = """
+This test checks whether video encode and decode power consumption
+has regression.
+"""
+
+job.run_test('video_WebRtcPower')
diff --git a/client/site_tests/video_WebRtcPower/loopback.html b/client/site_tests/video_WebRtcPower/loopback.html
new file mode 100644
index 0000000..edf13c5
--- /dev/null
+++ b/client/site_tests/video_WebRtcPower/loopback.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html>
+<head><title>Loopback test</title></head>
+<body>
+ <video id="remoteVideo" autoplay muted></video>
+<script>
+var localStream, localPeerConnection, remotePeerConnection;
+var remoteVideo = document.getElementById("remoteVideo");
+
+function start() {
+ navigator.getUserMedia = navigator.getUserMedia ||
+ navigator.webkitGetUserMedia;
+ navigator.getUserMedia(
+ {
+ audio:false,
+ video:{
+ "mandatory": {
+ "minWidth": "1280",
+ "minHeight": "720",
+ }
+ }
+ },
+ gotLocalStream,
+ gotError);
+}
+
+function gotLocalStream(stream) {
+ localStream = stream;
+ var servers = null;
+
+ localPeerConnection = new webkitRTCPeerConnection(servers);
+ localPeerConnection.onicecandidate = gotLocalIceCandidate;
+
+ remotePeerConnection = new webkitRTCPeerConnection(servers);
+ remotePeerConnection.onicecandidate = gotRemoteIceCandidate;
+ remotePeerConnection.onaddstream = gotRemoteStream;
+
+ localPeerConnection.addStream(localStream);
+ localPeerConnection.createOffer(gotLocalDescription);
+}
+
+function gotError(error) {
+ console.log("navigator.getUserMedia error: ", error);
+}
+
+function gotRemoteStream(event) {
+ remoteVideo.src = URL.createObjectURL(event.stream);
+}
+
+function gotLocalDescription(description) {
+ localPeerConnection.setLocalDescription(description);
+ remotePeerConnection.setRemoteDescription(description);
+ remotePeerConnection.createAnswer(gotRemoteDescription);
+}
+
+function gotRemoteDescription(description) {
+ remotePeerConnection.setLocalDescription(description);
+ localPeerConnection.setRemoteDescription(description);
+}
+
+function gotLocalIceCandidate(event) {
+ if (event.candidate)
+ remotePeerConnection.addIceCandidate(new RTCIceCandidate(event.candidate));
+}
+
+function gotRemoteIceCandidate(event) {
+ if (event.candidate)
+ localPeerConnection.addIceCandidate(new RTCIceCandidate(event.candidate));
+}
+
+window.onload=start;
+</script>
+</body>
+</html>
diff --git a/client/site_tests/video_WebRtcPower/video_WebRtcPower.py b/client/site_tests/video_WebRtcPower/video_WebRtcPower.py
new file mode 100755
index 0000000..d352aa4
--- /dev/null
+++ b/client/site_tests/video_WebRtcPower/video_WebRtcPower.py
@@ -0,0 +1,230 @@
+# Copyright (c) 2014 The Chromium OS 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 contextlib import closing
+import logging
+import os
+import time
+import urllib2
+
+from autotest_lib.client.bin import test, utils
+from autotest_lib.client.common_lib import error
+from autotest_lib.client.common_lib.cros import chrome
+from autotest_lib.client.cros import power_status, power_utils
+from autotest_lib.client.cros import service_stopper
+
+
+# Chrome flags to use fake camera and skip camera permission.
+EXTRA_BROWSER_ARGS = ['--use-fake-device-for-media-stream',
+ '--use-fake-ui-for-media-stream']
+NO_WEBRTC_HARDWARE_ACCELERATION_BROWSER_ARGS = ['--disable-webrtc-hw-decoding',
+ '--disable-webrtc-hw-encoding']
+
+FAKE_FILE_ARG = '--use-file-for-fake-video-capture="%s"'
+DOWNLOAD_BASE = 'http://commondatastorage.googleapis.com/chromiumos-test-assets-public/crowd/'
+VIDEO_NAME = 'crowd720_25frames.y4m'
+
+WEBRTC_INTERNALS_URL = 'chrome://webrtc-internals'
+RTC_INIT_HISTOGRAM = 'Media.RTCVideoDecoderInitDecodeSuccess'
+HISTOGRAMS_URL = 'chrome://histograms/' + RTC_INIT_HISTOGRAM
+
+# Minimum battery charge percentage we prefer to run the test
+BATTERY_INITIAL_CHARGED_MIN = 30
+
+WEBRTC_WITH_HARDWARE_ACCELERATION = 'webrtc_with_hardware_acceleration'
+WEBRTC_WITHOUT_HARDWARE_ACCELERATION = 'webrtc_without_hardware_acceleration'
+
+# Measure duration in seconds
+MEASURE_DURATION = 120
+# Time to exclude from calculation after firing a task [seconds].
+STABILIZATION_DURATION = 5
+
+class video_WebRtcPower(test.test):
+ """The test outputs the power consumption for WebRTC to performance
+ dashboard.
+ """
+ version = 1
+
+ def initialize(self):
+ # Objects that need to be taken care of in cleanup() are initialized
+ # here to None. Otherwise we run the risk of AttributeError raised in
+ # cleanup() masking a real error that caused the test to fail during
+ # initialize() before those variables were assigned.
+ self._backlight = None
+
+ self._services = service_stopper.ServiceStopper(
+ service_stopper.ServiceStopper.POWER_DRAW_SERVICES)
+ self._services.stop_services()
+
+ self._power_status = power_status.get_status()
+ # Verify that we are running on battery and the battery is
+ # sufficiently charged.
+ self._power_status.assert_battery_state(BATTERY_INITIAL_CHARGED_MIN)
+
+
+ def start_loopback(self, cr):
+ """
+ Opens WebRTC loopback page.
+
+ @param cr: Autotest Chrome instance.
+ """
+ tab = cr.browser.tabs[0]
+ tab.Navigate(cr.browser.http_server.UrlOf(
+ os.path.join(self.bindir, 'loopback.html')))
+ tab.WaitForDocumentReadyStateToBeComplete()
+
+
+ def assert_hardware_accelerated(self, cr, is_hardware_accelerated):
+ """
+ Checks if WebRTC decoding is hardware accelerated.
+
+ @param cr: Autotest Chrome instance.
+ @param is_hardware_accelerated: if is_hardware_accelerated is True then
+ assert hardware accelerated otherwise assert hardware not accelerated.
+
+ @raises error.TestError if decoding is not hardware accelerated while
+ is_hardware_accelerated is True or if decoding is hardware accelerated
+ while is_hardware_accelerated is False.
+ """
+ tab = cr.browser.tabs.New()
+ def histograms_loaded():
+ """Returns true if histogram is loaded."""
+ tab.Navigate(HISTOGRAMS_URL)
+ tab.WaitForDocumentReadyStateToBeComplete()
+ return tab.EvaluateJavaScript(
+ 'document.documentElement.innerText.search("%s") != -1'
+ % RTC_INIT_HISTOGRAM)
+
+ if is_hardware_accelerated:
+ utils.poll_for_condition(
+ histograms_loaded,
+ timeout=5,
+ exception=error.TestError(
+ 'Cannot find rtc video decoder histogram.'),
+ sleep_interval=1)
+
+ if tab.EvaluateJavaScript(
+ 'document.documentElement.innerText.search('
+ '"1 = 100.0%") == -1'):
+ raise error.TestError(
+ 'Video decode acceleration is not working.')
+ else:
+ time.sleep(5)
+ if histograms_loaded():
+ raise error.TestError(
+ 'Video decode acceleration should not be working.')
+
+ tab.Close()
+
+
+ def run_once(self):
+ # Download test video.
+ url = DOWNLOAD_BASE + VIDEO_NAME
+ local_path = os.path.join(self.bindir, VIDEO_NAME)
+ self.download_file(url, local_path)
+
+ self._backlight = power_utils.Backlight()
+ self._backlight.set_default()
+
+ measurements = [power_status.SystemPower(
+ self._power_status.battery_path)]
+ self._power_logger = power_status.PowerLogger(measurements)
+ self._power_logger.start()
+
+ # Run the WebRTC tests.
+ self.test_webrtc(local_path)
+
+ keyvals = self._power_logger.calc()
+ measurement_type = '_' + measurements[0].domain + '_pwr'
+ energy_rate_with_hw = keyvals[WEBRTC_WITH_HARDWARE_ACCELERATION +
+ measurement_type]
+ self.output_perf_value(
+ description='webrtc_energy_rate.mean',
+ value=energy_rate_with_hw,
+ units='W', higher_is_better=False)
+ # Save the results to the autotest results directory
+ self._power_logger.save_results(self.resultsdir)
+
+ # Find the energy of full battery
+ batinfo = self._power_status.battery[0]
+ self.energy_full_design = batinfo.energy_full_design
+ logging.info("energy_full_design = %0.3f Wh",
+ self.energy_full_design)
+
+ logging.info('Expected battery life using WebRtc with'
+ 'hardware acceleration : %0.3f hours',
+ self.energy_full_design / energy_rate_with_hw)
+
+ energy_rate_without_hw = keyvals[WEBRTC_WITHOUT_HARDWARE_ACCELERATION +
+ measurement_type]
+ logging.info('Expected battery life using WebRtc without'
+ 'hardware acceleration : %0.3f hours',
+ self.energy_full_design / energy_rate_without_hw)
+
+
+ def test_webrtc(self, local_path):
+ """
+ Runs the WebRTC test with and without hardware acceleration.
+
+ @param local_path: the path to the video file.
+ @param test_duration: test duration for a run (seconds).
+ """
+ EXTRA_BROWSER_ARGS.append(FAKE_FILE_ARG % local_path)
+ with chrome.Chrome(extra_browser_args=EXTRA_BROWSER_ARGS) as cr:
+ # Open WebRTC loopback page.
+ cr.browser.SetHTTPServerDirectories(self.bindir)
+ self.start_loopback(cr)
+
+ # Make sure decode is hardware accelerated.
+ self.assert_hardware_accelerated(cr, True)
+
+ # Record the start time and the end time of this power
+ # measurement test run.
+ time.sleep(STABILIZATION_DURATION)
+ start_time = time.time()
+ time.sleep(MEASURE_DURATION)
+ self._power_logger.checkpoint(WEBRTC_WITH_HARDWARE_ACCELERATION,
+ start_time)
+
+ # Start chrome with test flag
+ # and disabled WebRTC hardware encode and decode flag.
+ with chrome.Chrome(extra_browser_args=EXTRA_BROWSER_ARGS +
+ NO_WEBRTC_HARDWARE_ACCELERATION_BROWSER_ARGS) as cr:
+
+ # Open WebRTC loopback page.
+ cr.browser.SetHTTPServerDirectories(self.bindir)
+ self.start_loopback(cr)
+
+ # Make sure decode is not hardware accelerated.
+ self.assert_hardware_accelerated(cr, False)
+
+ # Record the start time and the end time of this power
+ # measurement test run.
+ time.sleep(STABILIZATION_DURATION)
+ start_time = time.time()
+ time.sleep(MEASURE_DURATION)
+ self._power_logger.checkpoint(WEBRTC_WITHOUT_HARDWARE_ACCELERATION,
+ start_time)
+
+
+ def download_file(self, url, local_path):
+ """
+ Downloads a file from the specified URL.
+
+ @param url: URL of the file.
+ @param local_path: the path that the file will be saved to.
+ """
+ logging.info('Downloading "%s" to "%s"', url, local_path)
+ with closing(urllib2.urlopen(url)) as r, open(local_path, 'wb') as w:
+ w.write(r.read())
+
+
+ def cleanup(self):
+ # cleanup() is run by common_lib/test.py.
+ if self._backlight:
+ self._backlight.restore()
+ if self._services:
+ self._services.restore_services()
+
+ super(video_WebRtcPower, self).cleanup()
diff --git a/server/site_tests/video_PowerConsumption/control.webrtc b/server/site_tests/video_PowerConsumption/control.webrtc
new file mode 100644
index 0000000..94365a8
--- /dev/null
+++ b/server/site_tests/video_PowerConsumption/control.webrtc
@@ -0,0 +1,44 @@
+# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+AUTHOR = "Chrome OS Team"
+NAME = "video_PowerConsumption"
+TIME = "MEDIUM"
+TEST_CATEGORY = "Performance"
+TEST_CLASS = "video"
+SUITE = "video"
+TEST_TYPE = "server"
+DEPENDENCIES = "rpm, hw_video_acc_vp8"
+BUG_TEMPLATE = {
+ 'labels': ['OS-Chrome', 'Cr-OS-Kernel-Video'],
+}
+
+DOC = """
+The test outputs the video power consumption for video
+encode and decode.
+"""
+
+import logging
+
+from autotest_lib.client.common_lib import error
+from autotest_lib.server import site_host_attributes
+
+
+def _run_client_test(machine):
+ """Runs client test with battery actively discharging."""
+ client = hosts.create_host(machine)
+ if not client.has_power():
+ msg = 'This test requires RPM support.'
+ logging.info('********************%s', msg)
+ raise error.TestError(msg)
+
+ client.power_off()
+ try:
+ client_at = autotest.Autotest(client)
+ client_at.run_test('video_WebRtcPower')
+ finally:
+ client.power_on()
+
+
+job.parallel_on_machines(_run_client_test, machines)
diff --git a/tko/perf_upload/perf_dashboard_config.json b/tko/perf_upload/perf_dashboard_config.json
index 0c9a29f..1019a94 100644
--- a/tko/perf_upload/perf_dashboard_config.json
+++ b/tko/perf_upload/perf_dashboard_config.json
@@ -378,5 +378,9 @@
{
"autotest_name": "video_WebRtcPerf",
"master_name": "ChromeOSVideo"
+ },
+ {
+ "autotest_name": "video_WebRtcPower",
+ "master_name": "ChromeOSVideo"
}
]