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 re
19import tempfile
20from typing import List, Optional, Set
21
22from . test_utils import TestBase, TestHelper
23from simpleperf_utils import remove
24
25
26class TestReportSample(TestBase):
27    def get_record_data_string(self, record_file: str, options: Optional[List[str]] = None):
28        args = ['report_sample.py', '-i', TestHelper.testdata_path(record_file)]
29        if options:
30            args += options
31        report = self.run_cmd(args, return_output=True)
32        return report.replace('\r', '')
33
34    def test_no_flags(self):
35        got = self.get_record_data_string('perf_display_bitmaps.data')
36        with open(TestHelper.testdata_path('perf_display_bitmaps.perf-script')) as f:
37            want = f.read()
38        self.assertEqual(got, want)
39
40    def test_output_flag(self):
41        # Test short form flag.
42        remove('some.output')
43        got = self.get_record_data_string('perf_display_bitmaps.data',
44                                          ['-o', 'some.output'])
45        self.assertEqual(got, '')
46        self.check_exist(filename='some.output')
47
48        # Test long form flag
49        remove("some.output")
50        got = self.get_record_data_string('perf_display_bitmaps.data',
51                                          ['--output_file', 'some.output'])
52        self.assertEqual(got, '')
53        self.check_exist(filename="some.output")
54
55        # Verify that the output file contains expected data
56        with open(TestHelper.testdata_path('perf_display_bitmaps.perf-script')) as f:
57            want = f.read()
58        with open('some.output') as f:
59            got = f.read()
60        self.assertEqual(got, want)
61
62        # Verify that an output spec of '-' is stdout
63        remove("some.output")
64        got = self.get_record_data_string('perf_display_bitmaps.data', ['-o', '-'])
65        self.assertEqual(got, want)
66
67    def test_comm_filter_to_renderthread(self):
68        got = self.get_record_data_string('perf_display_bitmaps.data', ['--comm', 'RenderThread'])
69        self.assertIn('RenderThread', got)
70        self.assertNotIn('com.example.android.displayingbitmaps', got)
71
72        with open(TestHelper.testdata_path('perf_display_bitmaps.RenderThread.perf-script')) as f:
73            want = f.read()
74        self.assertEqual(got, want)
75
76    def test_comm_filter_to_ui_thread(self):
77        got = self.get_record_data_string('perf_display_bitmaps.data', [
78                                          '--comm', 'com.example.android.displayingbitmaps'])
79        self.assertIn('com.example.android.displayingbitmaps', got)
80        self.assertNotIn('RenderThread', got)
81        with open(TestHelper.testdata_path('perf_display_bitmaps.UiThread.perf-script')) as f:
82            want = f.read()
83        self.assertEqual(got, want)
84
85    def test_header(self):
86        got = self.get_record_data_string('perf_display_bitmaps.data', ['--header'])
87        with open(TestHelper.testdata_path('perf_display_bitmaps.header.perf-script')) as f:
88            want = f.read()
89        self.assertEqual(got, want)
90
91    def test_trace_offcpu(self):
92        got = self.get_record_data_string('perf_with_trace_offcpu_v2.data', [
93                                          '--trace-offcpu', 'on-cpu'])
94        self.assertIn('cpu-clock:u', got)
95        self.assertNotIn('sched:sched_switch', got)
96
97    def test_sample_filters(self):
98        def get_threads_for_filter(filter: str) -> Set[int]:
99            report = self.get_record_data_string('perf_display_bitmaps.data', filter.split())
100            pattern = re.compile(r'\s+31850/(\d+)\s+')
101            threads = set()
102            for m in re.finditer(pattern, report):
103                threads.add(int(m.group(1)))
104            return threads
105
106        self.assertNotIn(31850, get_threads_for_filter('--exclude-pid 31850'))
107        self.assertIn(31850, get_threads_for_filter('--include-pid 31850'))
108        self.assertIn(31850, get_threads_for_filter('--pid 31850'))
109        self.assertNotIn(31881, get_threads_for_filter('--exclude-tid 31881'))
110        self.assertIn(31881, get_threads_for_filter('--include-tid 31881'))
111        self.assertIn(31881, get_threads_for_filter('--tid 31881'))
112        self.assertNotIn(31881, get_threads_for_filter(
113            '--exclude-process-name com.example.android.displayingbitmaps'))
114        self.assertIn(31881, get_threads_for_filter(
115            '--include-process-name com.example.android.displayingbitmaps'))
116        self.assertNotIn(31850, get_threads_for_filter(
117            '--exclude-thread-name com.example.android.displayingbitmaps'))
118        self.assertIn(31850, get_threads_for_filter(
119            '--include-thread-name com.example.android.displayingbitmaps'))
120
121        with tempfile.NamedTemporaryFile('w', delete=False) as filter_file:
122            filter_file.write('GLOBAL_BEGIN 684943449406175\nGLOBAL_END 684943449406176')
123            filter_file.flush()
124            threads = get_threads_for_filter('--filter-file ' + filter_file.name)
125            self.assertIn(31881, threads)
126            self.assertNotIn(31850, threads)
127        os.unlink(filter_file.name)
128
129    def test_show_art_frames(self):
130        art_frame_str = 'art::interpreter::DoCall'
131        report = self.get_record_data_string('perf_with_interpreter_frames.data')
132        self.assertNotIn(art_frame_str, report)
133        report = self.get_record_data_string(
134            'perf_with_interpreter_frames.data', ['--show-art-frames'])
135        self.assertIn(art_frame_str, report)
136