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 import itertools | 5 import itertools |
6 | 6 |
7 from metrics import Metric | 7 from metrics import Metric |
8 from telemetry.core.timeline import bounds | 8 from telemetry.core.timeline import bounds |
9 from telemetry.page import page_measurement | 9 from telemetry.page import page_measurement |
10 | 10 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
133 | 133 |
134 # We want to generate a consistant picture of our thread usage, despite | 134 # We want to generate a consistant picture of our thread usage, despite |
135 # having several process configurations (in-proc-gpu/single-proc). | 135 # having several process configurations (in-proc-gpu/single-proc). |
136 # Since we can't isolate renderer threads in single-process mode, we | 136 # Since we can't isolate renderer threads in single-process mode, we |
137 # always sum renderer-process threads' times. We also sum all io-threads | 137 # always sum renderer-process threads' times. We also sum all io-threads |
138 # for simplicity. | 138 # for simplicity. |
139 TimelineThreadCategories = { | 139 TimelineThreadCategories = { |
140 "Chrome_InProcGpuThread": "GPU", | 140 "Chrome_InProcGpuThread": "GPU", |
141 "CrGpuMain" : "GPU", | 141 "CrGpuMain" : "GPU", |
142 "AsyncTransferThread" : "GPU_transfer", | 142 "AsyncTransferThread" : "GPU_transfer", |
143 "CrBrowserMain" : "browser_main", | 143 "CrBrowserMain" : "browser", |
144 "Browser Compositor" : "browser_compositor", | 144 "Browser Compositor" : "browser", |
145 "CrRendererMain" : "renderer_main", | 145 "CrRendererMain" : "renderer_main", |
146 "Compositor" : "renderer_compositor", | 146 "Compositor" : "renderer_compositor", |
147 "IOThread" : "IO", | 147 "IOThread" : "IO", |
148 "CompositorRasterWorker": "raster", | 148 "CompositorRasterWorker": "raster", |
149 "DummyThreadName1" : "other", | 149 "DummyThreadName1" : "other", |
150 "DummyThreadName2" : "total_fast_path", | 150 "DummyThreadName2" : "total_fast_path", |
151 "DummyThreadName3" : "total_all" | 151 "DummyThreadName3" : "total_all" |
152 } | 152 } |
153 | 153 |
154 MatchBySubString = ["IOThread", "CompositorRasterWorker"] | 154 MatchBySubString = ["IOThread", "CompositorRasterWorker"] |
155 | 155 |
156 AllThreads = TimelineThreadCategories.values() | 156 AllThreads = TimelineThreadCategories.values() |
157 NoThreads = [] | 157 NoThreads = [] |
158 FastPathThreads = ["GPU", | 158 |
159 "browser_main", | 159 FastPathThreads = ["GPU", "renderer_compositor", "browser", "IO"] |
160 "browser_compositor", | |
161 "renderer_compositor", | |
162 "IO"] | |
163 MainThread = ["renderer_main"] | |
164 FastPathResults = AllThreads | 160 FastPathResults = AllThreads |
165 FastPathDetails = NoThreads | 161 FastPathDetails = NoThreads |
166 SilkResults = ["renderer_main", "total_all"] | 162 SilkResults = ["renderer_main", "total_all"] |
167 SilkDetails = MainThread | 163 SilkDetails = ["renderer_main"] |
168 | 164 |
169 # TODO(epenner): Thread names above are likely fairly stable but trace names | 165 # TODO(epenner): Thread names above are likely fairly stable but trace names |
170 # could change. We should formalize this trace to keep this robust. | 166 # could change. We should formalize these traces to keep this robust. |
171 CompositorFrameTraceName = "::SwapBuffers" | 167 OverheadTraceCategory = "trace_event_overhead" |
nduca
2014/02/05 00:34:11
global vars sould be prefixed with _ when not inte
| |
168 OverheadTraceName = "overhead" | |
169 FrameTraceName = "::SwapBuffers" | |
170 FrameTraceThread = "renderer_compositor" | |
171 | |
172 def ClockOverhead(event): | |
nduca
2014/02/05 00:34:11
GetClockOverheadFromEvent
| |
173 if (event.category == OverheadTraceCategory and | |
174 event.name == OverheadTraceName): | |
175 return event.duration | |
176 else: | |
177 return 0 | |
178 | |
179 def CpuOverhead(event): | |
nduca
2014/02/05 00:34:11
GetCpuOverheadFromEvent or someting like that
| |
180 if (event.category == OverheadTraceCategory and | |
181 event.name == OverheadTraceName and | |
182 event.thread_duration): | |
183 return event.thread_duration | |
184 else: | |
185 return 0 | |
172 | 186 |
173 def ThreadCategoryName(thread_name): | 187 def ThreadCategoryName(thread_name): |
174 thread_category = "other" | 188 thread_category = "other" |
175 for substring, category in TimelineThreadCategories.iteritems(): | 189 for substring, category in TimelineThreadCategories.iteritems(): |
176 if substring in MatchBySubString and substring in thread_name: | 190 if substring in MatchBySubString and substring in thread_name: |
177 thread_category = category | 191 thread_category = category |
178 if thread_name in TimelineThreadCategories: | 192 if thread_name in TimelineThreadCategories: |
179 thread_category = TimelineThreadCategories[thread_name] | 193 thread_category = TimelineThreadCategories[thread_name] |
180 return thread_category | 194 return thread_category |
181 | 195 |
182 def ThreadTimeResultName(thread_category): | 196 def ThreadTimeResultName(thread_category): |
183 return "thread_" + thread_category + "_clock_time_per_frame" | 197 return "thread_" + thread_category + "_clock_time_per_frame" |
184 | 198 |
185 def ThreadCpuTimeResultName(thread_category): | 199 def ThreadCpuTimeResultName(thread_category): |
186 return "thread_" + thread_category + "_cpu_time_per_frame" | 200 return "thread_" + thread_category + "_cpu_time_per_frame" |
187 | 201 |
188 def ThreadDetailResultName(thread_category, detail): | 202 def ThreadDetailResultName(thread_category, detail): |
189 return "thread_" + thread_category + "|" + detail | 203 return "thread_" + thread_category + "|" + detail |
190 | 204 |
191 class ResultsForThread(object): | 205 class ResultsForThread(object): |
192 def __init__(self, model, action_ranges, name): | 206 def __init__(self, model, action_ranges, name): |
193 self.model = model | 207 self.model = model |
194 self.toplevel_slices = [] | 208 self.toplevel_slices = [] |
195 self.all_slices = [] | 209 self.all_slices = [] |
196 self.name = name | 210 self.name = name |
197 self.action_ranges = action_ranges | 211 self.action_ranges = action_ranges |
198 | 212 |
199 @property | 213 @property |
200 def clock_time(self): | 214 def clock_time(self): |
201 return sum([x.duration for x in self.toplevel_slices]) | 215 clock_duration = sum([x.duration for x in self.toplevel_slices]) |
216 clock_overhead = sum([ClockOverhead(x) for x in self.all_slices]) | |
217 return clock_duration - clock_overhead | |
202 | 218 |
203 @property | 219 @property |
204 def cpu_time(self): | 220 def cpu_time(self): |
205 res = 0 | 221 cpu_duration = 0 |
222 cpu_overhead = sum([CpuOverhead(x) for x in self.all_slices]) | |
206 for x in self.toplevel_slices: | 223 for x in self.toplevel_slices: |
207 # Only report thread-duration if we have it for all events. | 224 # Only report thread-duration if we have it for all events. |
208 # | 225 # |
209 # A thread_duration of 0 is valid, so this only returns 0 if it is None. | 226 # A thread_duration of 0 is valid, so this only returns 0 if it is None. |
210 if x.thread_duration == None: | 227 if x.thread_duration == None: |
211 if not x.duration: | 228 if not x.duration: |
212 continue | 229 continue |
213 else: | 230 else: |
214 return 0 | 231 return 0 |
215 else: | 232 else: |
216 res += x.thread_duration | 233 cpu_duration += x.thread_duration |
217 return res | 234 return cpu_duration - cpu_overhead |
218 | 235 |
219 def ActionSlices(self, slices): | 236 def ActionSlices(self, slices): |
220 slices_in_actions = [] | 237 slices_in_actions = [] |
221 for event in slices: | 238 for event in slices: |
222 for action_range in self.action_ranges: | 239 for action_range in self.action_ranges: |
223 if action_range.Contains(bounds.Bounds.CreateFromEvent(event)): | 240 if action_range.Contains(bounds.Bounds.CreateFromEvent(event)): |
224 slices_in_actions.append(event) | 241 slices_in_actions.append(event) |
225 break | 242 break |
226 return slices_in_actions | 243 return slices_in_actions |
227 | 244 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
286 | 303 |
287 # Group all threads. | 304 # Group all threads. |
288 for thread in self._model.GetAllThreads(): | 305 for thread in self._model.GetAllThreads(): |
289 thread_category_results['total_all'].AppendThreadSlices(thread) | 306 thread_category_results['total_all'].AppendThreadSlices(thread) |
290 | 307 |
291 # Also group fast-path threads. | 308 # Also group fast-path threads. |
292 for thread in self._model.GetAllThreads(): | 309 for thread in self._model.GetAllThreads(): |
293 if ThreadCategoryName(thread.name) in FastPathThreads: | 310 if ThreadCategoryName(thread.name) in FastPathThreads: |
294 thread_category_results['total_fast_path'].AppendThreadSlices(thread) | 311 thread_category_results['total_fast_path'].AppendThreadSlices(thread) |
295 | 312 |
296 # Calculate the number of frames from the CC thread. | 313 # Calculate the number of frames. |
297 cc_slices = thread_category_results['renderer_compositor'].all_slices | 314 frame_slices = thread_category_results[FrameTraceThread].all_slices |
298 num_frames = self.CountSlices(cc_slices, CompositorFrameTraceName) | 315 num_frames = self.CountSlices(frame_slices, FrameTraceName) |
299 | 316 |
300 # Report the desired results and details. | 317 # Report the desired results and details. |
301 for thread_results in thread_category_results.values(): | 318 for thread_results in thread_category_results.values(): |
302 if thread_results.name in self.results_to_report: | 319 if thread_results.name in self.results_to_report: |
303 thread_results.AddResults(num_frames, results) | 320 thread_results.AddResults(num_frames, results) |
304 # TOOD(nduca): When generic results objects are done, this special case | 321 # TOOD(nduca): When generic results objects are done, this special case |
305 # can be replaced with a generic UI feature. | 322 # can be replaced with a generic UI feature. |
306 if thread_results.name in self.details_to_report: | 323 if thread_results.name in self.details_to_report: |
307 thread_results.AddDetailedResults(num_frames, results) | 324 thread_results.AddDetailedResults(num_frames, results) |
OLD | NEW |