Chromium Code Reviews| 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 |