timemory 3.3.0
Modular C++ Toolkit for Performance Analysis and Logging. Profiling API and Tools for C, C++, CUDA, Fortran, and Python. The C++ template API is essentially a framework to creating tools: it is designed to provide a unifying interface for recording various performance measurements alongside data logging and interfaces to other tools.
signals.hpp
Go to the documentation of this file.
1// MIT License
2//
3// Copyright (c) 2020, The Regents of the University of California,
4// through Lawrence Berkeley National Laboratory (subject to receipt of any
5// required approvals from the U.S. Dept. of Energy). All rights reserved.
6//
7// Permission is hereby granted, free of charge, to any person obtaining a copy
8// of this software and associated documentation files (the "Software"), to deal
9// in the Software without restriction, including without limitation the rights
10// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11// copies of the Software, and to permit persons to whom the Software is
12// furnished to do so, subject to the following conditions:
13//
14// The above copyright notice and this permission notice shall be included in
15// all copies or substantial portions of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23// SOFTWARE.
24//
25
26//======================================================================================//
27// This global method should be used on LINUX or MacOSX platforms with gcc,
28// clang, or intel compilers for activating signal detection and forcing
29// exception being thrown that can be handled when detected.
30//======================================================================================//
31
32#pragma once
33
34#include "timemory/backends/dmp.hpp"
35#include "timemory/backends/process.hpp"
36#include "timemory/backends/signals.hpp"
37#include "timemory/backends/threading.hpp"
41
42#include <cfenv>
43#include <csignal>
44#include <initializer_list>
45#include <set>
46#include <type_traits>
47
48#if defined(SIGNAL_AVAILABLE)
49# include <dlfcn.h>
50#endif
51
52//======================================================================================//
53//
54// declarations
55//
56namespace tim
57{
58//
61//
62template <typename Tp,
63 enable_if_t<!std::is_enum<Tp>::value && std::is_integral<Tp>::value> = 0>
64bool
65enable_signal_detection(std::initializer_list<Tp>&&);
66//
67//--------------------------------------------------------------------------------------//
68//
69void
71//
72//--------------------------------------------------------------------------------------//
73//
74inline void
76{
78 {
81 }
82}
83//
84//--------------------------------------------------------------------------------------//
85//
86#if defined(SIGNAL_AVAILABLE)
87static void
88termination_signal_message(int sig, siginfo_t* sinfo, std::ostream& message);
89#endif
90//
91} // namespace tim
92//
93//======================================================================================//
94//
95#if defined(SIGNAL_AVAILABLE)
96//
97//--------------------------------------------------------------------------------------//
98//
99// static void TIMEMORY_ATTRIBUTE(signal)
100// timemory_termination_signal_handler(int sig, siginfo_t* sinfo, void* /* context */);
101//
102static void
103timemory_termination_signal_handler(int sig, siginfo_t* sinfo, void* /* context */)
104{
105 tim::sys_signal _sig = (tim::sys_signal)(sig);
106
107 if(tim::signal_settings::get_enabled().find(_sig) ==
109 {
110 std::stringstream ss;
111 ss << "signal " << sig << " not caught";
112 TIMEMORY_EXCEPTION(ss.str());
113 }
114
115 tim::termination_signal_message(sig, sinfo, std::cerr);
116
118
119 std::stringstream message;
120 message << "\n";
121
122# if defined(PSIGINFO_AVAILABLE)
123 if(sinfo)
124 {
125 psiginfo(sinfo, message.str().c_str());
126 }
127 else
128 {
129 std::cerr << message.str() << std::endl;
130 }
131# else
132 std::cerr << message.str() << std::endl;
133# endif
134 exit(sig);
135}
136
137//======================================================================================//
138
139namespace tim
140{
141//--------------------------------------------------------------------------------------//
142
143static struct sigaction&
144tim_signal_termaction()
145{
146 static struct sigaction _instance;
147 return _instance;
148}
149
150//--------------------------------------------------------------------------------------//
151
152static struct sigaction&
153tim_signal_oldaction()
154{
155 static struct sigaction _instance;
156 return _instance;
157}
158
159//--------------------------------------------------------------------------------------//
160
161static void
162termination_signal_message(int sig, siginfo_t* sinfo, std::ostream& os)
163{
164 // std::stringstream message;
165 auto& message = os;
166 sys_signal _sig = (sys_signal)(sig);
167
168 message << "\n### ERROR ### ";
169 if(dmp::is_initialized())
170 message << " [ rank : " << dmp::rank() << " ] ";
171 message << "Error code : " << sig;
172 if(sinfo)
173 message << " @ " << sinfo->si_addr;
174 message << " : " << signal_settings::str(_sig);
175
176 if(sig == SIGSEGV)
177 {
178 if(sinfo)
179 {
180 switch(sinfo->si_code)
181 {
182 case SEGV_MAPERR: message << "Address not mapped to object."; break;
183 case SEGV_ACCERR:
184 message << "Invalid permissions for mapped object.";
185 break;
186 default:
187 message << "Unknown segmentation fault error: " << sinfo->si_code
188 << ".";
189 break;
190 }
191 }
192 else
193 {
194 message << "Segmentation fault (unknown).";
195 }
196 }
197 else if(sig == SIGFPE)
198 {
199 if(sinfo)
200 {
201 switch(sinfo->si_code)
202 {
203 case FE_DIVBYZERO: message << "Floating point divide by zero."; break;
204 case FE_OVERFLOW: message << "Floating point overflow."; break;
205 case FE_UNDERFLOW: message << "Floating point underflow."; break;
206 case FE_INEXACT: message << "Floating point inexact result."; break;
207 case FE_INVALID: message << "Floating point invalid operation."; break;
208 default:
209 message << "Unknown floating point exception error: "
210 << sinfo->si_code << ".";
211 break;
212 }
213 }
214 else
215 {
216 message << "Unknown error.";
217 }
218 }
219
220 message << std::endl;
221
223
224 char prefix[512];
225 memset(prefix, '\0', 512 * sizeof(char));
226 sprintf(prefix, "[PID=%i][TID=%i]", (int) process::get_id(),
227 (int) threading::get_id());
228
229 size_t ntot = 0;
230 auto bt = tim::get_backtrace<32>();
231 for(const auto& itr : bt)
232 {
233 if(strlen(itr) == 0)
234 break;
235 ++ntot;
236 }
237
238 std::stringstream serr;
239 serr << "\nBacktrace:\n";
240 for(size_t i = 0; i < bt.size(); ++i)
241 {
242 if(!bt.at(i))
243 break;
244 if(strlen(bt.at(i)) == 0)
245 break;
246 message << prefix << "[" << i << '/' << ntot << "]> " << bt.at(i) << "\n";
247 }
248
249 // message << serr.str().c_str() << std::flush;
250 os << std::flush;
251
252 try
253 {
255 } catch(std::exception& e)
256 {
257 std::cerr << "signal_settings::exit_action(" << sig << ") threw an exception"
258 << std::endl;
259 std::cerr << e.what() << std::endl;
260 }
261}
262
263//--------------------------------------------------------------------------------------//
264
265inline bool
267{
269 {
272 return false;
273 }
274
275 // don't re-enable
277 return false;
278
279 if(operations.empty())
280 {
281 operations = signal_settings::get_enabled();
282 }
283 else
284 {
285 auto _enabled = signal_settings::get_enabled();
286 if(!_enabled.empty())
287 {
288 for(const auto& itr : _enabled)
290 }
292 for(const auto& itr : operations)
294 }
295
296 std::set<int> _signals;
297 for(auto operation : operations)
298 _signals.insert(static_cast<int>(operation));
299
300 sigfillset(&tim_signal_termaction().sa_mask);
301 for(const auto& itr : _signals)
302 sigdelset(&tim_signal_termaction().sa_mask, itr);
303 tim_signal_termaction().sa_sigaction = timemory_termination_signal_handler;
304 tim_signal_termaction().sa_flags = SA_SIGINFO;
305 for(const auto& itr : _signals)
306 {
307 sigaction(itr, &tim_signal_termaction(), &tim_signal_oldaction());
308 }
310
312 std::cout << signal_settings::str() << std::endl;
313
314 return true;
315}
316
317//--------------------------------------------------------------------------------------//
318
319template <typename Tp,
320 enable_if_t<!std::is_enum<Tp>::value && std::is_integral<Tp>::value>>
321inline bool
322enable_signal_detection(std::initializer_list<Tp>&& _signals)
323{
324 auto operations = signal_settings::signal_set_t{};
325 for(const auto& itr : _signals)
326 operations.insert(static_cast<sys_signal>(itr));
327 return enable_signal_detection(operations);
328}
329
330//--------------------------------------------------------------------------------------//
331
332inline void
334{
335 // don't re-disable
337 return;
338
339 sigemptyset(&tim_signal_termaction().sa_mask);
340 tim_signal_termaction().sa_handler = SIG_DFL;
341
342 auto _disable = [](const signal_settings::signal_set_t& _set) {
343 for(auto itr : _set)
344 {
345 int _itr = static_cast<int>(itr);
346 sigaction(_itr, &tim_signal_termaction(), nullptr);
347 }
348 };
349
352
354}
355
356//--------------------------------------------------------------------------------------//
357
358} // namespace tim
359
360//======================================================================================//
361
362#else /* Not a supported architecture */
363
364//======================================================================================//
365
366namespace tim
367{
369
370template <typename Tp,
371 enable_if_t<!std::is_enum<Tp>::value && std::is_integral<Tp>::value>>
372inline bool
373enable_signal_detection(std::initializer_list<Tp>&&)
374{
375 return false;
376}
377
378inline void
380{}
381
382} // namespace tim
383
384//======================================================================================//
385
386#endif
387
static std::string str(const sys_signal &)
Definition: signals.hpp:147
static void enable(const sys_signal &)
Definition: signals.hpp:74
static void check_environment()
Definition: signals.hpp:90
static void exit_action(int errcode)
Definition: signals.hpp:288
static void disable(const sys_signal &)
Definition: signals.hpp:82
static signal_set_t get_enabled()
Definition: signals.hpp:296
std::set< sys_signal > signal_set_t
static void set_active(bool val)
Definition: signals.hpp:272
static signal_set_t get_disabled()
Definition: signals.hpp:304
static bool is_active()
Definition: signals.hpp:248
static bool & allow()
static signal_set_t get_default()
Definition: signals.hpp:312
Definition: kokkosp.cpp:39
bool enable_signal_detection(signal_settings::signal_set_t=signal_settings::get_default())
Definition: signals.hpp:368
sys_signal
Definition: declaration.hpp:69
void disable_signal_detection()
Definition: signals.hpp:379
const std::string std::ostream * os
void update_signal_detection(const signal_settings::signal_set_t &_signals)
Definition: signals.hpp:75
The declaration for the types for utility without definitions.
#define TIMEMORY_EXCEPTION(...)
Definition: types.hpp:138