Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
test_fpe.py
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file test_fpe.py
1 import sys
2 import os
3 import re
4 from pathlib import Path
5 
6 import pytest
7 
8 import acts
9 import acts.examples
10 
11 pytestmark = [
12  pytest.mark.skipif(
13  sys.platform != "linux",
14  reason="FPE monitoring currently only supported on Linux",
15  ),
16  pytest.mark.skipif(
17  "ACTS_SEQUENCER_DISABLE_FPEMON" in os.environ,
18  reason="Sequencer is configured to disable FPE monitoring",
19  ),
20 ]
21 
22 
23 _names = {
24  acts.FpeType.FLTDIV: "DivByZero",
25  acts.FpeType.FLTOVF: "Overflow",
26  acts.FpeType.FLTINV: "Invalid",
27 }
28 
29 
30 _types = [
31  pytest.param(acts.FpeType.FLTDIV, id="FLTDIV"),
32  pytest.param(acts.FpeType.FLTOVF, id="FLTOVF"),
33  pytest.param(acts.FpeType.FLTINV, id="FLTINV"),
34 ]
35 
36 _src = (Path(__file__).parent / "../src/Framework.cpp").resolve()
37 _locs = {}
38 with _src.open() as fh:
39  _name_to_type = {v.lower(): k for k, v in _names.items()}
40  for i, line in enumerate(fh):
41  m = re.match(r".*// ?MARK: (.*)", line)
42  if m is None:
43  continue
44  (name,) = m.groups()
45  _locs[_name_to_type[name]] = (str(_src), (i + 1, i + 2))
46 
47 
48 class FpeMaker(acts.examples.IAlgorithm):
49  def __init__(self, name):
50  acts.examples.IAlgorithm.__init__(self, name, acts.logging.INFO)
51 
52  def execute(self, context):
53  i = context.eventNumber % 4
54 
55  if i == 0 or i == 1:
56  acts.FpeMonitor._trigger_divbyzero()
57  elif i == 2:
58  acts.FpeMonitor._trigger_overflow()
59  elif i == 3:
60  acts.FpeMonitor._trigger_invalid()
61 
62  return acts.examples.ProcessCode.SUCCESS
63 
64 
65 class FuncAlg(acts.examples.IAlgorithm):
66  def __init__(self, name, func):
67  acts.examples.IAlgorithm.__init__(self, name, acts.logging.INFO)
68  self.func = func
69 
70  def execute(self, context):
71  self.func(context)
72  return acts.examples.ProcessCode.SUCCESS
73 
74 
75 @pytest.fixture(autouse=True)
77  prev = acts.logging.getFailureThreshold()
78  acts.logging.setFailureThreshold(acts.logging.MAX)
79  yield
80  acts.logging.setFailureThreshold(prev)
81 
82 
85  events=3 * 100,
86  trackFpes=False,
87  )
88  s.addAlgorithm(FpeMaker("FpeMaker"))
89 
90  s.run()
91 
92  res = s.fpeResult
93 
94  for x in acts.FpeType.values:
95  assert res.count(x) == 0
96 
97 
98 @pytest.fixture(params=_types)
99 def fpe_type(request):
100  yield request.param
101 
102 
105  events=10,
106  failOnFirstFpe=False,
107  )
108 
109  s.addAlgorithm(
110  FuncAlg(
111  _names[fpe_type],
112  lambda _: getattr(
113  acts.FpeMonitor, f"_trigger_{_names[fpe_type].lower()}"
114  )(),
115  )
116  )
117  with pytest.raises(RuntimeError):
118  s.run()
119  # fails, but will have run all 10 events
120  res = s.fpeResult
121  for x in acts.FpeType.values:
122  assert res.count(x) == (s.config.events if x == fpe_type else 0)
123 
124 
127  events=10,
128  failOnFirstFpe=True,
129  numThreads=1,
130  )
131 
132  s.addAlgorithm(
133  FuncAlg(
134  _names[fpe_type],
135  lambda _: getattr(
136  acts.FpeMonitor, f"_trigger_{_names[fpe_type].lower()}"
137  )(),
138  )
139  )
140 
141  with pytest.raises(acts.FpeFailure):
142  s.run()
143 
144  res = s.fpeResult
145  for x in acts.FpeType.values:
146  assert res.count(x) == (1 if x == fpe_type else 0)
147 
148 
150  class Alg(acts.examples.IAlgorithm):
151  def __init__(self):
152  acts.examples.IAlgorithm.__init__(self, "Alg", acts.logging.INFO)
153 
154  def execute(self, context):
155  assert context.fpeMonitor is None
156  return acts.examples.ProcessCode.SUCCESS
157 
159  events=10,
160  trackFpes=False,
161  numThreads=-1,
162  )
163  s.addAlgorithm(Alg())
164  s.run()
165 
166 
167 def test_fpe_rearm(fpe_type):
168  trigger = getattr(acts.FpeMonitor, f"_trigger_{_names[fpe_type].lower()}")
169 
170  class Alg(acts.examples.IAlgorithm):
171  def __init__(self):
172  acts.examples.IAlgorithm.__init__(self, "Alg", acts.logging.INFO)
173 
174  def execute(self, context):
175  assert context.fpeMonitor is not None
176  trigger()
177  context.fpeMonitor.rearm()
178  trigger()
179  return acts.examples.ProcessCode.SUCCESS
180 
182  events=10,
183  failOnFirstFpe=False,
184  numThreads=-1,
185  )
186  s.addAlgorithm(Alg())
187  with pytest.raises(RuntimeError):
188  s.run()
189 
190  res = s.fpeResult
191  for x in acts.FpeType.values:
192  assert res.count(x) == (s.config.events * 2 if x == fpe_type else 0)
193 
194 
196  trigger = getattr(acts.FpeMonitor, f"_trigger_{_names[fpe_type].lower()}")
197 
198  def func(context):
199  trigger()
200  assert context.fpeMonitor is not None
201  context.fpeMonitor.rearm()
202  trigger()
203 
204  # Mask, but it's below threshold
205 
207  events=10,
208  numThreads=-1,
209  failOnFirstFpe=True,
210  fpeMasks=[
211  acts.examples.Sequencer.FpeMask(*_locs[fpe_type], fpe_type, 1),
212  ],
213  )
214 
215  s.addAlgorithm(FuncAlg("Alg", func))
216 
217  with pytest.raises(acts.FpeFailure):
218  s.run()
219 
220  # Mask
221 
223  events=10,
224  numThreads=-1,
225  failOnFirstFpe=True,
226  fpeMasks=[
227  acts.examples.Sequencer.FpeMask(*_locs[fpe_type], fpe_type, 3),
228  ],
229  )
230 
231  s.addAlgorithm(FuncAlg("Alg", func))
232 
233  s.run()
234 
235  res = s.fpeResult
236  for x in acts.FpeType.values:
237  assert res.count(x) == (s.config.events * 2 if x == fpe_type else 0)
238 
239 
240 def test_masking_load_yaml(fpe_type, tmp_path, monkeypatch):
241  def eq(self, other):
242  return (
243  self.file == other.file
244  and self.lines == other.lines
245  and self.type == other.type
246  and self.count == other.count
247  )
248 
249  monkeypatch.setattr(acts.examples.Sequencer.FpeMask, "__eq__", eq)
250 
251  import yaml
252 
253  masks = [
254  acts.examples.Sequencer.FpeMask(*_locs[fpe_type], fpe_type, 1),
255  ]
256  file = tmp_path / "fpe_mask.yml"
257  with file.open("w") as fh:
258  yaml.dump(acts.examples.Sequencer.FpeMask.toDict(masks), fh)
259 
261 
262  assert masks2 == masks
263 
264 
265 def test_fpe_context(fpe_type):
266  trigger = getattr(acts.FpeMonitor, f"_trigger_{_names[fpe_type].lower()}")
267  trigger()
268 
269  with acts.FpeMonitor.context() as fpe:
270  trigger()
271 
272  print(fpe.result)
273 
274 
277  events=10000,
278  failOnFirstFpe=False,
279  )
280 
281  s.addAlgorithm(FuncAlg("Invalid", lambda _: acts.FpeMonitor._trigger_invalid()))
282  with pytest.raises(RuntimeError):
283  s.run()
284 
285  res = s.fpeResult
286  for x in acts.FpeType.values:
287  assert res.count(x) == (s.config.events if x == acts.FpeType.FLTINV else 0)