162306a36Sopenharmony_ci#!/usr/bin/env python3
262306a36Sopenharmony_ci# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
362306a36Sopenharmony_ciimport unittest
462306a36Sopenharmony_cifrom metric import Constant
562306a36Sopenharmony_cifrom metric import Event
662306a36Sopenharmony_cifrom metric import Expression
762306a36Sopenharmony_cifrom metric import ParsePerfJson
862306a36Sopenharmony_cifrom metric import RewriteMetricsInTermsOfOthers
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ciclass TestMetricExpressions(unittest.TestCase):
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci  def test_Operators(self):
1462306a36Sopenharmony_ci    a = Event('a')
1562306a36Sopenharmony_ci    b = Event('b')
1662306a36Sopenharmony_ci    self.assertEqual((a | b).ToPerfJson(), 'a | b')
1762306a36Sopenharmony_ci    self.assertEqual((a ^ b).ToPerfJson(), 'a ^ b')
1862306a36Sopenharmony_ci    self.assertEqual((a & b).ToPerfJson(), 'a & b')
1962306a36Sopenharmony_ci    self.assertEqual((a < b).ToPerfJson(), 'a < b')
2062306a36Sopenharmony_ci    self.assertEqual((a > b).ToPerfJson(), 'a > b')
2162306a36Sopenharmony_ci    self.assertEqual((a + b).ToPerfJson(), 'a + b')
2262306a36Sopenharmony_ci    self.assertEqual((a - b).ToPerfJson(), 'a - b')
2362306a36Sopenharmony_ci    self.assertEqual((a * b).ToPerfJson(), 'a * b')
2462306a36Sopenharmony_ci    self.assertEqual((a / b).ToPerfJson(), 'a / b')
2562306a36Sopenharmony_ci    self.assertEqual((a % b).ToPerfJson(), 'a % b')
2662306a36Sopenharmony_ci    one = Constant(1)
2762306a36Sopenharmony_ci    self.assertEqual((a + one).ToPerfJson(), 'a + 1')
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci  def test_Brackets(self):
3062306a36Sopenharmony_ci    a = Event('a')
3162306a36Sopenharmony_ci    b = Event('b')
3262306a36Sopenharmony_ci    c = Event('c')
3362306a36Sopenharmony_ci    self.assertEqual((a * b + c).ToPerfJson(), 'a * b + c')
3462306a36Sopenharmony_ci    self.assertEqual((a + b * c).ToPerfJson(), 'a + b * c')
3562306a36Sopenharmony_ci    self.assertEqual(((a + a) + a).ToPerfJson(), 'a + a + a')
3662306a36Sopenharmony_ci    self.assertEqual(((a + b) * c).ToPerfJson(), '(a + b) * c')
3762306a36Sopenharmony_ci    self.assertEqual((a + (b * c)).ToPerfJson(), 'a + b * c')
3862306a36Sopenharmony_ci    self.assertEqual(((a / b) * c).ToPerfJson(), 'a / b * c')
3962306a36Sopenharmony_ci    self.assertEqual((a / (b * c)).ToPerfJson(), 'a / (b * c)')
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci  def test_ParsePerfJson(self):
4262306a36Sopenharmony_ci    # Based on an example of a real metric.
4362306a36Sopenharmony_ci    before = '(a + b + c + d) / (2 * e)'
4462306a36Sopenharmony_ci    after = before
4562306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).ToPerfJson(), after)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci    # Parsing should handle events with '-' in their name. Note, in
4862306a36Sopenharmony_ci    # the json file the '\' are doubled to '\\'.
4962306a36Sopenharmony_ci    before = r'topdown\-fe\-bound / topdown\-slots - 1'
5062306a36Sopenharmony_ci    after = before
5162306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).ToPerfJson(), after)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci    # Parsing should handle escaped modifiers. Note, in the json file
5462306a36Sopenharmony_ci    # the '\' are doubled to '\\'.
5562306a36Sopenharmony_ci    before = r'arb@event\=0x81\,umask\=0x1@ + arb@event\=0x84\,umask\=0x1@'
5662306a36Sopenharmony_ci    after = before
5762306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).ToPerfJson(), after)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci    # Parsing should handle exponents in numbers.
6062306a36Sopenharmony_ci    before = r'a + 1e12 + b'
6162306a36Sopenharmony_ci    after = before
6262306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).ToPerfJson(), after)
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci  def test_IfElseTests(self):
6562306a36Sopenharmony_ci    # if-else needs rewriting to Select and back.
6662306a36Sopenharmony_ci    before = r'Event1 if #smt_on else Event2'
6762306a36Sopenharmony_ci    after = f'({before})'
6862306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).ToPerfJson(), after)
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci    before = r'Event1 if 0 else Event2'
7162306a36Sopenharmony_ci    after = f'({before})'
7262306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).ToPerfJson(), after)
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci    before = r'Event1 if 1 else Event2'
7562306a36Sopenharmony_ci    after = f'({before})'
7662306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).ToPerfJson(), after)
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci    # Ensure the select is evaluate last.
7962306a36Sopenharmony_ci    before = r'Event1 + 1 if Event2 < 2 else Event3 + 3'
8062306a36Sopenharmony_ci    after = (r'Select(Event(r"Event1") + Constant(1), Event(r"Event2") < '
8162306a36Sopenharmony_ci             r'Constant(2), Event(r"Event3") + Constant(3))')
8262306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).ToPython(), after)
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci    before = r'Event1 > 1 if Event2 < 2 else Event3 > 3'
8562306a36Sopenharmony_ci    after = (r'Select(Event(r"Event1") > Constant(1), Event(r"Event2") < '
8662306a36Sopenharmony_ci             r'Constant(2), Event(r"Event3") > Constant(3))')
8762306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).ToPython(), after)
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci    before = r'min(a + b if c > 1 else c + d, e + f)'
9062306a36Sopenharmony_ci    after = r'min((a + b if c > 1 else c + d), e + f)'
9162306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).ToPerfJson(), after)
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci    before = r'a if b else c if d else e'
9462306a36Sopenharmony_ci    after = r'(a if b else (c if d else e))'
9562306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).ToPerfJson(), after)
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci  def test_ToPython(self):
9862306a36Sopenharmony_ci    # pylint: disable=eval-used
9962306a36Sopenharmony_ci    # Based on an example of a real metric.
10062306a36Sopenharmony_ci    before = '(a + b + c + d) / (2 * e)'
10162306a36Sopenharmony_ci    py = ParsePerfJson(before).ToPython()
10262306a36Sopenharmony_ci    after = eval(py).ToPerfJson()
10362306a36Sopenharmony_ci    self.assertEqual(before, after)
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci  def test_Simplify(self):
10662306a36Sopenharmony_ci    before = '1 + 2 + 3'
10762306a36Sopenharmony_ci    after = '6'
10862306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci    before = 'a + 0'
11162306a36Sopenharmony_ci    after = 'a'
11262306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci    before = '0 + a'
11562306a36Sopenharmony_ci    after = 'a'
11662306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci    before = 'a | 0'
11962306a36Sopenharmony_ci    after = 'a'
12062306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci    before = '0 | a'
12362306a36Sopenharmony_ci    after = 'a'
12462306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci    before = 'a * 0'
12762306a36Sopenharmony_ci    after = '0'
12862306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci    before = '0 * a'
13162306a36Sopenharmony_ci    after = '0'
13262306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci    before = 'a * 1'
13562306a36Sopenharmony_ci    after = 'a'
13662306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci    before = '1 * a'
13962306a36Sopenharmony_ci    after = 'a'
14062306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci    before = 'a if 0 else b'
14362306a36Sopenharmony_ci    after = 'b'
14462306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci    before = 'a if 1 else b'
14762306a36Sopenharmony_ci    after = 'a'
14862306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci    before = 'a if b else a'
15162306a36Sopenharmony_ci    after = 'a'
15262306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci    # Pattern used to add a slots event to metrics that require it.
15562306a36Sopenharmony_ci    before = '0 * SLOTS'
15662306a36Sopenharmony_ci    after = '0 * SLOTS'
15762306a36Sopenharmony_ci    self.assertEqual(ParsePerfJson(before).Simplify().ToPerfJson(), after)
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci  def test_RewriteMetricsInTermsOfOthers(self):
16062306a36Sopenharmony_ci    Expression.__eq__ = lambda e1, e2: e1.Equals(e2)
16162306a36Sopenharmony_ci    before = [('cpu', 'm1', ParsePerfJson('a + b + c + d')),
16262306a36Sopenharmony_ci              ('cpu', 'm2', ParsePerfJson('a + b + c'))]
16362306a36Sopenharmony_ci    after = {('cpu', 'm1'): ParsePerfJson('m2 + d')}
16462306a36Sopenharmony_ci    self.assertEqual(RewriteMetricsInTermsOfOthers(before), after)
16562306a36Sopenharmony_ci    Expression.__eq__ = None
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ciif __name__ == '__main__':
16862306a36Sopenharmony_ci  unittest.main()
169