Import Geant4 10.7.0 source tree

This commit is contained in:
Gabriele Cosmo
2020-12-04 12:30:43 +01:00
parent 67ba86d073
commit dab42d2018
3770 changed files with 226369 additions and 286486 deletions
+60
View File
@@ -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
//
+24 -13
View File
@@ -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
+1 -1
View File
@@ -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
+9 -6
View File
@@ -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() {}
+588
View File
@@ -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() {}