OLD | NEW |
---|---|
(Empty) | |
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 import logging | |
5 | |
6 from telemetry.web_perf.metrics import timeline_based_metric | |
7 from telemetry.web_perf import timeline_interaction_record as tir_module | |
8 | |
9 # A top slice (defined below) of a main thread can cause the webapp to behave | |
10 # unresponsively if its thread duration is greater than or equals to | |
11 # USER_PERCEIVABLE_DELAY_THRESHOLD_MS. Human eyes can perceive delay at low as | |
12 # 100ms, but since we use thread time instead of wall-time, we reduce the | |
13 # threshold further to 50ms to make room for other OS's activity. | |
14 USER_PERCEIVABLE_DELAY_THRESHOLD_MS = 50 | |
15 | |
16 | |
17 def _IsTopSlice(event): | |
18 """Whether event refers to a top MessageLoop task, i.e: there is no | |
19 other MessageLoop task on top of this task and contains it. | |
20 | |
21 Returns: | |
22 True if this timeline event refers to the top MesssageLoop task. | |
23 False otherwise. | |
24 """ | |
25 return event.name == 'MessageLoop::RunTask' and event.category == 'toplevel' | |
26 | |
27 | |
28 class _MainthreadJankStat(object): | |
29 """A small wrapper class for storing stats related to mainthread jank.""" | |
30 | |
31 def __init__(self): | |
32 self.num_big_top_slices = 0 | |
33 self.sum_top_slices_thread_time = 0 | |
34 self.sum_big_top_slices_thread_time = 0 | |
35 self.biggest_top_slice_thread_time = 0 | |
36 | |
37 | |
38 def _ComputeMainthreadJankStats(renderer_thread, record): | |
39 """Computes the mainthread jank stat on the record range. | |
40 | |
41 Returns: | |
42 An instance of _MainthreadJankStat, which has: | |
43 | |
44 num_big_top_slices is the number of top slices whose thread time ranges | |
45 overlapped with (thread_start, thread_end) and the overlapped thread | |
46 duration is greater than or equal USER_PERCEIVABLE_DELAY_THRESHOLD_MS. | |
47 | |
48 sum_top_slices_thread_time is the total thread duration of all top slices | |
49 whose thread time ranges overlapped with the (thread_start, thread_end) | |
50 time of record. | |
51 | |
52 sum_big_top_slices_thread_time is the total thread duration of all top | |
53 slices whose thread time ranges overlapped with (thread_start, thread_end) | |
54 and the overlapped thread duration is greater than or equal | |
55 USER_PERCEIVABLE_DELAY_THRESHOLD_MS. | |
56 | |
57 biggest_top_slice_thread_time is the biggest thread duration of all | |
58 top slices whose thread time ranges overlapped with | |
59 (thread_start, thread_end). | |
60 | |
61 Note: thread duration of each slices is computed using overlapped range | |
62 with (thread_start, thread_end). | |
63 """ | |
64 stat = _MainthreadJankStat() | |
65 # If a slice overlaps with record in thread time, it will also overlap with | |
66 # the record in wall-time. Hence we can iterate through all slices that | |
67 # overlap with record's start & end in wall time. | |
68 for s in renderer_thread.IterAllSlicesOverlappedWithTimeRange( | |
69 record.start, record.end): | |
70 if not _IsTopSlice(s): | |
nduca
2014/05/29 23:33:12
so we have "toplevel slices" on a thread that are
nednguyen
2014/05/30 16:38:26
Done. I just iterate through all the top slices. I
| |
71 continue | |
72 jank_thread_duration = record.GetOverlappedThreadTimeForSlice(s) | |
73 stat.sum_top_slices_thread_time += jank_thread_duration | |
74 stat.biggest_top_slice_thread_time = max( | |
75 stat.biggest_top_slice_thread_time, jank_thread_duration) | |
76 if jank_thread_duration >= USER_PERCEIVABLE_DELAY_THRESHOLD_MS: | |
77 stat.num_big_top_slices += 1 | |
78 stat.sum_big_top_slices_thread_time += jank_thread_duration | |
79 return stat | |
80 | |
81 | |
82 class MainthreadJankMetric(timeline_based_metric.TimelineBasedMetric): | |
83 """Computes the mainthread jank metrics on the record ranges. | |
84 | |
85 num_big_mainthread_jank is the number of top slices whose thread time | |
86 ranges overlapped with any thread time ranges of the records and the | |
87 overlapped thread duration is greater than or equal | |
88 USER_PERCEIVABLE_DELAY_THRESHOLD_MS. | |
89 | |
90 total_mainthread_jank_thread_time is the total thread duration of all top | |
91 slices whose thread time ranges overlapped with any thread time ranges of | |
92 the records. | |
93 | |
94 total_big_jank_thread_time is the total thread duration of all top | |
95 slices whose thread time ranges overlapped with any thread time ranges of | |
96 the records and the overlapped thread duration is greater than or equal | |
97 USER_PERCEIVABLE_DELAY_THRESHOLD_MS. | |
98 | |
99 biggest_jank_thread_time is the biggest thread duration of all | |
100 top slices whose thread time ranges overlapped with any of records' thread | |
101 time ranges. | |
102 """ | |
103 | |
104 def __init__(self): | |
105 super(MainthreadJankMetric, self).__init__() | |
106 | |
107 def AddResults(self, _, renderer_thread, interaction_records, results): | |
108 self.VerifyNonOverlappedRecords(interaction_records) | |
109 num_big_janks = 0 | |
110 total_mainthread_jank_thread_time = 0 | |
111 total_big_jank_thread_time = 0 | |
112 biggest_jank_thread_time = 0 | |
113 | |
114 try: | |
115 for record in interaction_records: | |
116 record_jank_stat = _ComputeMainthreadJankStats(renderer_thread, record) | |
117 num_big_janks += record_jank_stat.num_big_top_slices | |
118 total_mainthread_jank_thread_time += ( | |
119 record_jank_stat.sum_top_slices_thread_time) | |
120 total_big_jank_thread_time += ( | |
121 record_jank_stat.sum_big_top_slices_thread_time) | |
122 biggest_jank_thread_time = ( | |
123 max(biggest_jank_thread_time, | |
124 record_jank_stat.biggest_top_slice_thread_time)) | |
125 # TODO(nednguyen): maybe fall back to use wall-time for computing the | |
126 # metrics. | |
127 except tir_module.NoThreadTimeDataException as e: | |
128 logging.warning( | |
129 'Main thread jank metrics cannot be computed since trace does not ' | |
nduca
2014/05/29 23:33:12
this is going to spam the console hugely... can yo
nednguyen
2014/05/30 16:38:26
By hugely, do you mean one log line per list of re
| |
130 'contain thread time data. %s', repr(e)) | |
131 return | |
132 | |
133 results.Add('num_big_mainthread_janks', 'score', num_big_janks) | |
nduca
2014/05/29 23:33:12
are these all important? can you please pick 1 tha
nednguyen
2014/05/30 16:38:26
I think num_big_mainthread_janks and total_big_jan
| |
134 results.Add('total_mainthread_jank_thread_time', 'ms', | |
135 total_mainthread_jank_thread_time) | |
136 results.Add('total_big_jank_thread_time', 'ms', | |
137 total_big_jank_thread_time) | |
138 results.Add('biggest_jank_thread_time', 'ms', biggest_jank_thread_time) | |
OLD | NEW |