1# Copyright 2014 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
6# A top level slice of a main thread can cause the webapp to behave
7# unresponsively if its thread duration is greater than or equals to
8# USER_PERCEIVABLE_DELAY_THRESHOLD_MS. Human eyes can perceive delay at low as
9# 100ms, but since we use thread time instead of wall-time, we reduce the
10# threshold further to 50ms to make room for other OS's activities.
11USER_PERCEIVABLE_DELAY_THRESHOLD_MS = 50
12
13
14class _MainthreadJankStat(object):
15  """A small wrapper class for storing mainthread jank stats computed for
16  single record.
17  """
18
19  def __init__(self):
20    self.sum_big_top_slices_thread_time = 0
21    self.biggest_top_slice_thread_time = 0
22
23
24def _ComputeMainthreadJankStatsForRecord(renderer_thread, record):
25  """Computes the mainthread jank stat on a record range.
26
27  Returns:
28      An instance of _MainthreadJankStat, which has:
29
30      sum_big_top_slices_thread_time is the total thread duration of all top
31      slices whose thread time ranges overlapped with (thread_start, thread_end)
32      and the overlapped thread duration is greater than or equal
33      USER_PERCEIVABLE_DELAY_THRESHOLD_MS.
34
35      biggest_top_slice_thread_time is the biggest thread duration of all
36      top slices whose thread time ranges overlapped with
37      (thread_start, thread_end).
38
39      Note: thread duration of each slices is computed using overlapped range
40      with (thread_start, thread_end).
41  """
42  stat = _MainthreadJankStat()
43  for s in renderer_thread.toplevel_slices:
44    jank_thread_duration = record.GetOverlappedThreadTimeForSlice(s)
45    stat.biggest_top_slice_thread_time = max(
46        stat.biggest_top_slice_thread_time, jank_thread_duration)
47    if jank_thread_duration >= USER_PERCEIVABLE_DELAY_THRESHOLD_MS:
48      stat.sum_big_top_slices_thread_time += jank_thread_duration
49  return stat
50
51
52class MainthreadJankStats(object):
53  """
54    Utility class for extracting main thread jank statistics from the timeline
55    (or other loggin facilities), and providing them in a common format to
56    classes that compute benchmark metrics from this data.
57
58      total_big_jank_thread_time is the total thread duration of all top
59      slices whose thread time ranges overlapped with any thread time ranges of
60      the records and the overlapped thread duration is greater than or equal
61      USER_PERCEIVABLE_DELAY_THRESHOLD_MS.
62
63      biggest_jank_thread_time is the biggest thread duration of all
64      top slices whose thread time ranges overlapped with any of records' thread
65      time ranges.
66  """
67
68  def __init__(self, renderer_thread, interaction_records):
69    self._renderer_thread = renderer_thread
70    self._interaction_records = interaction_records
71    self._total_big_jank_thread_time = 0
72    self._biggest_jank_thread_time = 0
73    self._ComputeMainthreadJankStats()
74
75  @property
76  def total_big_jank_thread_time(self):
77    return self._total_big_jank_thread_time
78
79  @property
80  def biggest_jank_thread_time(self):
81    return self._biggest_jank_thread_time
82
83  def _ComputeMainthreadJankStats(self):
84    for record in self._interaction_records:
85      record_jank_stat = _ComputeMainthreadJankStatsForRecord(
86          self._renderer_thread, record)
87      self._total_big_jank_thread_time += (
88          record_jank_stat.sum_big_top_slices_thread_time)
89      self._biggest_jank_thread_time = (
90          max(self._biggest_jank_thread_time,
91              record_jank_stat.biggest_top_slice_thread_time))
92