summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/app_test.py13
-rwxr-xr-xtest/do_test.py3
-rw-r--r--test/pprof_proto_generator_test.py7
-rw-r--r--test/report_html_test.py15
-rw-r--r--test/report_lib_test.py65
-rw-r--r--test/sample_filter_test.py42
-rw-r--r--test/testdata/display_bitmaps.proto_databin0 -> 385461 bytes
-rw-r--r--test/testdata/etm/etm_test_loop_smallbin0 -> 4008 bytes
-rw-r--r--test/testdata/etm/perf_for_small_binary.databin0 -> 22680 bytes
-rw-r--r--test/testdata/etm/perf_inject_small.data32
-rw-r--r--test/testdata/lbr/inject_lbr.data14
-rw-r--r--test/testdata/lbr/perf_lbr.databin0 -> 23855 bytes
-rw-r--r--test/testdata/perf_test_vmlinux.databin0 -> 1529 bytes
-rw-r--r--test/testdata/perf_with_interpreter_frames.gecko.json1
-rw-r--r--test/testdata/perf_with_jit_symbol.gecko.json1
-rw-r--r--test/testdata/perf_with_tracepoint_event.gecko.json1
-rw-r--r--test/testdata/vmlinuxbin0 -> 2331 bytes
-rw-r--r--test/tools_test.py67
18 files changed, 255 insertions, 6 deletions
diff --git a/test/app_test.py b/test/app_test.py
index a13200a..2c6835d 100644
--- a/test/app_test.py
+++ b/test/app_test.py
@@ -23,6 +23,7 @@ import subprocess
import time
from typing import List, Tuple
+from simpleperf_report_lib import ReportLib
from simpleperf_utils import remove
from . test_utils import TestBase, TestHelper, AdbHelper, INFERNO_SCRIPT
@@ -268,7 +269,13 @@ class TestRecordingRealApps(TestBase):
def test_recording_endless_tunnel(self):
self.install_apk(TestHelper.testdata_path(
'EndlessTunnel.apk'), 'com.google.sample.tunnel')
- self.start_app('shell am start -n com.google.sample.tunnel/android.app.NativeActivity -a ' +
- 'android.intent.action.MAIN -c android.intent.category.LAUNCHER')
- self.record_data('com.google.sample.tunnel', '-e cpu-clock -g --duration 10')
+ # Test using --launch to start the app.
+ self.run_cmd(['app_profiler.py', '--app', 'com.google.sample.tunnel',
+ '--launch', '-r', '-e cpu-clock -g --duration 10'])
self.check_symbol_in_record_file('PlayScene::DoFrame')
+
+ # Check app versioncode.
+ report = ReportLib()
+ meta_info = report.MetaInfo()
+ self.assertEqual(meta_info.get('app_versioncode'), '1')
+ report.Close()
diff --git a/test/do_test.py b/test/do_test.py
index 012dc62..d341c20 100755
--- a/test/do_test.py
+++ b/test/do_test.py
@@ -59,6 +59,7 @@ from . report_html_test import *
from . report_lib_test import *
from . report_sample_test import *
from . run_simpleperf_on_device_test import *
+from . sample_filter_test import *
from . stackcollapse_test import *
from . tools_test import *
from . test_utils import TestHelper
@@ -130,10 +131,12 @@ def get_test_type(test: str) -> Optional[str]:
'TestDebugUnwindReporter',
'TestInferno',
'TestPprofProtoGenerator',
+ 'TestProtoFileReportLib',
'TestPurgatorio',
'TestReportHtml',
'TestReportLib',
'TestReportSample',
+ 'TestSampleFilter',
'TestStackCollapse',
'TestTools',
'TestGeckoProfileGenerator'):
diff --git a/test/pprof_proto_generator_test.py b/test/pprof_proto_generator_test.py
index 297cf14..b8db48a 100644
--- a/test/pprof_proto_generator_test.py
+++ b/test/pprof_proto_generator_test.py
@@ -96,6 +96,10 @@ class TestPprofProtoGenerator(TestBase):
""" Test the build ids generated are not padded with zeros. """
self.assertIn('build_id: e3e938cc9e40de2cfe1a5ac7595897de(', self.run_generator())
+ def test_time_nanos(self):
+ """ Test the timestamp is adjusted to be nanoseconds. """
+ self.assertIn('time_nanos: 1516268753000000000\n', self.run_generator())
+
def test_build_id_with_binary_cache(self):
""" Test the build ids for elf files in binary_cache are not padded with zero. """
# Test with binary_cache.
@@ -291,3 +295,6 @@ class TestPprofProtoGenerator(TestBase):
self.assertIn(31881, threads)
self.assertNotIn(31850, threads)
os.unlink(filter_file.name)
+
+ def test_report_sample_proto_file(self):
+ self.run_generator('', testdata_file='display_bitmaps.proto_data')
diff --git a/test/report_html_test.py b/test/report_html_test.py
index 7241a5e..32e5821 100644
--- a/test/report_html_test.py
+++ b/test/report_html_test.py
@@ -276,3 +276,18 @@ class TestReportHtml(TestBase):
self.assertEqual(thread_names['AsyncTask.*'], 19)
self.assertNotIn('AsyncTask #3', thread_names)
self.assertNotIn('AsyncTask #4', thread_names)
+
+ def test_sort_call_graph_by_function_name(self):
+ record_data = self.get_record_data(
+ ['-i', TestHelper.testdata_path('perf_display_bitmaps.data'),
+ '--aggregate-threads', '.*'])
+
+ def get_func_name(func_id: int) -> str:
+ return record_data['functionMap'][str(func_id)]['f']
+
+ # Test if the top functions are sorted by function names.
+ thread = record_data['sampleInfo'][0]['processes'][0]['threads'][0]
+ top_functions = [get_func_name(c['f']) for c in thread['g']['c']]
+ self.assertIn('__libc_init', top_functions)
+ self.assertIn('__start_thread', top_functions)
+ self.assertEqual(top_functions, sorted(top_functions))
diff --git a/test/report_lib_test.py b/test/report_lib_test.py
index 8e212a2..1285448 100644
--- a/test/report_lib_test.py
+++ b/test/report_lib_test.py
@@ -15,10 +15,13 @@
# limitations under the License.
import os
+from pathlib import Path
+import shutil
import tempfile
from typing import Dict, List, Optional, Set
-from simpleperf_report_lib import ReportLib
+from simpleperf_report_lib import ReportLib, ProtoFileReportLib
+from simpleperf_utils import ReadElf
from . test_utils import TestBase, TestHelper
@@ -312,6 +315,25 @@ class TestReportLib(TestBase):
self.assertNotIn(31850, threads)
os.unlink(filter_file.name)
+ def test_set_sample_filter_for_cpu(self):
+ """ Test --cpu in ReportLib.SetSampleFilter(). """
+ def get_cpus_for_filter(filters: List[str]) -> Set[int]:
+ self.report_lib.Close()
+ self.report_lib = ReportLib()
+ self.report_lib.SetRecordFile(TestHelper.testdata_path('perf_display_bitmaps.data'))
+ self.report_lib.SetSampleFilter(filters)
+ cpus = set()
+ while self.report_lib.GetNextSample():
+ sample = self.report_lib.GetCurrentSample()
+ cpus.add(sample.cpu)
+ return cpus
+
+ cpus = get_cpus_for_filter(['--cpu', '0,1-2'])
+ self.assertIn(0, cpus)
+ self.assertIn(1, cpus)
+ self.assertIn(2, cpus)
+ self.assertNotIn(3, cpus)
+
def test_aggregate_threads(self):
""" Test using ReportLib.AggregateThreads(). """
def get_thread_names(aggregate_regex_list: Optional[List[str]]) -> Dict[str, int]:
@@ -332,3 +354,44 @@ class TestReportLib(TestBase):
self.assertEqual(thread_names['AsyncTask.*'], 19)
self.assertNotIn('AsyncTask #3', thread_names)
self.assertNotIn('AsyncTask #4', thread_names)
+
+ def test_use_vmlinux(self):
+ """ Test if we can use vmlinux in symfs_dir. """
+ record_file = TestHelper.testdata_path('perf_test_vmlinux.data')
+ # Create a symfs_dir.
+ symfs_dir = Path('symfs_dir')
+ symfs_dir.mkdir()
+ shutil.copy(TestHelper.testdata_path('vmlinux'), symfs_dir)
+ kernel_build_id = ReadElf(TestHelper.ndk_path).get_build_id(symfs_dir / 'vmlinux')
+ (symfs_dir / 'build_id_list').write_text('%s=vmlinux' % kernel_build_id)
+
+ # Check if vmlinux in symfs_dir is used, when we set record file before setting symfs_dir.
+ self.report_lib.SetRecordFile(record_file)
+ self.report_lib.SetSymfs(str(symfs_dir))
+ sample = self.report_lib.GetNextSample()
+ self.assertIsNotNone(sample)
+ symbol = self.report_lib.GetSymbolOfCurrentSample()
+ self.assertEqual(symbol.dso_name, "[kernel.kallsyms]")
+ # vaddr_in_file and symbol_addr are adjusted after using vmlinux.
+ self.assertEqual(symbol.vaddr_in_file, 0xffffffc008fb3e28)
+ self.assertEqual(symbol.symbol_name, "_raw_spin_unlock_irq")
+ self.assertEqual(symbol.symbol_addr, 0xffffffc008fb3e0c)
+ self.assertEqual(symbol.symbol_len, 0x4c)
+
+
+class TestProtoFileReportLib(TestBase):
+ def test_smoke(self):
+ report_lib = ProtoFileReportLib()
+ report_lib.SetRecordFile(TestHelper.testdata_path('display_bitmaps.proto_data'))
+ sample_count = 0
+ while True:
+ sample = report_lib.GetNextSample()
+ if sample is None:
+ report_lib.Close()
+ break
+ sample_count += 1
+ event = report_lib.GetEventOfCurrentSample()
+ self.assertEqual(event.name, 'cpu-clock')
+ report_lib.GetSymbolOfCurrentSample()
+ report_lib.GetCallChainOfCurrentSample()
+ self.assertEqual(sample_count, 525)
diff --git a/test/sample_filter_test.py b/test/sample_filter_test.py
new file mode 100644
index 0000000..46d51d0
--- /dev/null
+++ b/test/sample_filter_test.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json
+import os
+from pathlib import Path
+import re
+import tempfile
+from typing import List, Optional, Set
+
+from . test_utils import TestBase, TestHelper
+
+
+class TestSampleFilter(TestBase):
+ def test_show_time_range(self):
+ testdata_file = TestHelper.testdata_path('perf_display_bitmaps.data')
+ output = self.run_cmd(['sample_filter.py', '-i', testdata_file,
+ '--show-time-range'], return_output=True)
+ self.assertIn('0.134 s', output)
+
+ def test_split_time_range(self):
+ testdata_file = TestHelper.testdata_path('perf_display_bitmaps.data')
+ self.run_cmd(['sample_filter.py', '-i', testdata_file, '--split-time-range', '2'])
+ part1_data = Path('sample_filter_part1').read_text()
+ self.assertIn('GLOBAL_BEGIN 684943449406175', part1_data)
+ self.assertIn('GLOBAL_END 684943516618526', part1_data)
+ part2_data = Path('sample_filter_part2').read_text()
+ self.assertIn('GLOBAL_BEGIN 684943516618526', part2_data)
+ self.assertIn('GLOBAL_END 684943583830876', part2_data)
diff --git a/test/testdata/display_bitmaps.proto_data b/test/testdata/display_bitmaps.proto_data
new file mode 100644
index 0000000..6b8b269
--- /dev/null
+++ b/test/testdata/display_bitmaps.proto_data
Binary files differ
diff --git a/test/testdata/etm/etm_test_loop_small b/test/testdata/etm/etm_test_loop_small
new file mode 100644
index 0000000..600bf9e
--- /dev/null
+++ b/test/testdata/etm/etm_test_loop_small
Binary files differ
diff --git a/test/testdata/etm/perf_for_small_binary.data b/test/testdata/etm/perf_for_small_binary.data
new file mode 100644
index 0000000..9b012e5
--- /dev/null
+++ b/test/testdata/etm/perf_for_small_binary.data
Binary files differ
diff --git a/test/testdata/etm/perf_inject_small.data b/test/testdata/etm/perf_inject_small.data
new file mode 100644
index 0000000..560b492
--- /dev/null
+++ b/test/testdata/etm/perf_inject_small.data
@@ -0,0 +1,32 @@
+14
+14b4-14c4:1
+14c8-14fc:1
+150c-151c:1
+156c-1580:1
+1584-158c:1
+1590-15a4:10
+15a8-15b0:10
+15b4-15c4:2
+15c8-15dc:200
+15e0-15e0:2
+15e4-15f4:8
+15f8-160c:8000
+1610-1610:8
+1640-164c:1
+0
+12
+14c4->14c8:1
+14fc->150c:1
+151c->1640:1
+1580->15a8:1
+158c->0:1
+15a4->1584:1
+15b0->15e4:8
+15dc->15c8:198
+15e0->1590:2
+160c->15f8:7992
+1610->1590:8
+164c->0:1
+// build_id: 0xb9988f5e72de4b2580f98bef0ae8e4a000000000
+// /data/local/tmp/etm/etm_test_loop_small
+
diff --git a/test/testdata/lbr/inject_lbr.data b/test/testdata/lbr/inject_lbr.data
new file mode 100644
index 0000000..6f14164
--- /dev/null
+++ b/test/testdata/lbr/inject_lbr.data
@@ -0,0 +1,14 @@
+2
+1910-191b:31
+1940-194d:341
+4
+1914:1
+1940:3
+1944:4
+1948:11
+2
+191b->1910:32
+194d->1940:353
+// build_id: 0x0000000000000000000000000000000000000000
+// /home/yabinc/lbr_test_loop
+
diff --git a/test/testdata/lbr/perf_lbr.data b/test/testdata/lbr/perf_lbr.data
new file mode 100644
index 0000000..81fafe6
--- /dev/null
+++ b/test/testdata/lbr/perf_lbr.data
Binary files differ
diff --git a/test/testdata/perf_test_vmlinux.data b/test/testdata/perf_test_vmlinux.data
new file mode 100644
index 0000000..08de199
--- /dev/null
+++ b/test/testdata/perf_test_vmlinux.data
Binary files differ
diff --git a/test/testdata/perf_with_interpreter_frames.gecko.json b/test/testdata/perf_with_interpreter_frames.gecko.json
index 9959265..264dc44 100644
--- a/test/testdata/perf_with_interpreter_frames.gecko.json
+++ b/test/testdata/perf_with_interpreter_frames.gecko.json
@@ -2,6 +2,7 @@
"libs": [],
"meta": {
"abi": "aarch64",
+ "appBuildID": null,
"asyncstack": 1,
"categories": [
{
diff --git a/test/testdata/perf_with_jit_symbol.gecko.json b/test/testdata/perf_with_jit_symbol.gecko.json
index bb8940a..3988fef 100644
--- a/test/testdata/perf_with_jit_symbol.gecko.json
+++ b/test/testdata/perf_with_jit_symbol.gecko.json
@@ -2,6 +2,7 @@
"libs": [],
"meta": {
"abi": "aarch64",
+ "appBuildID": null,
"asyncstack": 1,
"categories": [
{
diff --git a/test/testdata/perf_with_tracepoint_event.gecko.json b/test/testdata/perf_with_tracepoint_event.gecko.json
index 2f5a926..2072b53 100644
--- a/test/testdata/perf_with_tracepoint_event.gecko.json
+++ b/test/testdata/perf_with_tracepoint_event.gecko.json
@@ -2,6 +2,7 @@
"libs": [],
"meta": {
"abi": "aarch64",
+ "appBuildID": null,
"asyncstack": 1,
"categories": [
{
diff --git a/test/testdata/vmlinux b/test/testdata/vmlinux
new file mode 100644
index 0000000..1239e5e
--- /dev/null
+++ b/test/testdata/vmlinux
Binary files differ
diff --git a/test/tools_test.py b/test/tools_test.py
index 5cdcbe0..2d57230 100644
--- a/test/tools_test.py
+++ b/test/tools_test.py
@@ -14,12 +14,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import io
import os
from pathlib import Path
from binary_cache_builder import BinaryCacheBuilder
-from simpleperf_utils import (Addr2Nearestline, AddrRange, BinaryFinder, Disassembly, Objdump, ReadElf,
- SourceFileSearcher, is_windows, remove)
+from simpleperf_utils import (Addr2Nearestline, AddrRange, BinaryFinder, Disassembly, Objdump,
+ ReadElf, SourceFileSearcher, is_windows, remove)
from . test_utils import TestBase, TestHelper
@@ -271,6 +272,68 @@ system/extras/simpleperf/runtest/two_functions.cpp:21:3
self.fail('for %s, %s:0x%x not found in disassemble code:\n%s' %
(dso_path, expected_line, expected_addr, s))
+ def test_objdump_parse_disassembly_for_functions(self):
+ # Parse kernel disassembly.
+ s = """
+ffffffc008000000 <_text>:
+; _text():
+; arch/arm64/kernel/head.S:60
+ffffffc008000000: ccmp x18, #0x0, #0xd, pl
+ffffffc008000004: b 0xffffffc009b2a37c <primary_entry>
+
+ffffffc008000008 <$d.1>:
+ffffffc008000008: 00 00 00 00 .word 0x00000000
+ffffffc0089bbb30 <readl>:
+; readl():
+; include/asm-generic/io.h:218
+ffffffc0089bbb30: paciasp
+ffffffc0089bbb34: stp x29, x30, [sp, #-0x30]!
+ """
+ addr_ranges = [AddrRange(0xffffffc008000000, 8),
+ AddrRange(0xffffffc008000010, 10),
+ AddrRange(0xffffffc0089bbb30, 20)]
+ binary_finder = BinaryFinder(TestHelper.testdata_dir, ReadElf(TestHelper.ndk_path))
+ objdump = Objdump(TestHelper.ndk_path, binary_finder)
+ result = objdump._parse_disassembly_for_functions(io.StringIO(s), addr_ranges)
+ self.assertEqual(len(result), 3)
+ self.assertEqual(
+ result[0].lines,
+ [('ffffffc008000000 <_text>:', 0xffffffc008000000),
+ ('; _text():', 0),
+ ('; arch/arm64/kernel/head.S:60', 0),
+ ('ffffffc008000000: ccmp x18, #0x0, #0xd, pl', 0xffffffc008000000),
+ ('ffffffc008000004: b 0xffffffc009b2a37c <primary_entry>',
+ 0xffffffc008000004),
+ ('', 0)])
+ self.assertEqual(len(result[1].lines), 0)
+ self.assertEqual(result[2].lines, [
+ ('ffffffc0089bbb30 <readl>:', 0xffffffc0089bbb30),
+ ('; readl():', 0),
+ ('; include/asm-generic/io.h:218', 0),
+ ('ffffffc0089bbb30: paciasp', 0xffffffc0089bbb30),
+ ('ffffffc0089bbb34: stp x29, x30, [sp, #-0x30]!', 0xffffffc0089bbb34),
+ ('', 0)])
+
+ # Parse user space library disassembly.
+ s = """
+0000000000200000 <art::gc::collector::ConcurrentCopying::ProcessMarkStack()>:
+; art::gc::collector::ConcurrentCopying::ProcessMarkStack():
+; art/runtime/gc/collector/concurrent_copying.cc:2121
+ 200000: stp x29, x30, [sp, #-0x20]!
+ 200004: stp x20, x19, [sp, #0x10]
+ """
+ addr_ranges = [AddrRange(0x200000, 8)]
+ result = objdump._parse_disassembly_for_functions(io.StringIO(s), addr_ranges)
+ self.assertEqual(len(result), 1)
+ self.assertEqual(result[0].lines, [
+ ('0000000000200000 <art::gc::collector::ConcurrentCopying::ProcessMarkStack()>:',
+ 0x200000),
+ ('; art::gc::collector::ConcurrentCopying::ProcessMarkStack():', 0),
+ ('; art/runtime/gc/collector/concurrent_copying.cc:2121', 0),
+ (' 200000: stp x29, x30, [sp, #-0x20]!', 0x200000),
+ (' 200004: stp x20, x19, [sp, #0x10]', 0x200004),
+ ('', 0)])
+
def test_readelf(self):
test_map = {
'simpleperf_runtest_two_functions_arm64': {