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

Side by Side Diff: gm/rebaseline_server/compare_rendered_pictures.py

Issue 480153002: Added 'renderMode' and 'builder' as columns to the SKP front-end. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years, 4 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
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 2
3 """ 3 """
4 Copyright 2014 Google Inc. 4 Copyright 2014 Google Inc.
5 5
6 Use of this source code is governed by a BSD-style license that can be 6 Use of this source code is governed by a BSD-style license that can be
7 found in the LICENSE file. 7 found in the LICENSE file.
8 8
9 Compare results of two render_pictures runs. 9 Compare results of two render_pictures runs.
10 10
11 TODO(epoger): Start using this module to compare ALL images (whether they 11 TODO(epoger): Start using this module to compare ALL images (whether they
12 were generated from GMs or SKPs), and rename it accordingly. 12 were generated from GMs or SKPs), and rename it accordingly.
13 """ 13 """
14 14
15 # System-level imports 15 # System-level imports
16 import logging 16 import logging
17 import os 17 import os
18 import shutil 18 import shutil
19 import subprocess 19 import subprocess
20 import tempfile 20 import tempfile
21 import time 21 import time
22 22
23 # Must fix up PYTHONPATH before importing from within Skia 23 # Must fix up PYTHONPATH before importing from within Skia
24 import fix_pythonpath # pylint: disable=W0611 24 import rs_fixpypath # pylint: disable=W0611
25 25
26 # Imports from within Skia 26 # Imports from within Skia
27 from py.utils import git_utils 27 from py.utils import git_utils
28 from py.utils import gs_utils 28 from py.utils import gs_utils
29 from py.utils import url_utils 29 from py.utils import url_utils
30 import buildbot_globals 30 import buildbot_globals
31 import column 31 import column
32 import gm_json 32 import gm_json
33 import imagediffdb 33 import imagediffdb
34 import imagepair 34 import imagepair
35 import imagepairset 35 import imagepairset
36 import results 36 import results
37 37
38 # URL under which all render_pictures images can be found in Google Storage. 38 # URL under which all render_pictures images can be found in Google Storage.
39 # 39 #
40 # TODO(epoger): In order to allow live-view of GMs and other images, read this 40 # TODO(epoger): In order to allow live-view of GMs and other images, read this
41 # from the input summary files, or allow the caller to set it within the 41 # from the input summary files, or allow the caller to set it within the
42 # GET_live_results call. 42 # GET_live_results call.
43 DEFAULT_IMAGE_BASE_GS_URL = 'gs://' + buildbot_globals.Get('skp_images_bucket') 43 DEFAULT_IMAGE_BASE_GS_URL = 'gs://' + buildbot_globals.Get('skp_images_bucket')
44 44
45 # Column descriptors, and display preferences for them. 45 # Column descriptors, and display preferences for them.
46 COLUMN__RESULT_TYPE = results.KEY__EXTRACOLUMNS__RESULT_TYPE 46 COLUMN__RESULT_TYPE = results.KEY__EXTRACOLUMNS__RESULT_TYPE
47 COLUMN__SOURCE_SKP = 'sourceSkpFile' 47 COLUMN__SOURCE_SKP = 'sourceSkpFile'
48 COLUMN__TILED_OR_WHOLE = 'tiledOrWhole' 48 COLUMN__TILED_OR_WHOLE = 'tiledOrWhole'
49 COLUMN__TILENUM = 'tilenum' 49 COLUMN__TILENUM = 'tilenum'
50 COLUMN__BUILDER_A = 'builderA'
epoger 2014/08/18 19:56:31 Interesting. One thing that's potentially tricky:
stephana 2014/08/18 20:24:53 IMO, if we are comparing output from two builders
epoger 2014/08/18 20:34:49 SGTM.
51 COLUMN__RENDER_MODE_A = 'renderModeA'
52 COLUMN__BUILDER_B = 'builderB'
53 COLUMN__RENDER_MODE_B = 'renderModeB'
54
50 FREEFORM_COLUMN_IDS = [ 55 FREEFORM_COLUMN_IDS = [
51 COLUMN__SOURCE_SKP, 56 COLUMN__SOURCE_SKP,
52 COLUMN__TILENUM, 57 COLUMN__TILENUM,
53 ] 58 ]
54 ORDERED_COLUMN_IDS = [ 59 ORDERED_COLUMN_IDS = [
55 COLUMN__RESULT_TYPE, 60 COLUMN__RESULT_TYPE,
56 COLUMN__SOURCE_SKP, 61 COLUMN__SOURCE_SKP,
57 COLUMN__TILED_OR_WHOLE, 62 COLUMN__TILED_OR_WHOLE,
58 COLUMN__TILENUM, 63 COLUMN__TILENUM,
64 COLUMN__BUILDER_A,
65 COLUMN__RENDER_MODE_A,
66 COLUMN__BUILDER_B,
67 COLUMN__RENDER_MODE_B,
59 ] 68 ]
60 69
61 # A special "repo:" URL type that we use to refer to Skia repo contents. 70 # A special "repo:" URL type that we use to refer to Skia repo contents.
62 # (Useful for comparing against expectations files we store in our repo.) 71 # (Useful for comparing against expectations files we store in our repo.)
63 REPO_URL_PREFIX = 'repo:' 72 REPO_URL_PREFIX = 'repo:'
64 REPO_BASEPATH = os.path.abspath(os.path.join( 73 REPO_BASEPATH = os.path.abspath(os.path.join(
65 os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir)) 74 os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir))
66 75
67 # Which sections within a JSON summary file can contain results. 76 # Which sections within a JSON summary file can contain results.
68 ALLOWED_SECTION_NAMES = [ 77 ALLOWED_SECTION_NAMES = [
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 (dict_num, num_union_dict_paths, dict_path)) 264 (dict_num, num_union_dict_paths, dict_path))
256 265
257 dictA = self.get_default(setA_dicts, None, dict_path) 266 dictA = self.get_default(setA_dicts, None, dict_path)
258 self._validate_dict_version(dictA) 267 self._validate_dict_version(dictA)
259 dictA_results = self.get_default(dictA, {}, setA_section) 268 dictA_results = self.get_default(dictA, {}, setA_section)
260 269
261 dictB = self.get_default(setB_dicts, None, dict_path) 270 dictB = self.get_default(setB_dicts, None, dict_path)
262 self._validate_dict_version(dictB) 271 self._validate_dict_version(dictB)
263 dictB_results = self.get_default(dictB, {}, setB_section) 272 dictB_results = self.get_default(dictB, {}, setB_section)
264 273
274 get2 = lambda dic, k: None if not dic else \
epoger 2014/08/18 19:56:32 I think this provides a subset of functionality th
stephana 2014/08/18 20:24:53 Done.
275 (dic.get(gm_json.JSONKEY_DESCRIPTIONS, {}) or {}).get(k, None)
276 builder_A = get2(dictA, gm_json.JSONKEY_DESCRIPTIONS_BUILDER)
277 render_mode_A = get2(dictA, gm_json.JSONKEY_DESCRIPTIONS_RENDER_MODE)
278 builder_B = get2(dictB, gm_json.JSONKEY_DESCRIPTIONS_BUILDER)
279 render_mode_B = get2(dictB, gm_json.JSONKEY_DESCRIPTIONS_RENDER_MODE)
280
265 skp_names = sorted(set(dictA_results.keys() + dictB_results.keys())) 281 skp_names = sorted(set(dictA_results.keys() + dictB_results.keys()))
266 # Just for manual testing... truncate to an arbitrary subset. 282 # Just for manual testing... truncate to an arbitrary subset.
267 if self.truncate_results: 283 if self.truncate_results:
268 skp_names = skp_names[1:3] 284 skp_names = skp_names[1:3]
269 for skp_name in skp_names: 285 for skp_name in skp_names:
270 imagepairs_for_this_skp = [] 286 imagepairs_for_this_skp = []
271 287
272 whole_image_A = self.get_default( 288 whole_image_A = self.get_default(
273 dictA_results, None, 289 dictA_results, None,
274 skp_name, gm_json.JSONKEY_SOURCE_WHOLEIMAGE) 290 skp_name, gm_json.JSONKEY_SOURCE_WHOLEIMAGE)
275 whole_image_B = self.get_default( 291 whole_image_B = self.get_default(
276 dictB_results, None, 292 dictB_results, None,
277 skp_name, gm_json.JSONKEY_SOURCE_WHOLEIMAGE) 293 skp_name, gm_json.JSONKEY_SOURCE_WHOLEIMAGE)
278 imagepairs_for_this_skp.append(self._create_image_pair( 294 imagepairs_for_this_skp.append(self._create_image_pair(
279 image_dict_A=whole_image_A, image_dict_B=whole_image_B, 295 image_dict_A=whole_image_A, image_dict_B=whole_image_B,
296 builder_A=builder_A, render_mode_A=render_mode_A,
297 builder_B=builder_B, render_mode_B=render_mode_B,
280 source_skp_name=skp_name, tilenum=None)) 298 source_skp_name=skp_name, tilenum=None))
281 299
282 tiled_images_A = self.get_default( 300 tiled_images_A = self.get_default(
283 dictA_results, [], 301 dictA_results, [],
284 skp_name, gm_json.JSONKEY_SOURCE_TILEDIMAGES) 302 skp_name, gm_json.JSONKEY_SOURCE_TILEDIMAGES)
285 tiled_images_B = self.get_default( 303 tiled_images_B = self.get_default(
286 dictB_results, [], 304 dictB_results, [],
287 skp_name, gm_json.JSONKEY_SOURCE_TILEDIMAGES) 305 skp_name, gm_json.JSONKEY_SOURCE_TILEDIMAGES)
288 if tiled_images_A or tiled_images_B: 306 if tiled_images_A or tiled_images_B:
289 num_tiles_A = len(tiled_images_A) 307 num_tiles_A = len(tiled_images_A)
290 num_tiles_B = len(tiled_images_B) 308 num_tiles_B = len(tiled_images_B)
291 num_tiles = max(num_tiles_A, num_tiles_B) 309 num_tiles = max(num_tiles_A, num_tiles_B)
292 for tile_num in range(num_tiles): 310 for tile_num in range(num_tiles):
293 imagepairs_for_this_skp.append(self._create_image_pair( 311 imagepairs_for_this_skp.append(self._create_image_pair(
294 image_dict_A=(tiled_images_A[tile_num] 312 image_dict_A=(tiled_images_A[tile_num]
295 if tile_num < num_tiles_A else None), 313 if tile_num < num_tiles_A else None),
296 image_dict_B=(tiled_images_B[tile_num] 314 image_dict_B=(tiled_images_B[tile_num]
297 if tile_num < num_tiles_B else None), 315 if tile_num < num_tiles_B else None),
316 builder_A=builder_A, render_mode_A=render_mode_A,
317 builder_B=builder_B, render_mode_B=render_mode_B,
298 source_skp_name=skp_name, tilenum=tile_num)) 318 source_skp_name=skp_name, tilenum=tile_num))
299 319
300 for one_imagepair in imagepairs_for_this_skp: 320 for one_imagepair in imagepairs_for_this_skp:
301 if one_imagepair: 321 if one_imagepair:
302 all_image_pairs.add_image_pair(one_imagepair) 322 all_image_pairs.add_image_pair(one_imagepair)
303 result_type = one_imagepair.extra_columns_dict\ 323 result_type = one_imagepair.extra_columns_dict\
304 [COLUMN__RESULT_TYPE] 324 [COLUMN__RESULT_TYPE]
305 if result_type != results.KEY__RESULT_TYPE__SUCCEEDED: 325 if result_type != results.KEY__RESULT_TYPE__SUCCEEDED:
306 failing_image_pairs.add_image_pair(one_imagepair) 326 failing_image_pairs.add_image_pair(one_imagepair)
307 327
(...skipping 25 matching lines...) Expand all
333 header = result_dict[gm_json.JSONKEY_HEADER] 353 header = result_dict[gm_json.JSONKEY_HEADER]
334 header_type = header[gm_json.JSONKEY_HEADER_TYPE] 354 header_type = header[gm_json.JSONKEY_HEADER_TYPE]
335 if header_type != expected_header_type: 355 if header_type != expected_header_type:
336 raise Exception('expected header_type "%s", but got "%s"' % ( 356 raise Exception('expected header_type "%s", but got "%s"' % (
337 expected_header_type, header_type)) 357 expected_header_type, header_type))
338 header_revision = header[gm_json.JSONKEY_HEADER_REVISION] 358 header_revision = header[gm_json.JSONKEY_HEADER_REVISION]
339 if header_revision != expected_header_revision: 359 if header_revision != expected_header_revision:
340 raise Exception('expected header_revision %d, but got %d' % ( 360 raise Exception('expected header_revision %d, but got %d' % (
341 expected_header_revision, header_revision)) 361 expected_header_revision, header_revision))
342 362
343 def _create_image_pair(self, image_dict_A, image_dict_B, source_skp_name, 363 def _create_image_pair(self, image_dict_A, image_dict_B,
364 builder_A, render_mode_A,
365 builder_B, render_mode_B,
366 source_skp_name,
344 tilenum): 367 tilenum):
345 """Creates an ImagePair object for this pair of images. 368 """Creates an ImagePair object for this pair of images.
346 369
347 Args: 370 Args:
348 image_dict_A: dict with JSONKEY_IMAGE_* keys, or None if no image 371 image_dict_A: dict with JSONKEY_IMAGE_* keys, or None if no image
349 image_dict_B: dict with JSONKEY_IMAGE_* keys, or None if no image 372 image_dict_B: dict with JSONKEY_IMAGE_* keys, or None if no image
350 source_skp_name: string; name of the source SKP file 373 source_skp_name: string; name of the source SKP file
epoger 2014/08/18 19:56:32 please document the new args here
stephana 2014/08/18 20:24:53 Done.
351 tilenum: which tile, or None if a wholeimage 374 tilenum: which tile, or None if a wholeimage
352 375
353 Returns: 376 Returns:
354 An ImagePair object, or None if both image_dict_A and image_dict_B are 377 An ImagePair object, or None if both image_dict_A and image_dict_B are
355 None. 378 None.
356 """ 379 """
357 if (not image_dict_A) and (not image_dict_B): 380 if (not image_dict_A) and (not image_dict_B):
358 return None 381 return None
359 382
360 def _checksum_and_relative_url(dic): 383 def _checksum_and_relative_url(dic):
(...skipping 14 matching lines...) Expand all
375 elif not imageB_checksum: 398 elif not imageB_checksum:
376 result_type = results.KEY__RESULT_TYPE__NOCOMPARISON 399 result_type = results.KEY__RESULT_TYPE__NOCOMPARISON
377 elif imageA_checksum == imageB_checksum: 400 elif imageA_checksum == imageB_checksum:
378 result_type = results.KEY__RESULT_TYPE__SUCCEEDED 401 result_type = results.KEY__RESULT_TYPE__SUCCEEDED
379 else: 402 else:
380 result_type = results.KEY__RESULT_TYPE__FAILED 403 result_type = results.KEY__RESULT_TYPE__FAILED
381 404
382 extra_columns_dict = { 405 extra_columns_dict = {
383 COLUMN__RESULT_TYPE: result_type, 406 COLUMN__RESULT_TYPE: result_type,
384 COLUMN__SOURCE_SKP: source_skp_name, 407 COLUMN__SOURCE_SKP: source_skp_name,
408 COLUMN__BUILDER_A: builder_A,
409 COLUMN__RENDER_MODE_A: render_mode_A,
410 COLUMN__BUILDER_B: builder_B,
411 COLUMN__RENDER_MODE_B: render_mode_B,
385 } 412 }
386 if tilenum == None: 413 if tilenum == None:
387 extra_columns_dict[COLUMN__TILED_OR_WHOLE] = 'whole' 414 extra_columns_dict[COLUMN__TILED_OR_WHOLE] = 'whole'
388 extra_columns_dict[COLUMN__TILENUM] = 'N/A' 415 extra_columns_dict[COLUMN__TILENUM] = 'N/A'
389 else: 416 else:
390 extra_columns_dict[COLUMN__TILED_OR_WHOLE] = 'tiled' 417 extra_columns_dict[COLUMN__TILED_OR_WHOLE] = 'tiled'
391 extra_columns_dict[COLUMN__TILENUM] = str(tilenum) 418 extra_columns_dict[COLUMN__TILENUM] = str(tilenum)
392 419
393 try: 420 try:
394 return imagepair.ImagePair( 421 return imagepair.ImagePair(
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 if source_dir.lower().startswith(REPO_URL_PREFIX): 468 if source_dir.lower().startswith(REPO_URL_PREFIX):
442 repo_dir = os.path.join(REPO_BASEPATH, source_dir[len(REPO_URL_PREFIX):]) 469 repo_dir = os.path.join(REPO_BASEPATH, source_dir[len(REPO_URL_PREFIX):])
443 revision = subprocess.check_output( 470 revision = subprocess.check_output(
444 args=[git_utils.GIT, 'rev-parse', 'HEAD'], cwd=repo_dir).strip() 471 args=[git_utils.GIT, 'rev-parse', 'HEAD'], cwd=repo_dir).strip()
445 if assert_if_not and revision != assert_if_not: 472 if assert_if_not and revision != assert_if_not:
446 raise Exception('found revision %s that did not match %s' % ( 473 raise Exception('found revision %s that did not match %s' % (
447 revision, assert_if_not)) 474 revision, assert_if_not))
448 return revision 475 return revision
449 else: 476 else:
450 return None 477 return None
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698