OLD | NEW |
---|---|
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 | 5 |
6 from telemetry.web_perf.metrics import timeline_based_metric | 6 from telemetry.web_perf.metrics import timeline_based_metric |
7 from telemetry.value import scalar | 7 from telemetry.value import scalar |
8 | 8 |
9 | 9 |
10 class LoadTimesTimelineMetric(timeline_based_metric.TimelineBasedMetric): | 10 class LoadTimesTimelineMetric(timeline_based_metric.TimelineBasedMetric): |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
96 ReportSilkResults = ["renderer_main", "total_all"] | 96 ReportSilkResults = ["renderer_main", "total_all"] |
97 ReportSilkDetails = ["renderer_main"] | 97 ReportSilkDetails = ["renderer_main"] |
98 | 98 |
99 # TODO(epenner): Thread names above are likely fairly stable but trace names | 99 # TODO(epenner): Thread names above are likely fairly stable but trace names |
100 # could change. We should formalize these traces to keep this robust. | 100 # could change. We should formalize these traces to keep this robust. |
101 OverheadTraceCategory = "trace_event_overhead" | 101 OverheadTraceCategory = "trace_event_overhead" |
102 OverheadTraceName = "overhead" | 102 OverheadTraceName = "overhead" |
103 FrameTraceName = "::SwapBuffers" | 103 FrameTraceName = "::SwapBuffers" |
104 FrameTraceThreadName = "renderer_compositor" | 104 FrameTraceThreadName = "renderer_compositor" |
105 | 105 |
106 def Rate(numerator, denominator): | |
107 return (float(numerator) / denominator) if denominator else 0 | |
106 | 108 |
107 def ClockOverheadForEvent(event): | 109 def ClockOverheadForEvent(event): |
108 if (event.category == OverheadTraceCategory and | 110 if (event.category == OverheadTraceCategory and |
109 event.name == OverheadTraceName): | 111 event.name == OverheadTraceName): |
110 return event.duration | 112 return event.duration |
111 else: | 113 else: |
112 return 0 | 114 return 0 |
113 | 115 |
114 def CpuOverheadForEvent(event): | 116 def CpuOverheadForEvent(event): |
115 if (event.category == OverheadTraceCategory and | 117 if (event.category == OverheadTraceCategory and |
116 event.thread_duration): | 118 event.thread_duration): |
117 return event.thread_duration | 119 return event.thread_duration |
118 else: | 120 else: |
119 return 0 | 121 return 0 |
120 | 122 |
121 def ThreadCategoryName(thread_name): | 123 def ThreadCategoryName(thread_name): |
122 thread_category = "other" | 124 thread_category = "other" |
123 for substring, category in TimelineThreadCategories.iteritems(): | 125 for substring, category in TimelineThreadCategories.iteritems(): |
124 if substring in _MatchBySubString and substring in thread_name: | 126 if substring in _MatchBySubString and substring in thread_name: |
125 thread_category = category | 127 thread_category = category |
126 if thread_name in TimelineThreadCategories: | 128 if thread_name in TimelineThreadCategories: |
127 thread_category = TimelineThreadCategories[thread_name] | 129 thread_category = TimelineThreadCategories[thread_name] |
128 return thread_category | 130 return thread_category |
129 | 131 |
130 def ThreadTimeResultName(thread_category): | 132 def ThreadCpuTimeResultName(thread_category): |
131 return "thread_" + thread_category + "_clock_time_per_frame" | 133 # This isn't a good name, but I don't want to change it and lose continuity. |
134 return "thread_" + thread_category + "_cpu_time_per_frame" | |
132 | 135 |
133 def ThreadCpuTimeResultName(thread_category): | 136 def ThreadTasksResultName(thread_category): |
134 return "thread_" + thread_category + "_cpu_time_per_frame" | 137 return "tasks_per_frame_" + thread_category |
138 | |
139 def ThreadMeanFrameResultName(thread_category): | |
ernstm
2014/10/14 17:06:11
I would rename this to ThreadMeanFrameTimeResultNa
epenner
2014/10/18 01:02:30
Done.
| |
140 return "mean_frame_time_" + thread_category | |
135 | 141 |
136 def ThreadDetailResultName(thread_category, detail): | 142 def ThreadDetailResultName(thread_category, detail): |
137 detail_sanitized = detail.replace('.','_') | 143 detail_sanitized = detail.replace('.','_') |
138 return "thread_" + thread_category + "|" + detail_sanitized | 144 return "thread_" + thread_category + "|" + detail_sanitized |
139 | 145 |
140 | 146 |
141 class ResultsForThread(object): | 147 class ResultsForThread(object): |
142 def __init__(self, model, record_ranges, name): | 148 def __init__(self, model, record_ranges, name): |
143 self.model = model | 149 self.model = model |
144 self.toplevel_slices = [] | 150 self.toplevel_slices = [] |
145 self.all_slices = [] | 151 self.all_slices = [] |
146 self.name = name | 152 self.name = name |
147 self.record_ranges = record_ranges | 153 self.record_ranges = record_ranges |
154 self.all_action_time = \ | |
155 sum([record_range.bounds for record_range in self.record_ranges]) | |
148 | 156 |
149 @property | 157 @property |
150 def clock_time(self): | 158 def clock_time(self): |
151 clock_duration = sum([x.duration for x in self.toplevel_slices]) | 159 clock_duration = sum([x.duration for x in self.toplevel_slices]) |
152 clock_overhead = sum([ClockOverheadForEvent(x) for x in self.all_slices]) | 160 clock_overhead = sum([ClockOverheadForEvent(x) for x in self.all_slices]) |
153 return clock_duration - clock_overhead | 161 return clock_duration - clock_overhead |
154 | 162 |
155 @property | 163 @property |
156 def cpu_time(self): | 164 def cpu_time(self): |
157 cpu_duration = 0 | 165 cpu_duration = 0 |
(...skipping 17 matching lines...) Expand all Loading... | |
175 for record_range in self.record_ranges: | 183 for record_range in self.record_ranges: |
176 if record_range.ContainsInterval(event.start, event.end): | 184 if record_range.ContainsInterval(event.start, event.end): |
177 slices_in_actions.append(event) | 185 slices_in_actions.append(event) |
178 break | 186 break |
179 return slices_in_actions | 187 return slices_in_actions |
180 | 188 |
181 def AppendThreadSlices(self, thread): | 189 def AppendThreadSlices(self, thread): |
182 self.all_slices.extend(self.SlicesInActions(thread.all_slices)) | 190 self.all_slices.extend(self.SlicesInActions(thread.all_slices)) |
183 self.toplevel_slices.extend(self.SlicesInActions(thread.toplevel_slices)) | 191 self.toplevel_slices.extend(self.SlicesInActions(thread.toplevel_slices)) |
184 | 192 |
193 # Currently we report cpu-time per frame, tasks per frame, and possibly | |
194 # the mean frame (if there is a trace specified to find it). | |
185 def AddResults(self, num_frames, results): | 195 def AddResults(self, num_frames, results): |
186 cpu_per_frame = (float(self.cpu_time) / num_frames) if num_frames else 0 | 196 cpu_per_frame = Rate(self.cpu_time, num_frames) |
197 tasks_per_frame = Rate(len(self.toplevel_slices), num_frames) | |
187 results.AddValue(scalar.ScalarValue( | 198 results.AddValue(scalar.ScalarValue( |
188 results.current_page, ThreadCpuTimeResultName(self.name), | 199 results.current_page, ThreadCpuTimeResultName(self.name), |
189 'ms', cpu_per_frame)) | 200 'ms', cpu_per_frame)) |
201 results.AddValue(scalar.ScalarValue( | |
202 results.current_page, ThreadTasksResultName(self.name), | |
203 'tasks', tasks_per_frame)) | |
204 # Report mean frame time if this is the thread we are using for normalizing | |
205 # other results. We could report other frame rates (eg. renderer_main) but | |
206 # this might get confusing. | |
207 if self.name == FrameTraceThreadName: | |
208 num_frames = self.CountTracesWithName(FrameTraceName) | |
209 mean_frame = Rate(self.all_action_time, num_frames) | |
ernstm
2014/10/14 17:06:11
mean_frame -> mean_frame_time
epenner
2014/10/18 01:02:30
Done.
| |
210 results.AddValue(scalar.ScalarValue( | |
211 results.current_page, ThreadMeanFrameResultName(self.name), | |
212 'ms', mean_frame)) | |
190 | 213 |
191 def AddDetailedResults(self, num_frames, results): | 214 def AddDetailedResults(self, num_frames, results): |
192 slices_by_category = collections.defaultdict(list) | 215 slices_by_category = collections.defaultdict(list) |
193 for s in self.all_slices: | 216 for s in self.all_slices: |
194 slices_by_category[s.category].append(s) | 217 slices_by_category[s.category].append(s) |
195 all_self_times = [] | 218 all_self_times = [] |
196 for category, slices_in_category in slices_by_category.iteritems(): | 219 for category, slices_in_category in slices_by_category.iteritems(): |
197 self_time = sum([x.self_time for x in slices_in_category]) | 220 self_time = sum([x.self_time for x in slices_in_category]) |
198 all_self_times.append(self_time) | 221 all_self_times.append(self_time) |
199 self_time_result = (float(self_time) / num_frames) if num_frames else 0 | 222 self_time_result = (float(self_time) / num_frames) if num_frames else 0 |
200 results.AddValue(scalar.ScalarValue( | 223 results.AddValue(scalar.ScalarValue( |
201 results.current_page, ThreadDetailResultName(self.name, category), | 224 results.current_page, ThreadDetailResultName(self.name, category), |
202 'ms', self_time_result)) | 225 'ms', self_time_result)) |
203 all_measured_time = sum(all_self_times) | 226 all_measured_time = sum(all_self_times) |
204 all_action_time = \ | 227 idle_time = max(0, self.all_action_time - all_measured_time) |
205 sum([record_range.bounds for record_range in self.record_ranges]) | |
206 idle_time = max(0, all_action_time - all_measured_time) | |
207 idle_time_result = (float(idle_time) / num_frames) if num_frames else 0 | 228 idle_time_result = (float(idle_time) / num_frames) if num_frames else 0 |
208 results.AddValue(scalar.ScalarValue( | 229 results.AddValue(scalar.ScalarValue( |
209 results.current_page, ThreadDetailResultName(self.name, "idle"), | 230 results.current_page, ThreadDetailResultName(self.name, "idle"), |
210 'ms', idle_time_result)) | 231 'ms', idle_time_result)) |
211 | 232 |
233 def CountTracesWithName(self, substring): | |
234 count = 0 | |
235 for event in self.all_slices: | |
236 if substring in event.name: | |
237 count += 1 | |
238 return count | |
212 | 239 |
213 class ThreadTimesTimelineMetric(timeline_based_metric.TimelineBasedMetric): | 240 class ThreadTimesTimelineMetric(timeline_based_metric.TimelineBasedMetric): |
214 def __init__(self): | 241 def __init__(self): |
215 super(ThreadTimesTimelineMetric, self).__init__() | 242 super(ThreadTimesTimelineMetric, self).__init__() |
216 # Minimal traces, for minimum noise in CPU-time measurements. | 243 # Minimal traces, for minimum noise in CPU-time measurements. |
217 self.results_to_report = AllThreads | 244 self.results_to_report = AllThreads |
218 self.details_to_report = NoThreads | 245 self.details_to_report = NoThreads |
219 | 246 |
220 def CountSlices(self, slices, substring): | |
221 count = 0 | |
222 for event in slices: | |
223 if substring in event.name: | |
224 count += 1 | |
225 return count | |
226 | |
227 def AddResults(self, model, _, interaction_records, results): | 247 def AddResults(self, model, _, interaction_records, results): |
228 # Set up each thread category for consistant results. | 248 # Set up each thread category for consistant results. |
229 thread_category_results = {} | 249 thread_category_results = {} |
230 for name in TimelineThreadCategories.values(): | 250 for name in TimelineThreadCategories.values(): |
231 thread_category_results[name] = ResultsForThread( | 251 thread_category_results[name] = ResultsForThread( |
232 model, [r.GetBounds() for r in interaction_records], name) | 252 model, [r.GetBounds() for r in interaction_records], name) |
233 | 253 |
234 # Group the slices by their thread category. | 254 # Group the slices by their thread category. |
235 for thread in model.GetAllThreads(): | 255 for thread in model.GetAllThreads(): |
236 thread_category = ThreadCategoryName(thread.name) | 256 thread_category = ThreadCategoryName(thread.name) |
237 thread_category_results[thread_category].AppendThreadSlices(thread) | 257 thread_category_results[thread_category].AppendThreadSlices(thread) |
238 | 258 |
239 # Group all threads. | 259 # Group all threads. |
240 for thread in model.GetAllThreads(): | 260 for thread in model.GetAllThreads(): |
241 thread_category_results['total_all'].AppendThreadSlices(thread) | 261 thread_category_results['total_all'].AppendThreadSlices(thread) |
242 | 262 |
243 # Also group fast-path threads. | 263 # Also group fast-path threads. |
244 for thread in model.GetAllThreads(): | 264 for thread in model.GetAllThreads(): |
245 if ThreadCategoryName(thread.name) in FastPathThreads: | 265 if ThreadCategoryName(thread.name) in FastPathThreads: |
246 thread_category_results['total_fast_path'].AppendThreadSlices(thread) | 266 thread_category_results['total_fast_path'].AppendThreadSlices(thread) |
247 | 267 |
248 # Calculate the number of frames. | 268 # Calculate the number of frames. |
249 frame_slices = thread_category_results[FrameTraceThreadName].all_slices | 269 frame_rate_thread = thread_category_results[FrameTraceThreadName] |
250 num_frames = self.CountSlices(frame_slices, FrameTraceName) | 270 num_frames = frame_rate_thread.CountTracesWithName(FrameTraceName) |
251 | 271 |
252 # Report the desired results and details. | 272 # Report the desired results and details. |
253 for thread_results in thread_category_results.values(): | 273 for thread_results in thread_category_results.values(): |
254 if thread_results.name in self.results_to_report: | 274 if thread_results.name in self.results_to_report: |
255 thread_results.AddResults(num_frames, results) | 275 thread_results.AddResults(num_frames, results) |
256 # TOOD(nduca): When generic results objects are done, this special case | 276 # TOOD(nduca): When generic results objects are done, this special case |
257 # can be replaced with a generic UI feature. | 277 # can be replaced with a generic UI feature. |
258 if thread_results.name in self.details_to_report: | 278 if thread_results.name in self.details_to_report: |
259 thread_results.AddDetailedResults(num_frames, results) | 279 thread_results.AddDetailedResults(num_frames, results) |
OLD | NEW |