Beispiel #1
0
    def testMatchesStackFrameWhenFrameHasMissingFields(self):
        """``MatchesStackFrame`` shouldn't crash when frames have missing fields."""
        frame_with_no_path = ProfilerStackFrame(0,
                                                0.5,
                                                0.21,
                                                False,
                                                dep_path=None,
                                                function='func',
                                                file_path=None,
                                                raw_file_path='src/f.cc')
        self.assertFalse(
            self.chromium_project.MatchesStackFrame(frame_with_no_path))

        frame_with_no_raw_path = ProfilerStackFrame(0,
                                                    0.5,
                                                    0.21,
                                                    False,
                                                    dep_path='src',
                                                    function='func',
                                                    file_path='f.cc',
                                                    raw_file_path=None)
        self.assertTrue(
            self.chromium_project.MatchesStackFrame(frame_with_no_raw_path))

        frame_with_no_function = ProfilerStackFrame(0,
                                                    0.5,
                                                    0.21,
                                                    False,
                                                    dep_path='src',
                                                    function=None,
                                                    file_path='f.cc',
                                                    raw_file_path='src/f.cc')
        self.assertTrue(
            self.chromium_project.MatchesStackFrame(frame_with_no_function))
Beispiel #2
0
    def testBlameUrlForProfilerStackFrame(self):
        """Tests that ``ProfilerStackFrame.BlameUrl`` generates the correct url."""
        frame = ProfilerStackFrame(0, 0, float('inf'), False, 'src', 'func',
                                   'f.cc', 'src/f.cc')
        self.assertEqual(frame.BlameUrl('1'), None)

        frame = frame._replace(repo_url='https://repo_url')
        self.assertEqual(frame.BlameUrl('1'), 'https://repo_url/+blame/1/f.cc')
Beispiel #3
0
    def testCrashedLineNumbersForProfilerStackFrame(self):
        """Tests the ``crashed_line_numbers`` property."""
        frame = ProfilerStackFrame(
            0,
            0,
            0,
            False,
            function_start_line=5,
            lines_old=(FunctionLine(line=10, sample_fraction=0.3),
                       FunctionLine(line=15, sample_fraction=0.7)),
            lines_new=(FunctionLine(line=12, sample_fraction=0.5),
                       FunctionLine(line=19, sample_fraction=0.5)))
        self.assertEqual(frame.crashed_line_numbers, (5, 12, 19))

        frame2 = ProfilerStackFrame(0, 0, 0, False, function_start_line=10)
        self.assertEqual(frame2.crashed_line_numbers, (10, ))

        frame3 = ProfilerStackFrame(0, 0, 0, False)
        self.assertIsNone(frame3.crashed_line_numbers)
Beispiel #4
0
    def testParseFrame(self):
        """Tests successfully parsing a stacktrace with one frame."""
        frame_dict = {
            'difference':
            0.01,
            'log_change_factor':
            -8.1,
            'responsible':
            False,
            'filename':
            'chrome/app/chrome_exe_main_win.cc',
            'function_name':
            'wWinMain',
            'function_start_line':
            484,
            'lines': [[{
                'line': 490,
                'sample_fraction': 0.7
            }, {
                'line': 511,
                'sample_fraction': 0.3
            }],
                      [{
                          'line': 490,
                          'sample_fraction': 0.9
                      }, {
                          'line': 511,
                          'sample_fraction': 0.1
                      }]]
        }
        deps = {'chrome': Dependency('chrome', 'https://repo', '1')}
        frame, language_type = ProfilerStackFrame.Parse(frame_dict, 1, deps)

        self.assertEqual(frame.index, 1)
        self.assertEqual(frame.difference, 0.01)
        self.assertEqual(frame.log_change_factor, -8.1)
        self.assertEqual(frame.responsible, False)
        self.assertEqual(frame.dep_path, 'chrome')
        self.assertEqual(frame.function, 'wWinMain')
        self.assertEqual(frame.file_path, 'app/chrome_exe_main_win.cc')
        self.assertEqual(frame.raw_file_path,
                         'chrome/app/chrome_exe_main_win.cc')
        self.assertEqual(frame.repo_url, 'https://repo')
        self.assertEqual(frame.function_start_line, 484)
        expected_lines_old = (
            FunctionLine(line=490, sample_fraction=0.7),
            FunctionLine(line=511, sample_fraction=0.3),
        )
        expected_lines_new = (
            FunctionLine(line=490, sample_fraction=0.9),
            FunctionLine(line=511, sample_fraction=0.1),
        )
        self.assertEqual(frame.lines_old, expected_lines_old)
        self.assertEqual(frame.lines_new, expected_lines_new)
        self.assertEqual(language_type, LanguageType.CPP)
Beispiel #5
0
    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()
Beispiel #6
0
    def testFilteringIncludesExtraFrameInShiftCase(self):
        """Tests that one extra frame is included in a 'shift' case.

    In a 'shift' case (i.e. where execution time at the root has shifted
    entirely from one function to another), the subtree and one extra frame
    above it should be included.
    """
        parser = UMASamplingProfilerParser()
        frame1 = {
            'difference': 0,
            'log_change_factor': 0,
            'responsible': False
        }
        frame2 = {
            'difference': 0.1,
            'log_change_factor': float('inf'),
            'responsible': True
        }
        frame3 = {
            'difference': 0.1,
            'log_change_factor': float('-inf'),
            'responsible': True
        }
        subtree_root_depth = 2
        subtree_stacks = [
            # In this case the root is the first ``frame2`` or ``frame3`` instance.
            {
                'frames': [frame1, frame1, frame2, frame2]
            },
            {
                'frames': [frame1, frame1, frame3, frame3, frame3]
            },
        ]
        deps = {'chrome/': Dependency('chrome/', 'https://repo', '1')}

        stacktrace = parser.Parse(subtree_stacks, subtree_root_depth, deps)

        filtered_stacks = (
            CallStack(
                0,
                [
                    ProfilerStackFrame(1, 0.0, 0.0, False),  # extra node
                    ProfilerStackFrame(2, 0.1, float('inf'), True),
                    ProfilerStackFrame(3, 0.1, float('inf'), True),
                ]),
            CallStack(
                0,
                [
                    ProfilerStackFrame(1, 0.0, 0.0, False),  # extra node
                    ProfilerStackFrame(2, 0.1, float('-inf'), True),
                    ProfilerStackFrame(3, 0.1, float('-inf'), True),
                    ProfilerStackFrame(4, 0.1, float('-inf'), True),
                ]),
        )
        self.assertEqual(stacktrace.stacks, filtered_stacks)
Beispiel #7
0
    def testFilterFramesBeforeSubtree(self):
        """Tests that the frames before the subtree root are filtered out."""
        parser = UMASamplingProfilerParser()
        frame1 = {
            'difference': 0,
            'log_change_factor': 0,
            'responsible': False
        }
        frame2 = {
            'difference': 0.1,
            'log_change_factor': 0.1,
            'responsible': True
        }
        subtree_root_depth = 2
        subtree_stacks = [
            # In this case the root is the first ``frame2`` instance.
            {
                'frames': [frame1, frame1, frame2, frame2]
            },
            {
                'frames': [frame1, frame1, frame2, frame2, frame2]
            },
        ]
        deps = {'chrome': Dependency('chrome', 'https://repo', '1')}

        stacktrace = parser.Parse(subtree_stacks, subtree_root_depth, deps)

        filtered_stacks = (
            CallStack(0, [
                ProfilerStackFrame(2, 0.1, 0.1, True),
                ProfilerStackFrame(3, 0.1, 0.1, True),
            ]),
            CallStack(0, [
                ProfilerStackFrame(2, 0.1, 0.1, True),
                ProfilerStackFrame(3, 0.1, 0.1, True),
                ProfilerStackFrame(4, 0.1, 0.1, True),
            ]),
        )
        self.assertEqual(stacktrace.stacks, filtered_stacks)
Beispiel #8
0
    def testIndexFramesWithCrashedGroupWhenFrameHasNoDepPath(self):
        """Tests a bug with ``IndexFramesWithCrashedGroup``.

    This function would crash when passed a frame with a ``None`` dep path.
    Instead it should ignore this frame.
    """
        frame = ProfilerStackFrame(0, 0.1, 0.5, True, dep_path=None)
        stack = CallStack(0, frame_list=[frame])
        stack_trace = Stacktrace([stack], stack)
        deps = {'src': Dependency('src', 'h://repo', 'rev3')}

        indexed_frame_infos = crash_util.IndexFramesWithCrashedGroup(
            stack_trace, Factory, deps)
        self.assertDictEqual(indexed_frame_infos, {})
Beispiel #9
0
    def testParseFrameWithMissingFields(self):
        """Tests parsing a frame with the optional fields missing."""
        frame_dict = {
            'difference': 0.01,
            'log_change_factor': -8.1,
            'responsible': False,
            # other fields are absent e.g. filename
        }
        deps = {'chrome': Dependency('chrome', 'https://repo', '1')}
        frame, language_type = ProfilerStackFrame.Parse(frame_dict, 0, deps)

        self.assertEqual(frame.index, 0)
        self.assertEqual(frame.difference, 0.01)
        self.assertEqual(frame.log_change_factor, -8.1)
        self.assertEqual(frame.responsible, False)
        self.assertIsNone(frame.dep_path)
        self.assertIsNone(frame.function)
        self.assertIsNone(frame.file_path)
        self.assertIsNone(frame.raw_file_path)
        self.assertIsNone(frame.repo_url)
        self.assertIsNone(frame.function_start_line)
        self.assertIsNone(frame.lines_old)
        self.assertIsNone(frame.lines_new)
        self.assertEqual(language_type, LanguageType.CPP)
Beispiel #10
0
    def testDistanceBetweenTouchedFileAndFrameInfos(self):
        """Tests ``DistanceBetweenTouchedFileAndFrameInfos`` method."""
        feature = min_distance.MinDistanceFeature(self._get_repository,
                                                  _MAXIMUM)
        frame1 = StackFrame(0,
                            'src/',
                            'func',
                            'a.cc',
                            'src/a.cc', [7],
                            repo_url='https://repo_url')
        frame2 = StackFrame(0,
                            'src/',
                            'func',
                            'a.cc',
                            'src/a.cc', [17],
                            repo_url='https://repo_url')
        profiler_frame = ProfilerStackFrame(0,
                                            -0.1,
                                            -5.3,
                                            True,
                                            function_start_line=13)
        profiler_frame_without_line_number = ProfilerStackFrame(
            0, -0.1, -5.3, True, function_start_line=None)
        touched_file = FileChangeInfo(ChangeType.MODIFY, 'file', 'file')

        blame = Blame('rev', 'src/')
        blame.AddRegions([
            Region(0, 10, 'rev', 'a1', 'e1', 't1'),
            Region(11, 20, 'dummy_rev', 'a2', 'e2', 't2')
        ])

        url_to_blame = {'rev/file': blame}

        def _MockGetBlame(path, revision):
            revision_path = '%s/%s' % (revision, path)
            return url_to_blame.get(revision_path)

        with mock.patch('libs.gitiles.gitiles_repository.GitilesRepository.'
                        'GetBlame') as mock_get_blame:
            mock_get_blame.side_effect = _MockGetBlame

            distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos(
                'rev', touched_file,
                [FrameInfo(frame1, 0),
                 FrameInfo(frame2, 0)],
                Dependency('src/', 'https://repo', 'rev'))
            self.assertEqual(distance_info, min_distance.Distance(0, frame1))

            distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos(
                'wrong_rev', touched_file,
                [FrameInfo(frame1, 0),
                 FrameInfo(frame2, 0)],
                Dependency('src/', 'https://repo', 'wrong_rev'))
            self.assertIsNone(distance_info)

            # Test with a ProfilerStackFrame
            distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos(
                'rev', touched_file, [
                    FrameInfo(profiler_frame, 0),
                    FrameInfo(profiler_frame_without_line_number, 0)
                ], Dependency('src/', 'https://repo', 'rev'))
            self.assertEqual(distance_info,
                             min_distance.Distance(4, profiler_frame))

            # Test that the distance remains at ``inf`` if the ProfilerStackFrames
            # passed in do not have line numbers.
            distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos(
                'rev', touched_file,
                [FrameInfo(profiler_frame_without_line_number, 0)],
                Dependency('src/', 'https://repo', 'rev'))
            self.assertEqual(distance_info,
                             min_distance.Distance(float('inf'), None))
Beispiel #11
0
 def testFailureWhenProfilerStackFrameIndexIsNone(self):
     """Tests that a TypeError is raised when the ``index`` is ``None``."""
     with self.assertRaises(TypeError):
         ProfilerStackFrame(None, 0, float('inf'), False, 'src', 'func',
                            'f.cc', 'src/f.cc')