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

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

Issue 138923004: Telemetry: Normalize fast-path results with frames. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Customize silk/fastpath results. Created 6 years, 11 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
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 5
6 from metrics import Metric 6 from metrics import Metric
7 from telemetry.page import page_measurement
7 8
8 TRACING_MODE = 'tracing-mode' 9 TRACING_MODE = 'tracing-mode'
9 TIMELINE_MODE = 'timeline-mode' 10 TIMELINE_MODE = 'timeline-mode'
10 11
12 class MissingFramesError(page_measurement.MeasurementFailure):
13 def __init__(self):
14 super(MissingFramesError, self).__init__(
15 'No frames found in trace. Unable to normalize results.')
16
11 class TimelineMetric(Metric): 17 class TimelineMetric(Metric):
12 def __init__(self, mode): 18 def __init__(self, mode):
13 """ Initializes a TimelineMetric object. 19 """ Initializes a TimelineMetric object.
14 """ 20 """
15 super(TimelineMetric, self).__init__() 21 super(TimelineMetric, self).__init__()
16 assert mode in (TRACING_MODE, TIMELINE_MODE) 22 assert mode in (TRACING_MODE, TIMELINE_MODE)
17 self._mode = mode 23 self._mode = mode
18 self._model = None 24 self._model = None
19 self._renderer_process = None 25 self._renderer_process = None
20 26
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 # for simplicity. 113 # for simplicity.
108 TimelineThreadCategories = { 114 TimelineThreadCategories = {
109 "Chrome_InProcGpuThread": "GPU", 115 "Chrome_InProcGpuThread": "GPU",
110 "CrGPUMain" : "GPU", 116 "CrGPUMain" : "GPU",
111 "AsyncTransferThread" : "GPU_transfer", 117 "AsyncTransferThread" : "GPU_transfer",
112 "CrBrowserMain" : "browser_main", 118 "CrBrowserMain" : "browser_main",
113 "Browser Compositor" : "browser_compositor", 119 "Browser Compositor" : "browser_compositor",
114 "CrRendererMain" : "renderer_main", 120 "CrRendererMain" : "renderer_main",
115 "Compositor" : "renderer_compositor", 121 "Compositor" : "renderer_compositor",
116 "IOThread" : "IO", 122 "IOThread" : "IO",
117 "CompositorRasterWorker": "raster" 123 "CompositorRasterWorker": "raster",
124 "DummyThreadName1" : "other",
125 "DummyThreadName2" : "total_fast_path",
126 "DummyThreadName3" : "total_all"
118 } 127 }
128
119 MatchBySubString = ["IOThread", "CompositorRasterWorker"] 129 MatchBySubString = ["IOThread", "CompositorRasterWorker"]
120 FastPath = ["GPU", 130 FastPath = ["GPU",
121 "browser_main", 131 "browser_main",
122 "browser_compositor", 132 "browser_compositor",
123 "renderer_compositor", 133 "renderer_compositor",
124 "IO"] 134 "IO"]
125 135
136 AllThreads = TimelineThreadCategories.values()
137 NoThreads = []
138 MainThread = ["renderer_main"]
139 FastPathResults = AllThreads
140 FastPathDetails = NoThreads
141 SilkResults = ["renderer_main", "total_all"]
142 SilkDetails = MainThread
126 143
127 def ThreadTimePercentageName(category): 144 def ThreadCategoryName(thread_name):
128 return "thread_" + category + "_clock_time_percentage" 145 thread_category = "other"
146 for substring, category in TimelineThreadCategories.iteritems():
147 if substring in MatchBySubString and substring in thread_name:
148 thread_category = category
149 if thread_name in TimelineThreadCategories:
150 thread_category = TimelineThreadCategories[thread_name]
151 return thread_category
129 152
130 def ThreadCPUTimePercentageName(category): 153 def ThreadTimeResultName(thread_category):
131 return "thread_" + category + "_cpu_time_percentage" 154 return "thread_" + thread_category + "_clock_time_per_frame"
155
156 def ThreadCpuTimeResultName(thread_category):
157 return "thread_" + thread_category + "_cpu_time_per_frame"
158
159 def ThreadDetailResultName(thread_category, detail):
160 return "thread_" + thread_category + "|" + detail
132 161
133 class ResultsForThread(object): 162 class ResultsForThread(object):
134 def __init__(self, model): 163 def __init__(self, model, name):
135 self.model = model 164 self.model = model
136 self.toplevel_slices = [] 165 self.toplevel_slices = []
137 self.all_slices = [] 166 self.all_slices = []
167 self.name = name
138 168
139 @property 169 @property
140 def clock_time(self): 170 def clock_time(self):
141 return sum([x.duration for x in self.toplevel_slices]) 171 return sum([x.duration for x in self.toplevel_slices])
142 172
143 @property 173 @property
144 def cpu_time(self): 174 def cpu_time(self):
145 res = 0 175 res = 0
146 for x in self.toplevel_slices: 176 for x in self.toplevel_slices:
147 # Only report thread-duration if we have it for all events. 177 # Only report thread-duration if we have it for all events.
148 # 178 #
149 # A thread_duration of 0 is valid, so this only returns 0 if it is None. 179 # A thread_duration of 0 is valid, so this only returns 0 if it is None.
150 if x.thread_duration == None: 180 if x.thread_duration == None:
151 return 0 181 return 0
152 else: 182 else:
153 res += x.thread_duration 183 res += x.thread_duration
154 return res 184 return res
155 185
156 def AddDetailedResults(self, thread_category_name, results): 186 def AppendThreadSlices(self, thread):
187 self.all_slices.extend(thread.all_slices)
188 self.toplevel_slices.extend(thread.toplevel_slices)
189
190 def AddResults(self, num_frames, results):
191 clock_report_name = ThreadTimeResultName(self.name)
192 cpu_report_name = ThreadCpuTimeResultName(self.name)
193 clock_per_frame = float(self.clock_time) / num_frames
194 cpu_per_frame = float(self.cpu_time) / num_frames
195 results.Add(clock_report_name, 'ms', clock_per_frame)
196 results.Add(cpu_report_name, 'ms', cpu_per_frame)
197
198 def AddDetailedResults(self, num_frames, results):
157 slices_by_category = collections.defaultdict(list) 199 slices_by_category = collections.defaultdict(list)
158 for s in self.all_slices: 200 for s in self.all_slices:
159 slices_by_category[s.category].append(s) 201 slices_by_category[s.category].append(s)
160 all_self_times = [] 202 all_self_times = []
161 for category, slices_in_category in slices_by_category.iteritems(): 203 for category, slices_in_category in slices_by_category.iteritems():
162 self_time = sum([x.self_time for x in slices_in_category]) 204 self_time = sum([x.self_time for x in slices_in_category])
163 results.Add('%s|%s' % (thread_category_name, category), 'ms', self_time)
164 all_self_times.append(self_time) 205 all_self_times.append(self_time)
206 self_time_result = float(self_time) / num_frames
207 results.Add(ThreadDetailResultName(self.name, category),
208 'ms', self_time_result)
165 all_measured_time = sum(all_self_times) 209 all_measured_time = sum(all_self_times)
166 idle_time = max(0, 210 idle_time = max(0, self.model.bounds.bounds - all_measured_time)
167 self.model.bounds.bounds - all_measured_time) 211 idle_time_result = float(idle_time) / num_frames
168 results.Add('%s|idle' % thread_category_name, 'ms', idle_time) 212 results.Add(ThreadDetailResultName(self.name, "idle"),
213 'ms', idle_time_result)
169 214
170 class ThreadTimesTimelineMetric(TimelineMetric): 215 class ThreadTimesTimelineMetric(TimelineMetric):
171 def __init__(self): 216 def __init__(self):
172 super(ThreadTimesTimelineMetric, self).__init__(TRACING_MODE) 217 super(ThreadTimesTimelineMetric, self).__init__(TRACING_MODE)
173 self.report_renderer_main_details = False 218 self.results_to_report = AllThreads
219 self.details_to_report = NoThreads
174 220
175 def GetThreadCategoryName(self, thread): 221 def CalcFrameCount(self):
176 # First determine if we care about this thread. 222 gpu_swaps = 0
177 # Check substrings first, followed by exact matches 223 for thread in self._model.GetAllThreads():
178 thread_category = None 224 if (ThreadCategoryName(thread.name) == "GPU"):
179 for substring, category in TimelineThreadCategories.iteritems(): 225 for event in thread.IterAllSlices():
180 if substring in thread.name: 226 if ":RealSwapBuffers" in event.name:
181 thread_category = category 227 gpu_swaps += 1
182 if thread.name in TimelineThreadCategories: 228 return gpu_swaps
183 thread_category = TimelineThreadCategories[thread.name]
184 if thread_category == None:
185 thread_category = "other"
186
187 return thread_category
188 229
189 def AddResults(self, tab, results): 230 def AddResults(self, tab, results):
190 results_per_thread_category = collections.defaultdict( 231 num_frames = self.CalcFrameCount()
191 lambda: ResultsForThread(self._model)) 232 if not num_frames:
233 raise MissingFramesError()
192 234
193 # Set up each category anyway so that we get consistant results. 235 # Set up each thread category for consistant results.
194 for category in TimelineThreadCategories.values(): 236 thread_category_results = {}
195 results_per_thread_category[category] = ResultsForThread(self.model) 237 for name in TimelineThreadCategories.values():
196 results_for_all_threads = results_per_thread_category['total_fast_path'] 238 thread_category_results[name] = ResultsForThread(self.model, name)
197 239
198 # Group the slices by their thread category. 240 # Group the slices by their thread category.
199 for thread in self._model.GetAllThreads(): 241 for thread in self._model.GetAllThreads():
200 # First determine if we care about this thread. 242 thread_category = ThreadCategoryName(thread.name)
201 # Check substrings first, followed by exact matches 243 thread_category_results[thread_category].AppendThreadSlices(thread)
202 thread_category = self.GetThreadCategoryName(thread)
203 244
204 results_for_thread = results_per_thread_category[thread_category] 245 # Group all threads.
205 for event in thread.all_slices: 246 for thread in self._model.GetAllThreads():
206 results_for_thread.all_slices.append(event) 247 thread_category_results['total_all'].AppendThreadSlices(thread)
207 results_for_all_threads.all_slices.append(event)
208 for event in thread.toplevel_slices:
209 results_for_thread.toplevel_slices.append(event)
210 results_for_all_threads.toplevel_slices.append(event)
211 248
212 for thread_category, results_for_thread_category in ( 249 # Also group fast-path threads.
213 results_per_thread_category.iteritems()): 250 for thread in self._model.GetAllThreads():
214 thread_report_name = ThreadTimePercentageName(thread_category) 251 if ThreadCategoryName(thread.name) in FastPath:
215 time_as_percentage = (float(results_for_thread_category.clock_time) / 252 thread_category_results['total_fast_path'].AppendThreadSlices(thread)
216 self._model.bounds.bounds) * 100
217 results.Add(thread_report_name, '%', time_as_percentage)
218 253
219 for thread_category, results_for_thread_category in ( 254 # Report the desired results and details.
220 results_per_thread_category.iteritems()): 255 for thread_results in thread_category_results.values():
221 cpu_time_report_name = ThreadCPUTimePercentageName(thread_category) 256 if thread_results.name in self.results_to_report:
222 time_as_percentage = (float(results_for_thread_category.cpu_time) / 257 thread_results.AddResults(num_frames, results)
223 self._model.bounds.bounds) * 100 258 # TOOD(nduca): When generic results objects are done, this special case
224 results.Add(cpu_time_report_name, '%', time_as_percentage) 259 # can be replaced with a generic UI feature.
225 260 if thread_results.name in self.details_to_report:
226 # TOOD(nduca): When generic results objects are done, this special case 261 thread_results.AddDetailedResults(num_frames, results)
227 # can be replaced with a generic UI feature.
228 for thread_category, results_for_thread_category in (
229 results_per_thread_category.iteritems()):
230 if (thread_category == 'renderer_main' and
231 self.report_renderer_main_details):
232 results_for_thread_category.AddDetailedResults(thread_category, results)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698