| Index: tools/perf/metrics/timeline.py
|
| diff --git a/tools/perf/metrics/timeline.py b/tools/perf/metrics/timeline.py
|
| index 1a1ca25e219edde5f445920118c05da1725b3db6..984707d825b5cf3fc198a1ffea35d046069c732f 100644
|
| --- a/tools/perf/metrics/timeline.py
|
| +++ b/tools/perf/metrics/timeline.py
|
| @@ -101,6 +101,8 @@ OverheadTraceName = "overhead"
|
| FrameTraceName = "::SwapBuffers"
|
| FrameTraceThreadName = "renderer_compositor"
|
|
|
| +IntervalNames = ["frame", "ms"]
|
| +
|
| def Rate(numerator, denominator):
|
| return DivideIfPossibleOrZero(numerator, denominator)
|
|
|
| @@ -127,19 +129,40 @@ def ThreadCategoryName(thread_name):
|
| thread_category = TimelineThreadCategories[thread_name]
|
| return thread_category
|
|
|
| -def ThreadCpuTimeResultName(thread_category):
|
| +def ThreadCpuTimeResultName(thread_category, interval_name):
|
| # This isn't a good name, but I don't want to change it and lose continuity.
|
| - return "thread_" + thread_category + "_cpu_time_per_frame"
|
| + return "thread_" + thread_category + "_cpu_time_per_" + interval_name
|
|
|
| -def ThreadTasksResultName(thread_category):
|
| - return "tasks_per_frame_" + thread_category
|
| +def ThreadTasksResultName(thread_category, interval_name):
|
| + return "tasks_per_" + interval_name + "_" + thread_category
|
|
|
| def ThreadMeanFrameTimeResultName(thread_category):
|
| return "mean_frame_time_" + thread_category
|
|
|
| -def ThreadDetailResultName(thread_category, detail):
|
| +def ThreadDetailResultName(thread_category, interval_name, detail):
|
| detail_sanitized = detail.replace('.','_')
|
| - return "thread_" + thread_category + "|" + detail_sanitized
|
| + interval_sanitized = ""
|
| + # Special-case per-frame detail names to preserve continuity.
|
| + if interval_name == "frame":
|
| + interval_sanitized = ""
|
| + else:
|
| + interval_sanitized = "_per_" + interval_name
|
| + return (
|
| + "thread_" + thread_category + interval_sanitized + "|" + detail_sanitized)
|
| +
|
| +def _ReportCpuTimePerIntervalAsPercent(interval_name):
|
| + # When measuring ms of CPU time per ms of system time, report a %.
|
| + return interval_name == "ms"
|
| +
|
| +def ThreadCpuTimeUnits(interval_name):
|
| + if _ReportCpuTimePerIntervalAsPercent(interval_name):
|
| + return "%"
|
| + return "ms"
|
| +
|
| +def ThreadCpuTimeValue(cpu_time_per_interval, interval_name):
|
| + if _ReportCpuTimePerIntervalAsPercent(interval_name):
|
| + return cpu_time_per_interval * 100.0
|
| + return cpu_time_per_interval
|
|
|
|
|
| class ResultsForThread(object):
|
| @@ -188,28 +211,21 @@ class ResultsForThread(object):
|
| self.all_slices.extend(self.SlicesInActions(thread.all_slices))
|
| self.toplevel_slices.extend(self.SlicesInActions(thread.toplevel_slices))
|
|
|
| - # Currently we report cpu-time per frame, tasks per frame, and possibly
|
| - # the mean frame (if there is a trace specified to find it).
|
| - def AddResults(self, num_frames, results):
|
| - cpu_per_frame = Rate(self.cpu_time, num_frames)
|
| - tasks_per_frame = Rate(len(self.toplevel_slices), num_frames)
|
| + # Reports cpu-time per interval and tasks per interval.
|
| + def AddResults(self, num_intervals, interval_name, results):
|
| + cpu_per_interval = Rate(self.cpu_time, num_intervals)
|
| + tasks_per_interval = Rate(len(self.toplevel_slices), num_intervals)
|
| results.AddValue(scalar.ScalarValue(
|
| - results.current_page, ThreadCpuTimeResultName(self.name),
|
| - 'ms', cpu_per_frame))
|
| + results.current_page,
|
| + ThreadCpuTimeResultName(self.name, interval_name),
|
| + ThreadCpuTimeUnits(interval_name),
|
| + ThreadCpuTimeValue(cpu_per_interval, interval_name)))
|
| results.AddValue(scalar.ScalarValue(
|
| - results.current_page, ThreadTasksResultName(self.name),
|
| - 'tasks', tasks_per_frame))
|
| - # Report mean frame time if this is the thread we are using for normalizing
|
| - # other results. We could report other frame rates (eg. renderer_main) but
|
| - # this might get confusing.
|
| - if self.name == FrameTraceThreadName:
|
| - num_frames = self.CountTracesWithName(FrameTraceName)
|
| - mean_frame_time = Rate(self.all_action_time, num_frames)
|
| - results.AddValue(scalar.ScalarValue(
|
| - results.current_page, ThreadMeanFrameTimeResultName(self.name),
|
| - 'ms', mean_frame_time))
|
| + results.current_page,
|
| + ThreadTasksResultName(self.name, interval_name),
|
| + 'tasks', tasks_per_interval))
|
|
|
| - def AddDetailedResults(self, num_frames, results):
|
| + def AddDetailedResults(self, num_intervals, interval_name, results):
|
| slices_by_category = collections.defaultdict(list)
|
| for s in self.all_slices:
|
| slices_by_category[s.category].append(s)
|
| @@ -217,16 +233,20 @@ class ResultsForThread(object):
|
| for category, slices_in_category in slices_by_category.iteritems():
|
| self_time = sum([x.self_time for x in slices_in_category])
|
| all_self_times.append(self_time)
|
| - self_time_result = (float(self_time) / num_frames) if num_frames else 0
|
| + self_time_per_interval = Rate(self_time, num_intervals)
|
| results.AddValue(scalar.ScalarValue(
|
| - results.current_page, ThreadDetailResultName(self.name, category),
|
| - 'ms', self_time_result))
|
| + results.current_page,
|
| + ThreadDetailResultName(self.name, interval_name, category),
|
| + ThreadCpuTimeUnits(interval_name),
|
| + ThreadCpuTimeValue(self_time_per_interval, interval_name)))
|
| all_measured_time = sum(all_self_times)
|
| idle_time = max(0, self.all_action_time - all_measured_time)
|
| - idle_time_result = (float(idle_time) / num_frames) if num_frames else 0
|
| + idle_time_per_interval = Rate(idle_time, num_intervals)
|
| results.AddValue(scalar.ScalarValue(
|
| - results.current_page, ThreadDetailResultName(self.name, "idle"),
|
| - 'ms', idle_time_result))
|
| + results.current_page,
|
| + ThreadDetailResultName(self.name, interval_name, "idle"),
|
| + ThreadCpuTimeUnits(interval_name),
|
| + ThreadCpuTimeValue(idle_time_per_interval, interval_name)))
|
|
|
| def CountTracesWithName(self, substring):
|
| count = 0
|
| @@ -235,6 +255,7 @@ class ResultsForThread(object):
|
| count += 1
|
| return count
|
|
|
| +
|
| class ThreadTimesTimelineMetric(timeline_based_metric.TimelineBasedMetric):
|
| def __init__(self):
|
| super(ThreadTimesTimelineMetric, self).__init__()
|
| @@ -247,7 +268,7 @@ class ThreadTimesTimelineMetric(timeline_based_metric.TimelineBasedMetric):
|
| thread_category_results = {}
|
| for name in TimelineThreadCategories.values():
|
| thread_category_results[name] = ResultsForThread(
|
| - model, [r.GetBounds() for r in interaction_records], name)
|
| + model, [r.GetBounds() for r in interaction_records], name)
|
|
|
| # Group the slices by their thread category.
|
| for thread in model.GetAllThreads():
|
| @@ -263,15 +284,30 @@ class ThreadTimesTimelineMetric(timeline_based_metric.TimelineBasedMetric):
|
| if ThreadCategoryName(thread.name) in FastPathThreads:
|
| thread_category_results['total_fast_path'].AppendThreadSlices(thread)
|
|
|
| - # Calculate the number of frames.
|
| + # Calculate the interaction's number of frames.
|
| frame_rate_thread = thread_category_results[FrameTraceThreadName]
|
| num_frames = frame_rate_thread.CountTracesWithName(FrameTraceName)
|
|
|
| - # Report the desired results and details.
|
| - for thread_results in thread_category_results.values():
|
| - if thread_results.name in self.results_to_report:
|
| - thread_results.AddResults(num_frames, results)
|
| - # TOOD(nduca): When generic results objects are done, this special case
|
| - # can be replaced with a generic UI feature.
|
| - if thread_results.name in self.details_to_report:
|
| - thread_results.AddDetailedResults(num_frames, results)
|
| + # Calculate the interaction's duration.
|
| + all_threads = thread_category_results['total_all']
|
| + num_ms = all_threads.all_action_time
|
| +
|
| + # Report the desired results and details for each interval type.
|
| + intervals = [('frame', num_frames), ('ms', num_ms)]
|
| + for (interval_name, num_intervals) in intervals:
|
| + for thread_results in thread_category_results.values():
|
| + if thread_results.name in self.results_to_report:
|
| + thread_results.AddResults(num_intervals, interval_name, results)
|
| + # TOOD(nduca): When generic results objects are done, this special case
|
| + # can be replaced with a generic UI feature.
|
| + if thread_results.name in self.details_to_report:
|
| + thread_results.AddDetailedResults(
|
| + num_intervals, interval_name, results)
|
| +
|
| + # Report mean frame time for the frame rate thread. We could report other
|
| + # frame rates (eg. renderer_main) but this might get confusing.
|
| + mean_frame_time = Rate(frame_rate_thread.all_action_time, num_frames)
|
| + results.AddValue(scalar.ScalarValue(
|
| + results.current_page,
|
| + ThreadMeanFrameTimeResultName(FrameTraceThreadName),
|
| + 'ms', mean_frame_time))
|
|
|