~ [ 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.9.12)


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