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 google.protobuf 18from typing import List, Optional 19 20from binary_cache_builder import BinaryCacheBuilder 21from pprof_proto_generator import load_pprof_profile 22from . test_utils import TestBase, TestHelper 23 24 25class TestPprofProtoGenerator(TestBase): 26 def run_generator(self, options=None, testdata_file='perf_with_interpreter_frames.data'): 27 testdata_path = TestHelper.testdata_path(testdata_file) 28 options = options or [] 29 self.run_cmd(['pprof_proto_generator.py', '-i', testdata_path] + options) 30 return self.run_cmd(['pprof_proto_generator.py', '--show'], return_output=True) 31 32 def generate_profile(self, options: Optional[List[str]], testdata_files: List[str]): 33 testdata_paths = [TestHelper.testdata_path(f) for f in testdata_files] 34 options = options or [] 35 self.run_cmd(['pprof_proto_generator.py', '-i'] + testdata_paths + options) 36 return load_pprof_profile('pprof.profile') 37 38 def test_show_art_frames(self): 39 art_frame_str = 'art::interpreter::DoCall' 40 # By default, don't show art frames. 41 self.assertNotIn(art_frame_str, self.run_generator()) 42 # Use --show_art_frames to show art frames. 43 self.assertIn(art_frame_str, self.run_generator(['--show_art_frames'])) 44 45 def test_pid_filter(self): 46 key = 'PlayScene::DoFrame()' # function in process 10419 47 self.assertIn(key, self.run_generator()) 48 self.assertIn(key, self.run_generator(['--pid', '10419'])) 49 self.assertIn(key, self.run_generator(['--pid', '10419', '10416'])) 50 self.assertNotIn(key, self.run_generator(['--pid', '10416'])) 51 52 def test_tid_filter(self): 53 key1 = 'art::ProfileSaver::Run()' # function in thread 10459 54 key2 = 'PlayScene::DoFrame()' # function in thread 10463 55 for options in ([], ['--tid', '10459', '10463']): 56 output = self.run_generator(options) 57 self.assertIn(key1, output) 58 self.assertIn(key2, output) 59 output = self.run_generator(['--tid', '10459']) 60 self.assertIn(key1, output) 61 self.assertNotIn(key2, output) 62 output = self.run_generator(['--tid', '10463']) 63 self.assertNotIn(key1, output) 64 self.assertIn(key2, output) 65 66 def test_comm_filter(self): 67 key1 = 'art::ProfileSaver::Run()' # function in thread 'Profile Saver' 68 key2 = 'PlayScene::DoFrame()' # function in thread 'e.sample.tunnel' 69 for options in ([], ['--comm', 'Profile Saver', 'e.sample.tunnel']): 70 output = self.run_generator(options) 71 self.assertIn(key1, output) 72 self.assertIn(key2, output) 73 output = self.run_generator(['--comm', 'Profile Saver']) 74 self.assertIn(key1, output) 75 self.assertNotIn(key2, output) 76 output = self.run_generator(['--comm', 'e.sample.tunnel']) 77 self.assertNotIn(key1, output) 78 self.assertIn(key2, output) 79 80 def test_build_id(self): 81 """ Test the build ids generated are not padded with zeros. """ 82 self.assertIn('build_id: e3e938cc9e40de2cfe1a5ac7595897de(', self.run_generator()) 83 84 def test_location_address(self): 85 """ Test if the address of a location is within the memory range of the corresponding 86 mapping. 87 """ 88 profile = self.generate_profile(None, ['perf_with_interpreter_frames.data']) 89 # pylint: disable=no-member 90 for location in profile.location: 91 mapping = profile.mapping[location.mapping_id - 1] 92 self.assertLessEqual(mapping.memory_start, location.address) 93 self.assertGreaterEqual(mapping.memory_limit, location.address) 94 95 def test_multiple_perf_data(self): 96 """ Test reporting multiple recording file. """ 97 profile1 = self.generate_profile(None, ['aggregatable_perf1.data']) 98 profile2 = self.generate_profile(None, ['aggregatable_perf2.data']) 99 profile_both = self.generate_profile( 100 None, ['aggregatable_perf1.data', 'aggregatable_perf2.data']) 101 # pylint: disable=no-member 102 self.assertGreater(len(profile_both.sample), len(profile1.sample)) 103 self.assertGreater(len(profile_both.sample), len(profile2.sample)) 104 105 def test_proguard_mapping_file(self): 106 """ Test --proguard-mapping-file option. """ 107 testdata_file = 'perf_need_proguard_mapping.data' 108 proguard_mapping_file = TestHelper.testdata_path('proguard_mapping.txt') 109 original_methodname = 'androidx.fragment.app.FragmentActivity.startActivityForResult' 110 # Can't show original method name without proguard mapping file. 111 self.assertNotIn(original_methodname, self.run_generator(testdata_file=testdata_file)) 112 # Show original method name with proguard mapping file. 113 self.assertIn(original_methodname, self.run_generator( 114 ['--proguard-mapping-file', proguard_mapping_file], testdata_file)) 115 116 def test_use_binary_cache(self): 117 testdata_file = TestHelper.testdata_path('runtest_two_functions_arm64_perf.data') 118 119 # Build binary_cache. 120 binary_cache_builder = BinaryCacheBuilder(TestHelper.ndk_path, False) 121 binary_cache_builder.build_binary_cache(testdata_file, [TestHelper.testdata_dir]) 122 123 # Generate profile. 124 output = self.run_generator(testdata_file=testdata_file) 125 self.assertIn('simpleperf_runtest_two_functions_arm64', output) 126 self.assertIn('two_functions.cpp', output) 127