Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FpeMonitor.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file FpeMonitor.hpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2022 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 #pragma once
10 
12 
13 #include <array>
14 #include <atomic>
15 #include <csignal>
16 #include <cstddef>
17 #include <limits>
18 #include <memory>
19 #include <mutex>
20 #include <stack>
21 
22 #include <boost/container/static_vector.hpp>
23 #include <boost/stacktrace/stacktrace_fwd.hpp>
24 
25 namespace Acts {
26 
27 enum class FpeType : uint32_t {
28  INTDIV = FPE_INTDIV,
29  INTOVF = FPE_INTOVF,
30  FLTDIV = FPE_FLTDIV,
31  FLTOVF = FPE_FLTOVF,
32  FLTUND = FPE_FLTUND,
33  FLTRES = FPE_FLTRES,
34  FLTINV = FPE_FLTINV,
35  FLTSUB = FPE_FLTSUB,
36 };
37 
38 std::ostream &operator<<(std::ostream &os, FpeType type);
39 
40 class FpeMonitor {
41  public:
42  struct Buffer {
43  Buffer(std::size_t bufferSize)
44  : m_data{std::make_unique<std::byte[]>(bufferSize)},
45  m_size{bufferSize} {}
46 
47  Buffer(const Buffer &) = delete;
48  Buffer(Buffer &&other) {
49  m_data = std::move(other.m_data);
50  m_size = other.m_size;
51  m_offset = other.m_offset;
52  other.m_size = 0;
53  other.m_offset = 0;
54  }
55 
56  std::pair<void *, std::size_t> next() {
57  return {m_data.get() + m_offset, m_size - m_offset};
58  }
59 
60  void pushOffset(std::size_t offset) {
61  assert(m_offset + offset < m_size);
62  m_offset = offset;
63  }
64 
65  void reset() { m_offset = 0; }
66 
67  std::size_t size() const { return m_size; }
68  std::size_t offset() const { return m_offset; }
69 
70  std::byte *data() { return m_data.get(); }
71 
72  private:
73  std::unique_ptr<std::byte[]> m_data;
74  std::size_t m_size{};
75  std::size_t m_offset{};
76  };
77 
78  struct Result {
79  struct FpeInfo {
80  std::size_t count;
82  std::shared_ptr<const boost::stacktrace::stacktrace> st;
83 
84  FpeInfo(std::size_t countIn, FpeType typeIn,
85  std::shared_ptr<const boost::stacktrace::stacktrace> stIn);
86  ~FpeInfo();
87  };
88 
89  Result merged(const Result &with) const;
90  void merge(const Result &with);
91 
92  bool encountered(FpeType type) const;
93  unsigned int count(FpeType type) const;
94 
95  const std::vector<FpeInfo> &stackTraces() const;
96  unsigned int numStackTraces() const;
97 
98  void deduplicate();
99 
100  bool contains(FpeType type, const boost::stacktrace::stacktrace &st) const;
101 
102  void summary(
103  std::ostream &os,
104  std::size_t depth = std::numeric_limits<std::size_t>::max()) const;
105 
106  Result() = default;
107 
108  operator bool() const { return !m_stracktraces.empty(); }
109 
110  void add(Acts::FpeType type, void *stackPtr, std::size_t bufferSize);
111 
112  private:
113  std::vector<FpeInfo> m_stracktraces;
114  std::array<unsigned int, 32> m_counts{};
115 
116  friend FpeMonitor;
117  };
118 
119  FpeMonitor();
120  explicit FpeMonitor(int excepts);
121  FpeMonitor(FpeMonitor &&other) = default;
122  ~FpeMonitor();
123 
124  Result &result();
125 
126  void consumeRecorded();
127 
128  void rearm();
129 
130  static std::string stackTraceToString(const boost::stacktrace::stacktrace &st,
131  std::size_t depth);
132  static std::string getSourceLocation(const boost::stacktrace::frame &frame);
133 
134  private:
135  void enable();
136  void disable();
137 
138  static void ensureSignalHandlerInstalled();
139  static void signalHandler(int signal, siginfo_t *si, void *ctx);
140 
141  struct GlobalState {
142  std::atomic_bool isSignalHandlerInstalled{false};
143  std::mutex mutex{};
144  };
145 
146  static std::stack<FpeMonitor *> &stack();
147  static GlobalState &globalState();
148 
149  int m_excepts = 0;
150 
152 
153  Buffer m_buffer{65536};
154 
155  boost::container::static_vector<std::tuple<FpeType, void *, std::size_t>, 128>
157 };
158 
159 } // namespace Acts