~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/pmu-events/metric.py

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /tools/perf/pmu-events/metric.py (Version linux-6.12-rc7) and /tools/perf/pmu-events/metric.py (Version linux-6.2.16)


  1 # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-      1 # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
  2 """Parse or generate representations of perf m      2 """Parse or generate representations of perf metrics."""
  3 import ast                                          3 import ast
  4 import decimal                                      4 import decimal
  5 import json                                         5 import json
  6 import re                                           6 import re
  7 from typing import Dict, List, Optional, Set,  !!   7 from typing import Dict, List, Optional, Set, Union
  8                                                     8 
  9                                                     9 
 10 class Expression:                                  10 class Expression:
 11   """Abstract base class of elements in a metr     11   """Abstract base class of elements in a metric expression."""
 12                                                    12 
 13   def ToPerfJson(self) -> str:                     13   def ToPerfJson(self) -> str:
 14     """Returns a perf json file encoded repres     14     """Returns a perf json file encoded representation."""
 15     raise NotImplementedError()                    15     raise NotImplementedError()
 16                                                    16 
 17   def ToPython(self) -> str:                       17   def ToPython(self) -> str:
 18     """Returns a python expr parseable represe     18     """Returns a python expr parseable representation."""
 19     raise NotImplementedError()                    19     raise NotImplementedError()
 20                                                    20 
 21   def Simplify(self):                              21   def Simplify(self):
 22     """Returns a simplified version of self.""     22     """Returns a simplified version of self."""
 23     raise NotImplementedError()                    23     raise NotImplementedError()
 24                                                    24 
 25   def Equals(self, other) -> bool:                 25   def Equals(self, other) -> bool:
 26     """Returns true when two expressions are t     26     """Returns true when two expressions are the same."""
 27     raise NotImplementedError()                    27     raise NotImplementedError()
 28                                                    28 
 29   def Substitute(self, name: str, expression:  << 
 30     raise NotImplementedError()                << 
 31                                                << 
 32   def __str__(self) -> str:                        29   def __str__(self) -> str:
 33     return self.ToPerfJson()                       30     return self.ToPerfJson()
 34                                                    31 
 35   def __or__(self, other: Union[int, float, 'E     32   def __or__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 36     return Operator('|', self, other)              33     return Operator('|', self, other)
 37                                                    34 
 38   def __ror__(self, other: Union[int, float, '     35   def __ror__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 39     return Operator('|', other, self)              36     return Operator('|', other, self)
 40                                                    37 
 41   def __xor__(self, other: Union[int, float, '     38   def __xor__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 42     return Operator('^', self, other)              39     return Operator('^', self, other)
 43                                                    40 
 44   def __and__(self, other: Union[int, float, '     41   def __and__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 45     return Operator('&', self, other)              42     return Operator('&', self, other)
 46                                                    43 
 47   def __rand__(self, other: Union[int, float,  << 
 48     return Operator('&', other, self)          << 
 49                                                << 
 50   def __lt__(self, other: Union[int, float, 'E     44   def __lt__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 51     return Operator('<', self, other)              45     return Operator('<', self, other)
 52                                                    46 
 53   def __gt__(self, other: Union[int, float, 'E     47   def __gt__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 54     return Operator('>', self, other)              48     return Operator('>', self, other)
 55                                                    49 
 56   def __add__(self, other: Union[int, float, '     50   def __add__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 57     return Operator('+', self, other)              51     return Operator('+', self, other)
 58                                                    52 
 59   def __radd__(self, other: Union[int, float,      53   def __radd__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 60     return Operator('+', other, self)              54     return Operator('+', other, self)
 61                                                    55 
 62   def __sub__(self, other: Union[int, float, '     56   def __sub__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 63     return Operator('-', self, other)              57     return Operator('-', self, other)
 64                                                    58 
 65   def __rsub__(self, other: Union[int, float,      59   def __rsub__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 66     return Operator('-', other, self)              60     return Operator('-', other, self)
 67                                                    61 
 68   def __mul__(self, other: Union[int, float, '     62   def __mul__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 69     return Operator('*', self, other)              63     return Operator('*', self, other)
 70                                                    64 
 71   def __rmul__(self, other: Union[int, float,      65   def __rmul__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 72     return Operator('*', other, self)              66     return Operator('*', other, self)
 73                                                    67 
 74   def __truediv__(self, other: Union[int, floa     68   def __truediv__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 75     return Operator('/', self, other)              69     return Operator('/', self, other)
 76                                                    70 
 77   def __rtruediv__(self, other: Union[int, flo     71   def __rtruediv__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 78     return Operator('/', other, self)              72     return Operator('/', other, self)
 79                                                    73 
 80   def __mod__(self, other: Union[int, float, '     74   def __mod__(self, other: Union[int, float, 'Expression']) -> 'Operator':
 81     return Operator('%', self, other)              75     return Operator('%', self, other)
 82                                                    76 
 83                                                    77 
 84 def _Constify(val: Union[bool, int, float, Exp     78 def _Constify(val: Union[bool, int, float, Expression]) -> Expression:
 85   """Used to ensure that the nodes in the expr     79   """Used to ensure that the nodes in the expression tree are all Expression."""
 86   if isinstance(val, bool):                        80   if isinstance(val, bool):
 87     return Constant(1 if val else 0)               81     return Constant(1 if val else 0)
 88   if isinstance(val, (int, float)):                82   if isinstance(val, (int, float)):
 89     return Constant(val)                           83     return Constant(val)
 90   return val                                       84   return val
 91                                                    85 
 92                                                    86 
 93 # Simple lookup for operator precedence, used      87 # Simple lookup for operator precedence, used to avoid unnecessary
 94 # brackets. Precedence matches that of the sim !!  88 # brackets. Precedence matches that of python and the simple expression parser.
 95 # but differs from python where comparisons ar << 
 96 # the bitwise &, ^, | but not the logical vers << 
 97 # parser doesn't have.                         << 
 98 _PRECEDENCE = {                                    89 _PRECEDENCE = {
 99     '|': 0,                                        90     '|': 0,
100     '^': 1,                                        91     '^': 1,
101     '&': 2,                                        92     '&': 2,
102     '<': 3,                                        93     '<': 3,
103     '>': 3,                                        94     '>': 3,
104     '+': 4,                                        95     '+': 4,
105     '-': 4,                                        96     '-': 4,
106     '*': 5,                                        97     '*': 5,
107     '/': 5,                                        98     '/': 5,
108     '%': 5,                                        99     '%': 5,
109 }                                                 100 }
110                                                   101 
111                                                   102 
112 class Operator(Expression):                       103 class Operator(Expression):
113   """Represents a binary operator in the parse    104   """Represents a binary operator in the parse tree."""
114                                                   105 
115   def __init__(self, operator: str, lhs: Union    106   def __init__(self, operator: str, lhs: Union[int, float, Expression],
116                rhs: Union[int, float, Expressi    107                rhs: Union[int, float, Expression]):
117     self.operator = operator                      108     self.operator = operator
118     self.lhs = _Constify(lhs)                     109     self.lhs = _Constify(lhs)
119     self.rhs = _Constify(rhs)                     110     self.rhs = _Constify(rhs)
120                                                   111 
121   def Bracket(self,                               112   def Bracket(self,
122               other: Expression,                  113               other: Expression,
123               other_str: str,                     114               other_str: str,
124               rhs: bool = False) -> str:          115               rhs: bool = False) -> str:
125     """If necessary brackets the given other v    116     """If necessary brackets the given other value.
126                                                   117 
127     If ``other`` is an operator then a bracket    118     If ``other`` is an operator then a bracket is necessary when
128     this/self operator has higher precedence.     119     this/self operator has higher precedence. Consider: '(a + b) * c',
129     ``other_str`` will be 'a + b'. A bracket i    120     ``other_str`` will be 'a + b'. A bracket is necessary as without
130     the bracket 'a + b * c' will evaluate 'b *    121     the bracket 'a + b * c' will evaluate 'b * c' first. However, '(a
131     * b) + c' doesn't need a bracket as 'a * b    122     * b) + c' doesn't need a bracket as 'a * b' will always be
132     evaluated first. For 'a / (b * c)' (ie the    123     evaluated first. For 'a / (b * c)' (ie the same precedence level
133     operations) then we add the bracket to bes    124     operations) then we add the bracket to best match the original
134     input, but not for '(a / b) * c' where the    125     input, but not for '(a / b) * c' where the bracket is unnecessary.
135                                                   126 
136     Args:                                         127     Args:
137       other (Expression): is a lhs or rhs oper    128       other (Expression): is a lhs or rhs operator
138       other_str (str): ``other`` in the approp    129       other_str (str): ``other`` in the appropriate string form
139       rhs (bool):  is ``other`` on the RHS        130       rhs (bool):  is ``other`` on the RHS
140                                                   131 
141     Returns:                                      132     Returns:
142       str: possibly bracketed other_str           133       str: possibly bracketed other_str
143     """                                           134     """
144     if isinstance(other, Operator):               135     if isinstance(other, Operator):
145       if _PRECEDENCE.get(self.operator, -1) >     136       if _PRECEDENCE.get(self.operator, -1) > _PRECEDENCE.get(
146           other.operator, -1):                    137           other.operator, -1):
147         return f'({other_str})'                   138         return f'({other_str})'
148       if rhs and _PRECEDENCE.get(self.operator    139       if rhs and _PRECEDENCE.get(self.operator, -1) == _PRECEDENCE.get(
149           other.operator, -1):                    140           other.operator, -1):
150         return f'({other_str})'                   141         return f'({other_str})'
151     return other_str                              142     return other_str
152                                                   143 
153   def ToPerfJson(self):                           144   def ToPerfJson(self):
154     return (f'{self.Bracket(self.lhs, self.lhs    145     return (f'{self.Bracket(self.lhs, self.lhs.ToPerfJson())} {self.operator} '
155             f'{self.Bracket(self.rhs, self.rhs    146             f'{self.Bracket(self.rhs, self.rhs.ToPerfJson(), True)}')
156                                                   147 
157   def ToPython(self):                             148   def ToPython(self):
158     return (f'{self.Bracket(self.lhs, self.lhs    149     return (f'{self.Bracket(self.lhs, self.lhs.ToPython())} {self.operator} '
159             f'{self.Bracket(self.rhs, self.rhs    150             f'{self.Bracket(self.rhs, self.rhs.ToPython(), True)}')
160                                                   151 
161   def Simplify(self) -> Expression:               152   def Simplify(self) -> Expression:
162     lhs = self.lhs.Simplify()                     153     lhs = self.lhs.Simplify()
163     rhs = self.rhs.Simplify()                     154     rhs = self.rhs.Simplify()
164     if isinstance(lhs, Constant) and isinstanc    155     if isinstance(lhs, Constant) and isinstance(rhs, Constant):
165       return Constant(ast.literal_eval(lhs + s    156       return Constant(ast.literal_eval(lhs + self.operator + rhs))
166                                                   157 
167     if isinstance(self.lhs, Constant):            158     if isinstance(self.lhs, Constant):
168       if self.operator in ('+', '|') and lhs.v    159       if self.operator in ('+', '|') and lhs.value == '0':
169         return rhs                                160         return rhs
170                                                   161 
171       # Simplify multiplication by 0 except fo    162       # Simplify multiplication by 0 except for the slot event which
172       # is deliberately introduced using this     163       # is deliberately introduced using this pattern.
173       if self.operator == '*' and lhs.value ==    164       if self.operator == '*' and lhs.value == '0' and (
174           not isinstance(rhs, Event) or 'slots    165           not isinstance(rhs, Event) or 'slots' not in rhs.name.lower()):
175         return Constant(0)                        166         return Constant(0)
176                                                   167 
177       if self.operator == '*' and lhs.value ==    168       if self.operator == '*' and lhs.value == '1':
178         return rhs                                169         return rhs
179                                                   170 
180     if isinstance(rhs, Constant):                 171     if isinstance(rhs, Constant):
181       if self.operator in ('+', '|') and rhs.v    172       if self.operator in ('+', '|') and rhs.value == '0':
182         return lhs                                173         return lhs
183                                                   174 
184       if self.operator == '*' and rhs.value ==    175       if self.operator == '*' and rhs.value == '0':
185         return Constant(0)                        176         return Constant(0)
186                                                   177 
187       if self.operator == '*' and self.rhs.val    178       if self.operator == '*' and self.rhs.value == '1':
188         return lhs                                179         return lhs
189                                                   180 
190     return Operator(self.operator, lhs, rhs)      181     return Operator(self.operator, lhs, rhs)
191                                                   182 
192   def Equals(self, other: Expression) -> bool:    183   def Equals(self, other: Expression) -> bool:
193     if isinstance(other, Operator):               184     if isinstance(other, Operator):
194       return self.operator == other.operator a    185       return self.operator == other.operator and self.lhs.Equals(
195           other.lhs) and self.rhs.Equals(other    186           other.lhs) and self.rhs.Equals(other.rhs)
196     return False                                  187     return False
197                                                   188 
198   def Substitute(self, name: str, expression:  << 
199     if self.Equals(expression):                << 
200       return Event(name)                       << 
201     lhs = self.lhs.Substitute(name, expression << 
202     rhs = None                                 << 
203     if self.rhs:                               << 
204       rhs = self.rhs.Substitute(name, expressi << 
205     return Operator(self.operator, lhs, rhs)   << 
206                                                << 
207                                                   189 
208 class Select(Expression):                         190 class Select(Expression):
209   """Represents a select ternary in the parse     191   """Represents a select ternary in the parse tree."""
210                                                   192 
211   def __init__(self, true_val: Union[int, floa    193   def __init__(self, true_val: Union[int, float, Expression],
212                cond: Union[int, float, Express    194                cond: Union[int, float, Expression],
213                false_val: Union[int, float, Ex    195                false_val: Union[int, float, Expression]):
214     self.true_val = _Constify(true_val)           196     self.true_val = _Constify(true_val)
215     self.cond = _Constify(cond)                   197     self.cond = _Constify(cond)
216     self.false_val = _Constify(false_val)         198     self.false_val = _Constify(false_val)
217                                                   199 
218   def ToPerfJson(self):                           200   def ToPerfJson(self):
219     true_str = self.true_val.ToPerfJson()         201     true_str = self.true_val.ToPerfJson()
220     cond_str = self.cond.ToPerfJson()             202     cond_str = self.cond.ToPerfJson()
221     false_str = self.false_val.ToPerfJson()       203     false_str = self.false_val.ToPerfJson()
222     return f'({true_str} if {cond_str} else {f    204     return f'({true_str} if {cond_str} else {false_str})'
223                                                   205 
224   def ToPython(self):                             206   def ToPython(self):
225     return (f'Select({self.true_val.ToPython()    207     return (f'Select({self.true_val.ToPython()}, {self.cond.ToPython()}, '
226             f'{self.false_val.ToPython()})')      208             f'{self.false_val.ToPython()})')
227                                                   209 
228   def Simplify(self) -> Expression:               210   def Simplify(self) -> Expression:
229     cond = self.cond.Simplify()                   211     cond = self.cond.Simplify()
230     true_val = self.true_val.Simplify()           212     true_val = self.true_val.Simplify()
231     false_val = self.false_val.Simplify()         213     false_val = self.false_val.Simplify()
232     if isinstance(cond, Constant):                214     if isinstance(cond, Constant):
233       return false_val if cond.value == '0' el    215       return false_val if cond.value == '0' else true_val
234                                                   216 
235     if true_val.Equals(false_val):                217     if true_val.Equals(false_val):
236       return true_val                             218       return true_val
237                                                   219 
238     return Select(true_val, cond, false_val)      220     return Select(true_val, cond, false_val)
239                                                   221 
240   def Equals(self, other: Expression) -> bool:    222   def Equals(self, other: Expression) -> bool:
241     if isinstance(other, Select):                 223     if isinstance(other, Select):
242       return self.cond.Equals(other.cond) and     224       return self.cond.Equals(other.cond) and self.false_val.Equals(
243           other.false_val) and self.true_val.E    225           other.false_val) and self.true_val.Equals(other.true_val)
244     return False                                  226     return False
245                                                   227 
246   def Substitute(self, name: str, expression:  << 
247     if self.Equals(expression):                << 
248       return Event(name)                       << 
249     true_val = self.true_val.Substitute(name,  << 
250     cond = self.cond.Substitute(name, expressi << 
251     false_val = self.false_val.Substitute(name << 
252     return Select(true_val, cond, false_val)   << 
253                                                << 
254                                                   228 
255 class Function(Expression):                       229 class Function(Expression):
256   """A function in an expression like min, max    230   """A function in an expression like min, max, d_ratio."""
257                                                   231 
258   def __init__(self,                              232   def __init__(self,
259                fn: str,                           233                fn: str,
260                lhs: Union[int, float, Expressi    234                lhs: Union[int, float, Expression],
261                rhs: Optional[Union[int, float,    235                rhs: Optional[Union[int, float, Expression]] = None):
262     self.fn = fn                                  236     self.fn = fn
263     self.lhs = _Constify(lhs)                     237     self.lhs = _Constify(lhs)
264     self.rhs = _Constify(rhs)                     238     self.rhs = _Constify(rhs)
265                                                   239 
266   def ToPerfJson(self):                           240   def ToPerfJson(self):
267     if self.rhs:                                  241     if self.rhs:
268       return f'{self.fn}({self.lhs.ToPerfJson(    242       return f'{self.fn}({self.lhs.ToPerfJson()}, {self.rhs.ToPerfJson()})'
269     return f'{self.fn}({self.lhs.ToPerfJson()}    243     return f'{self.fn}({self.lhs.ToPerfJson()})'
270                                                   244 
271   def ToPython(self):                             245   def ToPython(self):
272     if self.rhs:                                  246     if self.rhs:
273       return f'{self.fn}({self.lhs.ToPython()}    247       return f'{self.fn}({self.lhs.ToPython()}, {self.rhs.ToPython()})'
274     return f'{self.fn}({self.lhs.ToPython()})'    248     return f'{self.fn}({self.lhs.ToPython()})'
275                                                   249 
276   def Simplify(self) -> Expression:               250   def Simplify(self) -> Expression:
277     lhs = self.lhs.Simplify()                     251     lhs = self.lhs.Simplify()
278     rhs = self.rhs.Simplify() if self.rhs else    252     rhs = self.rhs.Simplify() if self.rhs else None
279     if isinstance(lhs, Constant) and isinstanc    253     if isinstance(lhs, Constant) and isinstance(rhs, Constant):
280       if self.fn == 'd_ratio':                    254       if self.fn == 'd_ratio':
281         if rhs.value == '0':                      255         if rhs.value == '0':
282           return Constant(0)                      256           return Constant(0)
283         Constant(ast.literal_eval(f'{lhs} / {r    257         Constant(ast.literal_eval(f'{lhs} / {rhs}'))
284       return Constant(ast.literal_eval(f'{self    258       return Constant(ast.literal_eval(f'{self.fn}({lhs}, {rhs})'))
285                                                   259 
286     return Function(self.fn, lhs, rhs)            260     return Function(self.fn, lhs, rhs)
287                                                   261 
288   def Equals(self, other: Expression) -> bool:    262   def Equals(self, other: Expression) -> bool:
289     if isinstance(other, Function):               263     if isinstance(other, Function):
290       result = self.fn == other.fn and self.lh !! 264       return self.fn == other.fn and self.lhs.Equals(
291       if self.rhs:                             !! 265           other.lhs) and self.rhs.Equals(other.rhs)
292         result = result and self.rhs.Equals(ot << 
293       return result                            << 
294     return False                                  266     return False
295                                                   267 
296   def Substitute(self, name: str, expression:  << 
297     if self.Equals(expression):                << 
298       return Event(name)                       << 
299     lhs = self.lhs.Substitute(name, expression << 
300     rhs = None                                 << 
301     if self.rhs:                               << 
302       rhs = self.rhs.Substitute(name, expressi << 
303     return Function(self.fn, lhs, rhs)         << 
304                                                << 
305                                                   268 
306 def _FixEscapes(s: str) -> str:                   269 def _FixEscapes(s: str) -> str:
307   s = re.sub(r'([^\\]),', r'\1\\,', s)            270   s = re.sub(r'([^\\]),', r'\1\\,', s)
308   return re.sub(r'([^\\])=', r'\1\\=', s)         271   return re.sub(r'([^\\])=', r'\1\\=', s)
309                                                   272 
310                                                   273 
311 class Event(Expression):                          274 class Event(Expression):
312   """An event in an expression."""                275   """An event in an expression."""
313                                                   276 
314   def __init__(self, name: str, legacy_name: s    277   def __init__(self, name: str, legacy_name: str = ''):
315     self.name = _FixEscapes(name)                 278     self.name = _FixEscapes(name)
316     self.legacy_name = _FixEscapes(legacy_name    279     self.legacy_name = _FixEscapes(legacy_name)
317                                                   280 
318   def ToPerfJson(self):                           281   def ToPerfJson(self):
319     result = re.sub('/', '@', self.name)          282     result = re.sub('/', '@', self.name)
320     return result                                 283     return result
321                                                   284 
322   def ToPython(self):                             285   def ToPython(self):
323     return f'Event(r"{self.name}")'               286     return f'Event(r"{self.name}")'
324                                                   287 
325   def Simplify(self) -> Expression:               288   def Simplify(self) -> Expression:
326     return self                                   289     return self
327                                                   290 
328   def Equals(self, other: Expression) -> bool:    291   def Equals(self, other: Expression) -> bool:
329     return isinstance(other, Event) and self.n    292     return isinstance(other, Event) and self.name == other.name
330                                                   293 
331   def Substitute(self, name: str, expression:  << 
332     return self                                << 
333                                                << 
334                                                   294 
335 class Constant(Expression):                       295 class Constant(Expression):
336   """A constant within the expression tree."""    296   """A constant within the expression tree."""
337                                                   297 
338   def __init__(self, value: Union[float, str])    298   def __init__(self, value: Union[float, str]):
339     ctx = decimal.Context()                       299     ctx = decimal.Context()
340     ctx.prec = 20                                 300     ctx.prec = 20
341     dec = ctx.create_decimal(repr(value) if is    301     dec = ctx.create_decimal(repr(value) if isinstance(value, float) else value)
342     self.value = dec.normalize().to_eng_string    302     self.value = dec.normalize().to_eng_string()
343     self.value = self.value.replace('+', '')      303     self.value = self.value.replace('+', '')
344     self.value = self.value.replace('E', 'e')     304     self.value = self.value.replace('E', 'e')
345                                                   305 
346   def ToPerfJson(self):                           306   def ToPerfJson(self):
347     return self.value                             307     return self.value
348                                                   308 
349   def ToPython(self):                             309   def ToPython(self):
350     return f'Constant({self.value})'              310     return f'Constant({self.value})'
351                                                   311 
352   def Simplify(self) -> Expression:               312   def Simplify(self) -> Expression:
353     return self                                   313     return self
354                                                   314 
355   def Equals(self, other: Expression) -> bool:    315   def Equals(self, other: Expression) -> bool:
356     return isinstance(other, Constant) and sel    316     return isinstance(other, Constant) and self.value == other.value
357                                                   317 
358   def Substitute(self, name: str, expression:  << 
359     return self                                << 
360                                                << 
361                                                   318 
362 class Literal(Expression):                        319 class Literal(Expression):
363   """A runtime literal within the expression t    320   """A runtime literal within the expression tree."""
364                                                   321 
365   def __init__(self, value: str):                 322   def __init__(self, value: str):
366     self.value = value                            323     self.value = value
367                                                   324 
368   def ToPerfJson(self):                           325   def ToPerfJson(self):
369     return self.value                             326     return self.value
370                                                   327 
371   def ToPython(self):                             328   def ToPython(self):
372     return f'Literal({self.value})'               329     return f'Literal({self.value})'
373                                                   330 
374   def Simplify(self) -> Expression:               331   def Simplify(self) -> Expression:
375     return self                                   332     return self
376                                                   333 
377   def Equals(self, other: Expression) -> bool:    334   def Equals(self, other: Expression) -> bool:
378     return isinstance(other, Literal) and self    335     return isinstance(other, Literal) and self.value == other.value
379                                                   336 
380   def Substitute(self, name: str, expression:  << 
381     return self                                << 
382                                                << 
383                                                   337 
384 def min(lhs: Union[int, float, Expression], rh    338 def min(lhs: Union[int, float, Expression], rhs: Union[int, float,
385                                                   339                                                        Expression]) -> Function:
386   # pylint: disable=redefined-builtin             340   # pylint: disable=redefined-builtin
387   # pylint: disable=invalid-name                  341   # pylint: disable=invalid-name
388   return Function('min', lhs, rhs)                342   return Function('min', lhs, rhs)
389                                                   343 
390                                                   344 
391 def max(lhs: Union[int, float, Expression], rh    345 def max(lhs: Union[int, float, Expression], rhs: Union[int, float,
392                                                   346                                                        Expression]) -> Function:
393   # pylint: disable=redefined-builtin             347   # pylint: disable=redefined-builtin
394   # pylint: disable=invalid-name                  348   # pylint: disable=invalid-name
395   return Function('max', lhs, rhs)                349   return Function('max', lhs, rhs)
396                                                   350 
397                                                   351 
398 def d_ratio(lhs: Union[int, float, Expression]    352 def d_ratio(lhs: Union[int, float, Expression],
399             rhs: Union[int, float, Expression]    353             rhs: Union[int, float, Expression]) -> Function:
400   # pylint: disable=redefined-builtin             354   # pylint: disable=redefined-builtin
401   # pylint: disable=invalid-name                  355   # pylint: disable=invalid-name
402   return Function('d_ratio', lhs, rhs)            356   return Function('d_ratio', lhs, rhs)
403                                                   357 
404                                                   358 
405 def source_count(event: Event) -> Function:       359 def source_count(event: Event) -> Function:
406   # pylint: disable=redefined-builtin             360   # pylint: disable=redefined-builtin
407   # pylint: disable=invalid-name                  361   # pylint: disable=invalid-name
408   return Function('source_count', event)          362   return Function('source_count', event)
409                                                   363 
410                                                   364 
411 def has_event(event: Event) -> Function:       << 
412   # pylint: disable=redefined-builtin          << 
413   # pylint: disable=invalid-name               << 
414   return Function('has_event', event)          << 
415                                                << 
416 def strcmp_cpuid_str(cpuid: Event) -> Function << 
417   # pylint: disable=redefined-builtin          << 
418   # pylint: disable=invalid-name               << 
419   return Function('strcmp_cpuid_str', cpuid)   << 
420                                                << 
421 class Metric:                                     365 class Metric:
422   """An individual metric that will specifiabl    366   """An individual metric that will specifiable on the perf command line."""
423   groups: Set[str]                                367   groups: Set[str]
424   expr: Expression                                368   expr: Expression
425   scale_unit: str                                 369   scale_unit: str
426   constraint: bool                                370   constraint: bool
427                                                   371 
428   def __init__(self,                              372   def __init__(self,
429                name: str,                         373                name: str,
430                description: str,                  374                description: str,
431                expr: Expression,                  375                expr: Expression,
432                scale_unit: str,                   376                scale_unit: str,
433                constraint: bool = False):         377                constraint: bool = False):
434     self.name = name                              378     self.name = name
435     self.description = description                379     self.description = description
436     self.expr = expr.Simplify()                   380     self.expr = expr.Simplify()
437     # Workraound valid_only_metric hiding cert    381     # Workraound valid_only_metric hiding certain metrics based on unit.
438     scale_unit = scale_unit.replace('/sec', '     382     scale_unit = scale_unit.replace('/sec', ' per sec')
439     if scale_unit[0].isdigit():                   383     if scale_unit[0].isdigit():
440       self.scale_unit = scale_unit                384       self.scale_unit = scale_unit
441     else:                                         385     else:
442       self.scale_unit = f'1{scale_unit}'          386       self.scale_unit = f'1{scale_unit}'
443     self.constraint = constraint                  387     self.constraint = constraint
444     self.groups = set()                           388     self.groups = set()
445                                                   389 
446   def __lt__(self, other):                        390   def __lt__(self, other):
447     """Sort order."""                             391     """Sort order."""
448     return self.name < other.name                 392     return self.name < other.name
449                                                   393 
450   def AddToMetricGroup(self, group):              394   def AddToMetricGroup(self, group):
451     """Callback used when being added to a Met    395     """Callback used when being added to a MetricGroup."""
452     self.groups.add(group.name)                   396     self.groups.add(group.name)
453                                                   397 
454   def Flatten(self) -> Set['Metric']:             398   def Flatten(self) -> Set['Metric']:
455     """Return a leaf metric."""                   399     """Return a leaf metric."""
456     return set([self])                            400     return set([self])
457                                                   401 
458   def ToPerfJson(self) -> Dict[str, str]:         402   def ToPerfJson(self) -> Dict[str, str]:
459     """Return as dictionary for Json generatio    403     """Return as dictionary for Json generation."""
460     result = {                                    404     result = {
461         'MetricName': self.name,                  405         'MetricName': self.name,
462         'MetricGroup': ';'.join(sorted(self.gr    406         'MetricGroup': ';'.join(sorted(self.groups)),
463         'BriefDescription': self.description,     407         'BriefDescription': self.description,
464         'MetricExpr': self.expr.ToPerfJson(),     408         'MetricExpr': self.expr.ToPerfJson(),
465         'ScaleUnit': self.scale_unit              409         'ScaleUnit': self.scale_unit
466     }                                             410     }
467     if self.constraint:                           411     if self.constraint:
468       result['MetricConstraint'] = 'NO_NMI_WAT    412       result['MetricConstraint'] = 'NO_NMI_WATCHDOG'
469                                                   413 
470     return result                                 414     return result
471                                                   415 
472                                                   416 
473 class _MetricJsonEncoder(json.JSONEncoder):       417 class _MetricJsonEncoder(json.JSONEncoder):
474   """Special handling for Metric objects."""      418   """Special handling for Metric objects."""
475                                                   419 
476   def default(self, o):                           420   def default(self, o):
477     if isinstance(o, Metric):                     421     if isinstance(o, Metric):
478       return o.ToPerfJson()                       422       return o.ToPerfJson()
479     return json.JSONEncoder.default(self, o)      423     return json.JSONEncoder.default(self, o)
480                                                   424 
481                                                   425 
482 class MetricGroup:                                426 class MetricGroup:
483   """A group of metrics.                          427   """A group of metrics.
484                                                   428 
485   Metric groups may be specificd on the perf c    429   Metric groups may be specificd on the perf command line, but within
486   the json they aren't encoded. Metrics may be    430   the json they aren't encoded. Metrics may be in multiple groups
487   which can facilitate arrangements similar to    431   which can facilitate arrangements similar to trees.
488   """                                             432   """
489                                                   433 
490   def __init__(self, name: str, metric_list: L    434   def __init__(self, name: str, metric_list: List[Union[Metric,
491                                                   435                                                         'MetricGroup']]):
492     self.name = name                              436     self.name = name
493     self.metric_list = metric_list                437     self.metric_list = metric_list
494     for metric in metric_list:                    438     for metric in metric_list:
495       metric.AddToMetricGroup(self)               439       metric.AddToMetricGroup(self)
496                                                   440 
497   def AddToMetricGroup(self, group):              441   def AddToMetricGroup(self, group):
498     """Callback used when a MetricGroup is add    442     """Callback used when a MetricGroup is added into another."""
499     for metric in self.metric_list:               443     for metric in self.metric_list:
500       metric.AddToMetricGroup(group)              444       metric.AddToMetricGroup(group)
501                                                   445 
502   def Flatten(self) -> Set[Metric]:               446   def Flatten(self) -> Set[Metric]:
503     """Returns a set of all leaf metrics."""      447     """Returns a set of all leaf metrics."""
504     result = set()                                448     result = set()
505     for x in self.metric_list:                    449     for x in self.metric_list:
506       result = result.union(x.Flatten())          450       result = result.union(x.Flatten())
507                                                   451 
508     return result                                 452     return result
509                                                   453 
510   def ToPerfJson(self) -> str:                    454   def ToPerfJson(self) -> str:
511     return json.dumps(sorted(self.Flatten()),     455     return json.dumps(sorted(self.Flatten()), indent=2, cls=_MetricJsonEncoder)
512                                                   456 
513   def __str__(self) -> str:                       457   def __str__(self) -> str:
514     return self.ToPerfJson()                      458     return self.ToPerfJson()
515                                                   459 
516                                                   460 
517 class _RewriteIfExpToSelect(ast.NodeTransforme    461 class _RewriteIfExpToSelect(ast.NodeTransformer):
518   """Transformer to convert if-else nodes to S << 
519                                                   462 
520   def visit_IfExp(self, node):                    463   def visit_IfExp(self, node):
521     # pylint: disable=invalid-name                464     # pylint: disable=invalid-name
522     self.generic_visit(node)                      465     self.generic_visit(node)
523     call = ast.Call(                              466     call = ast.Call(
524         func=ast.Name(id='Select', ctx=ast.Loa    467         func=ast.Name(id='Select', ctx=ast.Load()),
525         args=[node.body, node.test, node.orels    468         args=[node.body, node.test, node.orelse],
526         keywords=[])                              469         keywords=[])
527     ast.copy_location(call, node.test)            470     ast.copy_location(call, node.test)
528     return call                                   471     return call
529                                                   472 
530                                                   473 
531 def ParsePerfJson(orig: str) -> Expression:       474 def ParsePerfJson(orig: str) -> Expression:
532   """A simple json metric expression decoder.     475   """A simple json metric expression decoder.
533                                                   476 
534   Converts a json encoded metric expression by    477   Converts a json encoded metric expression by way of python's ast and
535   eval routine. First tokens are mapped to Eve    478   eval routine. First tokens are mapped to Event calls, then
536   accidentally converted keywords or literals     479   accidentally converted keywords or literals are mapped to their
537   appropriate calls. Python's ast is used to m    480   appropriate calls. Python's ast is used to match if-else that can't
538   be handled via operator overloading. Finally    481   be handled via operator overloading. Finally the ast is evaluated.
539                                                   482 
540   Args:                                           483   Args:
541     orig (str): String to parse.                  484     orig (str): String to parse.
542                                                   485 
543   Returns:                                        486   Returns:
544     Expression: The parsed string.                487     Expression: The parsed string.
545   """                                             488   """
546   # pylint: disable=eval-used                     489   # pylint: disable=eval-used
547   py = orig.strip()                               490   py = orig.strip()
548   # First try to convert everything that looks << 
549   # This isn't very selective so is followed u << 
550   py = re.sub(r'([a-zA-Z][^-+/\* \\\(\),]*(?:\    491   py = re.sub(r'([a-zA-Z][^-+/\* \\\(\),]*(?:\\.[^-+/\* \\\(\),]*)*)',
551               r'Event(r"\1")', py)                492               r'Event(r"\1")', py)
552   # If it started with a # it should have been << 
553   py = re.sub(r'#Event\(r"([^"]*)"\)', r'Liter    493   py = re.sub(r'#Event\(r"([^"]*)"\)', r'Literal("#\1")', py)
554   # Convert accidentally converted hex constan << 
555   # but keep it wrapped in Event(), otherwise  << 
556   # a double by the Bison parser               << 
557   py = re.sub(r'0Event\(r"[xX]([0-9a-fA-F]*)"\ << 
558   # Convert accidentally converted scientific  << 
559   py = re.sub(r'([0-9]+)Event\(r"(e[0-9]+)"\)'    494   py = re.sub(r'([0-9]+)Event\(r"(e[0-9]+)"\)', r'\1\2', py)
560   # Convert all the known keywords back from e !! 495   keywords = ['if', 'else', 'min', 'max', 'd_ratio', 'source_count']
561   keywords = ['if', 'else', 'min', 'max', 'd_r << 
562   for kw in keywords:                             496   for kw in keywords:
563     py = re.sub(rf'Event\(r"{kw}"\)', kw, py)     497     py = re.sub(rf'Event\(r"{kw}"\)', kw, py)
564   try:                                         !! 498 
565     parsed = ast.parse(py, mode='eval')        !! 499   parsed = ast.parse(py, mode='eval')
566   except SyntaxError as e:                     << 
567     raise SyntaxError(f'Parsing expression:\n{ << 
568   _RewriteIfExpToSelect().visit(parsed)           500   _RewriteIfExpToSelect().visit(parsed)
569   parsed = ast.fix_missing_locations(parsed)      501   parsed = ast.fix_missing_locations(parsed)
570   return _Constify(eval(compile(parsed, orig,     502   return _Constify(eval(compile(parsed, orig, 'eval')))
571                                                << 
572                                                << 
573 def RewriteMetricsInTermsOfOthers(metrics: Lis << 
574                                   )-> Dict[Tup << 
575   """Shorten metrics by rewriting in terms of  << 
576                                                << 
577   Args:                                        << 
578     metrics (list): pmus, metric names and the << 
579   Returns:                                     << 
580     Dict: mapping from a pmu, metric name pair << 
581   """                                          << 
582   updates: Dict[Tuple[str, str], Expression] = << 
583   for outer_pmu, outer_name, outer_expression  << 
584     if outer_pmu is None:                      << 
585       outer_pmu = 'cpu'                        << 
586     updated = outer_expression                 << 
587     while True:                                << 
588       for inner_pmu, inner_name, inner_express << 
589         if inner_pmu is None:                  << 
590           inner_pmu = 'cpu'                    << 
591         if inner_pmu.lower() != outer_pmu.lowe << 
592           continue                             << 
593         if inner_name.lower() == outer_name.lo << 
594           continue                             << 
595         if (inner_pmu, inner_name) in updates: << 
596           inner_expression = updates[(inner_pm << 
597         updated = updated.Substitute(inner_nam << 
598       if updated.Equals(outer_expression):     << 
599         break                                  << 
600       if (outer_pmu, outer_name) in updates an << 
601         break                                  << 
602       updates[(outer_pmu, outer_name)] = updat << 
603   return updates                               << 
                                                      

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php