Import Geant4 10.7.0 source tree
This commit is contained in:
@@ -16,6 +16,66 @@ commit in the repository !
|
||||
* Reverse chronological order (last date on top), please *
|
||||
----------------------------------------------------------
|
||||
|
||||
December 2, 2020 Gabriele (global-V10-06-27)
|
||||
- Removed condition restricting to __x86_64__ architectures for macOS
|
||||
configuration in tls.hh.
|
||||
|
||||
November 21, 2020 Gabriele Cosmo (global-V10-06-26)
|
||||
- Fixed compilation warnings in G4Profiler.
|
||||
- Updated tag IDs for release 10.7.
|
||||
|
||||
November 12, 2020 Jonathan Madsen (global-V10-06-25)
|
||||
- Added new G4Profiler.hh header
|
||||
- Implemented new profiling routines which allow per-{run,event,track,step}
|
||||
configuration w.r.t. when to profiler, what to collect in the profiler,
|
||||
and how to label the entries.
|
||||
Also, includes user-profiling config and macros.
|
||||
- Use of TIMEMORY_AUTO_TIMER is now deprecated.
|
||||
|
||||
October 29, 2020 Ben Morgan (global-V10-06-25)
|
||||
- Always use new CMake system.
|
||||
|
||||
October 30, 2020 Gabriele Cosmo (global-V10-06-24)
|
||||
- Updated tag IDs for geant4-10-06-ref-10.
|
||||
|
||||
October 20, 2020 Jonathan Madsen (global-V10-06-23)
|
||||
- Added G4Backtrace.hh for printing backtraces from raised signals
|
||||
- This is a more generic implementation of G4FPEDetection and can
|
||||
catch FPE issues but, by default, does not interfere with it.
|
||||
- The default backtraced signals are: SIGQUIT, SIGILL, SIGABRT, SIGKILL,
|
||||
SIGBUS, SIGSEGV.
|
||||
- The default signals can be overridden within user-code before and
|
||||
after the creation of the run-manager (See "Usage" section in G4Backtrace.hh)
|
||||
- The default signals can be overridden via environment variable
|
||||
G4BACKTRACE.
|
||||
|
||||
September 30, 2020 Gabriele Cosmo (global-V10-06-22)
|
||||
- Updated tag IDs for geant4-10-06-ref-09.
|
||||
|
||||
September 25, 2020 Vladimir Ivanchenko (global-V10-06-21)
|
||||
- G4PhysicsLinearVector, G4PhysicsLogVector - fixed scale of energy; this
|
||||
problem does not affect results in general; it fix data table scale
|
||||
and may change dEdx and cross sections numerically on small level.
|
||||
|
||||
September 24, 2020 Gabriele Cosmo (global-V10-06-20)
|
||||
- Re-instate static pointer for 'masterG4coutDestination' in G4coutDestination
|
||||
with proper symbol exporting on Windows (necessary for MT builds).
|
||||
Restores trapping of G4cout from workers in Qt GUI.
|
||||
|
||||
August 31, 2020 Gabriele Cosmo (global-V10-06-19)
|
||||
- Updated tag IDs for geant4-10-06-ref-08.
|
||||
|
||||
August 4, 2020 Daren Sawkey (global-V10-06-18)
|
||||
- New G4PhysicsOrderedFreeVector(std::vector, std::vector) constructor.
|
||||
|
||||
July 23, 2020 Gabriele Cosmo (global-V10-06-17)
|
||||
- Updated tag IDs for geant4-10-06-ref-07.
|
||||
|
||||
July 17, 2020 Gabriele Cosmo (global-V10-06-16)
|
||||
- Updated e_SI value for electron charge in G4SIunits.h, based
|
||||
on May 2019 redefinition of SI units.
|
||||
Reference: https://www.britannica.com/science/electron-charge.
|
||||
|
||||
June 26, 2020 Gabriele Cosmo (global-V10-06-15)
|
||||
- Updated tag IDs for geant4-10-06-ref-06.
|
||||
|
||||
|
||||
@@ -0,0 +1,811 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
// G4Backtrace
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// Prints backtraces after signals are caught. Available on Unix.
|
||||
//
|
||||
// Usage:
|
||||
// A standard set of signals are enabled by default:
|
||||
//
|
||||
// SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
|
||||
//
|
||||
// These should not interfere with debuggers and/or G4FPEDetection.
|
||||
// In order to turn off handling for one or more signals, one can do:
|
||||
//
|
||||
// G4BackTrace::DefaultSignals() = std::set<int>{};
|
||||
// G4BackTrace::DefaultSignals() = std::set<int>{ SIGSEGV };
|
||||
//
|
||||
// and so on, *before* creating the run-manager. After the run-manager
|
||||
// has been created, one should disable the signals:
|
||||
//
|
||||
// G4BackTrace::Disable(G4BackTrace::DefaultSignals());
|
||||
//
|
||||
// Additionally, at runtime, the environment variable "G4BACKTRACE" can
|
||||
// be set to select a specific set of signals or none, e.g. in bash:
|
||||
//
|
||||
// export G4BACKTRACE="SIGQUIT,SIGSEGV"
|
||||
// export G4BACKTRACE="none"
|
||||
//
|
||||
// The environment variable is case-insensitive and can use any of the
|
||||
// following delimiters: space, comma, semi-colon, colon
|
||||
//
|
||||
// Author: J.Madsen, 19 October 2020
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
#ifndef G4Backtrace_hh
|
||||
#define G4Backtrace_hh 1
|
||||
|
||||
#include "G4Types.hh"
|
||||
#include "G4String.hh"
|
||||
#include "G4Threading.hh"
|
||||
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
# if !defined(G4MACOS)
|
||||
# define G4MACOS
|
||||
# endif
|
||||
# if !defined(G4UNIX)
|
||||
# define G4UNIX
|
||||
# endif
|
||||
#elif defined(__linux__) || defined(__linux) || defined(linux) || \
|
||||
defined(__gnu_linux__)
|
||||
# if !defined(G4LINUX)
|
||||
# define G4LINUX
|
||||
# endif
|
||||
# if !defined(G4UNIX)
|
||||
# define G4UNIX
|
||||
# endif
|
||||
#elif defined(__unix__) || defined(__unix) || defined(unix)
|
||||
# if !defined(G4UNIX)
|
||||
# define G4UNIX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(G4UNIX)
|
||||
# include <cxxabi.h>
|
||||
# include <execinfo.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(G4LINUX)
|
||||
# include <features.h>
|
||||
#endif
|
||||
|
||||
#include <cfenv>
|
||||
#include <csignal>
|
||||
#include <type_traits>
|
||||
|
||||
template <typename FuncT>
|
||||
using G4ResultOf_t = typename std::result_of<FuncT>::type;
|
||||
|
||||
// compatible OS and compiler
|
||||
#if defined(G4UNIX) && \
|
||||
(defined(__GNUC__) || defined(__clang__) || defined(_INTEL_COMPILER))
|
||||
# if !defined(G4SIGNAL_AVAILABLE)
|
||||
# define G4SIGNAL_AVAILABLE
|
||||
# endif
|
||||
# if !defined(G4DEMANGLE_AVAILABLE)
|
||||
# define G4DEMANGLE_AVAILABLE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(G4PSIGINFO_AVAILABLE)
|
||||
# if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
|
||||
# define G4PSIGINFO_AVAILABLE 1
|
||||
# else
|
||||
# define G4PSIGINFO_AVAILABLE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline G4String G4Demangle(const char* _str)
|
||||
{
|
||||
#if defined(G4DEMANGLE_AVAILABLE)
|
||||
// demangling a string when delimiting
|
||||
int _status = 0;
|
||||
char* _ret = ::abi::__cxa_demangle(_str, nullptr, nullptr, &_status);
|
||||
if(_ret && _status == 0)
|
||||
return G4String(const_cast<const char*>(_ret));
|
||||
return _str;
|
||||
#else
|
||||
return _str;
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline G4String G4Demangle(const G4String& _str)
|
||||
{
|
||||
return G4Demangle(_str.c_str());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
template <typename Tp>
|
||||
inline G4String G4Demangle()
|
||||
{
|
||||
return G4Demangle(typeid(Tp).name());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
//
|
||||
// ONLY IF G4SIGNAL_AVAILABLE
|
||||
//
|
||||
//----------------------------------------------------------------------------//
|
||||
//
|
||||
#if defined(G4SIGNAL_AVAILABLE)
|
||||
//
|
||||
// these are not in the original POSIX.1-1990 standard so we are defining
|
||||
// them in case the OS hasn't
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGTRAP
|
||||
# define SIGTRAP 5
|
||||
# endif
|
||||
// not specified in POSIX.1-2001, but nevertheless appears on most other
|
||||
// UNIX systems, where its default action is typically to terminate the
|
||||
// process with a core dump.
|
||||
# ifndef SIGEMT
|
||||
# define SIGEMT 7
|
||||
# endif
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGURG
|
||||
# define SIGURG 16
|
||||
# endif
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGXCPU
|
||||
# define SIGXCPU 24
|
||||
# endif
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGXFSZ
|
||||
# define SIGXFSZ 25
|
||||
# endif
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGVTALRM
|
||||
# define SIGVTALRM 26
|
||||
# endif
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGPROF
|
||||
# define SIGPROF 27
|
||||
# endif
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGINFO
|
||||
# define SIGINFO 29
|
||||
# endif
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
# include <algorithm>
|
||||
# include <array>
|
||||
# include <cstdlib>
|
||||
# include <functional>
|
||||
# include <iomanip>
|
||||
# include <iostream>
|
||||
# include <map>
|
||||
# include <mutex>
|
||||
# include <regex>
|
||||
# include <set>
|
||||
# include <sstream>
|
||||
# include <string>
|
||||
# include <tuple>
|
||||
# include <vector>
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
class G4Backtrace
|
||||
{
|
||||
public:
|
||||
using sigaction_t = struct sigaction;
|
||||
using exit_action_t = std::function<void(int)>;
|
||||
using frame_func_t = std::function<G4String(const char*)>;
|
||||
using signal_set_t = std::set<int>;
|
||||
|
||||
public:
|
||||
struct actions
|
||||
{
|
||||
using id_entry_t = std::tuple<std::string, int, std::string>;
|
||||
using id_list_t = std::vector<id_entry_t>;
|
||||
|
||||
std::shared_ptr<std::mutex> lock = std::make_shared<std::mutex>();
|
||||
std::map<int, bool> is_active = {};
|
||||
std::map<int, sigaction_t> current = {};
|
||||
std::map<int, sigaction_t> previous = {};
|
||||
std::vector<exit_action_t> exit_actions = {};
|
||||
const id_list_t identifiers = {
|
||||
id_entry_t("SIGHUP", SIGHUP, "terminal line hangup"),
|
||||
id_entry_t("SIGINT", SIGINT, "interrupt program"),
|
||||
id_entry_t("SIGQUIT", SIGQUIT, "quit program"),
|
||||
id_entry_t("SIGILL", SIGILL, "illegal instruction"),
|
||||
id_entry_t("SIGTRAP", SIGTRAP, "trace trap"),
|
||||
id_entry_t("SIGABRT", SIGABRT, "abort program (formerly SIGIOT)"),
|
||||
id_entry_t("SIGEMT", SIGEMT, "emulate instruction executed"),
|
||||
id_entry_t("SIGFPE", SIGFPE, "floating-point exception"),
|
||||
id_entry_t("SIGKILL", SIGKILL, "kill program"),
|
||||
id_entry_t("SIGBUS", SIGBUS, "bus error"),
|
||||
id_entry_t("SIGSEGV", SIGSEGV, "segmentation violation"),
|
||||
id_entry_t("SIGSYS", SIGSYS, "non-existent system call invoked"),
|
||||
id_entry_t("SIGPIPE", SIGPIPE, "write on a pipe with no reader"),
|
||||
id_entry_t("SIGALRM", SIGALRM, "real-time timer expired"),
|
||||
id_entry_t("SIGTERM", SIGTERM, "software termination signal"),
|
||||
id_entry_t("SIGURG", SIGURG, "urgent condition present on socket"),
|
||||
id_entry_t("SIGSTOP", SIGSTOP, "stop (cannot be caught or ignored)"),
|
||||
id_entry_t("SIGTSTP", SIGTSTP, "stop signal generated from keyboard"),
|
||||
id_entry_t("SIGCONT", SIGCONT, "continue after stop"),
|
||||
id_entry_t("SIGCHLD", SIGCHLD, "child status has changed"),
|
||||
id_entry_t("SIGTTIN", SIGTTIN,
|
||||
"background read attempted from control terminal"),
|
||||
id_entry_t("SIGTTOU", SIGTTOU,
|
||||
"background write attempted to control terminal"),
|
||||
id_entry_t("SIGIO ", SIGIO, "I/O is possible on a descriptor"),
|
||||
id_entry_t("SIGXCPU", SIGXCPU, "cpu time limit exceeded"),
|
||||
id_entry_t("SIGXFSZ", SIGXFSZ, "file size limit exceeded"),
|
||||
id_entry_t("SIGVTALRM", SIGVTALRM, "virtual time alarm"),
|
||||
id_entry_t("SIGPROF", SIGPROF, "profiling timer alarm"),
|
||||
id_entry_t("SIGWINCH", SIGWINCH, "Window size change"),
|
||||
id_entry_t("SIGINFO", SIGINFO, "status request from keyboard"),
|
||||
id_entry_t("SIGUSR1", SIGUSR1, "User defined signal 1"),
|
||||
id_entry_t("SIGUSR2", SIGUSR2, "User defined signal 2")
|
||||
};
|
||||
};
|
||||
|
||||
public:
|
||||
// a functor called for each frame in the backtrace
|
||||
static frame_func_t& FrameFunctor();
|
||||
// default set of signals
|
||||
static signal_set_t& DefaultSignals();
|
||||
// the signal handler
|
||||
static void Handler(int sig, siginfo_t* sinfo, void* context);
|
||||
// information message about the signal, performs exit-actions
|
||||
// and prints back-trace
|
||||
static void Message(int sig, siginfo_t* sinfo, std::ostream&);
|
||||
// calls user-provided functions after signal is caught but before abort
|
||||
static void ExitAction(int sig);
|
||||
// enable signals via a string (which is tokenized)
|
||||
static int Enable(const std::string&);
|
||||
// enable signals via set of integers, anything less than zero is ignored
|
||||
static int Enable(const signal_set_t& _signals = DefaultSignals());
|
||||
// disable signals
|
||||
static int Disable(signal_set_t _signals = {});
|
||||
// gets the numeric value for a signal name
|
||||
static int GetSignal(const std::string&);
|
||||
// provides a description of the signal
|
||||
static std::string Description(int sig);
|
||||
|
||||
// adds an exit action
|
||||
template <typename FuncT>
|
||||
static void AddExitAction(FuncT&& func);
|
||||
|
||||
// gets a backtrace of "Depth" frames. The offset parameter is used
|
||||
// to ignore initial frames (such as this function). A callback
|
||||
// can be provided to inspect and/or tweak the frame string
|
||||
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
|
||||
static std::array<G4ResultOf_t<FuncT(const char*)>, Depth> GetMangled(
|
||||
FuncT&& func = FrameFunctor());
|
||||
|
||||
// gets a demangled backtrace of "Depth" frames. The offset parameter is
|
||||
// used to ignore initial frames (such as this function). A callback
|
||||
// can be provided to inspect and/or tweak the frame string
|
||||
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
|
||||
static std::array<G4ResultOf_t<FuncT(const char*)>, Depth> GetDemangled(
|
||||
FuncT&& func = FrameFunctor());
|
||||
|
||||
private:
|
||||
static actions& GetData()
|
||||
{
|
||||
static auto _instance = actions{};
|
||||
return _instance;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
// a functor called for each frame in the backtrace
|
||||
inline G4Backtrace::frame_func_t& G4Backtrace::FrameFunctor()
|
||||
{
|
||||
static frame_func_t _instance = [](const char* inp) { return G4String(inp); };
|
||||
return _instance;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
// default set of signals
|
||||
inline G4Backtrace::signal_set_t& G4Backtrace::DefaultSignals()
|
||||
{
|
||||
static signal_set_t _instance = { SIGQUIT, SIGILL, SIGABRT,
|
||||
SIGKILL, SIGBUS, SIGSEGV };
|
||||
return _instance;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
template <typename FuncT>
|
||||
inline void G4Backtrace::AddExitAction(FuncT&& func)
|
||||
{
|
||||
GetData().exit_actions.emplace_back(std::forward<FuncT>(func));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline void G4Backtrace::ExitAction(int sig)
|
||||
{
|
||||
for(auto& itr : GetData().exit_actions)
|
||||
itr(sig);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
template <size_t Depth, size_t Offset, typename FuncT>
|
||||
inline std::array<G4ResultOf_t<FuncT(const char*)>, Depth>
|
||||
G4Backtrace::GetMangled(FuncT&& func)
|
||||
{
|
||||
static_assert((Depth - Offset) >= 1, "Error Depth - Offset should be >= 1");
|
||||
|
||||
using type = G4ResultOf_t<FuncT(const char*)>;
|
||||
// destination
|
||||
std::array<type, Depth> btrace;
|
||||
btrace.fill((std::is_pointer<type>::value) ? nullptr : type{});
|
||||
|
||||
// plus one for this stack-frame
|
||||
std::array<void*, Depth + Offset> buffer;
|
||||
// size of returned buffer
|
||||
auto sz = backtrace(buffer.data(), Depth + Offset);
|
||||
// size of relevant data
|
||||
auto n = sz - Offset;
|
||||
|
||||
// skip ahead (Offset + 1) stack frames
|
||||
char** bsym = backtrace_symbols(buffer.data() + Offset, n);
|
||||
|
||||
// report errors
|
||||
if(bsym == nullptr)
|
||||
perror("backtrace_symbols");
|
||||
else
|
||||
{
|
||||
for(decltype(n) i = 0; i < n; ++i)
|
||||
btrace[i] = func(bsym[i]);
|
||||
free(bsym);
|
||||
}
|
||||
return btrace;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
template <size_t Depth, size_t Offset, typename FuncT>
|
||||
inline std::array<G4ResultOf_t<FuncT(const char*)>, Depth>
|
||||
G4Backtrace::GetDemangled(FuncT&& func)
|
||||
{
|
||||
auto demangle_bt = [&](const char* cstr) {
|
||||
auto _trim = [](std::string& _sub, size_t& _len) {
|
||||
size_t _pos = 0;
|
||||
while((_pos = _sub.find_first_of(' ')) == 0)
|
||||
{
|
||||
_sub = _sub.erase(_pos, 1);
|
||||
--_len;
|
||||
}
|
||||
while((_pos = _sub.find_last_of(' ')) == _sub.length() - 1)
|
||||
{
|
||||
_sub = _sub.substr(0, _sub.length() - 1);
|
||||
--_len;
|
||||
}
|
||||
return _sub;
|
||||
};
|
||||
|
||||
auto str = G4Demangle(std::string(cstr));
|
||||
auto beg = str.find("(");
|
||||
if(beg == std::string::npos)
|
||||
{
|
||||
beg = str.find("_Z");
|
||||
if(beg != std::string::npos)
|
||||
beg -= 1;
|
||||
}
|
||||
auto end = str.find("+", beg);
|
||||
if(beg != std::string::npos && end != std::string::npos)
|
||||
{
|
||||
auto len = end - (beg + 1);
|
||||
auto sub = str.substr(beg + 1, len);
|
||||
auto dem = G4Demangle(_trim(sub, len));
|
||||
str = str.replace(beg + 1, len, dem);
|
||||
}
|
||||
else if(beg != std::string::npos)
|
||||
{
|
||||
auto len = str.length() - (beg + 1);
|
||||
auto sub = str.substr(beg + 1, len);
|
||||
auto dem = G4Demangle(_trim(sub, len));
|
||||
str = str.replace(beg + 1, len, dem);
|
||||
}
|
||||
else if(end != std::string::npos)
|
||||
{
|
||||
auto len = end;
|
||||
auto sub = str.substr(beg, len);
|
||||
auto dem = G4Demangle(_trim(sub, len));
|
||||
str = str.replace(beg, len, dem);
|
||||
}
|
||||
return func(str.c_str());
|
||||
};
|
||||
return GetMangled<Depth, Offset>(demangle_bt);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline void G4Backtrace::Message(int sig, siginfo_t* sinfo, std::ostream& os)
|
||||
{
|
||||
std::stringstream message;
|
||||
message << "\n### CAUGHT SIGNAL: " << sig << " ### ";
|
||||
if(sinfo)
|
||||
message << "address: " << sinfo->si_addr << ", ";
|
||||
message << Description(sig) << ". ";
|
||||
|
||||
if(sig == SIGSEGV)
|
||||
{
|
||||
if(sinfo)
|
||||
{
|
||||
switch(sinfo->si_code)
|
||||
{
|
||||
case SEGV_MAPERR:
|
||||
message << "Address not mapped to object.";
|
||||
break;
|
||||
case SEGV_ACCERR:
|
||||
message << "Invalid permissions for mapped object.";
|
||||
break;
|
||||
default:
|
||||
message << "Unknown segmentation fault error: " << sinfo->si_code
|
||||
<< ".";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message << "Segmentation fault (unknown).";
|
||||
}
|
||||
}
|
||||
else if(sig == SIGFPE)
|
||||
{
|
||||
if(sinfo)
|
||||
{
|
||||
switch(sinfo->si_code)
|
||||
{
|
||||
case FE_DIVBYZERO:
|
||||
message << "Floating point divide by zero.";
|
||||
break;
|
||||
case FE_OVERFLOW:
|
||||
message << "Floating point overflow.";
|
||||
break;
|
||||
case FE_UNDERFLOW:
|
||||
message << "Floating point underflow.";
|
||||
break;
|
||||
case FE_INEXACT:
|
||||
message << "Floating point inexact result.";
|
||||
break;
|
||||
case FE_INVALID:
|
||||
message << "Floating point invalid operation.";
|
||||
break;
|
||||
default:
|
||||
message << "Unknown floating point exception error: "
|
||||
<< sinfo->si_code << ".";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message << "Unknown floating point exception";
|
||||
if(sinfo)
|
||||
message << ": " << sinfo->si_code;
|
||||
message << ". ";
|
||||
}
|
||||
}
|
||||
|
||||
message << std::endl;
|
||||
try
|
||||
{
|
||||
sigignore(sig);
|
||||
ExitAction(sig);
|
||||
} catch(std::exception& e)
|
||||
{
|
||||
std::cerr << "ExitAction(" << sig << ") threw an exception" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
|
||||
auto bt = GetDemangled<256, 3>(FrameFunctor());
|
||||
std::stringstream prefix;
|
||||
prefix << "[PID=" << getpid() << ", TID=" << G4Threading::G4GetThreadId()
|
||||
<< "]";
|
||||
std::vector<G4String> btvec;
|
||||
for(auto& itr : bt)
|
||||
{
|
||||
if(itr.length() > 0)
|
||||
btvec.emplace_back(std::move(itr));
|
||||
}
|
||||
std::stringstream serr;
|
||||
serr << "\nBacktrace:\n";
|
||||
auto _w = std::log10(btvec.size()) + 1;
|
||||
for(size_t i = 0; i < btvec.size(); ++i)
|
||||
{
|
||||
serr << prefix.str() << "[" << std::setw(_w) << std::right << i << '/'
|
||||
<< std::setw(_w) << std::right << btvec.size() << "]> " << std::left
|
||||
<< btvec.at(i) << '\n';
|
||||
}
|
||||
os << serr.str().c_str() << '\n';
|
||||
os << message.str() << std::flush;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline void G4Backtrace::Handler(int sig, siginfo_t* sinfo, void*)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk{ *(GetData().lock) };
|
||||
|
||||
{
|
||||
std::stringstream msg;
|
||||
Message(sig, sinfo, msg);
|
||||
std::cerr << msg.str() << std::flush;
|
||||
}
|
||||
|
||||
std::stringstream msg;
|
||||
msg << "\n\n";
|
||||
|
||||
if(sinfo && G4PSIGINFO_AVAILABLE > 0)
|
||||
{
|
||||
# if G4PSIGINFO_AVAILABLE > 0
|
||||
psiginfo(sinfo, msg.str().c_str());
|
||||
# endif
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << msg.str() << std::endl;
|
||||
}
|
||||
|
||||
// ignore any termination signals
|
||||
sigignore(SIGKILL);
|
||||
sigignore(SIGTERM);
|
||||
sigignore(SIGABRT);
|
||||
abort();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline int G4Backtrace::Enable(const signal_set_t& _signals)
|
||||
{
|
||||
static bool _first = true;
|
||||
std::unique_lock<std::mutex> lk{ *(GetData().lock) };
|
||||
if(_first)
|
||||
{
|
||||
std::string _msg = "!!! G4Backtrace is activated !!!";
|
||||
std::stringstream _filler;
|
||||
std::stringstream _spacer;
|
||||
_filler.fill('#');
|
||||
_filler << std::setw(_msg.length()) << "";
|
||||
_spacer << std::setw(10) << "";
|
||||
std::cout << "\n\n"
|
||||
<< _spacer.str() << _filler.str() << "\n"
|
||||
<< _spacer.str() << _msg << "\n"
|
||||
<< _spacer.str() << _filler.str() << "\n\n"
|
||||
<< std::flush;
|
||||
}
|
||||
_first = false;
|
||||
int cnt = 0;
|
||||
for(auto& itr : _signals)
|
||||
{
|
||||
if(itr < 0)
|
||||
continue;
|
||||
if(GetData().is_active[itr])
|
||||
continue;
|
||||
++cnt;
|
||||
sigfillset(&(GetData().current[itr].sa_mask));
|
||||
sigdelset(&(GetData().current[itr].sa_mask), itr);
|
||||
GetData().current[itr].sa_sigaction = &Handler;
|
||||
GetData().current[itr].sa_flags = SA_SIGINFO;
|
||||
sigaction(itr, &(GetData().current[itr]), &(GetData().previous[itr]));
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline int G4Backtrace::Enable(const std::string& _signals)
|
||||
{
|
||||
if(_signals.empty())
|
||||
return 0;
|
||||
|
||||
auto _add_signal = [](std::string sig, signal_set_t& _targ) {
|
||||
if(!sig.empty())
|
||||
{
|
||||
for(auto& itr : sig)
|
||||
itr = toupper(itr);
|
||||
_targ.insert(G4Backtrace::GetSignal(sig));
|
||||
}
|
||||
};
|
||||
|
||||
const std::regex wsp_re("[ ,;:\t\n]+");
|
||||
auto _maxid = GetData().identifiers.size();
|
||||
auto _result = std::vector<std::string>(_maxid, "");
|
||||
std::copy(
|
||||
std::sregex_token_iterator(_signals.begin(), _signals.end(), wsp_re, -1),
|
||||
std::sregex_token_iterator(), _result.begin());
|
||||
signal_set_t _sigset{};
|
||||
for(auto& itr : _result)
|
||||
_add_signal(itr, _sigset);
|
||||
return Enable(_sigset);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline int G4Backtrace::Disable(signal_set_t _signals)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk{ *(GetData().lock) };
|
||||
|
||||
if(_signals.empty())
|
||||
{
|
||||
for(auto& itr : GetData().is_active)
|
||||
_signals.insert(itr.first);
|
||||
}
|
||||
|
||||
int cnt = 0;
|
||||
for(auto& itr : _signals)
|
||||
{
|
||||
if(itr < 0)
|
||||
continue;
|
||||
if(!GetData().is_active[itr])
|
||||
continue;
|
||||
++cnt;
|
||||
sigaction(itr, &(GetData().previous[itr]), nullptr);
|
||||
GetData().current.erase(itr);
|
||||
GetData().is_active[itr] = false;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline int G4Backtrace::GetSignal(const std::string& sid)
|
||||
{
|
||||
for(auto&& itr : GetData().identifiers)
|
||||
{
|
||||
if(std::get<0>(itr) == sid)
|
||||
return std::get<1>(itr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline std::string G4Backtrace::Description(int sig)
|
||||
{
|
||||
for(auto&& itr : GetData().identifiers)
|
||||
{
|
||||
if(std::get<1>(itr) == sig)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << " signal = " << std::setw(8) << std::get<0>(itr)
|
||||
<< ", value = " << std::setw(4) << std::get<1>(itr)
|
||||
<< ", description = " << std::get<2>(itr);
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
std::stringstream ss;
|
||||
ss << " signal = " << std::setw(8) << "unknown"
|
||||
<< ", value = " << std::setw(4) << sig;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#else
|
||||
|
||||
# include <array>
|
||||
# include <functional>
|
||||
# include <map>
|
||||
# include <set>
|
||||
# include <string>
|
||||
# include <tuple>
|
||||
# include <vector>
|
||||
|
||||
// dummy implementation
|
||||
class G4Backtrace
|
||||
{
|
||||
public:
|
||||
struct fake_siginfo
|
||||
{};
|
||||
struct fake_sigaction
|
||||
{};
|
||||
|
||||
using siginfo_t = fake_siginfo;
|
||||
using sigaction_t = fake_sigaction;
|
||||
using exit_action_t = std::function<void(int)>;
|
||||
using frame_func_t = std::function<G4String(const char*)>;
|
||||
using signal_set_t = std::set<int>;
|
||||
|
||||
public:
|
||||
struct actions
|
||||
{
|
||||
using id_entry_t = std::tuple<std::string, int, std::string>;
|
||||
using id_list_t = std::vector<id_entry_t>;
|
||||
|
||||
std::map<int, bool> is_active = {};
|
||||
std::map<int, sigaction_t> current = {};
|
||||
std::map<int, sigaction_t> previous = {};
|
||||
std::vector<exit_action_t> exit_actions = {};
|
||||
const id_list_t identifiers = {};
|
||||
};
|
||||
|
||||
public:
|
||||
static void Handler(int, siginfo_t*, void*) {}
|
||||
static void Message(int, siginfo_t*, std::ostream&) {}
|
||||
static void ExitAction(int) {}
|
||||
static int Enable(const std::string&) { return 0; }
|
||||
static int Enable(const signal_set_t& = DefaultSignals()) { return 0; }
|
||||
static int Disable(signal_set_t = {}) { return 0; }
|
||||
static int GetSignal(const std::string&) { return -1; }
|
||||
static std::string Description(int) { return std::string{}; }
|
||||
|
||||
template <typename FuncT>
|
||||
static void AddExitAction(FuncT&&)
|
||||
{}
|
||||
|
||||
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
|
||||
static std::array<G4ResultOf_t<FuncT(const char*)>, Depth> GetMangled(
|
||||
FuncT&& func = FrameFunctor())
|
||||
{
|
||||
using type = G4ResultOf_t<FuncT(const char*)>;
|
||||
auto ret = std::array<type, Depth>{};
|
||||
ret.fill(func(""));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
|
||||
static std::array<G4ResultOf_t<FuncT(const char*)>, Depth> GetDemangled(
|
||||
FuncT&& func = FrameFunctor())
|
||||
{
|
||||
using type = G4ResultOf_t<FuncT(const char*)>;
|
||||
auto ret = std::array<type, Depth>{};
|
||||
ret.fill(func(""));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// a functor called for each frame in the backtrace
|
||||
static frame_func_t& FrameFunctor()
|
||||
{
|
||||
static frame_func_t _instance = [](const char* _s) { return G4String(_s); };
|
||||
return _instance;
|
||||
}
|
||||
|
||||
// default set of signals
|
||||
static signal_set_t& DefaultSignals()
|
||||
{
|
||||
static signal_set_t _instance = {};
|
||||
return _instance;
|
||||
}
|
||||
|
||||
static actions& GetData()
|
||||
{
|
||||
static auto _instance = actions{};
|
||||
return _instance;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#endif // G4SIGNAL_AVAILABLE
|
||||
#endif // G4Backtrace_hh
|
||||
@@ -51,6 +51,8 @@ class G4PhysicsOrderedFreeVector : public G4PhysicsVector
|
||||
// The vector will be filled from extern file using Retrieve()
|
||||
// or InsertValues() methods
|
||||
|
||||
G4PhysicsOrderedFreeVector(const std::vector<G4double>& Energies,
|
||||
const std::vector<G4double>& Values);
|
||||
G4PhysicsOrderedFreeVector(G4double* Energies, G4double* Values,
|
||||
std::size_t VectorLength);
|
||||
// The vector is filled in this constructor.
|
||||
|
||||
@@ -0,0 +1,561 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
// G4Profiler
|
||||
//
|
||||
// Class description:
|
||||
//
|
||||
// Class providing the internal profiling interface for Geant4.
|
||||
|
||||
// Author: Jonathan Madsen, LBNL - November 2020
|
||||
// --------------------------------------------------------------------
|
||||
#ifndef G4Profiler_hh
|
||||
#define G4Profiler_hh 1
|
||||
|
||||
// Fundamental definitions
|
||||
#ifndef G4GMAKE
|
||||
# include "G4GlobalConfig.hh"
|
||||
#endif
|
||||
|
||||
// for meta-programming stuff
|
||||
#include "G4Profiler.icc"
|
||||
|
||||
#if defined(GEANT4_USE_TIMEMORY)
|
||||
# include <timemory/utility/argparse.hpp>
|
||||
#endif
|
||||
|
||||
#include "globals.hh"
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
class G4Run;
|
||||
class G4Event;
|
||||
class G4Track;
|
||||
class G4Step;
|
||||
|
||||
struct G4ProfileType
|
||||
{
|
||||
enum : size_t
|
||||
{
|
||||
Run = 0,
|
||||
Event,
|
||||
Track,
|
||||
Step,
|
||||
User,
|
||||
TypeEnd
|
||||
};
|
||||
};
|
||||
|
||||
struct G4ProfileOp
|
||||
{
|
||||
enum : int
|
||||
{
|
||||
Query = 0,
|
||||
Label,
|
||||
Tool
|
||||
};
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
class G4Profiler
|
||||
{
|
||||
public:
|
||||
using array_type = std::array<bool, G4ProfileType::TypeEnd>;
|
||||
|
||||
#if defined(GEANT4_USE_TIMEMORY)
|
||||
using ArgumentParser = tim::argparse::argument_parser;
|
||||
#else
|
||||
struct ArgumentParser
|
||||
{
|
||||
explicit ArgumentParser(std::string) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
static void Configure(const std::vector<std::string>& args);
|
||||
static void Configure(int argc, char** argv);
|
||||
static void Configure(ArgumentParser&, const std::vector<std::string>& args);
|
||||
static void Configure(ArgumentParser&, int argc, char** argv);
|
||||
static void Finalize();
|
||||
|
||||
static bool GetEnabled(size_t v) { return GetEnabled().at(v); }
|
||||
static void SetEnabled(size_t v, bool val) { GetEnabled().at(v) = val; }
|
||||
|
||||
static bool GetPerEvent() { return GetPerEventImpl(); }
|
||||
static void SetPerEvent(bool val) { GetPerEventImpl() = val; }
|
||||
|
||||
private:
|
||||
static array_type& GetEnabled();
|
||||
static bool& GetPerEventImpl()
|
||||
{
|
||||
static bool _value = false;
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// maps enumerations to types
|
||||
//
|
||||
template <size_t Category>
|
||||
struct G4ProfilerObject
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template <size_t Category>
|
||||
using G4ProfilerObject_t = typename G4ProfilerObject<Category>::type;
|
||||
|
||||
template <>
|
||||
struct G4ProfilerObject<G4ProfileType::Run>
|
||||
{
|
||||
using type = const G4Run*;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct G4ProfilerObject<G4ProfileType::Event>
|
||||
{
|
||||
using type = const G4Event*;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct G4ProfilerObject<G4ProfileType::Track>
|
||||
{
|
||||
using type = const G4Track*;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct G4ProfilerObject<G4ProfileType::Step>
|
||||
{
|
||||
using type = const G4Step*;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct G4ProfilerObject<G4ProfileType::User>
|
||||
{
|
||||
using type = const std::string&;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// default set of profiler args
|
||||
template <size_t Category>
|
||||
struct G4ProfilerArgs
|
||||
{
|
||||
// this resolves to the G4ProfilerObject type-trait above, e.g.
|
||||
// "const G4Step*" when category is G4ProfileType::Step
|
||||
using value_type = G4ProfilerObject_t<Category>;
|
||||
|
||||
// two-dimensional type-list where each inner type-list is a set
|
||||
// of arguments to support creating a profiler type from
|
||||
using type = G4TypeList<G4PROFILER_ARG_SET(value_type)>;
|
||||
// so above means there are functors in use which apply:
|
||||
//
|
||||
// G4StepProfiler _profiler(const G4Step*);
|
||||
//
|
||||
};
|
||||
|
||||
template <size_t Category>
|
||||
using G4ProfilerArgs_t = typename G4ProfilerArgs<Category>::type;
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
template <size_t Category, typename RetT, typename CommonT = G4CommonTypeList<>>
|
||||
struct G4ProfilerFunctors
|
||||
{
|
||||
using type = G4Impl::Functors_t<RetT, CommonT, G4ProfilerArgs_t<Category>>;
|
||||
};
|
||||
|
||||
template <size_t Category, typename RetT, typename... CommonT>
|
||||
using G4ProfilerFunctors_t =
|
||||
typename G4ProfilerFunctors<Category, RetT,
|
||||
G4CommonTypeList<CommonT...>>::type;
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#ifdef GEANT4_USE_TIMEMORY
|
||||
|
||||
// Pre-declare the timemory component that will be used
|
||||
namespace tim
|
||||
{
|
||||
namespace component
|
||||
{
|
||||
template <size_t, typename Tag>
|
||||
struct user_bundle;
|
||||
} // namespace component
|
||||
|
||||
template <typename... Types>
|
||||
class auto_tuple;
|
||||
|
||||
template <typename Tag, typename... Types>
|
||||
class auto_bundle;
|
||||
} // namespace tim
|
||||
|
||||
namespace g4tim
|
||||
{
|
||||
using namespace tim;
|
||||
using tim::component::user_bundle;
|
||||
|
||||
struct G4api : public tim::concepts::api
|
||||
{};
|
||||
|
||||
using ProfilerArgparser = argparse::argument_parser;
|
||||
|
||||
} // namespace g4tim
|
||||
|
||||
using G4RunProfiler = g4tim::user_bundle<G4ProfileType::Run, G4ProfileType>;
|
||||
using G4EventProfiler = g4tim::user_bundle<G4ProfileType::Event, G4ProfileType>;
|
||||
using G4TrackProfiler = g4tim::user_bundle<G4ProfileType::Track, G4ProfileType>;
|
||||
using G4StepProfiler = g4tim::user_bundle<G4ProfileType::Step, G4ProfileType>;
|
||||
using G4UserProfiler = g4tim::user_bundle<G4ProfileType::User, G4ProfileType>;
|
||||
|
||||
template <typename... Types>
|
||||
using G4ProfilerBundle = g4tim::auto_bundle<g4tim::G4api, Types...>;
|
||||
|
||||
#else
|
||||
|
||||
namespace g4tim
|
||||
{
|
||||
struct ProfilerArgparser
|
||||
{};
|
||||
|
||||
/// this provides a dummy wrapper for the profiling
|
||||
template <typename... Types>
|
||||
struct handler
|
||||
{
|
||||
template <typename... Args>
|
||||
handler(Args&&...)
|
||||
{}
|
||||
~handler() = default;
|
||||
handler(const handler&) = default;
|
||||
handler(handler&&) = default;
|
||||
handler& operator=(const handler&) = default;
|
||||
handler& operator=(handler&&) = default;
|
||||
|
||||
void record() {}
|
||||
template <typename... Args>
|
||||
void start(Args&&...)
|
||||
{}
|
||||
template <typename... Args>
|
||||
void stop(Args&&...)
|
||||
{}
|
||||
void push() {}
|
||||
void pop() {}
|
||||
void reset() {}
|
||||
void report_at_exit(bool) {}
|
||||
template <typename... Args>
|
||||
void mark_begin(Args&&...)
|
||||
{}
|
||||
template <typename... Args>
|
||||
void mark_end(Args&&...)
|
||||
{}
|
||||
friend std::ostream& operator<<(std::ostream& os, const handler&)
|
||||
{
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t Idx, typename Tp>
|
||||
struct user_bundle
|
||||
{
|
||||
template <typename... Args>
|
||||
user_bundle(Args&&...)
|
||||
{}
|
||||
|
||||
template <typename... Types, typename... Args>
|
||||
static void configure(Args&&...)
|
||||
{}
|
||||
|
||||
static void reset() {}
|
||||
};
|
||||
|
||||
} // namespace g4tim
|
||||
|
||||
using G4RunProfiler = g4tim::handler<>;
|
||||
using G4EventProfiler = g4tim::handler<>;
|
||||
using G4TrackProfiler = g4tim::handler<>;
|
||||
using G4StepProfiler = g4tim::handler<>;
|
||||
using G4UserProfiler = g4tim::handler<>;
|
||||
|
||||
template <typename... Types>
|
||||
using G4ProfilerBundle = g4tim::handler<Types...>;
|
||||
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
/// @brief G4ProfilerConfig
|
||||
/// This class is used to determine whether to activate profiling in the code
|
||||
///
|
||||
/// @example extended/parallel/ThreadsafeScorers/ts_scorers.cc
|
||||
/// The main for this file contains an example for configuring the G4Profiler
|
||||
/// for G4Track and G4Step
|
||||
///
|
||||
template <size_t Category>
|
||||
class G4ProfilerConfig
|
||||
{
|
||||
public:
|
||||
using type = G4ProfilerBundle<g4tim::user_bundle<Category, G4ProfileType>>;
|
||||
using this_type = G4ProfilerConfig<Category>;
|
||||
|
||||
static constexpr size_t arg_sets =
|
||||
G4TypeListSize<G4ProfilerArgs_t<Category>>::value;
|
||||
|
||||
using QueryFunc_t = G4ProfilerFunctors_t<Category, bool>;
|
||||
using LabelFunc_t = G4ProfilerFunctors_t<Category, std::string>;
|
||||
using ToolFunc_t = std::tuple<std::function<type*(const std::string&)>>;
|
||||
|
||||
public:
|
||||
// when constructed with no args, should call operator()
|
||||
G4ProfilerConfig() = default;
|
||||
|
||||
// constructor calls Query(...), Label(...), Tool(...)
|
||||
template <typename Arg, typename... Args>
|
||||
G4ProfilerConfig(Arg, Args...);
|
||||
|
||||
// will delete m_bundle is allocated
|
||||
~G4ProfilerConfig();
|
||||
|
||||
// default the move-constructor and move-assignment
|
||||
G4ProfilerConfig(G4ProfilerConfig&&) = default;
|
||||
G4ProfilerConfig& operator=(G4ProfilerConfig&&) = default;
|
||||
|
||||
// do not allow copy-construct and copy-assign bc of raw pointer
|
||||
G4ProfilerConfig(const G4ProfilerConfig&) = delete;
|
||||
G4ProfilerConfig& operator=(const G4ProfilerConfig&) = delete;
|
||||
|
||||
// if constructed without args, this function should be called
|
||||
template <typename... Args>
|
||||
bool operator()(Args...);
|
||||
|
||||
// provide nullptr check
|
||||
operator bool() const { return (m_bundle != nullptr); }
|
||||
|
||||
private:
|
||||
type* m_bundle = nullptr;
|
||||
|
||||
static QueryFunc_t& GetQueries()
|
||||
{
|
||||
static QueryFunc_t _value;
|
||||
return _value;
|
||||
}
|
||||
|
||||
static LabelFunc_t& GetLables()
|
||||
{
|
||||
static LabelFunc_t _value;
|
||||
return _value;
|
||||
}
|
||||
|
||||
static ToolFunc_t& GetTools()
|
||||
{
|
||||
static ToolFunc_t _value;
|
||||
return _value;
|
||||
}
|
||||
|
||||
public:
|
||||
// invokes the functor that determines whether to enable profiling
|
||||
template <typename... Args>
|
||||
static bool Query(Args... _args);
|
||||
|
||||
// invokes the functor for generating a Label when profiling is enabled
|
||||
template <typename... Args>
|
||||
static std::string Label(Args... _args);
|
||||
|
||||
// invokes the functor for configuring a Tool instance
|
||||
template <typename... Args>
|
||||
static type* Tool(const std::string&);
|
||||
|
||||
using QueryHandler_t = FuncHandler<this_type, QueryFunc_t, bool>;
|
||||
using LabelHandler_t = FuncHandler<this_type, LabelFunc_t, std::string>;
|
||||
using ToolHandler_t = FuncHandler<this_type, ToolFunc_t, type*>;
|
||||
|
||||
static QueryHandler_t GetQueryFunctor();
|
||||
static QueryHandler_t GetFallbackQueryFunctor();
|
||||
|
||||
static LabelHandler_t GetLabelFunctor();
|
||||
static LabelHandler_t GetFallbackLabelFunctor();
|
||||
|
||||
static ToolHandler_t GetToolFunctor();
|
||||
static ToolHandler_t GetFallbackToolFunctor();
|
||||
|
||||
private:
|
||||
template <bool B, typename Lhs, typename Rhs>
|
||||
using conditional_t = typename std::conditional<B, Lhs, Rhs>::type;
|
||||
|
||||
// this provides the global statics for the functors
|
||||
template <int Idx>
|
||||
struct PersistentSettings
|
||||
{
|
||||
// determine the functor type
|
||||
using functor_type = conditional_t<
|
||||
Idx == G4ProfileOp::Query, QueryFunc_t,
|
||||
conditional_t<Idx == G4ProfileOp::Label, LabelFunc_t, ToolFunc_t>>;
|
||||
|
||||
PersistentSettings() = default;
|
||||
~PersistentSettings() = default;
|
||||
// default member initialization
|
||||
functor_type m_functor;
|
||||
};
|
||||
|
||||
template <int Idx>
|
||||
static PersistentSettings<Idx>& GetPersistentFallback();
|
||||
|
||||
template <int Idx>
|
||||
static PersistentSettings<Idx>& GetPersistent();
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
// alias for getting type
|
||||
template <size_t Category>
|
||||
using G4ProfilerConfig_t = typename G4ProfilerConfig<Category>::type;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template <size_t Cat>
|
||||
template <typename Arg, typename... Args>
|
||||
G4ProfilerConfig<Cat>::G4ProfilerConfig(Arg _arg, Args... _args)
|
||||
{
|
||||
this->operator()(_arg, _args...);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template <size_t Cat>
|
||||
template <typename... Args>
|
||||
bool G4ProfilerConfig<Cat>::operator()(Args... _args)
|
||||
{
|
||||
if(Query(_args...))
|
||||
{
|
||||
m_bundle = Tool(Label(_args...));
|
||||
if(m_bundle)
|
||||
m_bundle->start(_args...);
|
||||
return (m_bundle != nullptr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
// invokes the functor that determines whether to enable profiling
|
||||
template <size_t Cat>
|
||||
template <typename... Args>
|
||||
bool G4ProfilerConfig<Cat>::Query(Args... _args)
|
||||
{
|
||||
return QueryHandler_t{ GetPersistent<G4ProfileOp::Query>().m_functor }(
|
||||
_args...);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
// invokes the functor for generating a label when profiling is enabled
|
||||
template <size_t Cat>
|
||||
template <typename... Args>
|
||||
std::string G4ProfilerConfig<Cat>::Label(Args... _args)
|
||||
{
|
||||
return LabelHandler_t{ GetPersistent<G4ProfileOp::Label>().m_functor }(
|
||||
_args...);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
// invokes the functor for configuring a tool instance
|
||||
template <size_t Cat>
|
||||
template <typename... Args>
|
||||
typename G4ProfilerConfig<Cat>::type* G4ProfilerConfig<Cat>::Tool(
|
||||
const std::string& _args)
|
||||
{
|
||||
return ToolHandler_t{ GetPersistent<G4ProfileOp::Tool>().m_functor }(_args);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
// ensure that any implicit instantiations of the G4ProfilerConfig
|
||||
// are not done in another translation units because we will
|
||||
// explicitly instantiate G4ProfilerConfig in the .cc file
|
||||
|
||||
// line breaks make this much harder to read
|
||||
// clang-format off
|
||||
extern template class G4ProfilerConfig<G4ProfileType::Run>;
|
||||
extern template class G4ProfilerConfig<G4ProfileType::Event>;
|
||||
extern template class G4ProfilerConfig<G4ProfileType::Track>;
|
||||
extern template class G4ProfilerConfig<G4ProfileType::Step>;
|
||||
extern template class G4ProfilerConfig<G4ProfileType::User>;
|
||||
extern template G4ProfilerConfig<G4ProfileType::Run>::G4ProfilerConfig(const G4Run*);
|
||||
extern template G4ProfilerConfig<G4ProfileType::Event>::G4ProfilerConfig(const G4Event*);
|
||||
extern template G4ProfilerConfig<G4ProfileType::Track>::G4ProfilerConfig(const G4Track*);
|
||||
extern template G4ProfilerConfig<G4ProfileType::Step>::G4ProfilerConfig(const G4Step*);
|
||||
extern template G4ProfilerConfig<G4ProfileType::User>::G4ProfilerConfig(const std::string&);
|
||||
// clang-format on
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#ifndef GEANT4_USE_TIMEMORY
|
||||
|
||||
# include <ostream>
|
||||
# include <string>
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(GEANT4_USE_TIMEMORY)
|
||||
// two macros below create a unique variable name based on the line number
|
||||
# define G4USER_PROFILER_VAR_JOIN(X, Y) X##Y
|
||||
# define G4USER_PROFILER_VAR(Y) G4USER_PROFILER_VAR_JOIN(g4user_profiler_, Y)
|
||||
|
||||
// inserts just the string
|
||||
# define G4USER_SCOPED_PROFILE(...) \
|
||||
G4ProfilerConfig<G4ProfileType::User> G4USER_PROFILER_VAR(__LINE__)( \
|
||||
TIMEMORY_JOIN("", __VA_ARGS__))
|
||||
|
||||
// inserts the function
|
||||
# define G4USER_SCOPED_PROFILE_FUNC(...) \
|
||||
G4ProfilerConfig<G4ProfileType::User> G4USER_PROFILER_VAR(__LINE__)( \
|
||||
TIMEMORY_JOIN("", __FUNCTION__, "/", __VA_ARGS__))
|
||||
|
||||
// inserts the function and file
|
||||
# define G4USER_SCOPED_PROFILE_FUNC_FILE(...) \
|
||||
G4ProfilerConfig<G4ProfileType::User> G4USER_PROFILER_VAR(__LINE__)( \
|
||||
TIMEMORY_JOIN("", __FUNCTION__, '@', __FILE__, '/', __VA_ARGS__))
|
||||
|
||||
// inserts the function, file, and line number
|
||||
# define G4USER_SCOPED_PROFILE_FUNC_FILE_LINE(...) \
|
||||
G4ProfilerConfig<G4ProfileType::User> G4USER_PROFILER_VAR(__LINE__)( \
|
||||
TIMEMORY_JOIN("", __FUNCTION__, '@', __FILE__, ':', __LINE__, '/', \
|
||||
__VA_ARGS__))
|
||||
#else
|
||||
# define G4USER_SCOPED_PROFILE(...)
|
||||
# define G4USER_SCOPED_PROFILE_FUNC(...)
|
||||
# define G4USER_SCOPED_PROFILE_FUNC_FILE(...)
|
||||
# define G4USER_SCOPED_PROFILE_FUNC_FILE_LINE(...)
|
||||
#endif
|
||||
|
||||
#endif // G4Profiler_hh
|
||||
@@ -0,0 +1,391 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
// G4Profiler
|
||||
//
|
||||
// Template definition file
|
||||
//
|
||||
// Author: Jonathan Madsen, LBNL - November 2020
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
#if !defined(G4PROFILER_ICC_)
|
||||
# define G4PROFILER_ICC_ 1
|
||||
|
||||
# include <functional>
|
||||
# include <type_traits>
|
||||
# include <tuple>
|
||||
# include <initializer_list>
|
||||
# include <string>
|
||||
# include <sstream>
|
||||
|
||||
// for index_sequence implementation
|
||||
# include "PTL/Globals.hh"
|
||||
|
||||
# if defined(GEANT4_USE_TIMEMORY)
|
||||
# include <timemory/utility/utility.hpp>
|
||||
# endif
|
||||
|
||||
# if !defined(GEANT4_FOLD_EXPRESSION)
|
||||
# define GEANT4_FOLD_EXPRESSION(...) \
|
||||
::G4Impl::consume_parameters( \
|
||||
::std::initializer_list<int>{ (__VA_ARGS__, 0)... })
|
||||
# endif
|
||||
|
||||
# if !defined(G4PROFILER_ARG_SET)
|
||||
# define G4PROFILER_ARG_SET(...) G4TypeList<__VA_ARGS__>
|
||||
# endif
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// lightweight (w.r.t. compile-time) alternative to std::tuple that doesn't
|
||||
// store anything and cannot be instantiated because it has no definition. This
|
||||
// guards against meta-programming mistakes where:
|
||||
// std::function<void(const G4Step*)>
|
||||
// ends up as
|
||||
// std::function<void(G4TypeList<const G4Step*>)>
|
||||
template <typename... Types>
|
||||
struct G4TypeList;
|
||||
|
||||
// this is used in G4Impl::Functors to add a common set of arguments to all of
|
||||
// the functors
|
||||
template <typename... Types>
|
||||
struct G4CommonTypeList;
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
//
|
||||
template <typename... Types>
|
||||
struct G4TypeListSize;
|
||||
|
||||
template <typename... Types>
|
||||
struct G4TypeListSize<G4TypeList<Types...>>
|
||||
{
|
||||
static constexpr size_t value = sizeof...(Types);
|
||||
};
|
||||
|
||||
template <typename... Types>
|
||||
struct G4TypeListSize<std::tuple<Types...>>
|
||||
{
|
||||
static constexpr size_t value = std::tuple_size<std::tuple<Types...>>::value;
|
||||
};
|
||||
|
||||
namespace G4Impl
|
||||
{
|
||||
template <typename Tp>
|
||||
std::string demangle()
|
||||
{
|
||||
# if defined(GEANT4_USE_TIMEMORY)
|
||||
return tim::demangle<Tp>();
|
||||
# else
|
||||
return typeid(Tp).name();
|
||||
# endif
|
||||
}
|
||||
|
||||
template <typename... Tp>
|
||||
void consume_parameters(Tp&&...)
|
||||
{}
|
||||
//------------------------------------------------------------------------//
|
||||
// don't provide a definition that works without G4TypeList
|
||||
template <typename RetT, typename... Tail>
|
||||
struct Functors;
|
||||
//------------------------------------------------------------------------//
|
||||
template <typename RetT, typename... Tail>
|
||||
struct Functors<RetT, G4TypeList<Tail...>>
|
||||
{
|
||||
using type = std::function<RetT(Tail...)>;
|
||||
};
|
||||
//------------------------------------------------------------------------//
|
||||
template <typename RetT, typename... CommonT, typename... Tail>
|
||||
struct Functors<RetT, G4CommonTypeList<CommonT...>, G4TypeList<Tail...>>
|
||||
{
|
||||
using type = std::function<RetT(CommonT..., Tail...)>;
|
||||
};
|
||||
//------------------------------------------------------------------------//
|
||||
template <typename RetT, typename... Types, typename... Tail>
|
||||
struct Functors<RetT, G4TypeList<G4TypeList<Types...>, Tail...>>
|
||||
{
|
||||
using type = std::tuple<std::function<RetT(Types...)>,
|
||||
typename Functors<RetT, Tail>::type...>;
|
||||
};
|
||||
//------------------------------------------------------------------------//
|
||||
template <typename RetT, typename... CommonT, typename... Types,
|
||||
typename... Tail>
|
||||
struct Functors<RetT, G4CommonTypeList<CommonT...>,
|
||||
G4TypeList<G4TypeList<Types...>, Tail...>>
|
||||
{
|
||||
using type = std::tuple<
|
||||
std::function<RetT(CommonT..., Types...)>,
|
||||
typename Functors<RetT, G4CommonTypeList<CommonT...>, Tail>::type...>;
|
||||
};
|
||||
//------------------------------------------------------------------------//
|
||||
template <typename RetT, typename... Tail>
|
||||
using Functors_t = typename Functors<RetT, Tail...>::type;
|
||||
|
||||
} // namespace G4Impl
|
||||
|
||||
//
|
||||
// this allows the generic invocation or assignment of a functor
|
||||
//
|
||||
template <typename Type, typename FuncT, typename RetT = void>
|
||||
struct FuncHandler
|
||||
{
|
||||
using this_type = FuncHandler<Type, FuncT, RetT>;
|
||||
|
||||
// until Geant4 updates to C++14 as a minimum
|
||||
template <typename Tp>
|
||||
using decay_t = typename std::decay<Tp>::type;
|
||||
template <bool Bv, typename Tp = void>
|
||||
using enable_if_t = typename std::enable_if<Bv, Tp>::type;
|
||||
template <size_t... Idx>
|
||||
using index_sequence = PTL::mpl::index_sequence<Idx...>;
|
||||
template <size_t NumT>
|
||||
using make_index_sequence = PTL::mpl::make_index_sequence<NumT>;
|
||||
|
||||
static constexpr size_t size = std::tuple_size<FuncT>::value;
|
||||
|
||||
FuncHandler(FuncT& _functors)
|
||||
: m_functors(_functors)
|
||||
{}
|
||||
|
||||
// overloading the assignment operator will let users
|
||||
// be able to use one method for the G4ProfilerConfig
|
||||
// despite the potential variants. Thus this is valid:
|
||||
//
|
||||
// GetLabelFunctor() = [](int i) { return std::to_string(i); }
|
||||
// GetLabelFunctor() = [](float v) { return std::to_string(v); }
|
||||
//
|
||||
// but will only compile for types that are explicitly
|
||||
// supported --> the assign function iterates through the
|
||||
// specific variants at compile-time
|
||||
template <typename Func>
|
||||
void operator=(Func&& f)
|
||||
{
|
||||
assign(m_functors, std::forward<Func>(f), 0, make_index_sequence<size>{});
|
||||
}
|
||||
|
||||
private:
|
||||
FuncT& m_functors;
|
||||
|
||||
template <typename Tp>
|
||||
static enable_if_t<std::is_same<decay_t<Tp>, bool>::value, Tp>
|
||||
get_default_return_value()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Tp>
|
||||
static enable_if_t<std::is_same<decay_t<Tp>, std::string>::value, Tp>
|
||||
get_default_return_value()
|
||||
{
|
||||
// this may return an ugly mangled name but will at least but useful
|
||||
// and can be demangled with c++filt
|
||||
return std::string("label-functor-not-set-for-") + G4Impl::demangle<Tp>();
|
||||
}
|
||||
|
||||
template <typename Tp>
|
||||
static enable_if_t<std::is_pointer<decay_t<Tp>>::value, Tp>
|
||||
get_default_return_value()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
using return_t = decay_t<RetT>;
|
||||
|
||||
//
|
||||
// NOTE: All references to "iterations" in the comments
|
||||
// below refer to compile-time iterations, which are
|
||||
// implemented through recusion below. Iterations stop
|
||||
// when a valid statement has been found and thus necessitates
|
||||
// four versions of the same function: two of these functions
|
||||
// handle the end of the recursion 'sizeof...(Tail) == 0'
|
||||
// and the first of these functions (1.a) is used if a valid
|
||||
// statement is found and the second (1.b, if reached) introduces
|
||||
// a compilation error. The third and fourth start the iteration
|
||||
// when 'sizeof...(Tail) > 0'. If a valid statement is found
|
||||
// in the third function (2.a), recursion stops. If not, the
|
||||
// iteration is continued to the next index via the fourth
|
||||
// function (2.b).
|
||||
//
|
||||
|
||||
// INVOKE 1.a
|
||||
//
|
||||
// this is the end of the iteration through the potential
|
||||
// functor variants and the trailing '->' tests whether the
|
||||
// functor can be called with the given arguments. The
|
||||
// 'int' as the second parameter ensures (through overload
|
||||
// resolution rules) that this gets tested before the
|
||||
// function after this (1.b).
|
||||
// If the size of 'FuncT' is equal to 1, then this is also
|
||||
// the start of the iteration through the potential functor
|
||||
// variants.
|
||||
template <typename Tp, size_t Idx, size_t... Tail, typename... Args,
|
||||
enable_if_t<sizeof...(Tail) == 0, int> = 0>
|
||||
static auto invoke(Tp& _obj, int, index_sequence<Idx, Tail...>,
|
||||
Args&&... _args)
|
||||
-> decltype(std::get<Idx>(_obj)(std::forward<Args>(_args)...), return_t{})
|
||||
{
|
||||
// if the functor has been set, then execute it
|
||||
if(std::get<Idx>(_obj))
|
||||
return std::get<Idx>(_obj)(std::forward<Args>(_args)...);
|
||||
else
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Error! Functor "
|
||||
<< G4Impl::demangle<decltype(std::get<Idx>(_obj))>()
|
||||
<< " was not set for " << G4Impl::demangle<Type>();
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
// the default for booleans should return false
|
||||
return get_default_return_value<return_t>();
|
||||
}
|
||||
|
||||
// INVOKE 1.b
|
||||
//
|
||||
// this is the end of the iteration through the potential
|
||||
// functor variants and if this function is reached during
|
||||
// compile-time, this means that the given arguments are
|
||||
// not supported by any of the functors and will fail to
|
||||
// compile. The 'long' as the second parameter ensures that
|
||||
// it has lower precedence than the one above
|
||||
template <typename Tp, size_t Idx, size_t... Tail, typename... Args,
|
||||
enable_if_t<sizeof...(Tail) == 0, int> = 0>
|
||||
static auto invoke(Tp&, long, index_sequence<Idx, Tail...>, Args&&...)
|
||||
-> return_t
|
||||
{
|
||||
// this will cause a failure at compile-time.
|
||||
// this ensures that this static assert is dependent
|
||||
// on this function getting instantiated, simply putting
|
||||
// 'false' here would result in compile-time failure
|
||||
// even if no code ever instantiated this function
|
||||
static_assert(!std::is_same<Tp, Tp>::value, "Error! No valid functor!");
|
||||
throw std::runtime_error(
|
||||
"Error! No valid functor! This should have caused a compilation error!");
|
||||
return return_t{};
|
||||
}
|
||||
|
||||
// INVOKE 2.a
|
||||
//
|
||||
// If the size of 'FuncT' is greater than one, this is the
|
||||
// start of the iteration through the potential functor variants.
|
||||
// This version will be used if the X in '-> decltype(X, Y)'
|
||||
// is valid. If it is not valid, then overload resolution
|
||||
// rules will dictate that the compiler will move on to the
|
||||
// 'invoke' member function 2.b
|
||||
template <typename Tp, size_t Idx, size_t... Tail, typename... Args,
|
||||
enable_if_t<(sizeof...(Tail) > 0), int> = 0>
|
||||
static auto invoke(Tp& _obj, int, index_sequence<Idx, Tail...>,
|
||||
Args&&... _args)
|
||||
-> decltype(std::get<Idx>(_obj)(std::forward<Args>(_args)...), return_t{})
|
||||
{
|
||||
return std::get<Idx>(_obj)(std::forward<Args>(_args)...);
|
||||
}
|
||||
|
||||
// INVOKE 2.b
|
||||
//
|
||||
// If the above test was not valid, we discard the current index
|
||||
// ('Idx') and proceed to the next index. If there is only
|
||||
// one index remaining, then this will call proceed to the
|
||||
// first invoke member function (1.a). If there are multiple
|
||||
// indexes remaining, then this will proceed to the previous
|
||||
// invoke member function (2.a) and this will continue until
|
||||
// a valid match is found or will fail to compile.
|
||||
template <typename Tp, size_t Idx, size_t... Tail, typename... Args,
|
||||
enable_if_t<(sizeof...(Tail) > 0), int> = 0>
|
||||
static auto invoke(Tp& _obj, long, index_sequence<Idx, Tail...>,
|
||||
Args&&... _args)
|
||||
-> decltype(invoke(_obj, 0, index_sequence<Tail...>{},
|
||||
std::forward<Args>(_args)...))
|
||||
{
|
||||
return invoke(_obj, 0, index_sequence<Tail...>{},
|
||||
std::forward<Args>(_args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
// this uses the same principles as the invoke member function.
|
||||
// See the comments there.
|
||||
template <typename LhsT, typename RhsT, size_t Idx, size_t... Tail,
|
||||
enable_if_t<sizeof...(Tail) == 0, int> = 0>
|
||||
static auto assign(LhsT& _lhs, RhsT&& _rhs, int, index_sequence<Idx, Tail...>)
|
||||
-> decltype((std::get<Idx>(_lhs) = std::forward<RhsT>(_rhs)), void())
|
||||
{
|
||||
std::get<Idx>(_lhs) = std::forward<RhsT>(_rhs);
|
||||
}
|
||||
|
||||
// this uses the same principles as the invoke member function.
|
||||
// See the comments there.
|
||||
template <typename LhsT, typename RhsT, size_t Idx, size_t... Tail,
|
||||
enable_if_t<sizeof...(Tail) == 0, int> = 0>
|
||||
static void assign(LhsT&, RhsT&&, long, index_sequence<Idx, Tail...>)
|
||||
{
|
||||
// this will cause a failure at compile-time.
|
||||
// this ensures that this static assert is dependent
|
||||
// on this function getting instantiated, simply putting
|
||||
// 'false' here would result in compile-time failure
|
||||
// even if no code ever instantiated this function
|
||||
static_assert(!std::is_same<LhsT, LhsT>::value,
|
||||
"Error! No valid functor assignment!");
|
||||
throw std::runtime_error(
|
||||
"Error! No valid functor! This should have caused a compilation error!");
|
||||
}
|
||||
|
||||
// this uses the same principles as the invoke member function.
|
||||
// See the comments there.
|
||||
template <typename LhsT, typename RhsT, size_t Idx, size_t... Tail,
|
||||
enable_if_t<(sizeof...(Tail) > 0), int> = 0>
|
||||
static auto assign(LhsT& _lhs, RhsT&& _rhs, int, index_sequence<Idx, Tail...>)
|
||||
-> decltype((std::get<Idx>(_lhs) = std::forward<RhsT>(_rhs)), void())
|
||||
{
|
||||
std::get<Idx>(_lhs) = std::forward<RhsT>(_rhs);
|
||||
}
|
||||
|
||||
// this uses the same principles as the invoke member function.
|
||||
// See the comments there.
|
||||
template <typename LhsT, typename RhsT, size_t Idx, size_t... Tail,
|
||||
enable_if_t<(sizeof...(Tail) > 0), int> = 0>
|
||||
static void assign(LhsT& _lhs, RhsT&& _rhs, long,
|
||||
index_sequence<Idx, Tail...>)
|
||||
{
|
||||
assign(_lhs, std::forward<RhsT>(_rhs), 0, index_sequence<Tail...>{});
|
||||
}
|
||||
|
||||
public:
|
||||
// overloading the call operator makes it generic to call
|
||||
// the functors but will only compile for types that are
|
||||
// explicitly supported --> the invoke function iterates
|
||||
// through the specific variants at compile-time to
|
||||
// ensure using SFINAE
|
||||
template <typename... Args>
|
||||
auto operator()(Args&&... _args)
|
||||
-> decltype(std::declval<this_type>().invoke(std::declval<FuncT&>(), 0,
|
||||
make_index_sequence<size>{},
|
||||
std::forward<Args>(_args)...))
|
||||
{
|
||||
return invoke(m_functors, 0, make_index_sequence<size>{},
|
||||
std::forward<Args>(_args)...);
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#endif
|
||||
@@ -175,7 +175,7 @@ static constexpr double nanoampere = 1.e-9 * ampere;
|
||||
// Electric charge [Q]
|
||||
//
|
||||
static constexpr double coulomb = ampere * second;
|
||||
static constexpr double e_SI = 1.602176487e-19; // positron charge in coulomb
|
||||
static constexpr double e_SI = 1.602176634e-19; // positron charge in coulomb
|
||||
static constexpr double eplus = e_SI * coulomb; // positron charge
|
||||
|
||||
//
|
||||
|
||||
@@ -41,30 +41,39 @@
|
||||
|
||||
#include "globals.hh"
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#ifdef GEANT4_USE_TIMEMORY
|
||||
|
||||
# include <timemory/timemory.hpp>
|
||||
|
||||
using G4AutoTimer = tim::auto_timer;
|
||||
namespace g4tim
|
||||
{
|
||||
using namespace tim;
|
||||
} // namespace g4tim
|
||||
|
||||
using G4AutoTimer = g4tim::auto_timer;
|
||||
|
||||
#else
|
||||
|
||||
# include <ostream>
|
||||
# include <string>
|
||||
|
||||
namespace tim
|
||||
namespace g4tim
|
||||
{
|
||||
template <typename... _Args>
|
||||
void timemory_init(_Args...)
|
||||
{}
|
||||
inline void timemory_finalize() {}
|
||||
inline void print_env() {}
|
||||
|
||||
/// this provides "functionality" for *_HANDLE macros
|
||||
/// and can be omitted if these macros are not utilized
|
||||
struct dummy
|
||||
{
|
||||
template <typename... _Types, typename... _Args>
|
||||
static void configure(_Args&&...)
|
||||
{}
|
||||
template <typename... _Args>
|
||||
dummy(_Args&&...)
|
||||
{}
|
||||
@@ -74,10 +83,12 @@ namespace tim
|
||||
dummy& operator=(const dummy&) = default;
|
||||
dummy& operator=(dummy&&) = default;
|
||||
|
||||
void record() {}
|
||||
void start() {}
|
||||
void stop() {}
|
||||
void conditional_start() {}
|
||||
void conditional_stop() {}
|
||||
void push() {}
|
||||
void pop() {}
|
||||
void reset() {}
|
||||
void report_at_exit(bool) {}
|
||||
template <typename... _Args>
|
||||
void mark_begin(_Args&&...)
|
||||
@@ -91,7 +102,7 @@ namespace tim
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tim
|
||||
} // namespace g4tim
|
||||
|
||||
// startup/shutdown/configure
|
||||
# define TIMEMORY_INIT(...)
|
||||
@@ -128,8 +139,8 @@ namespace tim
|
||||
# define TIMEMORY_CALIPER_TYPE_APPLY(...)
|
||||
|
||||
// get an object
|
||||
# define TIMEMORY_BLANK_HANDLE(...) tim::dummy()
|
||||
# define TIMEMORY_BASIC_HANDLE(...) tim::dummy()
|
||||
# define TIMEMORY_BLANK_HANDLE(...) g4tim::dummy()
|
||||
# define TIMEMORY_BASIC_HANDLE(...) g4tim::dummy()
|
||||
# define TIMEMORY_HANDLE(...) tim::dummy()
|
||||
|
||||
// get a pointer to an object
|
||||
@@ -152,7 +163,7 @@ namespace tim
|
||||
# define TIMEMORY_DEBUG_BASIC_AUTO_TIMER(...)
|
||||
# define TIMEMORY_DEBUG_AUTO_TIMER(...)
|
||||
|
||||
using G4AutoTimer = tim::dummy;
|
||||
using G4AutoTimer = g4tim::dummy;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -59,13 +59,16 @@
|
||||
//
|
||||
# if defined G4GLOB_ALLOC_EXPORT
|
||||
# define G4GLOB_DLL G4DLLEXPORT
|
||||
# define G4MTGLOB_DLL __declspec(dllexport)
|
||||
# else
|
||||
# define G4GLOB_DLL G4DLLIMPORT
|
||||
# define G4MTGLOB_DLL __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# define G4DLLEXPORT
|
||||
# define G4DLLIMPORT
|
||||
# define G4GLOB_DLL
|
||||
# define G4MTGLOB_DLL
|
||||
#endif
|
||||
|
||||
#include <complex>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef G4VERSION_TAG
|
||||
# define G4VERSION_TAG "$Name: geant4-10-07-beta-01 $"
|
||||
# define G4VERSION_TAG "$Name: geant4-10-07 $"
|
||||
#endif
|
||||
|
||||
// as variables
|
||||
@@ -53,10 +53,10 @@
|
||||
#include "G4Types.hh"
|
||||
|
||||
#ifdef G4MULTITHREADED
|
||||
static const G4String G4Version = "$Name: geant4-10-07-beta-01 [MT]$";
|
||||
static const G4String G4Version = "$Name: geant4-10-07 [MT]$";
|
||||
#else
|
||||
static const G4String G4Version = "$Name: geant4-10-07-beta-01 $";
|
||||
static const G4String G4Version = "$Name: geant4-10-07 $";
|
||||
#endif
|
||||
static const G4String G4Date = "(26-June-2020)";
|
||||
static const G4String G4Date = "(4-December-2020)";
|
||||
|
||||
#endif
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
class G4coutDestination
|
||||
{
|
||||
public:
|
||||
|
||||
G4coutDestination() = default;
|
||||
virtual ~G4coutDestination();
|
||||
// Note: limitation on ICC for MIC cannot use 'default'
|
||||
@@ -83,7 +84,8 @@ class G4coutDestination
|
||||
// Transformers cannot remove an error message from stream
|
||||
|
||||
protected:
|
||||
G4coutDestination* masterG4coutDestination = nullptr;
|
||||
|
||||
G4MTGLOB_DLL static G4coutDestination* masterG4coutDestination;
|
||||
// For MT: if master G4coutDestination derived class wants to
|
||||
// intercept the thread outputs, derived class should set this pointer.
|
||||
// Needed for some G4UIsession like GUIs
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
# define G4_TLS 1
|
||||
|
||||
# if defined(G4MULTITHREADED)
|
||||
# if(defined(__MACH__) && defined(__clang__) && defined(__x86_64__)) || \
|
||||
# if(defined(__MACH__) && defined(__clang__)) || \
|
||||
(defined(__linux__) && defined(__clang__))
|
||||
# define G4ThreadLocalStatic static thread_local
|
||||
# define G4ThreadLocal thread_local
|
||||
|
||||
@@ -42,6 +42,7 @@ geant4_define_module(NAME G4globman
|
||||
G4AllocatorList.hh
|
||||
G4ApplicationState.hh
|
||||
G4AutoLock.hh
|
||||
G4Backtrace.hh
|
||||
G4BuffercoutDestination.hh
|
||||
G4Cache.hh
|
||||
G4CacheDetails.hh
|
||||
@@ -81,6 +82,8 @@ geant4_define_module(NAME G4globman
|
||||
G4Physics2DVector.hh
|
||||
G4Physics2DVector.icc
|
||||
G4Pow.hh
|
||||
G4Profiler.hh
|
||||
G4Profiler.icc
|
||||
G4ReferenceCountedHandle.hh
|
||||
G4RotationMatrix.hh
|
||||
G4SIunits.hh
|
||||
@@ -138,6 +141,7 @@ geant4_define_module(NAME G4globman
|
||||
G4PhysicsVector.cc
|
||||
G4Physics2DVector.cc
|
||||
G4Pow.cc
|
||||
G4Profiler.cc
|
||||
G4ReferenceCountedHandle.cc
|
||||
G4SliceTimer.cc
|
||||
G4StateManager.cc
|
||||
@@ -150,12 +154,11 @@ geant4_define_module(NAME G4globman
|
||||
LINK_LIBRARIES
|
||||
${CLHEP_LIBRARIES}
|
||||
${timemory_LIBRARIES}
|
||||
${PTL_LIBRARIES} # for index_sequence implementation. Remove after C++14
|
||||
)
|
||||
|
||||
# List any source specific properties here
|
||||
# For new system, must explicitly add path for generated header
|
||||
if(GEANT4_USE_NEW_CMAKE)
|
||||
geant4_module_include_directories(G4globman
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
|
||||
)
|
||||
endif()
|
||||
# For new system, must explicitly add path for generated header
|
||||
geant4_module_include_directories(G4globman
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
|
||||
)
|
||||
|
||||
@@ -61,7 +61,7 @@ G4PhysicsLinearVector::G4PhysicsLinearVector(G4double theEmin, G4double theEmax,
|
||||
}
|
||||
type = T_G4PhysicsLinearVector;
|
||||
|
||||
invdBin = 1. / ((theEmax - theEmin) / (G4double) numberOfNodes);
|
||||
invdBin = 1. / ((theEmax - theEmin) / (G4double) (numberOfNodes - 1));
|
||||
baseBin = theEmin * invdBin;
|
||||
|
||||
dataVector.reserve(numberOfNodes);
|
||||
|
||||
@@ -63,7 +63,7 @@ G4PhysicsLogVector::G4PhysicsLogVector(G4double theEmin, G4double theEmax,
|
||||
}
|
||||
type = T_G4PhysicsLogVector;
|
||||
|
||||
invdBin = 1. / (G4Log(theEmax / theEmin) / (G4double) numberOfNodes);
|
||||
invdBin = 1. / (G4Log(theEmax / theEmin) / (G4double) (numberOfNodes - 1));
|
||||
baseBin = G4Log(theEmin) * invdBin;
|
||||
|
||||
dataVector.reserve(numberOfNodes);
|
||||
|
||||
@@ -57,6 +57,30 @@ G4PhysicsOrderedFreeVector::G4PhysicsOrderedFreeVector(G4double* Energies,
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
G4PhysicsOrderedFreeVector::G4PhysicsOrderedFreeVector(
|
||||
const std::vector<G4double>& Energies, const std::vector<G4double>& Values)
|
||||
: G4PhysicsVector()
|
||||
{
|
||||
if(Energies.size() != Values.size())
|
||||
{
|
||||
G4ExceptionDescription ed;
|
||||
ed << "The sizes of the two std::vector arguments must be the same";
|
||||
G4Exception("G4PhysicsOrderedFreeVector::G4PhysicsOrderedFreeVector()",
|
||||
"glob04", FatalException, ed);
|
||||
}
|
||||
|
||||
type = T_G4PhysicsOrderedFreeVector;
|
||||
|
||||
dataVector.reserve(Energies.size());
|
||||
binVector.reserve(Energies.size());
|
||||
|
||||
for(std::size_t i = 0; i < Energies.size(); ++i)
|
||||
{
|
||||
InsertValues(Energies[i], Values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
G4PhysicsOrderedFreeVector::~G4PhysicsOrderedFreeVector() {}
|
||||
|
||||
|
||||
@@ -0,0 +1,588 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
// G4Profiler class implementation
|
||||
//
|
||||
// Author: J.Madsen (LBL), Aug 2020
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
#include "G4Profiler.hh"
|
||||
#include "G4TiMemory.hh"
|
||||
|
||||
#if defined(GEANT4_USE_TIMEMORY)
|
||||
# include <timemory/runtime/configure.hpp>
|
||||
#endif
|
||||
|
||||
#include <regex>
|
||||
#include <thread>
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
typename G4Profiler::array_type& G4Profiler::GetEnabled()
|
||||
{
|
||||
static array_type _instance = []() {
|
||||
array_type _tmp{};
|
||||
_tmp.fill(false);
|
||||
// environment settings introduce the defaults
|
||||
// but will be overridden by messenger and/or command line
|
||||
_tmp.at(G4ProfileType::Run) = G4GetEnv<bool>("G4PROFILE_RUN", true);
|
||||
_tmp.at(G4ProfileType::Event) = G4GetEnv<bool>("G4PROFILE_EVENT", false);
|
||||
_tmp.at(G4ProfileType::Track) = G4GetEnv<bool>("G4PROFILE_TRACK", false);
|
||||
_tmp.at(G4ProfileType::Step) = G4GetEnv<bool>("G4PROFILE_STEP", false);
|
||||
_tmp.at(G4ProfileType::User) = G4GetEnv<bool>("G4PROFILE_USER", true);
|
||||
return _tmp;
|
||||
}();
|
||||
return _instance;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
void G4Profiler::Configure(int argc, char** argv)
|
||||
{
|
||||
#if defined(GEANT4_USE_TIMEMORY)
|
||||
tim::timemory_init(argc, argv);
|
||||
std::vector<std::string> _args;
|
||||
for(int i = 0; i < argc; ++i)
|
||||
_args.push_back(argv[i]);
|
||||
Configure(_args);
|
||||
#else
|
||||
G4Impl::consume_parameters(argc, argv);
|
||||
#endif
|
||||
}
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
void G4Profiler::Configure(ArgumentParser& parser, int argc, char** argv)
|
||||
{
|
||||
#if defined(GEANT4_USE_TIMEMORY)
|
||||
tim::timemory_init(argc, argv);
|
||||
std::vector<std::string> _args;
|
||||
for(int i = 0; i < argc; ++i)
|
||||
_args.push_back(argv[i]);
|
||||
Configure(parser, _args);
|
||||
#else
|
||||
G4Impl::consume_parameters(parser, argc, argv);
|
||||
#endif
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
void G4Profiler::Configure(const std::vector<std::string>& args)
|
||||
{
|
||||
#if defined(GEANT4_USE_TIMEMORY)
|
||||
if(args.empty())
|
||||
return;
|
||||
ArgumentParser p{ args.at(0) };
|
||||
Configure(p, args);
|
||||
#else
|
||||
G4Impl::consume_parameters(args);
|
||||
#endif
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
void G4Profiler::Configure(ArgumentParser& parser,
|
||||
const std::vector<std::string>& args)
|
||||
{
|
||||
#if defined(GEANT4_USE_TIMEMORY)
|
||||
using parser_t = ArgumentParser;
|
||||
using parser_err_t = typename parser_t::result_type;
|
||||
|
||||
if(args.empty())
|
||||
return;
|
||||
|
||||
static std::mutex mtx;
|
||||
std::unique_lock<std::mutex> lk(mtx);
|
||||
|
||||
static auto tid = std::this_thread::get_id();
|
||||
if(std::this_thread::get_id() != tid)
|
||||
return;
|
||||
|
||||
// std::cout << "Arguments:";
|
||||
// for(auto itr : args)
|
||||
// std::cout << " " << itr;
|
||||
// std::cout << std::endl;
|
||||
|
||||
auto help_action = [](parser_t& p) {
|
||||
p.print_help();
|
||||
exit(EXIT_FAILURE);
|
||||
};
|
||||
|
||||
parser.enable_help();
|
||||
parser.on_error([=](parser_t& p, parser_err_t _err) {
|
||||
std::cerr << _err << std::endl;
|
||||
help_action(p);
|
||||
});
|
||||
|
||||
auto get_bool = [](const std::string& _str, bool _default) {
|
||||
if(_str.empty())
|
||||
return _default;
|
||||
using namespace std::regex_constants;
|
||||
const auto regex_config = egrep | icase;
|
||||
if(std::regex_match(_str, std::regex("on|true|yes|1", regex_config)))
|
||||
return true;
|
||||
else if(std::regex_match(_str, std::regex("off|false|no|0", regex_config)))
|
||||
return false;
|
||||
return _default;
|
||||
};
|
||||
//
|
||||
// Collection control
|
||||
//
|
||||
parser.add_argument()
|
||||
.names({ "-p", "--profile" })
|
||||
.description("Profiler modes")
|
||||
.choices({ "run", "event", "track", "step", "user" })
|
||||
.action([&](parser_t& p) {
|
||||
using namespace std::regex_constants;
|
||||
const auto regex_config = egrep | icase;
|
||||
for(auto&& itr : p.get<std::vector<std::string>>("profile"))
|
||||
{
|
||||
if(std::regex_match(itr, std::regex("run", regex_config)))
|
||||
G4Profiler::SetEnabled(G4ProfileType::Run, true);
|
||||
else if(std::regex_match(itr, std::regex("event", regex_config)))
|
||||
G4Profiler::SetEnabled(G4ProfileType::Event, true);
|
||||
else if(std::regex_match(itr, std::regex("track", regex_config)))
|
||||
G4Profiler::SetEnabled(G4ProfileType::Track, true);
|
||||
else if(std::regex_match(itr, std::regex("step", regex_config)))
|
||||
G4Profiler::SetEnabled(G4ProfileType::Step, true);
|
||||
else if(std::regex_match(itr, std::regex("user", regex_config)))
|
||||
G4Profiler::SetEnabled(G4ProfileType::User, true);
|
||||
}
|
||||
});
|
||||
//
|
||||
// Component controls
|
||||
//
|
||||
parser.add_argument()
|
||||
.names({ "-r", "--run-components" })
|
||||
.description("Components for run profiling (see 'timemory-avail -s')")
|
||||
.action([&](parser_t& p) {
|
||||
G4RunProfiler::reset();
|
||||
tim::configure<G4RunProfiler>(
|
||||
p.get<std::vector<std::string>>("run-components"));
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "-e", "--event-components" })
|
||||
.description("Components for event profiling (see 'timemory-avail -s')")
|
||||
.action([&](parser_t& p) {
|
||||
G4EventProfiler::reset();
|
||||
tim::configure<G4EventProfiler>(
|
||||
p.get<std::vector<std::string>>("event-components"));
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "-t", "--track-components" })
|
||||
.description("Components for track profiling (see 'timemory-avail -s')")
|
||||
.action([&](parser_t& p) {
|
||||
G4TrackProfiler::reset();
|
||||
tim::configure<G4TrackProfiler>(
|
||||
p.get<std::vector<std::string>>("track-components"));
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "-s", "--step-components" })
|
||||
.description("Components for step profiling (see 'timemory-avail -s')")
|
||||
.action([&](parser_t& p) {
|
||||
G4StepProfiler::reset();
|
||||
tim::configure<G4StepProfiler>(
|
||||
p.get<std::vector<std::string>>("step-components"));
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "-u", "--user-components" })
|
||||
.description("Components for user profiling (see 'timemory-avail -s')")
|
||||
.action([&](parser_t& p) {
|
||||
G4StepProfiler::reset();
|
||||
tim::configure<G4UserProfiler>(
|
||||
p.get<std::vector<std::string>>("user-components"));
|
||||
});
|
||||
//
|
||||
// Display controls
|
||||
//
|
||||
parser.add_argument()
|
||||
.names({ "-H", "--hierarchy", "--tree" })
|
||||
.description("Display the results as a call-stack hierarchy.")
|
||||
.max_count(1)
|
||||
.action([&](parser_t& p) {
|
||||
tim::settings::flat_profile() =
|
||||
!get_bool(p.get<std::string>("tree"), true);
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "-F", "--flat" })
|
||||
.description("Display the results as a flat call-stack")
|
||||
.max_count(1)
|
||||
.action([&](parser_t& p) {
|
||||
tim::settings::flat_profile() =
|
||||
get_bool(p.get<std::string>("flat"), true);
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "-T", "--timeline" })
|
||||
.description(
|
||||
"Do not merge duplicate entries at the same call-stack position")
|
||||
.max_count(1)
|
||||
.action([&](parser_t& p) {
|
||||
tim::settings::timeline_profile() =
|
||||
get_bool(p.get<std::string>("timeline"), true);
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "--per-thread" })
|
||||
.description(
|
||||
"Display the results for each individual thread (default: aggregation)")
|
||||
.max_count(1)
|
||||
.action([&](parser_t& p) {
|
||||
tim::settings::flat_profile() =
|
||||
get_bool(p.get<std::string>("per-thread"), true);
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "--per-event" })
|
||||
.description("Each G4Event is a unique entry")
|
||||
.max_count(1)
|
||||
.action([&](parser_t& p) {
|
||||
tim::settings::timeline_profile() =
|
||||
get_bool(p.get<std::string>("per-event"), true);
|
||||
});
|
||||
//
|
||||
// Output controls
|
||||
//
|
||||
parser.add_argument()
|
||||
.names({ "-D", "--dart" })
|
||||
.description("Enable Dart output (CTest/CDash data tracking)")
|
||||
.max_count(1)
|
||||
.action([&](parser_t& p) {
|
||||
tim::settings::dart_output() = get_bool(p.get<std::string>("dart"), true);
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "-J", "--json" })
|
||||
.description("Enable JSON output")
|
||||
.max_count(1)
|
||||
.action([&](parser_t& p) {
|
||||
tim::settings::json_output() = get_bool(p.get<std::string>("json"), true);
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "-P", "--plot" })
|
||||
.description("Plot the JSON output")
|
||||
.max_count(1)
|
||||
.action([&](parser_t& p) {
|
||||
tim::settings::plot_output() = get_bool(p.get<std::string>("plot"), true);
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "-X", "--text" })
|
||||
.description("Enable TEXT output")
|
||||
.max_count(1)
|
||||
.action([&](parser_t& p) {
|
||||
tim::settings::text_output() = get_bool(p.get<std::string>("text"), true);
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "-C", "--cout" })
|
||||
.description("Enable output to terminal")
|
||||
.max_count(1)
|
||||
.action([&](parser_t& p) {
|
||||
tim::settings::cout_output() = get_bool(p.get<std::string>("cout"), true);
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "-O", "--output-path" })
|
||||
.description("Set the output directory")
|
||||
.count(1)
|
||||
.action([&](parser_t& p) {
|
||||
tim::settings::output_path() = p.get<std::string>("output-path");
|
||||
});
|
||||
parser.add_argument()
|
||||
.names({ "-W", "--hw-counters" })
|
||||
.description(
|
||||
"Set the hardware counters to collect (see 'timemory-avail -H')")
|
||||
.action([&](parser_t& p) {
|
||||
tim::settings::papi_events() = p.get<std::string>("hw-counters");
|
||||
});
|
||||
|
||||
tim::settings::time_output() = true;
|
||||
tim::settings::time_format() = "%F_%I.%M_%p";
|
||||
|
||||
auto err = parser.parse(args);
|
||||
if(err)
|
||||
{
|
||||
std::cout << "Error! " << err << std::endl;
|
||||
help_action(parser);
|
||||
}
|
||||
|
||||
#else
|
||||
G4Impl::consume_parameters(parser, args);
|
||||
#endif
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
void G4Profiler::Finalize()
|
||||
{
|
||||
#if defined(GEANT4_USE_TIMEMORY)
|
||||
// generally safe to call multiple times but just in case
|
||||
// it is not necessary to call from worker threads, calling
|
||||
// once on master will merge any threads that accumulated
|
||||
// results. If a thread is destroyed, before finalize is
|
||||
// called on master thread, then it will merge itself into
|
||||
// the master thread before terminating. The biggest issue
|
||||
// is when finalize is never called on any threads (including
|
||||
// the master) so finalization happens after main exits. When
|
||||
// this happens, the order that data gets deleted is very
|
||||
// hard to predict so it commonly results in a segfault. Thus,
|
||||
// if the user does not call this function and does not
|
||||
// delete G4RunManager, a segfault is quite likely.
|
||||
static thread_local bool _once = false;
|
||||
if(!_once)
|
||||
tim::timemory_finalize();
|
||||
_once = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
template <size_t Ct>
|
||||
template <int Idx>
|
||||
typename G4ProfilerConfig<Ct>::template PersistentSettings<Idx>&
|
||||
G4ProfilerConfig<Ct>::GetPersistentFallback()
|
||||
{
|
||||
// G4RunManager::ConfigureProfilers() assigns defaults to these lambdas
|
||||
// based on environment variables. The users should (generally) not modify
|
||||
// these.
|
||||
static PersistentSettings<Idx> _instance = PersistentSettings<Idx>{};
|
||||
return _instance;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
template <size_t Ct>
|
||||
template <int Idx>
|
||||
typename G4ProfilerConfig<Ct>::template PersistentSettings<Idx>&
|
||||
G4ProfilerConfig<Ct>::GetPersistent()
|
||||
{
|
||||
//
|
||||
// The pointers here automatically initialize on the first
|
||||
// invocation on a thread and a reference is returned so they
|
||||
// can be cleanly "leaked" at the application termination. Assignment
|
||||
// is thread-safe and this scheme avoids having to deal with getters
|
||||
// and setters. It is designed such that we can set defaults but
|
||||
// the user can override them at any time.
|
||||
//
|
||||
// the first global instance copies from the fallback rountines, which are
|
||||
// assigned defaults in G4RunManager::ConfigureProfilers() but if the user
|
||||
// assigns new settings before creating G4RunManager, those defaults will
|
||||
// be ignored
|
||||
static PersistentSettings<Idx>* _instance =
|
||||
new PersistentSettings<Idx>(GetPersistentFallback<Idx>());
|
||||
static thread_local PersistentSettings<Idx>* _tlinstance = [=]() {
|
||||
static std::mutex mtx;
|
||||
std::unique_lock<std::mutex> lk(mtx);
|
||||
// If this is the primary thread, just return the global instance from
|
||||
// above. Modifying that instance will result in all threads created later
|
||||
// to inherit those settings
|
||||
static bool _first = true;
|
||||
if(_first) // below uses comma operator to assign to false before return
|
||||
return ((_first = false), _instance);
|
||||
// if not first, make a copy from the primary thread
|
||||
return new PersistentSettings<Idx>(*_instance);
|
||||
}();
|
||||
return *_tlinstance;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template <size_t Cat>
|
||||
G4ProfilerConfig<Cat>::~G4ProfilerConfig()
|
||||
{
|
||||
delete m_bundle;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// primary (utilized) versions
|
||||
//
|
||||
template <size_t Cat>
|
||||
typename G4ProfilerConfig<Cat>::QueryHandler_t
|
||||
G4ProfilerConfig<Cat>::GetQueryFunctor()
|
||||
{
|
||||
return QueryHandler_t{ GetPersistent<G4ProfileOp::Query>().m_functor };
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
template <size_t Cat>
|
||||
typename G4ProfilerConfig<Cat>::LabelHandler_t
|
||||
G4ProfilerConfig<Cat>::GetLabelFunctor()
|
||||
{
|
||||
return LabelHandler_t{ GetPersistent<G4ProfileOp::Label>().m_functor };
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
template <size_t Cat>
|
||||
typename G4ProfilerConfig<Cat>::ToolHandler_t
|
||||
G4ProfilerConfig<Cat>::GetToolFunctor()
|
||||
{
|
||||
return ToolHandler_t{ GetPersistent<G4ProfileOp::Tool>().m_functor };
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// fallback versions
|
||||
//
|
||||
template <size_t Cat>
|
||||
typename G4ProfilerConfig<Cat>::QueryHandler_t
|
||||
G4ProfilerConfig<Cat>::GetFallbackQueryFunctor()
|
||||
{
|
||||
return QueryHandler_t{
|
||||
GetPersistentFallback<G4ProfileOp::Query>().m_functor
|
||||
};
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
template <size_t Cat>
|
||||
typename G4ProfilerConfig<Cat>::LabelHandler_t
|
||||
G4ProfilerConfig<Cat>::GetFallbackLabelFunctor()
|
||||
{
|
||||
return LabelHandler_t{
|
||||
GetPersistentFallback<G4ProfileOp::Label>().m_functor
|
||||
};
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
template <size_t Cat>
|
||||
typename G4ProfilerConfig<Cat>::ToolHandler_t
|
||||
G4ProfilerConfig<Cat>::GetFallbackToolFunctor()
|
||||
{
|
||||
return ToolHandler_t{ GetPersistentFallback<G4ProfileOp::Tool>().m_functor };
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
class G4Run;
|
||||
class G4Event;
|
||||
class G4Track;
|
||||
class G4Step;
|
||||
|
||||
using G4ProfType = G4ProfileType;
|
||||
using RunProfConfig = G4ProfilerConfig<G4ProfType::Run>;
|
||||
using EventProfConfig = G4ProfilerConfig<G4ProfType::Event>;
|
||||
using TrackProfConfig = G4ProfilerConfig<G4ProfType::Track>;
|
||||
using StepProfConfig = G4ProfilerConfig<G4ProfType::Step>;
|
||||
using UserProfConfig = G4ProfilerConfig<G4ProfType::User>;
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
// force instantiations
|
||||
template class G4ProfilerConfig<G4ProfType::Run>;
|
||||
template class G4ProfilerConfig<G4ProfType::Event>;
|
||||
template class G4ProfilerConfig<G4ProfType::Track>;
|
||||
template class G4ProfilerConfig<G4ProfType::Step>;
|
||||
template class G4ProfilerConfig<G4ProfType::User>;
|
||||
template G4ProfilerConfig<G4ProfType::Run>::G4ProfilerConfig(const G4Run*);
|
||||
template G4ProfilerConfig<G4ProfType::Event>::G4ProfilerConfig(const G4Event*);
|
||||
template G4ProfilerConfig<G4ProfType::Track>::G4ProfilerConfig(const G4Track*);
|
||||
template G4ProfilerConfig<G4ProfType::Step>::G4ProfilerConfig(const G4Step*);
|
||||
template G4ProfilerConfig<G4ProfileType::User>::G4ProfilerConfig(
|
||||
const std::string&);
|
||||
|
||||
#define G4PROFILE_INSTANTIATION(TYPE) \
|
||||
template TYPE::PersistentSettings<G4ProfileOp::Query>& \
|
||||
TYPE::GetPersistentFallback<G4ProfileOp::Query>(); \
|
||||
template TYPE::PersistentSettings<G4ProfileOp::Label>& \
|
||||
TYPE::GetPersistentFallback<G4ProfileOp::Label>(); \
|
||||
template TYPE::PersistentSettings<G4ProfileOp::Tool>& \
|
||||
TYPE::GetPersistentFallback<G4ProfileOp::Tool>(); \
|
||||
\
|
||||
template TYPE::PersistentSettings<G4ProfileOp::Query>& \
|
||||
TYPE::GetPersistent<G4ProfileOp::Query>(); \
|
||||
template TYPE::PersistentSettings<G4ProfileOp::Label>& \
|
||||
TYPE::GetPersistent<G4ProfileOp::Label>(); \
|
||||
template TYPE::PersistentSettings<G4ProfileOp::Tool>& \
|
||||
TYPE::GetPersistent<G4ProfileOp::Tool>();
|
||||
|
||||
G4PROFILE_INSTANTIATION(RunProfConfig)
|
||||
G4PROFILE_INSTANTIATION(EventProfConfig)
|
||||
G4PROFILE_INSTANTIATION(TrackProfConfig)
|
||||
G4PROFILE_INSTANTIATION(StepProfConfig)
|
||||
G4PROFILE_INSTANTIATION(UserProfConfig)
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
#if !defined(GEANT4_USE_TIMEMORY)
|
||||
# define TIMEMORY_WEAK_PREFIX
|
||||
# define TIMEMORY_WEAK_POSTFIX
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
extern "C"
|
||||
{
|
||||
// this allows the default setup to be overridden by linking
|
||||
// in an custom extern C function into the application
|
||||
TIMEMORY_WEAK_PREFIX
|
||||
void G4ProfilerInit(void) TIMEMORY_WEAK_POSTFIX;
|
||||
|
||||
// this gets executed when the library gets loaded
|
||||
void G4ProfilerInit(void)
|
||||
{
|
||||
#ifdef GEANT4_USE_TIMEMORY
|
||||
|
||||
// guard against re-initialization
|
||||
static bool _once = false;
|
||||
if(_once)
|
||||
return;
|
||||
_once = true;
|
||||
|
||||
puts(">>> G4ProfilerInit <<<");
|
||||
|
||||
//
|
||||
// the default settings
|
||||
//
|
||||
// large profiles can take a very long time to plot
|
||||
tim::settings::plot_output() = false;
|
||||
// large profiles can take quite a bit of console space
|
||||
tim::settings::cout_output() = false;
|
||||
// this creates a subdirectory with the timestamp of the run
|
||||
tim::settings::time_output() = false;
|
||||
// see `man 3 strftime` for formatting keys
|
||||
tim::settings::time_format() = "%F_%I.%M_%p";
|
||||
// set the default precision for timing
|
||||
tim::settings::timing_precision() = 6;
|
||||
// set the minimum width for outputs
|
||||
tim::settings::width() = 12;
|
||||
// set dart reports (when enabled) to only print the first entry
|
||||
tim::settings::dart_count() = 1;
|
||||
// set dart reports (when enabled) to use the component label
|
||||
// instead of the string identifer of the entry, e.g.
|
||||
// >>> G4Run/0 ... peak_rss ... 50 MB would report
|
||||
// 'peak_rss 50 MB' not 'G4Run/0 50 MB'
|
||||
tim::settings::dart_label() = true;
|
||||
|
||||
// allow environment overrides of the defaults
|
||||
tim::settings::parse();
|
||||
#endif
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
#ifdef GEANT4_USE_TIMEMORY
|
||||
namespace
|
||||
{
|
||||
static bool profiler_is_initialized = (G4ProfilerInit(), true);
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
@@ -32,6 +32,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
G4coutDestination* G4coutDestination::masterG4coutDestination = nullptr;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
G4coutDestination::~G4coutDestination() {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user