summaryrefslogtreecommitdiff
path: root/perf2cfg/tests/test_edit.py
blob: 4602c02fb2af4fb17fa596b8ce1d3e536d4ae45c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# Copyright (C) 2020 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 io
import textwrap
import unittest

from perf2cfg import analyze
from perf2cfg import edit


def empty_analyzer():
    return analyze.RecordAnalyzer()


def populated_analyzer():
    analyzer = analyze.RecordAnalyzer()
    analyzer.target_arch = 'aarch64'
    samples = [
        ('void hcf()', 4, 'cpu-cycles', 90),
        ('void hcf()', 8, 'cpu-cycles', 10),
        ('void hcf()', 8, 'cache-misses', 100),
    ]

    for sample in samples:
        analyzer.record_sample(*sample)

    return analyzer


def edit_string(analyzer, input_string):
    input_stream = io.StringIO(input_string)
    output_stream = io.StringIO()

    editor = edit.CfgEditor(analyzer, input_stream, output_stream)
    editor.edit()

    return output_stream


class TestEdit(unittest.TestCase):

    def test_empty_file(self):
        output_stream = edit_string(empty_analyzer(), '')
        self.assertEqual(output_stream.getvalue(), '')

    def test_wrong_filetype(self):
        with self.assertLogs() as ctx:
            edit_string(
                empty_analyzer(), """<!DOCTYPE html>
                <html>
                <head>
                  <title>I'm not a CFG file</title>
                </head>
                </html>""")

        self.assertEqual(
            ctx.output,
            ['ERROR:root:Line 1: Expected a `begin_compilation` directive'])

    def test_no_architecture(self):
        with self.assertLogs() as ctx:
            edit_string(
                populated_analyzer(), """begin_compilation
                  name "void noMetadata()"
                end_compilation""")

        self.assertEqual(ctx.output, [
            'WARNING:root:Could not deduce the CFG file ISA, assuming it is '
            'compatible with the target architecture aarch64'
        ])

    def test_wrong_architecture(self):
        with self.assertLogs() as ctx:
            edit_string(
                populated_analyzer(), """begin_compilation
                  name "isa:x86_64"
                end_compilation""")

        self.assertEqual(ctx.output, [
            'ERROR:root:The CFG file ISA x86_64 is incompatible with the '
            'target architecture aarch64'
        ])

    def test_annotate_method(self):
        with self.assertLogs() as ctx:
            output_stream = edit_string(
                populated_analyzer(),
                textwrap.dedent("""\
                    begin_compilation
                      name "isa:arm64 isa_features:a53,crc,-lse,-fp16,-dotprod,-sve"
                    end_compilation
                    begin_compilation
                      name "void hcf()"
                    end_compilation
                    begin_cfg
                      name "disassembly (after)"
                      begin_block
                        flags
                        begin_HIR
                          0 0 NOPSlide dex_pc:0 loop:none
                          0x00000000: d503201f nop
                          0x00000004: d503201f nop
                          0x00000008: d503201f nop
                          <|@
                        end_HIR
                      end_block
                    end_cfg"""))

        self.assertEqual(ctx.output, ['INFO:root:Annotated void hcf()'])
        self.assertEqual(
            output_stream.getvalue(),
            textwrap.dedent("""\
                begin_compilation
                  name "isa:arm64 isa_features:a53,crc,-lse,-fp16,-dotprod,-sve"
                end_compilation
                begin_compilation
                  name "[cpu-cycles: 100.00%, cache-misses: 100.00%] void hcf()"
                end_compilation
                begin_cfg
                  name "disassembly (after)"
                  begin_block
                    flags "cpu-cycles: 100.00%" "cache-misses: 100.00%" "HI"
                    begin_HIR
                      0 0 NOPSlide dex_pc:0 loop:none
                _                           0x00000000: d503201f nop
                cpu-cycles:     90 (90.00%) 0x00000004: d503201f nop
                cache-misses:     0 (0.00%)
                cpu-cycles:     10 (10.00%) 0x00000008: d503201f nop
                cache-misses: 100 (100.00%)
                      <|@
                    end_HIR
                  end_block
                end_cfg"""))