Chromium Code Reviews| Index: tools/perf/measurements/task_execution_time.py |
| diff --git a/tools/perf/measurements/task_execution_time.py b/tools/perf/measurements/task_execution_time.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4914471436252636727928561b48a5781ce3fe3d |
| --- /dev/null |
| +++ b/tools/perf/measurements/task_execution_time.py |
| @@ -0,0 +1,150 @@ |
| +# Copyright 2013 The Chromium Authors. All rights reserved. |
|
petrcermak
2014/10/08 14:01:48
Again should be "2014".
Sami
2014/10/08 14:51:53
Ditto about the copyright year.
|
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +from telemetry.core.platform import tracing_category_filter |
| +from telemetry.core.platform import tracing_options |
| +from telemetry.timeline.model import TimelineModel |
| +from telemetry.page import page_test |
| +from telemetry.value import scalar |
| +from telemetry.value import skip |
| + |
| +CATEGORIES = ['webkit.console', |
|
Sami
2014/10/08 14:51:52
Assuming these constants aren't meant to be public
picksi1
2014/10/08 15:58:26
Done.
|
| + 'blink.console', |
| + 'benchmark', |
| + 'toplevel', |
| + 'blink', |
| + 'cc', |
| + 'v8'] |
| + |
| +TIME_OUT_IN_SECONDS = 60 |
| +NUMBER_OF_RESULTS_TO_DISPLAY = 10 |
| + |
| +class TaskExecutionTime(page_test.PageTest): |
| + |
|
Sami
2014/10/08 14:51:53
I don't think we generally have blank lines betwee
|
| + def __init__(self): |
| + super(TaskExecutionTime, self).__init__('RunTaskExecutionTime') |
|
Sami
2014/10/08 14:51:53
Why not reuse RunSmoothness for this?
picksi1
2014/10/08 15:58:27
I guess these are currently the same; I made a sep
|
| + self._renderer_thread = None |
| + |
| + def WillNavigateToPage(self, page, tab): |
| + |
|
alexclarke
2014/10/08 13:28:28
nit: I assume we don't want blank lines after a fu
picksi1
2014/10/08 13:47:54
Yes, you're right. My eyes prefer it with spaces,
|
| + category_filter = tracing_category_filter.TracingCategoryFilter() |
| + |
| + for category in CATEGORIES: |
| + category_filter.AddIncludedCategory(category) |
| + |
| + options = tracing_options.TracingOptions() |
| + options.enable_chrome_trace = True |
| + |
| + tab.browser.platform.tracing_controller.Start( |
| + options, category_filter, TIME_OUT_IN_SECONDS) |
|
Sami
2014/10/08 14:51:53
indent +2
|
| + |
| + |
| + def DidRunActions(self, page, tab): |
|
petrcermak
2014/10/08 14:01:48
Is there any reason for double blank lines around
picksi1
2014/10/08 15:01:38
I've removed the blank lines after the function de
|
| + |
| + timeline_data = tab.browser.platform.tracing_controller.Stop() |
| + timeline_model = TimelineModel(timeline_data=timeline_data) |
| + self._renderer_thread = timeline_model.GetRendererThreadFromTabId(tab.id) |
| + |
| + |
| + def ValidateAndMeasurePage(self, page, tab, results): |
| + |
| + tasks = self.GetTasks(self._renderer_thread.parent) |
| + |
| + sorted_tasks = sorted(tasks, |
| + key = lambda slice: slice.meanSelfDuration, reverse=True) |
|
Sami
2014/10/08 14:51:53
nit: No spaces around "=" for named parameters.
picksi1
2014/10/08 15:58:27
Done.
|
| + |
| + # Tell summary code to not generate results for single pages as it makes |
| + # the results page difficult to read |
| + results.AddValue(skip.SkipValue.SetOnlyShowingSummaries(page)) |
|
Sami
2014/10/08 14:51:52
Instead of this trick, could we just report the su
picksi1
2014/10/08 15:58:26
We can't accumulate values between separate execut
Sami
2014/10/09 10:28:13
The documentation for Value suggests that the page
picksi1
2014/10/09 13:02:20
As discussed offline, I'll look into a way to chan
|
| + |
| + max_tasks = min(NUMBER_OF_RESULTS_TO_DISPLAY, len(sorted_tasks)) |
| + count = 0 |
| + while count < max_tasks: |
|
petrcermak
2014/10/08 14:01:48
"for count in xrange(max_tasks):" is more suited f
Sami
2014/10/08 14:51:53
nit: could also be written as:
for task in sort
picksi1
2014/10/08 15:01:38
Nice... Done!
picksi1
2014/10/08 15:58:27
Petr made this observation too. Done.
|
| + task = sorted_tasks.pop(0) |
|
petrcermak
2014/10/08 14:01:48
Popping from the beginning of a list is quite cost
picksi1
2014/10/08 15:01:38
Not needed any more with your earlier suggestion.
|
| + results.AddValue(scalar.ScalarValue( |
| + results.current_page, |
| + task.key, |
| + "ms", |
|
Sami
2014/10/08 14:51:53
' instead of "
picksi1
2014/10/08 15:58:26
Done.
|
| + task.meanSelfDuration, |
| + description="Slowest tasks")) |
|
Sami
2014/10/08 14:51:53
' instead of "
picksi1
2014/10/08 15:58:26
Done.
|
| + count = count + 1 |
| + |
| + |
| + def GetTasks(self, process): |
|
Sami
2014/10/08 14:51:52
Does this need to be a member or could it be a fre
picksi1
2014/10/08 15:58:26
It could be free. Is it not best to encapsulate it
Sami
2014/10/09 10:28:14
Encapsulation is fine, but it could still be a @cl
|
| + |
| + task_dictionary = {} |
| + |
| + parent = 0 |
| + depth = 1 |
|
petrcermak
2014/10/08 14:01:48
depth is a constant (you don't change it anywhere
picksi1
2014/10/08 15:01:38
I made it a constant to give it a name, rather tha
|
| + |
| + for task_slice in process.IterAllSlicesOfName('MessageLoop::RunTask'): |
|
petrcermak
2014/10/08 14:01:48
for parent, task_slice in enumerate(process.IterAl
|
| + ProcessTasksForSlice(task_dictionary, task_slice, depth, parent) |
| + parent = parent + 1 |
| + |
| + # Flatten dictionary into a list |
| + tasks = [sliceData for key, sliceData in task_dictionary.items()] |
|
petrcermak
2014/10/08 14:01:48
return task_dictionary.values()
Sami
2014/10/08 14:51:53
nit: Same as writing task_dictionary.values()
picksi1
2014/10/08 15:01:38
Done.
|
| + |
| + return tasks |
| + |
| + |
| +class SliceData: |
| + |
| + def __init__(self, key, self_duration, total_duration, depth, parent): |
| + |
| + self.key = key |
| + self.count = 1 |
| + |
| + self.sum_self_duration = self_duration |
|
petrcermak
2014/10/08 14:01:48
Shouldn't there be some systematic order (e.g. sum
picksi1
2014/10/08 15:01:38
Good call. I've re-ordered them.
|
| + self.sum_total_duration = total_duration |
| + |
| + self.min_self_duration = self_duration |
| + self.max_self_duration = self_duration |
| + self.min_total_duration = total_duration |
| + self.max_total_duration = total_duration |
| + |
| + self.tree_location = [(depth, parent)] |
| + |
| + |
| + def Update(self, self_duration, total_duration, depth, parent): |
| + |
| + self.count = self.count + 1 |
|
petrcermak
2014/10/08 14:01:48
self.count += 1
|
| + |
| + self.sum_self_duration = (self.sum_self_duration + self_duration) |
|
petrcermak
2014/10/08 14:01:48
Again, I would suggest using the += operator inste
picksi1
2014/10/08 15:01:38
Done.
|
| + self.sum_total_duration = (self.sum_self_duration + total_duration) |
| + |
| + self.min_self_duration = min(self.min_self_duration, self_duration) |
| + self.max_self_duration = max(self.max_self_duration, self_duration) |
| + self.min_total_duration = min(self.min_total_duration, total_duration) |
| + self.max_total_duration = max(self.max_total_duration, total_duration) |
| + |
| + self.tree_location.append( (depth, parent) ) |
|
petrcermak
2014/10/08 14:01:48
Extra whitespace around the tuple.
Sami
2014/10/08 14:51:53
nit: no spaces outside the parens.
|
| + |
| + @property |
| + def meanSelfDuration(self): |
|
Sami
2014/10/08 14:51:52
mean_self_duration.
Do we want mean or median? Th
picksi1
2014/10/08 15:58:26
Done
|
| + |
| + if self.count == 0: |
|
Sami
2014/10/08 14:51:53
If count starts at 1, does this ever happen?
picksi1
2014/10/08 15:58:26
Ha! You are correct... old habits die hard! This i
|
| + return 0 |
| + |
| + return self.sum_self_duration / self.count |
| + |
| + |
| +def ProcessTasksForSlice(dictionary, task_slice, depth, parent): |
| + |
| + # Deal with TRACE_EVENT_INSTANTs that have no duration |
| + self_duration = task_slice.self_thread_time or 0.0 |
| + total_duration = task_slice.thread_duration or 0.0 |
| + |
| + # There is at least one task that is tracked as both uppercase and lowercase, |
| + # forcing the name to lowercase coalesces both. |
| + key = task_slice.name.lower() |
| + if key in dictionary: |
| + dictionary[key].Update( |
| + self_duration, total_duration, depth, parent) |
| + else: |
| + dictionary[key] = SliceData( |
| + key, self_duration, total_duration, depth, parent) |
| + |
| + # Process sub slices recursively |
| + for sub_slice in task_slice.sub_slices: |
| + ProcessTasksForSlice(dictionary, sub_slice, depth+1, parent) |
|
Sami
2014/10/08 14:51:53
nit: add spaces around the '+'
|