Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FpeMonitorTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file FpeMonitorTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2023 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include <boost/test/unit_test.hpp>
10 
12 
13 #include <cmath>
14 #include <optional>
15 
16 namespace utf = boost::unit_test;
17 
18 namespace {
19 
20 __attribute__((noinline)) void divbyzero() {
21  volatile float j = 0.0;
22  volatile float r = 123 / j;
23  (void)r;
24 }
25 
26 __attribute__((noinline)) void overflow() {
27  std::cout << "PRE OVERFLOW" << std::endl;
28  volatile float j = std::numeric_limits<float>::max();
29  volatile float r = j * j;
30  (void)r;
31  std::cout << "POST OVERFLOW" << std::endl;
32 }
33 
34 __attribute__((noinline)) void invalid() {
35  volatile float j = -1;
36  volatile float r = std::sqrt(j);
37  (void)r;
38 }
39 
40 __attribute__((noinline)) void invalid2() {
41  volatile float k = 0;
42  volatile float p = k / 0.0;
43  (void)p;
44 }
45 
46 } // namespace
47 
48 namespace Acts::Test {
49 
50 BOOST_AUTO_TEST_SUITE(FpeMonitorTest)
51 
53  FpeMonitor mon;
54  BOOST_CHECK(!mon.result().encountered(FpeType::FLTINV));
55  BOOST_CHECK(!mon.result().encountered(FpeType::FLTOVF));
56  BOOST_CHECK(!mon.result().encountered(FpeType::FLTDIV));
57 
58  invalid();
59 
60  BOOST_CHECK(mon.result().encountered(FpeType::FLTINV));
61  BOOST_CHECK(!mon.result().encountered(FpeType::FLTOVF));
62  BOOST_CHECK(!mon.result().encountered(FpeType::FLTDIV));
63 }
64 
66  FpeMonitor mon;
67  BOOST_CHECK(!mon.result().encountered(FpeType::FLTINV));
68  BOOST_CHECK(!mon.result().encountered(FpeType::FLTOVF));
69  BOOST_CHECK(!mon.result().encountered(FpeType::FLTDIV));
70 
71  divbyzero();
72 
73  BOOST_CHECK(!mon.result().encountered(FpeType::FLTINV));
74  BOOST_CHECK(!mon.result().encountered(FpeType::FLTOVF));
75  BOOST_CHECK(mon.result().encountered(FpeType::FLTDIV));
76 }
77 
79  FpeMonitor mon;
80  BOOST_CHECK(!mon.result().encountered(FpeType::FLTINV));
81  BOOST_CHECK(!mon.result().encountered(FpeType::FLTOVF));
82  BOOST_CHECK(!mon.result().encountered(FpeType::FLTDIV));
83 
84  overflow();
85  BOOST_CHECK(!mon.result().encountered(FpeType::FLTINV));
86  BOOST_CHECK(mon.result().encountered(FpeType::FLTOVF));
87  BOOST_CHECK(!mon.result().encountered(FpeType::FLTDIV));
88 }
89 
90 BOOST_AUTO_TEST_CASE(Combinations) {
91  FpeMonitor mon;
92  BOOST_CHECK(!mon.result().encountered(FpeType::FLTINV));
93  BOOST_CHECK(!mon.result().encountered(FpeType::FLTOVF));
94  BOOST_CHECK(!mon.result().encountered(FpeType::FLTDIV));
95 
96  invalid();
97  BOOST_CHECK(mon.result().encountered(FpeType::FLTINV));
98  BOOST_CHECK(!mon.result().encountered(FpeType::FLTOVF));
99  BOOST_CHECK(!mon.result().encountered(FpeType::FLTDIV));
100 
101  overflow();
102  BOOST_CHECK(mon.result().encountered(FpeType::FLTINV));
103  BOOST_CHECK(mon.result().encountered(FpeType::FLTOVF));
104  BOOST_CHECK(!mon.result().encountered(FpeType::FLTDIV));
105 
106  divbyzero();
107 
108  BOOST_CHECK(mon.result().encountered(FpeType::FLTINV));
109  BOOST_CHECK(mon.result().encountered(FpeType::FLTOVF));
110  BOOST_CHECK(mon.result().encountered(FpeType::FLTDIV));
111 }
112 
113 BOOST_AUTO_TEST_CASE(ClearOnEnter) {
114  invalid();
115  divbyzero();
116  overflow();
117 
118  FpeMonitor mon;
119  BOOST_CHECK(!mon.result().encountered(FpeType::FLTINV));
120  BOOST_CHECK(!mon.result().encountered(FpeType::FLTOVF));
121  BOOST_CHECK(!mon.result().encountered(FpeType::FLTDIV));
122 }
123 
124 BOOST_AUTO_TEST_CASE(CheckRearmCount) {
125  FpeMonitor mon;
126  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTINV), 0);
127  BOOST_CHECK(mon.result().stackTraces().empty());
128 
129  invalid();
130  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTINV), 1);
131  BOOST_CHECK_EQUAL(mon.result().stackTraces().size(), 1);
132 
133  invalid();
134  // We can't observe this again because it's masked!
135  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTINV), 1);
136  BOOST_CHECK_EQUAL(mon.result().stackTraces().size(), 1);
137 
138  mon.rearm();
139  invalid();
140  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTINV), 2);
141  BOOST_CHECK_EQUAL(mon.result().stackTraces().size(),
142  1); // still at one because we deduplicated
143 
144  mon.rearm();
145  invalid2();
146  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTINV), 3);
147  BOOST_CHECK_EQUAL(mon.result().stackTraces().size(), 2);
148  mon.result().deduplicate(); // doesn't do anything here actually
149  BOOST_CHECK_EQUAL(mon.result().stackTraces().size(), 2);
150 }
151 
153  FpeMonitor mon;
154  BOOST_CHECK(!mon.result().encountered(FpeType::FLTINV));
155  BOOST_CHECK(!mon.result().encountered(FpeType::FLTOVF));
156  BOOST_CHECK(!mon.result().encountered(FpeType::FLTDIV));
157 
158  invalid();
159 
160  {
161  FpeMonitor mon2;
162  BOOST_CHECK(!mon2.result().encountered(FpeType::FLTINV));
163  BOOST_CHECK(!mon2.result().encountered(FpeType::FLTOVF));
164  BOOST_CHECK(!mon2.result().encountered(FpeType::FLTDIV));
165 
166  overflow();
167 
168  {
169  FpeMonitor mon3;
170  BOOST_CHECK(!mon3.result().encountered(FpeType::FLTINV));
171  BOOST_CHECK(!mon3.result().encountered(FpeType::FLTOVF));
172  BOOST_CHECK(!mon3.result().encountered(FpeType::FLTDIV));
173 
174  divbyzero();
175 
176  BOOST_CHECK(!mon3.result().encountered(FpeType::FLTINV));
177  BOOST_CHECK(!mon3.result().encountered(FpeType::FLTOVF));
178  BOOST_CHECK(mon3.result().encountered(FpeType::FLTDIV));
179 
180  // Test merging here
181  auto merged = mon.result().merged(mon2.result());
182  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTINV), 1);
183  BOOST_CHECK_EQUAL(mon2.result().count(FpeType::FLTOVF), 1);
184  BOOST_CHECK_EQUAL(merged.count(FpeType::FLTINV), 1);
185  BOOST_CHECK_EQUAL(merged.count(FpeType::FLTOVF), 1);
186  BOOST_CHECK_EQUAL(merged.numStackTraces(), 2);
187  merged = merged.merged(mon3.result());
188  BOOST_CHECK_EQUAL(merged.count(FpeType::FLTINV), 1);
189  BOOST_CHECK_EQUAL(merged.count(FpeType::FLTOVF), 1);
190  BOOST_CHECK_EQUAL(merged.count(FpeType::FLTDIV), 1);
191  BOOST_CHECK_EQUAL(merged.numStackTraces(), 3);
192  }
193 
194  BOOST_CHECK(!mon2.result().encountered(FpeType::FLTINV));
195  BOOST_CHECK(mon2.result().encountered(FpeType::FLTOVF));
196  BOOST_CHECK(!mon2.result().encountered(FpeType::FLTDIV));
197  }
198 
199  BOOST_CHECK(mon.result().encountered(FpeType::FLTINV));
200  BOOST_CHECK(!mon.result().encountered(FpeType::FLTOVF));
201  BOOST_CHECK(!mon.result().encountered(FpeType::FLTDIV));
202 }
203 
204 BOOST_AUTO_TEST_CASE(MergeDeduplication) {
205  FpeMonitor mon;
206  invalid();
207  {
208  FpeMonitor mon2;
209  invalid();
210 
211  auto merged = mon.result().merged(mon2.result());
212  BOOST_CHECK_EQUAL(merged.count(FpeType::FLTINV), 2);
213  BOOST_CHECK_EQUAL(merged.stackTraces().size(), 1);
214  }
215 }
216 
217 BOOST_AUTO_TEST_CASE(ScopedSuppression) {
218  FpeMonitor mon;
219  BOOST_CHECK(!mon.result().encountered(FpeType::FLTINV));
220  BOOST_CHECK(!mon.result().encountered(FpeType::FLTOVF));
221  BOOST_CHECK(!mon.result().encountered(FpeType::FLTDIV));
222 
223  invalid();
224 
225  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTINV), 1);
226  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTOVF), 0);
227  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTDIV), 0);
228 
229  {
230  FpeMonitor mon2{0}; // disable all
231  BOOST_CHECK(!mon2.result().encountered(FpeType::FLTINV));
232  BOOST_CHECK(!mon2.result().encountered(FpeType::FLTOVF));
233  BOOST_CHECK(!mon2.result().encountered(FpeType::FLTDIV));
234  invalid();
235  divbyzero();
236  overflow();
237  // were not registered in inner scope
238  BOOST_CHECK(!mon2.result().encountered(FpeType::FLTINV));
239  BOOST_CHECK(!mon2.result().encountered(FpeType::FLTOVF));
240  BOOST_CHECK(!mon2.result().encountered(FpeType::FLTDIV));
241  }
242 
243  // outer scope is also unchanged
244  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTINV), 1);
245  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTOVF), 0);
246  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTDIV), 0);
247 
248  invalid();
249 
250  // outer scope gets signal after being restored on the stack
251  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTINV), 2);
252  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTOVF), 0);
253  BOOST_CHECK_EQUAL(mon.result().count(FpeType::FLTDIV), 0);
254 }
255 
256 BOOST_AUTO_TEST_SUITE_END()
257 
258 } // namespace Acts::Test