// // ******************************************************************** // * 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 #endif #include "globals.hh" #include #include #include #include #include #include #include #include //----------------------------------------------------------------------------// 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; #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& args); static void Configure(int argc, char** argv); static void Configure(ArgumentParser&, const std::vector& 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 struct G4ProfilerObject { using type = void; }; template using G4ProfilerObject_t = typename G4ProfilerObject::type; template <> struct G4ProfilerObject { using type = const G4Run*; }; template <> struct G4ProfilerObject { using type = const G4Event*; }; template <> struct G4ProfilerObject { using type = const G4Track*; }; template <> struct G4ProfilerObject { using type = const G4Step*; }; template <> struct G4ProfilerObject { using type = const std::string&; }; //----------------------------------------------------------------------------// // default set of profiler args template struct G4ProfilerArgs { // this resolves to the G4ProfilerObject type-trait above, e.g. // "const G4Step*" when category is G4ProfileType::Step using value_type = G4ProfilerObject_t; // two-dimensional type-list where each inner type-list is a set // of arguments to support creating a profiler type from using type = G4TypeList; // so above means there are functors in use which apply: // // G4StepProfiler _profiler(const G4Step*); // }; template using G4ProfilerArgs_t = typename G4ProfilerArgs::type; //----------------------------------------------------------------------------// template > struct G4ProfilerFunctors { using type = G4Impl::Functors_t>; }; template using G4ProfilerFunctors_t = typename G4ProfilerFunctors>::type; //----------------------------------------------------------------------------// #ifdef GEANT4_USE_TIMEMORY // Pre-declare the timemory component that will be used namespace tim { namespace component { template struct user_bundle; } // namespace component template class auto_tuple; template 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; using G4EventProfiler = g4tim::user_bundle; using G4TrackProfiler = g4tim::user_bundle; using G4StepProfiler = g4tim::user_bundle; using G4UserProfiler = g4tim::user_bundle; template using G4ProfilerBundle = g4tim::auto_bundle; #else namespace g4tim { struct ProfilerArgparser {}; /// this provides a dummy wrapper for the profiling template struct handler { template handler(Args&&...) {} ~handler() = default; handler(const handler&) = default; handler(handler&&) = default; handler& operator=(const handler&) = default; handler& operator=(handler&&) = default; void record() {} template void start(Args&&...) {} template void stop(Args&&...) {} void push() {} void pop() {} void reset() {} void report_at_exit(bool) {} template void mark_begin(Args&&...) {} template void mark_end(Args&&...) {} friend std::ostream& operator<<(std::ostream& os, const handler&) { return os; } }; template struct user_bundle { template user_bundle(Args&&...) {} template 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 using G4ProfilerBundle = g4tim::handler; #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 class G4ProfilerConfig { public: using type = G4ProfilerBundle>; using this_type = G4ProfilerConfig; static constexpr size_t arg_sets = G4TypeListSize>::value; using QueryFunc_t = G4ProfilerFunctors_t; using LabelFunc_t = G4ProfilerFunctors_t; using ToolFunc_t = std::tuple>; public: // when constructed with no args, should call operator() G4ProfilerConfig() = default; // constructor calls Query(...), Label(...), Tool(...) template 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 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 static bool Query(Args... _args); // invokes the functor for generating a Label when profiling is enabled template static std::string Label(Args... _args); // invokes the functor for configuring a Tool instance template static type* Tool(const std::string&); using QueryHandler_t = FuncHandler; using LabelHandler_t = FuncHandler; using ToolHandler_t = FuncHandler; 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 using conditional_t = typename std::conditional::type; // this provides the global statics for the functors template struct PersistentSettings { // determine the functor type using functor_type = conditional_t< Idx == G4ProfileOp::Query, QueryFunc_t, conditional_t>; PersistentSettings() = default; ~PersistentSettings() = default; // default member initialization functor_type m_functor; }; template static PersistentSettings& GetPersistentFallback(); template static PersistentSettings& GetPersistent(); }; //----------------------------------------------------------------------------// // alias for getting type template using G4ProfilerConfig_t = typename G4ProfilerConfig::type; // ---------------------------------------------------------------------- template template G4ProfilerConfig::G4ProfilerConfig(Arg _arg, Args... _args) { this->operator()(_arg, _args...); } // ---------------------------------------------------------------------- template template bool G4ProfilerConfig::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 template bool G4ProfilerConfig::Query(Args... _args) { return QueryHandler_t{ GetPersistent().m_functor }( _args...); } //----------------------------------------------------------------------------// // invokes the functor for generating a label when profiling is enabled template template std::string G4ProfilerConfig::Label(Args... _args) { return LabelHandler_t{ GetPersistent().m_functor }( _args...); } //----------------------------------------------------------------------------// // invokes the functor for configuring a tool instance template template typename G4ProfilerConfig::type* G4ProfilerConfig::Tool( const std::string& _args) { return ToolHandler_t{ GetPersistent().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; extern template class G4ProfilerConfig; extern template class G4ProfilerConfig; extern template class G4ProfilerConfig; extern template class G4ProfilerConfig; extern template G4ProfilerConfig::G4ProfilerConfig(const G4Run*); extern template G4ProfilerConfig::G4ProfilerConfig(const G4Event*); extern template G4ProfilerConfig::G4ProfilerConfig(const G4Track*); extern template G4ProfilerConfig::G4ProfilerConfig(const G4Step*); extern template G4ProfilerConfig::G4ProfilerConfig(const std::string&); // clang-format on //----------------------------------------------------------------------------// #ifndef GEANT4_USE_TIMEMORY # include # include #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 G4USER_PROFILER_VAR(__LINE__)( \ TIMEMORY_JOIN("", __VA_ARGS__)) // inserts the function # define G4USER_SCOPED_PROFILE_FUNC(...) \ G4ProfilerConfig G4USER_PROFILER_VAR(__LINE__)( \ TIMEMORY_JOIN("", __FUNCTION__, "/", __VA_ARGS__)) // inserts the function and file # define G4USER_SCOPED_PROFILE_FUNC_FILE(...) \ G4ProfilerConfig 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 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