1#!/usr/bin/env python3 2# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 3import unittest 4from metric import Constant 5from metric import Event 6from metric import Expression 7from metric import ParsePerfJson 8from metric import RewriteMetricsInTermsOfOthers 9 10 11class TestMetricExpressions(unittest.TestCase): 12 13 def test_Operators(self): 14 a = Event('a') 15 b = Event('b') 16 self.assertEqual((a | b).ToPerfJson(), 'a | b') 17 self.assertEqual((a ^ b).ToPerfJson(), 'a ^ b') 18 self.assertEqual((a & b).ToPerfJson(), 'a & b') 19 self.assertEqual((a < b).ToPerfJson(), 'a < b') 20 self.assertEqual((a > b).ToPerfJson(), 'a > b') 21 self.assertEqual((a + b).ToPerfJson(), 'a + b') 22 self.assertEqual((a - b).ToPerfJson(), 'a - b') 23 self.assertEqual((a * b).ToPerfJson(), 'a * b') 24 self.assertEqual((a / b).ToPerfJson(), 'a / b') 25 self.assertEqual((a % b).ToPerfJson(), 'a % b') 26 one = Constant(1) 27 self.assertEqual((a + one).ToPerfJson(), 'a + 1') 28 29 def test_Brackets(self): 30 a = Event('a') 31 b = Event('b') 32 c = Event('c') 33 self.assertEqual((a * b + c).ToPerfJson(), 'a * b + c') 34 self.assertEqual((a + b * c).ToPerfJson(), 'a + b * c') 35 self.assertEqual(((a + a) + a).ToPerfJson(), 'a + a + a') 36 self.assertEqual(((a + b) * c).ToPerfJson(), '(a + b) * c') 37 self.assertEqual((a + (b * c)).ToPerfJson(), 'a + b * c') 38 self.assertEqual(((a / b) * c).ToPerfJson(), 'a / b * c') 39 self.assertEqual((a / (b * c)).ToPerfJson(), 'a / (b * c)') 40 41 def test_ParsePerfJson(self): 42 # Based on an example of a real metric. 43 before = '(a + b + c + d) / (2 * e)' 44 after = before 45 self.assertEqual(ParsePerfJson(before).ToPerfJson(), after) 46 47 # Parsing should handle events with '-' in their name. Note, in 48 # the json file the '\' are doubled to '\\'. 49 before = r'topdown\-fe\-bound / topdown\-slots - 1' 50 after = before 51 self.assertEqual(ParsePerfJson(before).ToPerfJson(), after) 52 53 # Parsing should handle escaped modifiers. Note, in the json file 54 # the '\' are doubled to '\\'. 55 before = r'arb@event\=0x81\,umask\=0x1@ + arb@event\=0x84\,umask\=0x1@' 56 after = before 57 self.assertEqual(ParsePerfJson(before).ToPerfJson(), after) 58 59 # Parsing should handle exponents in numbers. 60 before = r'a + 1e12 + b' 61 after = before 62 self.assertEqual(ParsePerfJson(before).ToPerfJson(), after) 63 64 before = r'a + 3e-12 + b' 65 after = before 66 self.assertEqual(ParsePerfJson(before).ToPerfJson(), after) 67 68 def test_IfElseTests(self): 69 # if-else needs rewriting to Select and back. 70 before = r'Event1 if #smt_on else Event2' 71 after = f'({before})' 72 self.assertEqual(ParsePerfJson(before).ToPerfJson(), after) 73 74 before = r'Event1 if 0 else Event2' 75 after = f'({before})' 76 self.assertEqual(ParsePerfJson(before).ToPerfJson(), after) 77 78 before = r'Event1 if 1 else Event2' 79 after = f'({before})' 80 self.assertEqual(ParsePerfJson(before).ToPerfJson(), after) 81 82 # Ensure the select is evaluate last. 83 before = r'Event1 + 1 if Event2 < 2 else Event3 + 3' 84 after = (r'Select(Event(r"Event1") + Constant(1), Event(r"Event2") < ' 85 r'Constant(2), Event(r"Event3") + Constant(3))') 86 self.assertEqual(ParsePerfJson(before).ToPython(), after) 87 88 before = r'Event1 > 1 if Event2 < 2 else Event3 > 3' 89 after = (r'Select(Event(r"Event1") > Constant(1), Event(r"Event2") < ' 90 r'Constant(2), Event(r"Event3") > Constant(3))') 91 self.assertEqual(ParsePerfJson(before).ToPython(), after) 92 93 before = r'min(a + b if c > 1 else c + d, e + f)' 94 after = r'min((a + b if c > 1 else c + d), e + f)' 95 self.assertEqual(ParsePerfJson(before).ToPerfJson(), after) 96 97 before = r'a if b else c if d else e' 98 after = r'(a if b else (c if d else e))' 99 self.assertEqual(ParsePerfJson(before).ToPerfJson(), after) 100 101 def test_ToPython(self): 102 # pylint: disable=eval-used 103 # Based on an example of a real metric. 104 before = '(a + b + c + d) / (2 * e)' 105 py = ParsePerfJson(before).ToPython() 106 after = eval(py).ToPerfJson() 107 self.assertEqual(before, after) 108 109 def test_Simplify(self): 110 before = '1 + 2 + 3' 111 after = '6' 112 self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) 113 114 before = 'a + 0' 115 after = 'a' 116 self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) 117 118 before = '0 + a' 119 after = 'a' 120 self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) 121 122 before = 'a | 0' 123 after = 'a' 124 self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) 125 126 before = '0 | a' 127 after = 'a' 128 self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) 129 130 before = 'a * 0' 131 after = '0' 132 self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) 133 134 before = '0 * a' 135 after = '0' 136 self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) 137 138 before = 'a * 1' 139 after = 'a' 140 self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) 141 142 before = '1 * a' 143 after = 'a' 144 self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) 145 146 before = 'a if 0 else b' 147 after = 'b' 148 self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) 149 150 before = 'a if 1 else b' 151 after = 'a' 152 self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) 153 154 before = 'a if b else a' 155 after = 'a' 156 self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) 157 158 # Pattern used to add a slots event to metrics that require it. 159 before = '0 * SLOTS' 160 after = '0 * SLOTS' 161 self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after) 162 163 def test_RewriteMetricsInTermsOfOthers(self): 164 Expression.__eq__ = lambda e1, e2: e1.Equals(e2) 165 before = [('cpu', 'm1', ParsePerfJson('a + b + c + d')), 166 ('cpu', 'm2', ParsePerfJson('a + b + c'))] 167 after = {('cpu', 'm1'): ParsePerfJson('m2 + d')} 168 self.assertEqual(RewriteMetricsInTermsOfOthers(before), after) 169 Expression.__eq__ = None 170 171if __name__ == '__main__': 172 unittest.main() 173