Skip to content
Snippets Groups Projects
Geant4DetectorConstructionResources.cpp 11.4 KiB
Newer Older
//==========================================================================
//  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 <DDG4/Geant4DetectorConstruction.h>

// 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/<pid>/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<StatusProcess> 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 <DD4hep/InstanceCount.h>
#include <DD4hep/Printout.h>
#include <DD4hep/Plugins.h>
#include <DD4hep/Detector.h>

#include <DDG4/Geant4Mapping.h>
#include <DDG4/Geant4Kernel.h>
#include <DDG4/Factories.h>

#include <stdexcept>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

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<StatusProcess>();
    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();
}