blob: 61faad30e5e45797cdfee4f411ac3d88ad71e617 [file]
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from analysis import callstack_filters
from analysis.stacktrace import CallStackBuffer
from analysis.stacktrace import ProfilerStackFrame
from analysis.stacktrace import StacktraceBuffer
class UMASamplingProfilerParser(object):
def Parse(self, stacks, subtree_root_depth, deps):
"""Parse the list of stacks provided by UMA into a ``Stacktrace`` object.
Args:
stacks (list): List of dicts representing stacks, e.g.:
[
{
'frames': [
{
'difference': 0.0018545067156028328,
'log_change_factor': -8.1878,
'responsible': false,
'filename': 'chrome/app/chrome_exe_main_win.cc',
'function_name': 'wWinMain',
'function_start_line': 484,
'callee_lines': [{'line': 490, 'sample_fraction': 0.9},
{'line': 511, 'sample_fraction': 0.1}]
},
...
]
},
...
]
subtree_root_depth (int): Depth of the subtree root. Frames above this
depth will be filtered out so that the ``Stacktrace`` object consists
only of the subtree.
deps (dict): Map dependency path to its corresponding Dependency.
Returns:
``Stacktrace`` object or ``None`` if the stacktrace is empty.
"""
# TODO(wittman): Change the filtering logic to use the ``responsible`` field
# after old data has been re-generated
if _IncludeFrameAboveRoot(stacks, subtree_root_depth):
filter_depth = subtree_root_depth - 1
else:
filter_depth = subtree_root_depth
filters = [callstack_filters.RemoveTopNFrames(filter_depth)]
stacktrace_buffer = StacktraceBuffer(filters=filters)
for stack in stacks:
# TODO(cweakliam) determine how best to calculate priority for a callstack
# (or if I even need to)
callstack_buffer = CallStackBuffer(priority=0)
for index, frame in enumerate(stack['frames']):
frame_object, language_type = ProfilerStackFrame.Parse(frame, index,
deps)
callstack_buffer.frames.append(frame_object)
if callstack_buffer:
callstack_buffer.language_type = language_type
stacktrace_buffer.AddFilteredStack(callstack_buffer)
return stacktrace_buffer.ToStacktrace()
def _IncludeFrameAboveRoot(stacks, subtree_root_depth):
"""Should the frame above the root of the subtree be included?
Include the frame if the performance change is a total shift of execution
at the root (due for example to the root function being added, deleted, or
renamed). Uses a simple heuristic rule to determine if this is the case.
"""
if subtree_root_depth == 0:
return False
root = stacks[0]['frames'][subtree_root_depth]
log_change_factor = root['log_change_factor']
return log_change_factor in (float('inf'), float('-inf'))