예제 #1
0
  def MeasurePage(self, page, tab, results):
    # Exit if threaded forced compositing is not enabled.
    if (not self._compositing_features_enabled):
      logging.warning('Warning: compositing feature status unknown or not '+
                      'forced and threaded. Skipping measurement.')
      sys.exit(0)

    # Rasterize only what's visible.
    tab.ExecuteJavaScript(
        'chrome.gpuBenchmarking.setRasterizeOnlyVisibleContent();')

    # Wait until the page has loaded and come to a somewhat steady state.
    # Needs to be adjusted for every device (~2 seconds for workstation).
    time.sleep(float(self.options.start_wait_time))

    # Render one frame before we start gathering a trace. On some pages, the
    # first frame requested has more variance in the number of pixels
    # rasterized.
    tab.ExecuteJavaScript(
        'window.__rafFired = false;'
        'window.webkitRequestAnimationFrame(function() {'
          'chrome.gpuBenchmarking.setNeedsDisplayOnAllLayers();'
          'window.__rafFired  = true;'
        '});')

    time.sleep(float(self.options.stop_wait_time))
    tab.browser.StartTracing('webkit.console,benchmark', 60)

    tab.ExecuteJavaScript(
        'window.__rafFired = false;'
        'window.webkitRequestAnimationFrame(function() {'
          'chrome.gpuBenchmarking.setNeedsDisplayOnAllLayers();'
          'console.time("' + TIMELINE_MARKER + '");'
          'window.__rafFired  = true;'
        '});')
    # Wait until the frame was drawn.
    # Needs to be adjusted for every device and for different
    # raster_record_repeat counts.
    # TODO(ernstm): replace by call-back.
    time.sleep(float(self.options.stop_wait_time))
    tab.ExecuteJavaScript(
        'console.timeEnd("' + TIMELINE_MARKER + '")')

    timeline = tab.browser.StopTracing().AsTimelineModel()
    try:
      timeline_markers = timeline.FindTimelineMarkers(TIMELINE_MARKER)
    except (MarkerMismatchError, MarkerOverlapError) as e:
      raise page_measurement.MeasurementFailure(str(e))
    renderer_process = timeline.GetRendererProcessFromTab(tab)
    stats = rendering_stats.RenderingStats(renderer_process, timeline_markers)

    results.Add('rasterize_time', 'ms',
                max(stats.rasterize_time))
    results.Add('record_time', 'ms',
                max(stats.record_time))
    results.Add('rasterized_pixels', 'pixels',
                max(stats.rasterized_pixel_count))
    results.Add('recorded_pixels', 'pixels',
                max(stats.recorded_pixel_count))
예제 #2
0
    def AddResults(self, model, renderer_thread, interaction_record, results):
        renderer_process = renderer_thread.parent
        time_bounds = bounds.Bounds()
        time_bounds.AddValue(interaction_record.start)
        time_bounds.AddValue(interaction_record.end)
        stats = rendering_stats.RenderingStats(renderer_process,
                                               model.browser_process,
                                               [time_bounds])
        if stats.mouse_wheel_scroll_latency:
            mean_mouse_wheel_scroll_latency = statistics.ArithmeticMean(
                stats.mouse_wheel_scroll_latency)
            mouse_wheel_scroll_latency_discrepancy = statistics.DurationsDiscrepancy(
                stats.mouse_wheel_scroll_latency)
            results.Add('mean_mouse_wheel_scroll_latency', 'ms',
                        round(mean_mouse_wheel_scroll_latency, 3))
            results.Add('mouse_wheel_scroll_latency_discrepancy', '',
                        round(mouse_wheel_scroll_latency_discrepancy, 4))

        if stats.touch_scroll_latency:
            mean_touch_scroll_latency = statistics.ArithmeticMean(
                stats.touch_scroll_latency)
            touch_scroll_latency_discrepancy = statistics.DurationsDiscrepancy(
                stats.touch_scroll_latency)
            results.Add('mean_touch_scroll_latency', 'ms',
                        round(mean_touch_scroll_latency, 3))
            results.Add('touch_scroll_latency_discrepancy', '',
                        round(touch_scroll_latency_discrepancy, 4))

        if stats.js_touch_scroll_latency:
            mean_js_touch_scroll_latency = statistics.ArithmeticMean(
                stats.js_touch_scroll_latency)
            js_touch_scroll_latency_discrepancy = statistics.DurationsDiscrepancy(
                stats.js_touch_scroll_latency)
            results.Add('mean_js_touch_scroll_latency', 'ms',
                        round(mean_js_touch_scroll_latency, 3))
            results.Add('js_touch_scroll_latency_discrepancy', '',
                        round(js_touch_scroll_latency_discrepancy, 4))

        # List of raw frame times.
        frame_times = FlattenList(stats.frame_times)
        results.Add('frame_times', 'ms', frame_times)

        # Arithmetic mean of frame times.
        mean_frame_time = statistics.ArithmeticMean(frame_times)
        results.Add('mean_frame_time', 'ms', round(mean_frame_time, 3))

        # Absolute discrepancy of frame time stamps.
        frame_discrepancy = statistics.TimestampsDiscrepancy(
            stats.frame_timestamps)
        results.Add('jank', 'ms', round(frame_discrepancy, 4))

        # Are we hitting 60 fps for 95 percent of all frames?
        # We use 19ms as a somewhat looser threshold, instead of 1000.0/60.0.
        percentile_95 = statistics.Percentile(frame_times, 95.0)
        results.Add('mostly_smooth', 'score',
                    1.0 if percentile_95 < 19.0 else 0.0)
예제 #3
0
    def Stop(self, page, tab):
        if tab.browser.platform.IsRawDisplayFrameRateSupported():
            tab.browser.platform.StopRawDisplayFrameRateMeasurement()
        tab.ExecuteJavaScript('console.timeEnd("' + TIMELINE_MARKER + '")')
        timeline_model = tab.browser.StopTracing().AsTimelineModel()
        timeline_ranges = [
            action.GetActiveRangeOnTimeline(timeline_model)
            for action in self._actions
        ]

        renderer_process = timeline_model.GetRendererProcessFromTab(tab)
        self._stats = rendering_stats.RenderingStats(
            renderer_process, timeline_model.browser_process, timeline_ranges)

        if not self._stats.frame_times:
            raise NotEnoughFramesError()
예제 #4
0
    def Stop(self, page, tab):
        tab.ExecuteJavaScript('console.timeEnd("' + TIMELINE_MARKER + '")')
        timeline_model = tab.browser.StopTracing().AsTimelineModel()
        try:
            timeline_markers = timeline_model.FindTimelineMarkers(
                self._timeline_marker_names)
        except MarkerMismatchError as e:
            raise page_measurement.MeasurementFailure(str(e))
        except MarkerOverlapError as e:
            raise page_measurement.MeasurementFailure(str(e))

        renderer_process = timeline_model.GetRendererProcessFromTab(tab)
        self._stats = rendering_stats.RenderingStats(renderer_process,
                                                     timeline_markers)

        if not self._stats.frame_times:
            raise NotEnoughFramesError()
예제 #5
0
  def Stop(self, page, tab):
    tab.ExecuteJavaScript('console.timeEnd("' + TIMELINE_MARKER + '")')
    timeline_model = tab.browser.StopTracing().AsTimelineModel()
    render_process_marker = timeline_model.FindTimelineMarkers(TIMELINE_MARKER)
    timeline_marker_labels = GetTimelineMarkerLabelsFromAction(
        self._compound_action)
    try:
      timeline_markers = timeline_model.FindTimelineMarkers(
          timeline_marker_labels)
    except MarkerMismatchError:
      # TODO(ernstm): re-raise exception as MeasurementFailure when the
      # reference build was updated.
      timeline_markers = render_process_marker
    except MarkerOverlapError as e:
      raise page_measurement.MeasurementFailure(str(e))

    self._stats = rendering_stats.RenderingStats(
        render_process_marker, timeline_markers)

    if not self._stats.frame_times:
      raise NotEnoughFramesError()
예제 #6
0
    def testCalcResultsTraceEvents(self):
        # Make the test repeatable by seeding the random number generator
        # (which is used by the mock timer) with a constant number.
        random.seed(1234567)
        mock_timer = MockTimer()
        trace_events = []
        total_time_seconds = 0.0
        num_frames_sent = 0.0
        first_frame = True
        previous_frame_time = None
        # This list represents time differences between frames in milliseconds.
        expected_frame_times = []

        # Append start trace events for the timeline marker and gesture marker,
        # with some amount of time in between them.
        trace_events.append({
            'name': RENDERER_PROCESS_MARKER,
            'tts': mock_timer.microseconds,
            'args': {},
            'pid': 20978,
            'ts': mock_timer.microseconds,
            'cat': 'webkit',
            'tid': 11,
            'ph': 'S',  # Phase: start.
            'id': '0x12345'
        })
        mock_timer.Advance()
        trace_events.append({
            'name': SYNTHETIC_GESTURE_MARKER,
            'tts': mock_timer.microseconds,
            'args': {},
            'pid': 20978,
            'ts': mock_timer.microseconds,
            'cat': 'webkit',
            'tid': 11,
            'ph': 'S',
            'id': '0xabcde'
        })

        # Generate 100 random mock frames and append their trace events.
        for _ in xrange(0, 100):
            mock_frame = MockFrame(mock_timer)
            mock_frame.AppendTraceEventForMainThreadStats(trace_events)
            mock_frame.AppendTraceEventForImplThreadStats(trace_events)
            # Exclude the first frame, because it may have started before the
            # benchmark run.
            if not first_frame:
                total_time_seconds += mock_frame.duration / 1e6
                num_frames_sent += mock_frame.main_stats['frame_count']
                num_frames_sent += mock_frame.impl_stats['frame_count']
            first_frame = False
            current_frame_time = mock_timer.microseconds / 1000.0
            if previous_frame_time:
                difference = current_frame_time - previous_frame_time
                difference = round(difference, 2)
                expected_frame_times.append(difference)
            previous_frame_time = current_frame_time

        # Append finish trace events for the timeline and gesture markers, in the
        # reverse order from how they were added, with some time in between.
        trace_events.append({
            'name': SYNTHETIC_GESTURE_MARKER,
            'tts': mock_timer.microseconds,
            'args': {},
            'pid': 20978,
            'ts': mock_timer.microseconds,
            'cat': 'webkit',
            'tid': 11,
            'ph': 'F',  # Phase: finish.
            'id': '0xabcde'
        })
        mock_timer.Advance()
        trace_events.append({
            'name': RENDERER_PROCESS_MARKER,
            'tts': mock_timer.microseconds,
            'args': {},
            'pid': 20978,
            'ts': mock_timer.microseconds,
            'cat': 'webkit',
            'tid': 11,
            'ph': 'F',
            'id': '0x12345'
        })

        # Create a timeline object from the trace.
        trace_result = TraceResult(ChromeRawTraceResult(trace_events))
        timeline = trace_result.AsTimelineModel()

        # Find the timeline marker and gesture marker in the timeline,
        # and create a RenderingStats object.
        renderer_process_markers = timeline.FindTimelineMarkers(
            RENDERER_PROCESS_MARKER)
        self.assertEquals(len(renderer_process_markers), 1)
        renderer_process = renderer_process_markers[0].start_thread.parent
        timeline_markers = timeline.FindTimelineMarkers(
            SYNTHETIC_GESTURE_MARKER)
        stats = rendering_stats.RenderingStats(renderer_process,
                                               timeline_markers)

        # Make a results object and add results to it from the smoothness metric.
        results = PageMeasurementResults()
        results.WillMeasurePage(page.Page('http://foo.com/', None))
        smoothness_metric = smoothness.SmoothnessMetric(None)
        smoothness_metric.SetStats(stats)
        smoothness_metric.AddResults(None, results)
        results.DidMeasurePage()

        self.assertEquals(expected_frame_times,
                          results.page_results[0]['frame_times'].value)
        self.assertAlmostEquals(
            1000.0 * (total_time_seconds / num_frames_sent),
            results.page_results[0]['mean_frame_time'].value,
            places=2)

        # We don't verify the correctness of the discrepancy computation itself,
        # because we have a separate unit test for that purpose.
        self.assertAlmostEquals(statistics.FrameDiscrepancy(
            stats.frame_timestamps, True),
                                results.page_results[0]['jank'].value,
                                places=4)

        # We do not verify the correctness of Percentile here; Percentile should
        # have its own test.
        # The 17 here represents a threshold of 17 ms; this should match the value
        # in the smoothness metric.
        self.assertEquals(
            statistics.Percentile(expected_frame_times, 95.0) < 17.0,
            results.page_results[0]['mostly_smooth'].value)
예제 #7
0
  def MeasurePage(self, page, tab, results):
    # Exit if threaded forced compositing is not enabled.
    if (not self._compositing_features_enabled):
      logging.warning('Warning: compositing feature status unknown or not '+
                      'forced and threaded. Skipping measurement.')
      sys.exit(0)

    # TODO(ernstm): Remove this temporary workaround when reference build has
    # been updated to branch 1671 or later.
    backend = tab.browser._browser_backend # pylint: disable=W0212
    if (not hasattr(backend, 'chrome_branch_number') or
        (sys.platform != 'android' and backend.chrome_branch_number < 1671)):
      print ('Warning: rasterize_and_record requires Chrome branch 1671 or '
             'later. Skipping measurement.')
      sys.exit(0)

    # Rasterize only what's visible.
    tab.ExecuteJavaScript(
        'chrome.gpuBenchmarking.setRasterizeOnlyVisibleContent();')

    # Wait until the page has loaded and come to a somewhat steady state.
    # Needs to be adjusted for every device (~2 seconds for workstation).
    time.sleep(float(self.options.start_wait_time))

    # Render one frame before we start gathering a trace. On some pages, the
    # first frame requested has more variance in the number of pixels
    # rasterized.
    tab.ExecuteJavaScript(
        'window.__rafFired = false;'
        'window.webkitRequestAnimationFrame(function() {'
          'chrome.gpuBenchmarking.setNeedsDisplayOnAllLayers();'
          'window.__rafFired  = true;'
        '});')

    time.sleep(float(self.options.stop_wait_time))
    tab.browser.StartTracing('webkit.console,benchmark', 60)

    tab.ExecuteJavaScript(
        'window.__rafFired = false;'
        'window.webkitRequestAnimationFrame(function() {'
          'chrome.gpuBenchmarking.setNeedsDisplayOnAllLayers();'
          'console.time("' + rendering_stats.RENDER_PROCESS_MARKER + '");'
          'window.__rafFired  = true;'
        '});')
    # Wait until the frame was drawn.
    # Needs to be adjusted for every device and for different
    # raster_record_repeat counts.
    # TODO(ernstm): replace by call-back.
    time.sleep(float(self.options.stop_wait_time))
    tab.ExecuteJavaScript(
        'console.timeEnd("' + rendering_stats.RENDER_PROCESS_MARKER + '")')

    timeline = tab.browser.StopTracing().AsTimelineModel()
    try:
      timeline_markers = timeline.FindTimelineMarkers(
          rendering_stats.RENDER_PROCESS_MARKER)
    except (MarkerMismatchError, MarkerOverlapError) as e:
      raise page_measurement.MeasurementFailure(str(e))
    stats = rendering_stats.RenderingStats(timeline_markers, timeline_markers)

    results.Add('rasterize_time', 'ms',
                max(stats.rasterize_time))
    results.Add('record_time', 'ms',
                max(stats.record_time))
    results.Add('rasterized_pixels', 'pixels',
                max(stats.rasterized_pixel_count))
    results.Add('recorded_pixels', 'pixels',
                max(stats.recorded_pixel_count))