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

Side by Side Diff: content/test/gpu/gpu_tests/pixel.py

Issue 106523006: Add options to GPU pixel test to use cloud storage for reference and error images. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed problems with temp files on Windows. Undid changes to Bitmap. Created 7 years 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | tools/telemetry/telemetry/page/cloud_storage.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 from datetime import datetime 4 from datetime import datetime
5 import glob 5 import glob
6 import optparse 6 import optparse
7 import os 7 import os
8 import re 8 import re
9 import tempfile
9 10
10 from telemetry import test 11 from telemetry import test
11 from telemetry.core import bitmap 12 from telemetry.core import bitmap
13 from telemetry.page import cloud_storage
12 from telemetry.page import page_test 14 from telemetry.page import page_test
13 15
14 test_data_dir = os.path.abspath(os.path.join( 16 test_data_dir = os.path.abspath(os.path.join(
15 os.path.dirname(__file__), '..', '..', 'data', 'gpu')) 17 os.path.dirname(__file__), '..', '..', 'data', 'gpu'))
16 18
17 default_generated_data_dir = os.path.join(test_data_dir, 'generated') 19 default_generated_data_dir = os.path.join(test_data_dir, 'generated')
18 default_reference_image_dir = os.path.join(test_data_dir, 'gpu_reference') 20 default_reference_image_dir = os.path.join(test_data_dir, 'gpu_reference')
19 21
22 error_image_cloud_storage_bucket = 'chromium-browser-gpu-tests'
23
20 test_harness_script = r""" 24 test_harness_script = r"""
21 var domAutomationController = {}; 25 var domAutomationController = {};
22 26
23 domAutomationController._succeeded = false; 27 domAutomationController._succeeded = false;
24 domAutomationController._finished = false; 28 domAutomationController._finished = false;
25 29
26 domAutomationController.setAutomationId = function(id) {} 30 domAutomationController.setAutomationId = function(id) {}
27 31
28 domAutomationController.send = function(msg) { 32 domAutomationController.send = function(msg) {
29 domAutomationController._finished = true; 33 domAutomationController._finished = true;
(...skipping 10 matching lines...) Expand all
40 44
41 class PixelTestFailure(Exception): 45 class PixelTestFailure(Exception):
42 pass 46 pass
43 47
44 def _DidTestSucceed(tab): 48 def _DidTestSucceed(tab):
45 return tab.EvaluateJavaScript('domAutomationController._succeeded') 49 return tab.EvaluateJavaScript('domAutomationController._succeeded')
46 50
47 class PixelValidator(page_test.PageTest): 51 class PixelValidator(page_test.PageTest):
48 def __init__(self): 52 def __init__(self):
49 super(PixelValidator, self).__init__('ValidatePage') 53 super(PixelValidator, self).__init__('ValidatePage')
54 # Parameters for cloud storage reference images.
55 self.vendor_id = None
56 self.device_id = None
57 self.vendor_string = None
58 self.device_string = None
50 59
51 def CustomizeBrowserOptions(self, options): 60 def CustomizeBrowserOptions(self, options):
52 options.AppendExtraBrowserArgs('--enable-gpu-benchmarking') 61 options.AppendExtraBrowserArgs('--enable-gpu-benchmarking')
53 62
54 def ValidatePage(self, page, tab, results): 63 def ValidatePage(self, page, tab, results):
55 if not _DidTestSucceed(tab): 64 if not _DidTestSucceed(tab):
56 raise page_test.Failure('Page indicated a failure') 65 raise page_test.Failure('Page indicated a failure')
57 66
58 if not tab.screenshot_supported: 67 if not tab.screenshot_supported:
59 raise page_test.Failure('Browser does not support screenshot capture') 68 raise page_test.Failure('Browser does not support screenshot capture')
60 69
61 screenshot = tab.Screenshot(5) 70 screenshot = tab.Screenshot(5)
62 71
63 if not screenshot: 72 if not screenshot:
64 raise page_test.Failure('Could not capture screenshot') 73 raise page_test.Failure('Could not capture screenshot')
65 74
66 if hasattr(page, 'test_rect'): 75 if hasattr(page, 'test_rect'):
67 screenshot = screenshot.Crop( 76 screenshot = screenshot.Crop(
68 page.test_rect[0], page.test_rect[1], 77 page.test_rect[0], page.test_rect[1],
69 page.test_rect[2], page.test_rect[3]) 78 page.test_rect[2], page.test_rect[3])
70 79
71 image_name = PixelValidator.UrlToImageName(page.display_name) 80 image_name = PixelValidator.UrlToImageName(page.display_name)
72 81
73 ref_png = PixelValidator.GetReferenceImage(self.options.reference_dir, 82 if self.options.upload_refimg_to_cloud_storage:
74 image_name, page.revision, screenshot) 83 if self._ConditionallyUploadToCloudStorage(image_name, page, tab,
84 screenshot):
85 # This is the new reference image; there's nothing to compare against.
86 ref_png = screenshot
87 else:
88 # There was a preexisting reference image, so we might as well
89 # compare against it.
90 ref_png = self._DownloadFromCloudStorage(image_name, page, tab)
91 elif self.options.download_refimg_from_cloud_storage:
92 # This bot doesn't have the ability to properly generate a
93 # reference image, so download it from cloud storage.
94 ref_png = self._DownloadFromCloudStorage(image_name, page, tab)
95 else:
96 # Legacy path using on-disk results.
97 ref_png = PixelValidator.GetReferenceImage(self.options.reference_dir,
98 image_name, page.revision, screenshot)
75 99
76 # Test new snapshot against existing reference image 100 # Test new snapshot against existing reference image
77 if not ref_png.IsEqual(screenshot, tolerance=2): 101 if not ref_png.IsEqual(screenshot, tolerance=2):
78 PixelValidator.WriteErrorImages(self.options.generated_dir, image_name, 102 if self.options.test_machine_name:
79 self.options.build_revision, screenshot, ref_png) 103 self._UploadErrorImagesToCloudStorage(image_name, ref_png, screenshot)
104 else:
105 PixelValidator.WriteErrorImages(self.options.generated_dir, image_name,
106 self.options.build_revision, screenshot, ref_png)
80 raise page_test.Failure('Reference image did not match captured screen') 107 raise page_test.Failure('Reference image did not match captured screen')
81 108
82 @staticmethod 109 @staticmethod
83 def UrlToImageName(url): 110 def UrlToImageName(url):
84 image_name = re.sub(r'^(http|https|file)://(/*)', '', url) 111 image_name = re.sub(r'^(http|https|file)://(/*)', '', url)
85 image_name = re.sub(r'\.\./', '', image_name) 112 image_name = re.sub(r'\.\./', '', image_name)
86 image_name = re.sub(r'(\.|/|-)', '_', image_name) 113 image_name = re.sub(r'(\.|/|-)', '_', image_name)
87 return image_name 114 return image_name
88 115
89 @staticmethod 116 @staticmethod
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 os.path.join(img_dir, 'DIFF_' + full_image_name), diff_png) 167 os.path.join(img_dir, 'DIFF_' + full_image_name), diff_png)
141 168
142 @staticmethod 169 @staticmethod
143 def WriteImage(image_path, png_image): 170 def WriteImage(image_path, png_image):
144 output_dir = os.path.dirname(image_path) 171 output_dir = os.path.dirname(image_path)
145 if not os.path.exists(output_dir): 172 if not os.path.exists(output_dir):
146 os.makedirs(output_dir) 173 os.makedirs(output_dir)
147 174
148 png_image.WritePngFile(image_path) 175 png_image.WritePngFile(image_path)
149 176
177 def _ComputeGpuInfo(self, tab):
178 if ((self.vendor_id and self.device_id) or
179 (self.vendor_string and self.device_string)):
180 return
181 browser = tab.browser
182 if not browser.supports_system_info:
183 raise Exception('System info must be supported by the browser')
184 system_info = browser.GetSystemInfo()
185 if not system_info.gpu:
186 raise Exception('GPU information was absent')
187 device = system_info.gpu.devices[0]
188 if device.vendor_id and device.device_id:
189 self.vendor_id = device.vendor_id
190 self.device_id = device.device_id
191 elif device.vendor_string and device.device_string:
192 self.vendor_string = device.vendor_string
193 self.device_string = device.device_string
194 else:
195 raise Exception('GPU device information was incomplete')
196
197 def _FormatGpuInfo(self, tab):
198 self._ComputeGpuInfo(tab)
199 if self.vendor_id:
200 return '%s_%04x_%04x' % (
201 self.options.os_type, self.vendor_id, self.device_id)
202 else:
203 return '%s_%s_%s' % (
204 self.options.os_type, self.vendor_string, self.device_string)
205
206 def _FormatReferenceImageName(self, img_name, page, tab):
207 return '%s_v%s_%s.png' % (
208 img_name,
209 page.revision,
210 self._FormatGpuInfo(tab))
211
212 def _UploadBitmapToCloudStorage(self, bucket, name, bitmap, public=False):
213 # This sequence of steps works on all platforms to write a temporary
214 # PNG to disk, following the pattern in bitmap_unittest.py. The key to
215 # avoiding PermissionErrors seems to be to not actually try to write to
216 # the temporary file object, but to re-open its name for all operations.
217 f = tempfile.NamedTemporaryFile()
218 bitmap.WritePngFile(f.name)
219 cloud_storage.Insert(bucket, name, f.name, publicly_readable=public)
220 f.close()
221
222 def _ConditionallyUploadToCloudStorage(self, img_name, page, tab, screenshot):
223 """Uploads the screenshot to cloud storage as the reference image
224 for this test, unless it already exists. Returns True if the
225 upload was actually performed."""
226 if not self.options.refimg_cloud_storage_bucket:
227 raise Exception('--refimg-cloud-storage-bucket argument is required')
228 cloud_name = self._FormatReferenceImageName(img_name, page, tab)
229 if not cloud_storage.Exists(self.options.refimg_cloud_storage_bucket,
230 cloud_name):
231 self._UploadBitmapToCloudStorage(self.options.refimg_cloud_storage_bucket,
232 cloud_name,
233 screenshot)
234 return True
235 return False
236
237 def _DownloadFromCloudStorage(self, img_name, page, tab):
238 """Downloads the reference image for the given test from cloud
239 storage, returning it as a Telemetry Bitmap object."""
240 # TODO(kbr): there's a race condition between the deletion of the
241 # temporary file and gsutil's overwriting it.
242 if not self.options.refimg_cloud_storage_bucket:
243 raise Exception('--refimg-cloud-storage-bucket argument is required')
244 f = tempfile.NamedTemporaryFile()
245 filename = f.name
246 f.close()
247 cloud_storage.Get(self.options.refimg_cloud_storage_bucket,
248 self._FormatReferenceImageName(img_name, page, tab),
249 filename)
250 return bitmap.Bitmap.FromPngFile(filename)
251
252 def _UploadErrorImagesToCloudStorage(self, image_name, ref_img, screenshot):
253 """For a failing run, uploads the reference image, failing image,
254 and diff image to cloud storage. This subsumes the functionality
255 of the archive_gpu_pixel_test_results.py script."""
256 machine_name = re.sub('\W+', '_', self.options.test_machine_name)
257 upload_dir = '%s_%s_telemetry' % (self.options.build_revision, machine_name)
258 base_bucket = '%s/runs/%s' % (error_image_cloud_storage_bucket, upload_dir)
259 image_name_with_revision = '%s_%s.png' % (
260 image_name, self.options.build_revision)
261 self._UploadBitmapToCloudStorage(
262 base_bucket + '/ref', image_name_with_revision, ref_img, public=True)
263 self._UploadBitmapToCloudStorage(
264 base_bucket + '/gen', image_name_with_revision, screenshot,
265 public=True)
266 diff_img = screenshot.Diff(ref_img)
267 self._UploadBitmapToCloudStorage(
268 base_bucket + '/diff', image_name_with_revision, diff_img,
269 public=True)
270 print ('See http://%s.commondatastorage.googleapis.com/'
271 'view_test_results.html?%s for this run\'s test results') % (
272 error_image_cloud_storage_bucket, upload_dir)
273
150 class Pixel(test.Test): 274 class Pixel(test.Test):
151 test = PixelValidator 275 test = PixelValidator
152 page_set = 'page_sets/pixel_tests.json' 276 page_set = 'page_sets/pixel_tests.json'
153 277
154 @staticmethod 278 @staticmethod
155 def AddTestCommandLineOptions(parser): 279 def AddTestCommandLineOptions(parser):
156 group = optparse.OptionGroup(parser, 'Pixel test options') 280 group = optparse.OptionGroup(parser, 'Pixel test options')
157 group.add_option('--generated-dir', 281 group.add_option('--generated-dir',
158 help='Overrides the default location for generated test images that do ' 282 help='Overrides the default location for generated test images that do '
159 'not match reference images', 283 'not match reference images',
160 default=default_generated_data_dir) 284 default=default_generated_data_dir)
161 group.add_option('--reference-dir', 285 group.add_option('--reference-dir',
162 help='Overrides the default location for reference images', 286 help='Overrides the default location for reference images',
163 default=default_reference_image_dir) 287 default=default_reference_image_dir)
164 group.add_option('--build-revision', 288 group.add_option('--build-revision',
165 help='Chrome revision being tested.', 289 help='Chrome revision being tested.',
166 default="unknownrev") 290 default="unknownrev")
291 group.add_option('--upload-refimg-to-cloud-storage',
292 dest='upload_refimg_to_cloud_storage',
293 action='store_true', default=False,
294 help='Upload resulting images to cloud storage as reference images')
295 group.add_option('--download-refimg-from-cloud-storage',
296 dest='download_refimg_from_cloud_storage',
297 action='store_true', default=False,
298 help='Download reference images from cloud storage')
299 group.add_option('--refimg-cloud-storage-bucket',
300 help='Name of the cloud storage bucket to use for reference images; '
301 'required with --upload-refimg-to-cloud-storage and '
302 '--download-refimg-from-cloud-storage. Example: '
303 '"chromium-gpu-archive/reference-images"')
304 group.add_option('--os-type',
305 help='Type of operating system on which the pixel test is being run, '
306 'used only to distinguish different operating systems with the same '
307 'graphics card. Any value is acceptable, but canonical values are '
308 '"win", "mac", and "linux", and probably, eventually, "chromeos" '
309 'and "android").',
310 default='')
311 group.add_option('--test-machine-name',
312 help='Name of the test machine. Specifying this argument causes this '
313 'script to upload failure images and diffs to cloud storage directly, '
314 'instead of relying on the archive_gpu_pixel_test_results.py script.',
315 default='')
167 parser.add_option_group(group) 316 parser.add_option_group(group)
168 317
169 def CreatePageSet(self, options): 318 def CreatePageSet(self, options):
170 page_set = super(Pixel, self).CreatePageSet(options) 319 page_set = super(Pixel, self).CreatePageSet(options)
171 for page in page_set.pages: 320 for page in page_set.pages:
172 page.script_to_evaluate_on_commit = test_harness_script 321 page.script_to_evaluate_on_commit = test_harness_script
173 return page_set 322 return page_set
OLDNEW
« no previous file with comments | « no previous file | tools/telemetry/telemetry/page/cloud_storage.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698