1# Copyright 2016 the V8 project authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import linux_perf_report as ipr
6import StringIO
7import unittest
8
9
10PERF_SCRIPT_OUTPUT = """
11# This line is a comment
12# This should be ignored too
13#
14#    cdefab01  aRandomSymbol::Name(to, be, ignored)
15
16   00000000 firstSymbol
17   00000123 secondSymbol
18
19   01234567 foo
20   abcdef76 BytecodeHandler:bar
21   76543210 baz
22
23# Indentation shouldn't matter (neither should this line)
24
25    01234567 foo
26      abcdef76 BytecodeHandler:bar
27        76543210 baz
28
29      01234567 beep
30   abcdef76 BytecodeHandler:bar
31    76543210 baz
32
33   01234567 hello
34   abcdef76 v8::internal::Compiler
35   00000000 Stub:CEntryStub
36   76543210 world
37   11111111 BytecodeHandler:nope
38
39   00000000 Lost
40   11111111 Builtin:InterpreterEntryTrampoline
41   22222222 bar
42
43   00000000 hello
44   11111111 LazyCompile:~Foo
45
46   11111111 Builtin:InterpreterEntryTrampoline
47   22222222 bar
48"""
49
50
51class LinuxPerfReportTest(unittest.TestCase):
52  def test_collapsed_callchains_generator(self):
53    perf_stream = StringIO.StringIO(PERF_SCRIPT_OUTPUT)
54    callchains = list(ipr.collapsed_callchains_generator(perf_stream))
55    self.assertListEqual(callchains, [
56      ['firstSymbol', 'secondSymbol', '[other]'],
57      ["foo", "BytecodeHandler:bar", "[interpreter]"],
58      ["foo", "BytecodeHandler:bar", "[interpreter]"],
59      ["beep", "BytecodeHandler:bar", "[interpreter]"],
60      ["hello", "v8::internal::Compiler", "Stub:CEntryStub", "[compiler]"],
61      ["Lost", "[misattributed]"],
62      ["hello", "LazyCompile:~Foo", "[jit]"],
63      ["[entry trampoline]"],
64    ])
65
66  def test_collapsed_callchains_generator_hide_other(self):
67    perf_stream = StringIO.StringIO(PERF_SCRIPT_OUTPUT)
68    callchains = list(ipr.collapsed_callchains_generator(perf_stream,
69                                                         hide_other=True,
70                                                         hide_compiler=True,
71                                                         hide_jit=True))
72    self.assertListEqual(callchains, [
73      ["foo", "BytecodeHandler:bar", "[interpreter]"],
74      ["foo", "BytecodeHandler:bar", "[interpreter]"],
75      ["beep", "BytecodeHandler:bar", "[interpreter]"],
76      ["Lost", "[misattributed]"],
77      ["[entry trampoline]"],
78    ])
79
80  def test_calculate_samples_count_per_callchain(self):
81    counters = ipr.calculate_samples_count_per_callchain([
82      ["foo", "BytecodeHandler:bar"],
83      ["foo", "BytecodeHandler:bar"],
84      ["beep", "BytecodeHandler:bar"],
85      ["hello", "v8::internal::Compiler", "[compiler]"],
86    ])
87    self.assertItemsEqual(counters, [
88      ('BytecodeHandler:bar;foo', 2),
89      ('BytecodeHandler:bar;beep', 1),
90      ('[compiler];v8::internal::Compiler;hello', 1),
91    ])
92
93  def test_calculate_samples_count_per_callchain(self):
94    counters = ipr.calculate_samples_count_per_callchain([
95      ["foo", "BytecodeHandler:bar"],
96      ["foo", "BytecodeHandler:bar"],
97      ["beep", "BytecodeHandler:bar"],
98    ])
99    self.assertItemsEqual(counters, [
100      ('BytecodeHandler:bar;foo', 2),
101      ('BytecodeHandler:bar;beep', 1),
102    ])
103
104  def test_calculate_samples_count_per_handler_show_compile(self):
105    counters = ipr.calculate_samples_count_per_handler([
106      ["foo", "BytecodeHandler:bar"],
107      ["foo", "BytecodeHandler:bar"],
108      ["beep", "BytecodeHandler:bar"],
109      ["hello", "v8::internal::Compiler", "[compiler]"],
110    ])
111    self.assertItemsEqual(counters, [
112      ("bar", 3),
113      ("[compiler]", 1)
114    ])
115
116  def test_calculate_samples_count_per_handler_(self):
117    counters = ipr.calculate_samples_count_per_handler([
118      ["foo", "BytecodeHandler:bar"],
119      ["foo", "BytecodeHandler:bar"],
120      ["beep", "BytecodeHandler:bar"],
121    ])
122    self.assertItemsEqual(counters, [("bar", 3)])
123
124  def test_multiple_handlers(self):
125    perf_stream = StringIO.StringIO("""
126        0000 foo(bar)
127        1234 BytecodeHandler:first
128        5678 a::random::call<to>(something, else)
129        9abc BytecodeHandler:second
130        def0 otherIrrelevant(stuff)
131        1111 entrypoint
132    """)
133    callchains = list(ipr.collapsed_callchains_generator(perf_stream, False))
134    self.assertListEqual(callchains, [
135      ["foo", "BytecodeHandler:first", "[interpreter]"],
136    ])
137
138  def test_compiler_symbols_regex(self):
139    compiler_symbols = [
140      "v8::internal::Parser",
141      "v8::internal::(anonymous namespace)::Compile",
142      "v8::internal::Compiler::foo",
143    ]
144    for compiler_symbol in compiler_symbols:
145      self.assertTrue(ipr.COMPILER_SYMBOLS_RE.match(compiler_symbol))
146
147  def test_jit_code_symbols_regex(self):
148    jit_code_symbols = [
149      "LazyCompile:~Foo blah.js",
150      "Eval:*",
151      "Script:*Bar tmp.js",
152    ]
153    for jit_code_symbol in jit_code_symbols:
154      self.assertTrue(ipr.JIT_CODE_SYMBOLS_RE.match(jit_code_symbol))
155
156  def test_strip_function_parameters(self):
157    def should_match(signature, name):
158      self.assertEqual(ipr.strip_function_parameters(signature), name)
159
160    should_match("foo(bar)", "foo"),
161    should_match("Foo(foomatic::(anonymous)::bar(baz))", "Foo"),
162    should_match("v8::(anonymous ns)::bar<thing(with, parentheses)>(baz, poe)",
163       "v8::(anonymous ns)::bar<thing(with, parentheses)>")
164
165if __name__ == '__main__':
166    unittest.main()
167