15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Jerkiness performance test for video playback.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Uses jerky tool, (http://go/jerky), to record a jerkiness metric for videos
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sensitive to jerkiness.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Jerkiness is defined as a percentage of the average on screen frame time by the
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)formula below.  Where smoothed_frame_time[i] represents a frame's on screen time
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)plus amortized measurement gap error (time taken to capture each frame).
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sqrt(average((avg_frame_time - smoothed_frame_time[i])^2, i=m..n))
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)------------------------------------------------------------------
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          avg_frame_time
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Currently, only the Linux binaries are checked in for this test since we only
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)have a Linux performance bot.  The current binary is a custom build with some
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)fixes from veganjerky (http://go/veganjerky) for timing, waiting, and stdout
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)flushing.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TODO(dalecurtis): Move Jerky tool sources into the Chromium tree.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TODO(dalecurtis): Jerky tool uses a questionable method for determining torn
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)frames, determine if it is actually worth recording.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import glob
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import tempfile
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import pyauto_media
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import pyauto
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import pyauto_utils
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# HTML test path; relative to src/chrome/test/data.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_TEST_HTML_PATH = os.path.join('media', 'html', 'media_jerky.html')
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Path under data path for test files.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_TEST_MEDIA_PATH = os.path.join('pyauto_private', 'media', 'birds')
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Path to Jerky tool executable.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_JERKY_PATH = os.path.join('pyauto_private', 'media', 'tools', 'jerky')
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Regular expression for extracting jerkiness percentage.  Sample line:
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   using 1:9 title 'test.log (35.36% jerky, 0 teared frames)' lw 2 with lines
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_JERKY_LOG_REGEX = re.compile(
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    r'\((\d{0,3}\.?\d{0,2})% jerky, (\d+) teared frames\)')
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Regular expression for extracting computed fps.  Sample line:
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# INFO: 33797 us per frame => 29.6 fps.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_JERKY_LOG_FPS_REGEX = re.compile(r' => (\d+\.\d+) fps')
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Minimum and maximum number of iterations for each test.  Due to timing issues
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the jerky tool may not always calculate the fps correctly.  When invalid
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# results are detected, the test is rerun up to the maxium # of times set below.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_JERKY_ITERATIONS_MIN = 3
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_JERKY_ITERATIONS_MAX = 10
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The media files used for testing.  Each entry represents a tuple of (filename,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# width, height, fps).  The width and height are used to create a calibration
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# pattern for jerky tool.  The fps is used to ensure Jerky tool computed a valid
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# result.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_TEST_VIDEOS = [('birds540.webm', 960, 540, 29.9)]
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetTempFilename():
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns an absolute path to an empty temp file."""
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  f, path = tempfile.mkstemp(prefix='jerky_tmp')
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  os.close(f)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return path
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MediaJerkyPerfTest(pyauto.PyUITest):
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """PyAuto test container.  See file doc string for more information."""
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def StartJerkyCapture(self):
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Starts jerky tool in capture mode and waits until its ready to capture.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A tuple of the jerky process and an absolute path to the capture log.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jerky_log = GetTempFilename()
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug('Logging data to %s', jerky_log)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    process = subprocess.Popen(
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        [os.path.join(self.DataDir(), _JERKY_PATH),
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         'capture', '--log', jerky_log],
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stdout=subprocess.PIPE)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Set the jerky tool process to soft-realtime w/ round-robin scheduling.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    subprocess.check_call(['sudo', 'chrt', '-r', '-p', str(process.pid)])
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Wait for server to start up.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    line = True
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while line:
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      line = process.stdout.readline()
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'Waiting for calibration pattern to disappear' in line:
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return process, jerky_log
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.fail('Failed to launch Jerky tool.')
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AnalyzeJerkyCapture(self, jerky_log):
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Run jerky analyze on the specified log and return various metrics.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Once analyze has completed, the jerky_log and associated outputs will be
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    removed.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jerky_log: Absolute path to the capture log.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Tuple of fps, jerkiness, and torn frames.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    results_log_base = GetTempFilename()
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    process = subprocess.Popen(
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        [os.path.join(self.DataDir(), _JERKY_PATH),
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         'analyze', '--ref', jerky_log, '--out', results_log_base],
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stdout=subprocess.PIPE)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Wait for process to end w/o risking deadlock.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stdout = process.communicate()[0]
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEquals(process.returncode, 0)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Scrape out the calculated FPS.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fps_match = None
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for line in stdout.splitlines():
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fps_match = _JERKY_LOG_FPS_REGEX.search(line)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if fps_match:
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Open *.error.gnuplot and scrape out jerkiness.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jerky_match = None
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    with open('%s.error.gnuplot' % results_log_base) as results:
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for line in results:
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        jerky_match = _JERKY_LOG_REGEX.search(line)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if jerky_match:
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Cleanup all the temp and results files jerky spits out.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for log in glob.glob('%s*' % results_log_base) + [jerky_log]:
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.unlink(log)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if fps_match and jerky_match:
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return (float(fps_match.group(1)), float(jerky_match.group(1)),
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              int(jerky_match.group(2)))
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return None, None, None
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testMediaJerkyPerformance(self):
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Launches Jerky tool and records jerkiness for HTML5 videos.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    For each video, the test starts up jerky tool then plays until the Jerky
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tool collects enough information.  Next the capture log is analyzed using
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Jerky's analyze command.  If the computed fps matches the expected fps the
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jerkiness metric is recorded.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The test will run up to _JERKY_ITERATIONS_MAX times in an attempt to get at
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    least _JERKY_ITERATIONS_MIN valid values.  The results are recorded under
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the 'jerkiness' variable for graphing on the bots.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.NavigateToURL(self.GetFileURLForDataPath(_TEST_HTML_PATH))
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Xvfb on the bots is restricted to 1024x768 at present.  Ensure we're using
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # all of the real estate we can.  Jerky tool needs a clear picture of every
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # frame, so we can't clip the video in any way.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetWindowDimensions(0, 0, 1024, 768)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for name, width, height, expected_fps in _TEST_VIDEOS:
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jerkiness = []
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      torn_frames = []
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_url = self.GetFileURLForDataPath(
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          os.path.join(_TEST_MEDIA_PATH, name))
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Initialize the calibration area for Jerky tool.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.assertTrue(self.ExecuteJavascript(
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'initializeTest(%d, %d);' % (width, height)))
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      runs_left = _JERKY_ITERATIONS_MIN
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      runs_total = 0
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while runs_left > 0 and runs_total < _JERKY_ITERATIONS_MAX:
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        runs_total += 1
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.info('Running Jerky perf test #%d for %s.', runs_total, name)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Startup Jerky tool in capture mode.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        jerky_process, jerky_log = self.StartJerkyCapture()
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Start playback of the test video.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.assertTrue(self.ExecuteJavascript("startTest('%s');" % file_url))
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Wait for jerky tool to finish if it hasn't already.
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.assertTrue(jerky_process.wait() == 0)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Stop playback of the test video so the next run can cleanly find the
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # calibration zone.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.assertTrue(self.ExecuteJavascript('stopTest();'))
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Analyze the results.
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        jerky_fps, jerky_percent, jerky_torn_frames = self.AnalyzeJerkyCapture(
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            jerky_log)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (jerky_fps is None or jerky_percent is None or
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            jerky_torn_frames is None):
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          logging.error('No metrics recorded for this run.')
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Ensure the results for this run are valid.
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if jerky_fps != expected_fps:
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          logging.error(
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'Invalid fps detected (actual: %f, expected: %f, jerkiness: %f). '
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'Discarding results for this run.', jerky_fps, expected_fps,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              jerky_percent)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        jerkiness.append(jerky_percent)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        torn_frames.append(jerky_torn_frames)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        runs_left -= 1
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_utils.PrintPerfResult('jerkiness', name, jerkiness, '%')
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pyauto_media.Main()
225