File indexing completed on 2025-01-18 09:27:41
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Utilities/Helpers.hpp"
0012
0013 #include <array>
0014 #include <atomic>
0015 #include <csignal>
0016 #include <cstddef>
0017 #include <limits>
0018 #include <memory>
0019 #include <mutex>
0020 #include <stack>
0021
0022 #include <boost/container/static_vector.hpp>
0023 #include <boost/stacktrace/stacktrace_fwd.hpp>
0024
0025 namespace Acts {
0026
0027 enum class FpeType : uint32_t {
0028 INTDIV = FPE_INTDIV,
0029 INTOVF = FPE_INTOVF,
0030 FLTDIV = FPE_FLTDIV,
0031 FLTOVF = FPE_FLTOVF,
0032 FLTUND = FPE_FLTUND,
0033 FLTRES = FPE_FLTRES,
0034 FLTINV = FPE_FLTINV,
0035 FLTSUB = FPE_FLTSUB,
0036 };
0037
0038 std::ostream &operator<<(std::ostream &os, FpeType type);
0039
0040 class FpeMonitor {
0041 public:
0042 struct Buffer {
0043 Buffer(std::size_t bufferSize)
0044 : m_data{std::make_unique<std::byte[]>(bufferSize)},
0045 m_size{bufferSize} {}
0046
0047 Buffer(const Buffer &) = delete;
0048 Buffer(Buffer &&other) {
0049 m_data = std::move(other.m_data);
0050 m_size = other.m_size;
0051 m_offset = other.m_offset;
0052 other.m_size = 0;
0053 other.m_offset = 0;
0054 }
0055
0056 std::pair<void *, std::size_t> next() {
0057 return {m_data.get() + m_offset, m_size - m_offset};
0058 }
0059
0060 void pushOffset(std::size_t offset) {
0061 assert(m_offset + offset < m_size);
0062 m_offset = offset;
0063 }
0064
0065 void reset() { m_offset = 0; }
0066
0067 std::size_t size() const { return m_size; }
0068 std::size_t offset() const { return m_offset; }
0069
0070 std::byte *data() { return m_data.get(); }
0071
0072 private:
0073 std::unique_ptr<std::byte[]> m_data;
0074 std::size_t m_size{};
0075 std::size_t m_offset{};
0076 };
0077
0078 struct Result {
0079 struct FpeInfo {
0080 std::size_t count;
0081 FpeType type;
0082 std::shared_ptr<const boost::stacktrace::stacktrace> st;
0083
0084 FpeInfo(std::size_t countIn, FpeType typeIn,
0085 std::shared_ptr<const boost::stacktrace::stacktrace> stIn);
0086 ~FpeInfo();
0087 };
0088
0089 Result merged(const Result &with) const;
0090 void merge(const Result &with);
0091
0092 bool encountered(FpeType type) const;
0093 unsigned int count(FpeType type) const;
0094
0095 const std::vector<FpeInfo> &stackTraces() const;
0096 unsigned int numStackTraces() const;
0097
0098 void deduplicate();
0099
0100 bool contains(FpeType type, const boost::stacktrace::stacktrace &st) const;
0101
0102 void summary(
0103 std::ostream &os,
0104 std::size_t depth = std::numeric_limits<std::size_t>::max()) const;
0105
0106 Result() = default;
0107
0108 operator bool() const { return !m_stracktraces.empty(); }
0109
0110 void add(Acts::FpeType type, void *stackPtr, std::size_t bufferSize);
0111
0112 private:
0113 std::vector<FpeInfo> m_stracktraces;
0114 std::array<unsigned int, 32> m_counts{};
0115
0116 friend FpeMonitor;
0117 };
0118
0119 FpeMonitor();
0120 explicit FpeMonitor(int excepts);
0121 FpeMonitor(FpeMonitor &&other) = default;
0122 ~FpeMonitor();
0123
0124 Result &result();
0125
0126 void consumeRecorded();
0127
0128 void rearm();
0129
0130 static std::string stackTraceToString(const boost::stacktrace::stacktrace &st,
0131 std::size_t depth);
0132 static std::string getSourceLocation(const boost::stacktrace::frame &frame);
0133
0134 private:
0135 void enable();
0136 void disable();
0137
0138 static void ensureSignalHandlerInstalled();
0139 static void signalHandler(int signal, siginfo_t *si, void *ctx);
0140
0141 struct GlobalState {
0142 std::atomic_bool isSignalHandlerInstalled{false};
0143 std::mutex mutex{};
0144 };
0145
0146 static std::stack<FpeMonitor *> &stack();
0147 static GlobalState &globalState();
0148
0149 int m_excepts = 0;
0150
0151 Result m_result;
0152
0153 Buffer m_buffer{65536};
0154
0155 boost::container::static_vector<std::tuple<FpeType, void *, std::size_t>, 128>
0156 m_recorded;
0157 };
0158
0159 }