xref: /aosp_15_r20/system/extras/simpleperf/scripts/test/cpp_app_test.py (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1#!/usr/bin/env python3
2#
3# Copyright (C) 2021 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17import os
18import unittest
19
20from simpleperf_utils import remove
21from . app_test import TestExampleBase
22from . test_utils import INFERNO_SCRIPT, TestHelper
23
24
25class TestExampleCpp(TestExampleBase):
26    @classmethod
27    def setUpClass(cls):
28        cls.prepare("SimpleperfExampleCpp", "simpleperf.example.cpp", ".MainActivity")
29
30    def test_app_profiler(self):
31        self.common_test_app_profiler()
32
33    def test_app_profiler_profile_from_launch(self):
34        self.run_app_profiler(start_activity=True, build_binary_cache=False)
35        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
36        self.check_strings_in_file("report.txt", ["BusyLoopThread", "__start_thread"])
37
38    def test_report(self):
39        self.common_test_report()
40        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
41        self.check_strings_in_file("report.txt", ["BusyLoopThread", "__start_thread"])
42
43    def test_annotate(self):
44        self.common_test_annotate()
45        self.check_file_under_dir("annotated_files", "native-lib.cpp")
46        summary_file = os.path.join("annotated_files", "summary")
47        self.check_annotation_summary(summary_file, [
48            ("native-lib.cpp", 20, 0),
49            ("BusyLoopThread", 20, 0),
50            ("line 43", 20, 0)])
51
52    def test_report_sample(self):
53        self.common_test_report_sample(
54            ["BusyLoopThread",
55             "__start_thread"])
56
57    def test_pprof_proto_generator(self):
58        check_strings_with_lines = [
59            "native-lib.cpp",
60            "BusyLoopThread",
61            # Check if dso name in perf.data is replaced by binary path in binary_cache.
62            'filename: binary_cache']
63        self.common_test_pprof_proto_generator(
64            check_strings_with_lines,
65            check_strings_without_lines=["BusyLoopThread"])
66
67    def test_inferno(self):
68        self.common_test_inferno()
69        self.run_app_profiler()
70        self.run_cmd([INFERNO_SCRIPT, "-sc"])
71        self.check_inferno_report_html([('BusyLoopThread', 20)])
72
73    def test_report_html(self):
74        self.common_test_report_html()
75        self.run_cmd(['report_html.py', '--add_source_code', '--source_dirs', 'testdata',
76                      '--add_disassembly', '--binary_filter', "libnative-lib.so"])
77
78
79class TestExampleCppProfileableApk(TestExampleCpp):
80    """ Test profiling a profileable released apk."""
81    @classmethod
82    def setUpClass(cls):
83        if TestHelper.android_version >= 10:
84            cls.prepare("SimpleperfExampleCpp",
85                        "simpleperf.example.cpp",
86                        ".MainActivity", apk_name='app-release.apk')
87
88    def setUp(self):
89        if TestHelper().android_version < 10:
90            raise unittest.SkipTest("Profileable apk isn't supported on Android < Q.")
91        super().setUp()
92
93
94class TestExampleCppRoot(TestExampleBase):
95    @classmethod
96    def setUpClass(cls):
97        cls.prepare("SimpleperfExampleCpp",
98                    "simpleperf.example.cpp",
99                    ".MainActivity",
100                    adb_root=True)
101
102    def test_app_profiler(self):
103        self.common_test_app_profiler()
104
105
106class TestExampleCppTraceOffCpu(TestExampleBase):
107    @classmethod
108    def setUpClass(cls):
109        cls.prepare("SimpleperfExampleCpp", "simpleperf.example.cpp", ".SleepActivity")
110
111    def test_smoke(self):
112        self.run_app_profiler(record_arg="-g -f 1000 --duration 10 -e cpu-clock:u --trace-offcpu")
113        self.run_cmd(["report.py", "-g", "--comms", "SleepThread", "-o", "report.txt"])
114        self.check_strings_in_file("report.txt", [
115            "SleepThread(void*)",
116            "RunFunction()",
117            "SleepFunction(unsigned long long)"])
118        if (self.adb.get_device_arch() in ['x86', 'x86_64'] and
119                TestHelper.get_kernel_version() < (4, 19)):
120            # Skip on x86 and kernel < 4.19, which doesn't have patch
121            # "perf/x86: Store user space frame-pointer value on a sample" and may fail to unwind
122            # system call.
123            TestHelper.log('Skip annotation test on x86 for kernel < 4.19.')
124            return
125        remove("annotated_files")
126        self.run_cmd(["annotate.py", "-s", self.example_path, "--comm",
127                      "SleepThread", '--summary-width', '1000'])
128        self.check_exist(dirname="annotated_files")
129        self.check_file_under_dir("annotated_files", "native-lib.cpp")
130        summary_file = os.path.join("annotated_files", "summary")
131        self.check_annotation_summary(summary_file, [
132            ("native-lib.cpp", 80, 20),
133            ("SleepThread", 80, 0),
134            ("RunFunction", 20, 20),
135            ("SleepFunction", 20, 0),
136            ("line 70", 20, 0),
137            ("line 80", 20, 0)])
138        self.run_cmd([INFERNO_SCRIPT, "-sc"])
139        self.check_inferno_report_html([('SleepThread', 80),
140                                        ('RunFunction', 20),
141                                        ('SleepFunction', 20)])
142
143
144class TestExampleCppJniCall(TestExampleBase):
145    @classmethod
146    def setUpClass(cls):
147        cls.prepare("SimpleperfExampleCpp", "simpleperf.example.cpp", ".MixActivity")
148
149    def test_smoke(self):
150        if self.adb.get_android_version() == 8:
151            TestHelper.log(
152                "Android O needs wrap.sh to use compiled java code. But cpp example doesn't use wrap.sh.")
153            return
154        self.run_app_profiler()
155        self.run_cmd(["report.py", "-g", "--comms", "BusyThread", "-o", "report.txt"])
156        self.check_strings_in_file("report.txt", [
157            "simpleperf.example.cpp.MixActivity$1.run",
158            "Java_simpleperf_example_cpp_MixActivity_callFunction"])
159        remove("annotated_files")
160        self.run_cmd(["annotate.py", "-s", self.example_path, "--comm",
161                      "BusyThread", '--summary-width', '1000'])
162        self.check_exist(dirname="annotated_files")
163        self.check_file_under_dir("annotated_files", "native-lib.cpp")
164        summary_file = os.path.join("annotated_files", "summary")
165        self.check_annotation_summary(summary_file, [("native-lib.cpp", 5, 0), ("line 37", 5, 0)])
166        if self.use_compiled_java_code:
167            self.check_file_under_dir("annotated_files", "MixActivity.java")
168            self.check_annotation_summary(summary_file, [
169                ("MixActivity.java", 80, 0),
170                ("run", 80, 0),
171                ("line 27", 20, 0),
172                ("native-lib.cpp", 5, 0),
173                ("line 37", 5, 0)])
174
175        self.run_cmd([INFERNO_SCRIPT, "-sc"])
176
177
178class TestExampleCppForce32Bit(TestExampleCpp):
179    @classmethod
180    def setUpClass(cls):
181        cls.prepare("SimpleperfExampleCpp",
182                    "simpleperf.example.cpp",
183                    ".MainActivity",
184                    abi=TestHelper.get_32bit_abi())
185
186
187class TestExampleCppRootForce32Bit(TestExampleCppRoot):
188    @classmethod
189    def setUpClass(cls):
190        cls.prepare("SimpleperfExampleCpp",
191                    "simpleperf.example.cpp",
192                    ".MainActivity",
193                    abi=TestHelper.get_32bit_abi(),
194                    adb_root=False)
195
196
197class TestExampleCppTraceOffCpuForce32Bit(TestExampleCppTraceOffCpu):
198    @classmethod
199    def setUpClass(cls):
200        cls.prepare("SimpleperfExampleCpp",
201                    "simpleperf.example.cpp",
202                    ".SleepActivity",
203                    abi=TestHelper.get_32bit_abi())
204
205    def test_smoke(self):
206        if (self.adb.get_device_arch() in ['x86', 'x86_64'] and
207                self.adb.get_android_version() in [10, 11]):
208            TestHelper.log("Skip test on x86. Because simpleperf can't unwind 32bit vdso.")
209            return
210        super().test_smoke()
211