Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(476)

Side by Side Diff: chrome/test/vr/perf/latency/webvr_latency_test.py

Issue 2823883003: Make VR latency results compatible with perf dashboard, refactor into classes (Closed)
Patch Set: Address nits Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/test/vr/perf/latency/run_latency_test.py ('k') | testing/buildbot/gn_isolate_map.pyl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2017 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
5 import motopho_thread as mt
6 import robot_arm as ra
7
8 import json
9 import glob
10 import logging
11 import numpy
12 import os
13 import re
14 import subprocess
15 import sys
16 import time
17
18
19 MOTOPHO_THREAD_TIMEOUT = 30
20
21
22 def GetTtyDevices(tty_pattern, vendor_ids):
23 """Finds all devices connected to tty that match a pattern and device id.
24
25 If a serial device is connected to the computer via USB, this function
26 will check all tty devices that match tty_pattern, and return the ones
27 that have vendor identification number in the list vendor_ids.
28
29 Args:
30 tty_pattern: The search pattern, such as r'ttyACM\d+'.
31 vendor_ids: The list of 16-bit USB vendor ids, such as [0x2a03].
32
33 Returns:
34 A list of strings of tty devices, for example ['ttyACM0'].
35 """
36 product_string = 'PRODUCT='
37 sys_class_dir = '/sys/class/tty/'
38
39 tty_devices = glob.glob(sys_class_dir + '*')
40
41 matcher = re.compile('.*' + tty_pattern)
42 tty_matches = [x for x in tty_devices if matcher.search(x)]
43 tty_matches = [x[len(sys_class_dir):] for x in tty_matches]
44
45 found_devices = []
46 for match in tty_matches:
47 class_filename = sys_class_dir + match + '/device/uevent'
48 with open(class_filename, 'r') as uevent_file:
49 # Look for the desired product id in the uevent text.
50 for line in uevent_file:
51 if product_string in line:
52 ids = line[len(product_string):].split('/')
53 ids = [int(x, 16) for x in ids]
54
55 for desired_id in vendor_ids:
56 if desired_id in ids:
57 found_devices.append(match)
58
59 return found_devices
60
61
62 class WebVrLatencyTest(object):
63 """Base class for all WebVR latency tests.
64
65 This is meant to be subclassed for each platform the test is run on. While
66 the latency test itself is cross-platform, the setup and teardown for
67 tests is platform-dependent.
68 """
69 def __init__(self, args):
70 self.args = args
71 self._num_samples = args.num_samples
72 self._flicker_app_url = args.url
73 assert (self._num_samples > 0),'Number of samples must be greater than 0'
74 self._device_name = 'generic_device'
75
76 # Connect to the Arduino that drives the servos
77 devices = GetTtyDevices(r'ttyACM\d+', [0x2a03, 0x2341])
78 assert (len(devices) == 1),'Found %d devices, expected 1' % len(devices)
79 self.robot_arm = ra.RobotArm(devices[0])
80
81 def RunTest(self):
82 """Runs the steps to start Chrome, measure/save latency, and clean up."""
83 self._Setup()
84 self._Run()
85 self._Teardown()
86
87 def _Setup(self):
88 """Perform any platform-specific setup."""
89 raise NotImplementedError(
90 'Platform-specific setup must be implemented in subclass')
91
92 def _Run(self):
93 """Run the latency test.
94
95 Handles the actual latency measurement, which is identical across
96 different platforms, as well as result saving.
97 """
98 # Motopho scripts use relative paths, so switch to the Motopho directory
99 os.chdir(self.args.motopho_path)
100
101 # Set up the thread that runs the Motopho script
102 motopho_thread = mt.MotophoThread(self._num_samples)
103 motopho_thread.start()
104
105 # Run multiple times so we can get an average and standard deviation
106 for _ in xrange(self._num_samples):
107 self.robot_arm.ResetPosition()
108 # Start the Motopho script
109 motopho_thread.StartIteration()
110 # Let the Motopho be stationary so the script can calculate the bias
111 time.sleep(3)
112 motopho_thread.BlockNextIteration()
113 # Move so we can measure latency
114 self.robot_arm.StartMotophoMovement()
115 if not motopho_thread.WaitForIterationEnd(MOTOPHO_THREAD_TIMEOUT):
116 # TODO(bsheedy): Look into ways to prevent Motopho from not sending any
117 # data until unplugged and replugged into the machine after a reboot.
118 logging.error('Motopho thread timeout, '
119 'Motopho may need to be replugged.')
120 self.robot_arm.StopAllMovement()
121 time.sleep(1)
122 self._SaveResults(motopho_thread.latencies, motopho_thread.correlations)
123
124 def _Teardown(self):
125 """Performs any platform-specific teardown."""
126 raise NotImplementedError(
127 'Platform-specific setup must be implemented in subclass')
128
129 def _RunCommand(self, cmd):
130 """Runs the given cmd list and returns its output.
131
132 Prints the command's output and exits if any error occurs.
133
134 Returns:
135 A string containing the stdout and stderr of the command.
136 """
137 try:
138 return subprocess.check_output(cmd, stderr=subprocess.STDOUT)
139 except subprocess.CalledProcessError as e:
140 logging.error('Failed command output: %s', e.output)
141 raise e
142
143 def _SetChromeCommandLineFlags(self, flags):
144 raise NotImplementedError(
145 'Command-line flag setting must be implemented in subclass')
146
147 def _SaveResults(self, latencies, correlations):
148 """Saves the results to a JSON file.
149
150 Saved JSON object is compatible with Chrome perf dashboard if
151 put in as the 'chart_data' value. Also logs the raw data and its
152 average/standard deviation.
153 """
154 avg_latency = sum(latencies) / len(latencies)
155 std_latency = numpy.std(latencies)
156 avg_correlation = sum(correlations) / len(correlations)
157 std_correlation = numpy.std(correlations)
158 logging.info('Raw latencies: %s\nRaw correlations: %s\n'
159 'Avg latency: %f +/- %f\nAvg correlation: %f +/- %f',
160 str(latencies), str(correlations), avg_latency, std_latency,
161 avg_correlation, std_correlation)
162
163 if not (self.args.output_dir and os.path.isdir(self.args.output_dir)):
164 logging.warning('No output directory set, not saving results to file')
165 return
166
167 results = {
168 'format_version': '1.0',
169 'benchmark_name': 'webvr_latency',
170 'benchmark_description': 'Measures the motion-to-photon latency of WebVR',
171 'charts': {
172 'correlation': {
173 'summary': {
174 'improvement_direction': 'up',
175 'name': 'correlation',
176 'std': std_correlation,
177 'type': 'list_of_scalar_values',
178 'units': '',
179 'values': correlations,
180 },
181 },
182 'latency': {
183 'summary': {
184 'improvement_direction': 'down',
185 'name': 'latency',
186 'std': std_latency,
187 'type': 'list_of_scalar_values',
188 'units': 'ms',
189 'values': latencies,
190 },
191 }
192 }
193 }
194
195 with file(os.path.join(self.args.output_dir,
196 self.args.results_file), 'w') as outfile:
197 json.dump(results, outfile)
OLDNEW
« no previous file with comments | « chrome/test/vr/perf/latency/run_latency_test.py ('k') | testing/buildbot/gn_isolate_map.pyl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698