diff --git a/DDG4/plugins/Geant4DetectorConstructionResources.cpp b/DDG4/plugins/Geant4DetectorConstructionResources.cpp new file mode 100644 index 000000000..f07c283a5 --- /dev/null +++ b/DDG4/plugins/Geant4DetectorConstructionResources.cpp @@ -0,0 +1,307 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// \author Markus Frank +// \date 2015-11-09 +// +//========================================================================== + +// Framework include files +#include + +// C/C++ include files + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + + /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit + namespace sim { + + /// Debug class to dump resources usage during detector construction + /** + * Debug class to dump resources usage during detector construction + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4DetectorConstructionResources : public Geant4DetectorConstruction { + public: + /// Class to store the status information of a process from /proc//status + /** + * + * \author M.Frank + * \version 1.0 + */ + class __attribute__((__packed__)) StatusProcess { + public: + char comm[399]; + char state; + int umask; + int tgid; + int ngid; + int pid; + int ppid; + int uid; + int gid; + int utrace; + int fdSize; + long vmPeak; + long vmSize; + long vmLock; + long vmPin; + long vmHWM; + long vmRSS; + long vmRSSano; + long vmRSSfil; + long vmRSSshm; + long vmData; + long vmStack; + long vmExe; + long vmLib; + long vmPTE; + long vmSwap; + /// Default constructor + StatusProcess() {} + }; + std::unique_ptr snapshot; + std::string when { "geometry|sensitives" }; + + void print_status(const char* tag, const StatusProcess& sp) const; + + public: + /// Initializing constructor for DDG4 + Geant4DetectorConstructionResources(Geant4Context* ctxt, const std::string& nam); + /// Default destructor + virtual ~Geant4DetectorConstructionResources(); + /// Sensitive detector construction callback. Called at "Construct()" + virtual void constructGeo(Geant4DetectorConstructionContext*) override; + /// Sensitives construction callback. Called at "ConstructSDandField()" + virtual void constructSensitives(Geant4DetectorConstructionContext* ctxt) override; + }; + } // End namespace sim +} // End namespace dd4hep + + +// Framework include files +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +using namespace dd4hep::sim; + +DECLARE_GEANT4ACTION(Geant4DetectorConstructionResources) + +namespace { + + class SysFile { + public: + class FileDescriptor { + /// File handle + int m_fd; + + public: + /// Initializing constructor + FileDescriptor(int value) : m_fd(value) {} + /// Default destructor. Non-virtuality is intended. Do not inherit! + ~FileDescriptor(); + /// Access file handle + int get() const { return m_fd; } + }; + + + public: + /// File name + std::string m_name; + /// Initializing constructor + SysFile(const char* name) : m_name(name) {} + /// Initializing constructor + SysFile(const std::string& name) : m_name(name) {} + /// Default destructor. Non-virtuality is intended. Do not inherit! + ~SysFile() {} + /// Read buffer from file in one go + int read(char* buffer, size_t len) const; + }; + + /// Default destructor. Non-virtuality is intended. Do not inherit! + SysFile::FileDescriptor::~FileDescriptor() { + if (m_fd > 0) ::close(m_fd); + m_fd = 0; + } + + /// Read buffer from file in one go + int SysFile::read(char* buf, size_t siz) const { + FileDescriptor fd(::open(m_name.c_str(),O_RDONLY)); + if( fd.get() < 0 ) { + std::string err = "Failed to open "+m_name+" "; + throw std::runtime_error(err+std::make_error_code(std::errc(errno)).message()); + } + std::size_t tmp = 0; + while ( tmp < siz ) { + int sc = ::read(fd.get(),buf+tmp,siz-tmp); + if ( sc > 0 ) { + tmp += sc; + } + else if ( sc == 0 ) { + buf[tmp] = 0; + return tmp; + } + else if ( errno == EINTR ) { + printf("EINTR~!!!!\n"); + continue; + } + else { + break; + } + } + if ( tmp != siz ) { + std::string err = "Read of system file "+m_name+" failed:"; + throw std::runtime_error(err+std::make_error_code(std::errc(errno)).message()); + } + return tmp; + } + + int read_info(Geant4DetectorConstructionResources::StatusProcess& proc, int proc_id) { + char buff[2048], *ptr=buff; + std::string fn = "/proc/"+std::to_string(proc_id)+"/status"; + int nitem=0, cnt=SysFile(fn.c_str()).read(buff,sizeof(buff)); + if(cnt>0) { + int ival; + long int lval; + + while(ptr && ptr<(buff+cnt)) { + char* p = ::strchr(ptr,'\t'); + char* end = ::strchr(ptr,'\n'); + + ptr = (end) ? end+1 : 0; + if ( 0 == p ) continue; + ++p; + switch(++nitem) { + case 1: ::sscanf(p,"%s",proc.comm); break; + case 2: ::sscanf(p,"%d",&ival); proc.umask = ival; break; + case 3: ::sscanf(p,"%c",&proc.state); break; + case 4: ::sscanf(p,"%d",&ival); proc.tgid = ival; break; + case 5: ::sscanf(p,"%d",&ival); proc.ngid = ival; break; + case 6: ::sscanf(p,"%d",&ival); proc.pid = ival; break; + case 7: ::sscanf(p,"%d",&ival); proc.ppid = ival; break; + case 8: ::sscanf(p,"%d",&ival); proc.utrace = ival; break; + case 9: ::sscanf(p,"%d",&ival); proc.uid = ival; break; + case 10: ::sscanf(p,"%d",&ival); proc.gid = ival; break; + case 11: ::sscanf(p,"%d",&ival); proc.fdSize = ival; break; + case 17: ::sscanf(p,"%ld",&lval); proc.vmPeak = lval; break; + case 18: ::sscanf(p,"%ld",&lval); proc.vmSize = lval; break; + case 19: ::sscanf(p,"%ld",&lval); proc.vmLock = lval; break; + case 20: ::sscanf(p,"%ld",&lval); proc.vmPin = lval; break; + case 21: ::sscanf(p,"%ld",&lval); proc.vmHWM = lval; break; + case 22: ::sscanf(p,"%ld",&lval); proc.vmRSS = lval; break; + case 23: ::sscanf(p,"%ld",&lval); proc.vmRSSano= lval; break; + case 24: ::sscanf(p,"%ld",&lval); proc.vmRSSfil= lval; break; + case 25: ::sscanf(p,"%ld",&lval); proc.vmRSSshm= lval; break; + case 26: ::sscanf(p,"%ld",&lval); proc.vmData = lval; break; + case 27: ::sscanf(p,"%ld",&lval); proc.vmStack = lval; break; + case 28: ::sscanf(p,"%ld",&lval); proc.vmExe = lval; break; + case 29: ::sscanf(p,"%ld",&lval); proc.vmLib = lval; break; + case 30: ::sscanf(p,"%ld",&lval); proc.vmPTE = lval; break; + case 31: ::sscanf(p,"%ld",&lval); proc.vmSwap = lval; break; + case 32: return 1; + default: break; + } + } + return 1; + } + return 0; + } +} + +/// Initializing constructor for other clients +Geant4DetectorConstructionResources::Geant4DetectorConstructionResources(Geant4Context* ctxt, const std::string& nam) +: Geant4DetectorConstruction(ctxt,nam) +{ + declareProperty("When", this->when); + InstanceCount::increment(this); +} + +/// Default destructor +Geant4DetectorConstructionResources::~Geant4DetectorConstructionResources() { + InstanceCount::decrement(this); +} + +/// Sensitive detector construction callback. Called at "Construct()" +void Geant4DetectorConstructionResources::constructGeo(Geant4DetectorConstructionContext*) { + if ( this->when.find("geometry") != std::string::npos ) { + this->snapshot = std::make_unique(); + read_info(*this->snapshot, ::getpid()); + this->print_status("ConstructGeo: ", *this->snapshot); + } +} + +void Geant4DetectorConstructionResources::print_status(const char* tag, const StatusProcess& sp) const { + this->always("%s Name: \t%s", tag, sp.comm); + this->always("%s State: \t%c", tag, sp.state); + this->always("%s Umask: \t%8d", tag, sp.umask); + this->always("%s Tgid: \t%8d", tag, sp.tgid); + this->always("%s Pid: \t%8d", tag, sp.pid); + this->always("%s PPid: \t%8d", tag, sp.ppid); + this->always("%s utrace: \t%8d", tag, sp.utrace); + this->always("%s Uid: \t%8d", tag, sp.uid); + this->always("%s Gid: \t%8d", tag, sp.gid); + this->always("%s FDSize: \t%8d", tag, sp.fdSize); + this->always("%s VmPeak: \t%8ld kB", tag, sp.vmPeak); + this->always("%s VmSize: \t%8ld kB", tag, sp.vmSize); + this->always("%s VmLck: \t%8ld kB", tag, sp.vmLock); + this->always("%s VmHWM: \t%8ld kB", tag, sp.vmHWM); + this->always("%s VmRSS: \t%8ld kB", tag, sp.vmRSS); + this->always("%s VmRSS anon: \t%8ld kB", tag, sp.vmRSSano); + this->always("%s VmRSS file: \t%8ld kB", tag, sp.vmRSSfil); + this->always("%s VmRSS shm: \t%8ld kB", tag, sp.vmRSSshm); + this->always("%s VmData: \t%8ld kB", tag, sp.vmData); + this->always("%s VmStk: \t%8ld kB", tag, sp.vmStack); + this->always("%s VmExe: \t%8ld kB", tag, sp.vmExe); + this->always("%s VmLib: \t%8ld kB", tag, sp.vmLib); + this->always("%s VmPTE: \t%8ld kB", tag, sp.vmPTE); +} + +/// Sensitive detector construction callback. Called at "ConstructSDandField()" +void Geant4DetectorConstructionResources::constructSensitives(Geant4DetectorConstructionContext*) { + if ( this->when.find("sensitives") != std::string::npos ) { + StatusProcess rd; + read_info(rd, ::getpid()); + this->print_status("ConstructSD: ", rd); +#if 0 + if ( snapshot ) { + const auto& snap = *this->snapshot; + this->always(" --> DIFFERENCE: FDSize: \t%8d", rd.fdSize - snap.fdSize); + this->always(" --> DIFFERENCE: VmPeak: \t%8ld kB", rd.vmPeak - snap.vmPeak); + this->always(" --> DIFFERENCE: VmSize: \t%8ld kB", rd.vmSize - snap.vmSize); + this->always(" --> DIFFERENCE: VmLck: \t%8ld kB", rd.vmLock - snap.vmLock); + this->always(" --> DIFFERENCE: VmHWM: \t%8ld kB", rd.vmHWM - snap.vmHWM); + this->always(" --> DIFFERENCE: VmRSS: \t%8ld kB", rd.vmRSS - snap.vmRSS); + this->always(" --> DIFFERENCE: VmRSS anon: \t%8ld kB", rd.vmRSSano - snap.vmRSSano); + this->always(" --> DIFFERENCE: VmRSS file: \t%8ld kB", rd.vmRSSfil - snap.vmRSSfil); + this->always(" --> DIFFERENCE: VmRSS shm: \t%8ld kB", rd.vmRSSshm - snap.vmRSSshm); + this->always(" --> DIFFERENCE: VmData: \t%8ld kB", rd.vmData - snap.vmData); + this->always(" --> DIFFERENCE: VmStk: \t%8ld kB", rd.vmStack - snap.vmStack); + this->always(" --> DIFFERENCE: VmExe: \t%8ld kB", rd.vmExe - snap.vmExe); + this->always(" --> DIFFERENCE: VmLib: \t%8ld kB", rd.vmLib - snap.vmLib); + this->always(" --> DIFFERENCE: VmPTE: \t%8ld kB", rd.vmPTE - snap.vmPTE); + } +#endif + } + snapshot.reset(); +} diff --git a/examples/ClientTests/CMakeLists.txt b/examples/ClientTests/CMakeLists.txt index 2e9ffca65..8ef15dc46 100644 --- a/examples/ClientTests/CMakeLists.txt +++ b/examples/ClientTests/CMakeLists.txt @@ -614,4 +614,22 @@ if (DD4HEP_USE_GEANT4) REGEX_FAIL "Error;ERROR; Exception" ) endif() + # + # Test Geant4VolumeManager resource usage + dd4hep_add_test_reg(ClientTests_g4_setup_BoxOfStraws_sensitive + COMMAND "${CMAKE_INSTALL_PREFIX}/bin/run_test_ClientTests.sh" + EXEC_ARGS ${Python_EXECUTABLE} ${ClientTestsEx_INSTALL}/scripts/BoxOfStraws.py + -print_level 3 -sensitive + REGEX_PASS "ResourcesAfterConstruction ConstructSD: VmRSS" + REGEX_FAIL "Error;ERROR; Exception" + ) + # + # Test without Geant4VolumeManager, but sensitive detector assignment using regex + dd4hep_add_test_reg(ClientTests_g4_setup_BoxOfStraws_non_sensitive + COMMAND "${CMAKE_INSTALL_PREFIX}/bin/run_test_ClientTests.sh" + EXEC_ARGS ${Python_EXECUTABLE} ${ClientTestsEx_INSTALL}/scripts/BoxOfStraws.py + -print_level 3 + REGEX_PASS "ResourcesAfterConstruction ConstructSD: VmRSS" + REGEX_FAIL "Error;ERROR; Exception" + ) endif(DD4HEP_USE_GEANT4) diff --git a/examples/ClientTests/compact/BoxOfStraws_sensitive.xml b/examples/ClientTests/compact/BoxOfStraws_sensitive.xml new file mode 100644 index 000000000..de951417c --- /dev/null +++ b/examples/ClientTests/compact/BoxOfStraws_sensitive.xml @@ -0,0 +1,88 @@ + + + + + + Detector scalability test with a box of straws + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:8,layer:16,straw:16,y:-12 + + + + + + + + + diff --git a/examples/ClientTests/scripts/BoxOfStraws.py b/examples/ClientTests/scripts/BoxOfStraws.py index d161c466f..55ba94738 100644 --- a/examples/ClientTests/scripts/BoxOfStraws.py +++ b/examples/ClientTests/scripts/BoxOfStraws.py @@ -33,7 +33,11 @@ def run(): kernel = DDG4.Kernel() logger = DDG4.Logger('BoxOfStraws') install_dir = os.environ['DD4hepExamplesINSTALL'] - kernel.loadGeometry(str('file:' + install_dir + '/examples/ClientTests/compact/BoxOfStraws.xml')) + + if args.sensitive: + kernel.loadGeometry(str('file:' + install_dir + '/examples/ClientTests/compact/BoxOfStraws_sensitive.xml')) + else: + kernel.loadGeometry(str('file:' + install_dir + '/examples/ClientTests/compact/BoxOfStraws.xml')) DDG4.importConstants(kernel.detectorDescription(), debug=False) geant4 = DDG4.Geant4(kernel) @@ -54,19 +58,25 @@ def run(): prt.OutputType = 3 # Print both: table and tree kernel.eventAction().adopt(prt) # + seq, act = geant4.addDetectorConstruction('Geant4DetectorConstructionResources/ResourcesBeforeConstruction') + act.When = "geometry"; + # # Configure G4 geometry setup seq, act = geant4.addDetectorConstruction('Geant4DetectorGeometryConstruction/ConstructGeo') act.DebugVolumes = True # - # Assign sensitive detectors according to the declarations 'tracker' or 'calorimeter', etc - seq, act = geant4.addDetectorConstruction('Geant4DetectorSensitivesConstruction/ConstructSD') + if args.sensitive: + # Assign sensitive detectors according to the declarations 'tracker' or 'calorimeter', etc + seq, act = geant4.addDetectorConstruction('Geant4DetectorSensitivesConstruction/ConstructSD') + else: + # Assign sensitive detectors in Geant4 by matching a regular expression in the detector sub-tree + seq, act = geant4.addDetectorConstruction('Geant4RegexSensitivesConstruction/ConstructSDRegEx') + act.Detector = 'BoxOfStrawsDet' + act.OutputLevel = Output.ALWAYS + act.Match = ['/world_volume_(.*)/BoxOfStrawsDet_(.*)/layer_(.*)/straw_(.*)/gas_(.*)'] # - # Assign sensitive detectors in Geant4 by matching a regular expression in the detector sub-tree - seq, act = geant4.addDetectorConstruction('Geant4RegexSensitivesConstruction/ConstructSDRegEx') - act.Detector = 'BoxOfStrawsDet' - act.OutputLevel = Output.ALWAYS - act.Match = ['/world_volume_(.*)/BoxOfStrawsDet_(.*)/layer_(.*)/straw_(.*)/gas_(.*)'] - act.Match = ['/world_volume_(.*)/BoxOfStrawsDet_(.*)/layer_(.*)/straw_(.*)'] + seq, act = geant4.addDetectorConstruction('Geant4DetectorConstructionResources/ResourcesAfterConstruction') + act.When = "sensitives"; # # Configure I/O geant4.setupROOTOutput('RootOutput', 'BoxOfStraws_' + time.strftime('%Y-%m-%d_%H-%M')) @@ -100,7 +110,12 @@ def run(): # Now build the physics list: phys = geant4.setupPhysics(str('QGSP_BERT')) phys.dump() - geant4.execute() + if args.simultate: + geant4.execute() + else: + geant4.kernel().configure() + geant4.kernel().initialize() + geant4.kernel().terminate() if __name__ == "__main__":