1# Copyright (C) 2020 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14import io 15import textwrap 16import unittest 17 18from perf2cfg import analyze 19from perf2cfg import edit 20 21 22def empty_analyzer(): 23 return analyze.RecordAnalyzer() 24 25 26def populated_analyzer(): 27 analyzer = analyze.RecordAnalyzer() 28 analyzer.target_arch = 'aarch64' 29 samples = [ 30 ('void hcf()', 4, 'cpu-cycles', 90), 31 ('void hcf()', 8, 'cpu-cycles', 10), 32 ('void hcf()', 8, 'cache-misses', 100), 33 ] 34 35 for sample in samples: 36 analyzer.record_sample(*sample) 37 38 return analyzer 39 40 41def edit_string(analyzer, input_string): 42 input_stream = io.StringIO(input_string) 43 output_stream = io.StringIO() 44 45 editor = edit.CfgEditor(analyzer, input_stream, output_stream) 46 editor.edit() 47 48 return output_stream 49 50 51class TestEdit(unittest.TestCase): 52 53 def test_empty_file(self): 54 output_stream = edit_string(empty_analyzer(), '') 55 self.assertEqual(output_stream.getvalue(), '') 56 57 def test_wrong_filetype(self): 58 with self.assertLogs() as ctx: 59 edit_string( 60 empty_analyzer(), """<!DOCTYPE html> 61 <html> 62 <head> 63 <title>I'm not a CFG file</title> 64 </head> 65 </html>""") 66 67 self.assertEqual( 68 ctx.output, 69 ['ERROR:root:Line 1: Expected a `begin_compilation` directive']) 70 71 def test_no_architecture(self): 72 with self.assertLogs() as ctx: 73 edit_string( 74 populated_analyzer(), """begin_compilation 75 name "void noMetadata()" 76 end_compilation""") 77 78 self.assertEqual(ctx.output, [ 79 'WARNING:root:Could not deduce the CFG file ISA, assuming it is ' 80 'compatible with the target architecture aarch64' 81 ]) 82 83 def test_wrong_architecture(self): 84 with self.assertLogs() as ctx: 85 edit_string( 86 populated_analyzer(), """begin_compilation 87 name "isa:x86_64" 88 end_compilation""") 89 90 self.assertEqual(ctx.output, [ 91 'ERROR:root:The CFG file ISA x86_64 is incompatible with the ' 92 'target architecture aarch64' 93 ]) 94 95 def test_annotate_method(self): 96 with self.assertLogs() as ctx: 97 output_stream = edit_string( 98 populated_analyzer(), 99 textwrap.dedent("""\ 100 begin_compilation 101 name "isa:arm64 isa_features:a53,crc,-lse,-fp16,-dotprod,-sve" 102 end_compilation 103 begin_compilation 104 name "void hcf()" 105 end_compilation 106 begin_cfg 107 name "disassembly (after)" 108 begin_block 109 flags 110 begin_HIR 111 0 0 NOPSlide dex_pc:0 loop:none 112 0x00000000: d503201f nop 113 0x00000004: d503201f nop 114 0x00000008: d503201f nop 115 <|@ 116 end_HIR 117 end_block 118 end_cfg""")) 119 120 self.assertEqual(ctx.output, ['INFO:root:Annotated void hcf()']) 121 self.assertEqual( 122 output_stream.getvalue(), 123 textwrap.dedent("""\ 124 begin_compilation 125 name "isa:arm64 isa_features:a53,crc,-lse,-fp16,-dotprod,-sve" 126 end_compilation 127 begin_compilation 128 name "[cpu-cycles: 100.00%, cache-misses: 100.00%] void hcf()" 129 end_compilation 130 begin_cfg 131 name "disassembly (after)" 132 begin_block 133 flags "cpu-cycles: 100.00%" "cache-misses: 100.00%" "HI" 134 begin_HIR 135 0 0 NOPSlide dex_pc:0 loop:none 136 _ 0x00000000: d503201f nop 137 cpu-cycles: 90 (90.00%) 0x00000004: d503201f nop 138 cache-misses: 0 (0.00%) 139 cpu-cycles: 10 (10.00%) 0x00000008: d503201f nop 140 cache-misses: 100 (100.00%) 141 <|@ 142 end_HIR 143 end_block 144 end_cfg""")) 145