Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(74)

Side by Side Diff: tools/perf/metrics/timeline.py

Issue 643343002: Telemetry: Add mean-frame-time and tasks-per-frame (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tools/perf/metrics/timeline_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 import collections 4 import collections
5 from telemetry.util.statistics import DivideIfPossibleOrZero
5 6
6 from telemetry.web_perf.metrics import timeline_based_metric 7 from telemetry.web_perf.metrics import timeline_based_metric
7 from telemetry.value import scalar 8 from telemetry.value import scalar
8 9
9 10
10 class LoadTimesTimelineMetric(timeline_based_metric.TimelineBasedMetric): 11 class LoadTimesTimelineMetric(timeline_based_metric.TimelineBasedMetric):
11 def __init__(self): 12 def __init__(self):
12 super(LoadTimesTimelineMetric, self).__init__() 13 super(LoadTimesTimelineMetric, self).__init__()
13 self.report_main_thread_only = True 14 self.report_main_thread_only = True
14 15
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 ReportMainThreadOnly = ["renderer_main"] 94 ReportMainThreadOnly = ["renderer_main"]
94 ReportSilkDetails = ["renderer_main"] 95 ReportSilkDetails = ["renderer_main"]
95 96
96 # TODO(epenner): Thread names above are likely fairly stable but trace names 97 # TODO(epenner): Thread names above are likely fairly stable but trace names
97 # could change. We should formalize these traces to keep this robust. 98 # could change. We should formalize these traces to keep this robust.
98 OverheadTraceCategory = "trace_event_overhead" 99 OverheadTraceCategory = "trace_event_overhead"
99 OverheadTraceName = "overhead" 100 OverheadTraceName = "overhead"
100 FrameTraceName = "::SwapBuffers" 101 FrameTraceName = "::SwapBuffers"
101 FrameTraceThreadName = "renderer_compositor" 102 FrameTraceThreadName = "renderer_compositor"
102 103
104 def Rate(numerator, denominator):
105 return DivideIfPossibleOrZero(numerator, denominator)
103 106
104 def ClockOverheadForEvent(event): 107 def ClockOverheadForEvent(event):
105 if (event.category == OverheadTraceCategory and 108 if (event.category == OverheadTraceCategory and
106 event.name == OverheadTraceName): 109 event.name == OverheadTraceName):
107 return event.duration 110 return event.duration
108 else: 111 else:
109 return 0 112 return 0
110 113
111 def CpuOverheadForEvent(event): 114 def CpuOverheadForEvent(event):
112 if (event.category == OverheadTraceCategory and 115 if (event.category == OverheadTraceCategory and
113 event.thread_duration): 116 event.thread_duration):
114 return event.thread_duration 117 return event.thread_duration
115 else: 118 else:
116 return 0 119 return 0
117 120
118 def ThreadCategoryName(thread_name): 121 def ThreadCategoryName(thread_name):
119 thread_category = "other" 122 thread_category = "other"
120 for substring, category in TimelineThreadCategories.iteritems(): 123 for substring, category in TimelineThreadCategories.iteritems():
121 if substring in _MatchBySubString and substring in thread_name: 124 if substring in _MatchBySubString and substring in thread_name:
122 thread_category = category 125 thread_category = category
123 if thread_name in TimelineThreadCategories: 126 if thread_name in TimelineThreadCategories:
124 thread_category = TimelineThreadCategories[thread_name] 127 thread_category = TimelineThreadCategories[thread_name]
125 return thread_category 128 return thread_category
126 129
127 def ThreadTimeResultName(thread_category): 130 def ThreadCpuTimeResultName(thread_category):
128 return "thread_" + thread_category + "_clock_time_per_frame" 131 # This isn't a good name, but I don't want to change it and lose continuity.
132 return "thread_" + thread_category + "_cpu_time_per_frame"
129 133
130 def ThreadCpuTimeResultName(thread_category): 134 def ThreadTasksResultName(thread_category):
131 return "thread_" + thread_category + "_cpu_time_per_frame" 135 return "tasks_per_frame_" + thread_category
136
137 def ThreadMeanFrameTimeResultName(thread_category):
138 return "mean_frame_time_" + thread_category
132 139
133 def ThreadDetailResultName(thread_category, detail): 140 def ThreadDetailResultName(thread_category, detail):
134 detail_sanitized = detail.replace('.','_') 141 detail_sanitized = detail.replace('.','_')
135 return "thread_" + thread_category + "|" + detail_sanitized 142 return "thread_" + thread_category + "|" + detail_sanitized
136 143
137 144
138 class ResultsForThread(object): 145 class ResultsForThread(object):
139 def __init__(self, model, record_ranges, name): 146 def __init__(self, model, record_ranges, name):
140 self.model = model 147 self.model = model
141 self.toplevel_slices = [] 148 self.toplevel_slices = []
142 self.all_slices = [] 149 self.all_slices = []
143 self.name = name 150 self.name = name
144 self.record_ranges = record_ranges 151 self.record_ranges = record_ranges
152 self.all_action_time = \
153 sum([record_range.bounds for record_range in self.record_ranges])
145 154
146 @property 155 @property
147 def clock_time(self): 156 def clock_time(self):
148 clock_duration = sum([x.duration for x in self.toplevel_slices]) 157 clock_duration = sum([x.duration for x in self.toplevel_slices])
149 clock_overhead = sum([ClockOverheadForEvent(x) for x in self.all_slices]) 158 clock_overhead = sum([ClockOverheadForEvent(x) for x in self.all_slices])
150 return clock_duration - clock_overhead 159 return clock_duration - clock_overhead
151 160
152 @property 161 @property
153 def cpu_time(self): 162 def cpu_time(self):
154 cpu_duration = 0 163 cpu_duration = 0
(...skipping 17 matching lines...) Expand all
172 for record_range in self.record_ranges: 181 for record_range in self.record_ranges:
173 if record_range.ContainsInterval(event.start, event.end): 182 if record_range.ContainsInterval(event.start, event.end):
174 slices_in_actions.append(event) 183 slices_in_actions.append(event)
175 break 184 break
176 return slices_in_actions 185 return slices_in_actions
177 186
178 def AppendThreadSlices(self, thread): 187 def AppendThreadSlices(self, thread):
179 self.all_slices.extend(self.SlicesInActions(thread.all_slices)) 188 self.all_slices.extend(self.SlicesInActions(thread.all_slices))
180 self.toplevel_slices.extend(self.SlicesInActions(thread.toplevel_slices)) 189 self.toplevel_slices.extend(self.SlicesInActions(thread.toplevel_slices))
181 190
191 # Currently we report cpu-time per frame, tasks per frame, and possibly
192 # the mean frame (if there is a trace specified to find it).
182 def AddResults(self, num_frames, results): 193 def AddResults(self, num_frames, results):
183 cpu_per_frame = (float(self.cpu_time) / num_frames) if num_frames else 0 194 cpu_per_frame = Rate(self.cpu_time, num_frames)
195 tasks_per_frame = Rate(len(self.toplevel_slices), num_frames)
184 results.AddValue(scalar.ScalarValue( 196 results.AddValue(scalar.ScalarValue(
185 results.current_page, ThreadCpuTimeResultName(self.name), 197 results.current_page, ThreadCpuTimeResultName(self.name),
186 'ms', cpu_per_frame)) 198 'ms', cpu_per_frame))
199 results.AddValue(scalar.ScalarValue(
200 results.current_page, ThreadTasksResultName(self.name),
201 'tasks', tasks_per_frame))
202 # Report mean frame time if this is the thread we are using for normalizing
203 # other results. We could report other frame rates (eg. renderer_main) but
204 # this might get confusing.
205 if self.name == FrameTraceThreadName:
206 num_frames = self.CountTracesWithName(FrameTraceName)
207 mean_frame_time = Rate(self.all_action_time, num_frames)
208 results.AddValue(scalar.ScalarValue(
209 results.current_page, ThreadMeanFrameTimeResultName(self.name),
210 'ms', mean_frame_time))
187 211
188 def AddDetailedResults(self, num_frames, results): 212 def AddDetailedResults(self, num_frames, results):
189 slices_by_category = collections.defaultdict(list) 213 slices_by_category = collections.defaultdict(list)
190 for s in self.all_slices: 214 for s in self.all_slices:
191 slices_by_category[s.category].append(s) 215 slices_by_category[s.category].append(s)
192 all_self_times = [] 216 all_self_times = []
193 for category, slices_in_category in slices_by_category.iteritems(): 217 for category, slices_in_category in slices_by_category.iteritems():
194 self_time = sum([x.self_time for x in slices_in_category]) 218 self_time = sum([x.self_time for x in slices_in_category])
195 all_self_times.append(self_time) 219 all_self_times.append(self_time)
196 self_time_result = (float(self_time) / num_frames) if num_frames else 0 220 self_time_result = (float(self_time) / num_frames) if num_frames else 0
197 results.AddValue(scalar.ScalarValue( 221 results.AddValue(scalar.ScalarValue(
198 results.current_page, ThreadDetailResultName(self.name, category), 222 results.current_page, ThreadDetailResultName(self.name, category),
199 'ms', self_time_result)) 223 'ms', self_time_result))
200 all_measured_time = sum(all_self_times) 224 all_measured_time = sum(all_self_times)
201 all_action_time = \ 225 idle_time = max(0, self.all_action_time - all_measured_time)
202 sum([record_range.bounds for record_range in self.record_ranges])
203 idle_time = max(0, all_action_time - all_measured_time)
204 idle_time_result = (float(idle_time) / num_frames) if num_frames else 0 226 idle_time_result = (float(idle_time) / num_frames) if num_frames else 0
205 results.AddValue(scalar.ScalarValue( 227 results.AddValue(scalar.ScalarValue(
206 results.current_page, ThreadDetailResultName(self.name, "idle"), 228 results.current_page, ThreadDetailResultName(self.name, "idle"),
207 'ms', idle_time_result)) 229 'ms', idle_time_result))
208 230
231 def CountTracesWithName(self, substring):
232 count = 0
233 for event in self.all_slices:
234 if substring in event.name:
235 count += 1
236 return count
209 237
210 class ThreadTimesTimelineMetric(timeline_based_metric.TimelineBasedMetric): 238 class ThreadTimesTimelineMetric(timeline_based_metric.TimelineBasedMetric):
211 def __init__(self): 239 def __init__(self):
212 super(ThreadTimesTimelineMetric, self).__init__() 240 super(ThreadTimesTimelineMetric, self).__init__()
213 # Minimal traces, for minimum noise in CPU-time measurements. 241 # Minimal traces, for minimum noise in CPU-time measurements.
214 self.results_to_report = AllThreads 242 self.results_to_report = AllThreads
215 self.details_to_report = NoThreads 243 self.details_to_report = NoThreads
216 244
217 def CountSlices(self, slices, substring):
218 count = 0
219 for event in slices:
220 if substring in event.name:
221 count += 1
222 return count
223
224 def AddResults(self, model, _, interaction_records, results): 245 def AddResults(self, model, _, interaction_records, results):
225 # Set up each thread category for consistant results. 246 # Set up each thread category for consistant results.
226 thread_category_results = {} 247 thread_category_results = {}
227 for name in TimelineThreadCategories.values(): 248 for name in TimelineThreadCategories.values():
228 thread_category_results[name] = ResultsForThread( 249 thread_category_results[name] = ResultsForThread(
229 model, [r.GetBounds() for r in interaction_records], name) 250 model, [r.GetBounds() for r in interaction_records], name)
230 251
231 # Group the slices by their thread category. 252 # Group the slices by their thread category.
232 for thread in model.GetAllThreads(): 253 for thread in model.GetAllThreads():
233 thread_category = ThreadCategoryName(thread.name) 254 thread_category = ThreadCategoryName(thread.name)
234 thread_category_results[thread_category].AppendThreadSlices(thread) 255 thread_category_results[thread_category].AppendThreadSlices(thread)
235 256
236 # Group all threads. 257 # Group all threads.
237 for thread in model.GetAllThreads(): 258 for thread in model.GetAllThreads():
238 thread_category_results['total_all'].AppendThreadSlices(thread) 259 thread_category_results['total_all'].AppendThreadSlices(thread)
239 260
240 # Also group fast-path threads. 261 # Also group fast-path threads.
241 for thread in model.GetAllThreads(): 262 for thread in model.GetAllThreads():
242 if ThreadCategoryName(thread.name) in FastPathThreads: 263 if ThreadCategoryName(thread.name) in FastPathThreads:
243 thread_category_results['total_fast_path'].AppendThreadSlices(thread) 264 thread_category_results['total_fast_path'].AppendThreadSlices(thread)
244 265
245 # Calculate the number of frames. 266 # Calculate the number of frames.
246 frame_slices = thread_category_results[FrameTraceThreadName].all_slices 267 frame_rate_thread = thread_category_results[FrameTraceThreadName]
247 num_frames = self.CountSlices(frame_slices, FrameTraceName) 268 num_frames = frame_rate_thread.CountTracesWithName(FrameTraceName)
248 269
249 # Report the desired results and details. 270 # Report the desired results and details.
250 for thread_results in thread_category_results.values(): 271 for thread_results in thread_category_results.values():
251 if thread_results.name in self.results_to_report: 272 if thread_results.name in self.results_to_report:
252 thread_results.AddResults(num_frames, results) 273 thread_results.AddResults(num_frames, results)
253 # TOOD(nduca): When generic results objects are done, this special case 274 # TOOD(nduca): When generic results objects are done, this special case
254 # can be replaced with a generic UI feature. 275 # can be replaced with a generic UI feature.
255 if thread_results.name in self.details_to_report: 276 if thread_results.name in self.details_to_report:
256 thread_results.AddDetailedResults(num_frames, results) 277 thread_results.AddDetailedResults(num_frames, results)
OLDNEW
« no previous file with comments | « no previous file | tools/perf/metrics/timeline_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698