| # Copyright 2016 the V8 project authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| import linux_perf_report as ipr | |
| import StringIO | |
| import unittest | |
| PERF_SCRIPT_OUTPUT = """ | |
| # This line is a comment | |
| # This should be ignored too | |
| # | |
| # cdefab01 aRandomSymbol::Name(to, be, ignored) | |
| 00000000 firstSymbol | |
| 00000123 secondSymbol | |
| 01234567 foo | |
| abcdef76 BytecodeHandler:bar | |
| 76543210 baz | |
| # Indentation shouldn't matter (neither should this line) | |
| 01234567 foo | |
| abcdef76 BytecodeHandler:bar | |
| 76543210 baz | |
| 01234567 beep | |
| abcdef76 BytecodeHandler:bar | |
| 76543210 baz | |
| 01234567 hello | |
| abcdef76 v8::internal::Compiler | |
| 00000000 Stub:CEntryStub | |
| 76543210 world | |
| 11111111 BytecodeHandler:nope | |
| 00000000 Lost | |
| 11111111 Builtin:InterpreterEntryTrampoline | |
| 22222222 bar | |
| 00000000 hello | |
| 11111111 LazyCompile:~Foo | |
| 11111111 Builtin:InterpreterEntryTrampoline | |
| 22222222 bar | |
| """ | |
| class LinuxPerfReportTest(unittest.TestCase): | |
| def test_collapsed_callchains_generator(self): | |
| perf_stream = StringIO.StringIO(PERF_SCRIPT_OUTPUT) | |
| callchains = list(ipr.collapsed_callchains_generator(perf_stream)) | |
| self.assertListEqual(callchains, [ | |
| ['firstSymbol', 'secondSymbol', '[other]'], | |
| ["foo", "BytecodeHandler:bar", "[interpreter]"], | |
| ["foo", "BytecodeHandler:bar", "[interpreter]"], | |
| ["beep", "BytecodeHandler:bar", "[interpreter]"], | |
| ["hello", "v8::internal::Compiler", "Stub:CEntryStub", "[compiler]"], | |
| ["Lost", "[misattributed]"], | |
| ["hello", "LazyCompile:~Foo", "[jit]"], | |
| ["[entry trampoline]"], | |
| ]) | |
| def test_collapsed_callchains_generator_hide_other(self): | |
| perf_stream = StringIO.StringIO(PERF_SCRIPT_OUTPUT) | |
| callchains = list(ipr.collapsed_callchains_generator(perf_stream, | |
| hide_other=True, | |
| hide_compiler=True, | |
| hide_jit=True)) | |
| self.assertListEqual(callchains, [ | |
| ["foo", "BytecodeHandler:bar", "[interpreter]"], | |
| ["foo", "BytecodeHandler:bar", "[interpreter]"], | |
| ["beep", "BytecodeHandler:bar", "[interpreter]"], | |
| ["Lost", "[misattributed]"], | |
| ["[entry trampoline]"], | |
| ]) | |
| def test_calculate_samples_count_per_callchain(self): | |
| counters = ipr.calculate_samples_count_per_callchain([ | |
| ["foo", "BytecodeHandler:bar"], | |
| ["foo", "BytecodeHandler:bar"], | |
| ["beep", "BytecodeHandler:bar"], | |
| ["hello", "v8::internal::Compiler", "[compiler]"], | |
| ]) | |
| self.assertItemsEqual(counters, [ | |
| ('BytecodeHandler:bar;foo', 2), | |
| ('BytecodeHandler:bar;beep', 1), | |
| ('[compiler];v8::internal::Compiler;hello', 1), | |
| ]) | |
| def test_calculate_samples_count_per_callchain(self): | |
| counters = ipr.calculate_samples_count_per_callchain([ | |
| ["foo", "BytecodeHandler:bar"], | |
| ["foo", "BytecodeHandler:bar"], | |
| ["beep", "BytecodeHandler:bar"], | |
| ]) | |
| self.assertItemsEqual(counters, [ | |
| ('BytecodeHandler:bar;foo', 2), | |
| ('BytecodeHandler:bar;beep', 1), | |
| ]) | |
| def test_calculate_samples_count_per_handler_show_compile(self): | |
| counters = ipr.calculate_samples_count_per_handler([ | |
| ["foo", "BytecodeHandler:bar"], | |
| ["foo", "BytecodeHandler:bar"], | |
| ["beep", "BytecodeHandler:bar"], | |
| ["hello", "v8::internal::Compiler", "[compiler]"], | |
| ]) | |
| self.assertItemsEqual(counters, [ | |
| ("bar", 3), | |
| ("[compiler]", 1) | |
| ]) | |
| def test_calculate_samples_count_per_handler_(self): | |
| counters = ipr.calculate_samples_count_per_handler([ | |
| ["foo", "BytecodeHandler:bar"], | |
| ["foo", "BytecodeHandler:bar"], | |
| ["beep", "BytecodeHandler:bar"], | |
| ]) | |
| self.assertItemsEqual(counters, [("bar", 3)]) | |
| def test_multiple_handlers(self): | |
| perf_stream = StringIO.StringIO(""" | |
| 0000 foo(bar) | |
| 1234 BytecodeHandler:first | |
| 5678 a::random::call<to>(something, else) | |
| 9abc BytecodeHandler:second | |
| def0 otherIrrelevant(stuff) | |
| 1111 entrypoint | |
| """) | |
| callchains = list(ipr.collapsed_callchains_generator(perf_stream, False)) | |
| self.assertListEqual(callchains, [ | |
| ["foo", "BytecodeHandler:first", "[interpreter]"], | |
| ]) | |
| def test_compiler_symbols_regex(self): | |
| compiler_symbols = [ | |
| "v8::internal::Parser", | |
| "v8::internal::(anonymous namespace)::Compile", | |
| "v8::internal::Compiler::foo", | |
| ] | |
| for compiler_symbol in compiler_symbols: | |
| self.assertTrue(ipr.COMPILER_SYMBOLS_RE.match(compiler_symbol)) | |
| def test_jit_code_symbols_regex(self): | |
| jit_code_symbols = [ | |
| "LazyCompile:~Foo blah.js", | |
| "Eval:*", | |
| "Script:*Bar tmp.js", | |
| ] | |
| for jit_code_symbol in jit_code_symbols: | |
| self.assertTrue(ipr.JIT_CODE_SYMBOLS_RE.match(jit_code_symbol)) | |
| def test_strip_function_parameters(self): | |
| def should_match(signature, name): | |
| self.assertEqual(ipr.strip_function_parameters(signature), name) | |
| should_match("foo(bar)", "foo"), | |
| should_match("Foo(foomatic::(anonymous)::bar(baz))", "Foo"), | |
| should_match("v8::(anonymous ns)::bar<thing(with, parentheses)>(baz, poe)", | |
| "v8::(anonymous ns)::bar<thing(with, parentheses)>") | |
| if __name__ == '__main__': | |
| unittest.main() |