def _monitor_tracing(self, trace_process, call_graph): calls = [] last_line_was_empty = False # call-stack ends when two empty lines follow eachother while self._thread_enabled: # If process died unexpectedly, report error if not trace_process.is_alive(): self._thread_error = 'Tracing stopped unexpectedly' break output = trace_process.get_output() # call-stack ended if output == '\n' and last_line_was_empty: stack = parse_stack(calls) call_graph.load_edges(stack.edges) call_graph.load_nodes(stack.nodes) call_graph.init_colors() calls.clear() # new line after a regular output elif output == '\n': last_line_was_empty = True # regular output from bcc trace elif output: last_line_was_empty = False calls.append(output) # Terminate process when tracing is stopped by the user if trace_process.is_alive(): trace_process.terminate() trace_process.join()
def test_parse_stack_returns_empty_stack_for_header_only(self): stack = [ "PID TID COMM FUNC ", ] result = parse_stack(stack) self.assertDictEqual(result.nodes, {}) self.assertDictEqual(result.edges, {})
def load_trace_output_from_file_to_call_graph(file_path, call_graph): text = Path(file_path).read_text() call_graph.clear() stacks = [stack.split('\n') for stack in text.split('\n\n')] for stack in stacks: graph = parse_stack(stack) call_graph.load_edges(graph.edges) call_graph.load_nodes(graph.nodes) call_graph.init_colors()
def test_parse_stack_returns_nodes_for_stack_with_one_call(self): stack = [ "19059 19059 dummy_source1 func1", "-14", "b'func1+0x0 [dummy_source1]'" ] expected_nodes = [{'call_count': 1, 'name': 'func1', 'source': 'dummy_source1'}] result = parse_stack(stack) self.assertListEqual(list(result.nodes.values()), expected_nodes) self.assertListEqual(list(result.edges.values()), [])
def test_parse_stack_returns_nodes_for_stack_with_params(self): stack = [ "19059 19059 dummy_source1 func1 b'param1' b'param2'", "-14", "b'func1+0x0 [dummy_source1]'", "b'func2+0x26 [dummy_source1]'", "b'func3+0x17 [dummy_source2]'", ] result = parse_stack(stack) self.assertListEqual( sorted(list(result.nodes.values()), key = lambda i: i['name']), [ {'call_count': 1, 'name': 'func1', 'source': 'dummy_source1'}, {'call_count': 0, 'name': 'func2', 'source': 'dummy_source1'}, {'call_count': 0, 'name': 'func3', 'source': 'dummy_source2'}, ] ) self.assertListEqual( sorted(list(result.edges.values()), key = lambda i: i['call_count']), [{'call_count': 0, 'param': []}, {'call_count': 1, 'param': ['param1', 'param2']}] )
def test_parse_stack_returns_empty_graph_for_empty_stack(self): result = parse_stack([]) self.assertDictEqual(result.nodes, {}) self.assertDictEqual(result.edges, {})
def test_parse_stack_returns_empty_graph_for_stack_with_no_calls_in_right_format(self): result = parse_stack(['no calls']) self.assertDictEqual(result.nodes, {}) self.assertDictEqual(result.edges, {})