Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:49:45

0001 #pragma once
0002 /**
0003 SProf.hh
0004 =========
0005 
0006 Collecting full process lifecycle into SProf is convenient
0007 BUT: have to avoid only saving at end of run : as with jobs prone to run out of
0008 memory want to have at least some of the profile data even when the job fails
0009 
0010 
0011 Multiple calls to SProf::Write that overwrite and extend
0012 ----------------------------------------------------------
0013 
0014 This is done for several reasons:
0015 
0016 1. want to have profile info even when job crashes, eg from OOM
0017 2. number of stamps is intended to be small enough that not a resource issue
0018 
0019 
0020 Ordinarily SProf::Clear is never called
0021 ----------------------------------------
0022 
0023 Objective of SProf is to capture profile time stamps and memory usage
0024 throughout the full lifecycle of a process, so there is no need to
0025 ever clear. Only in postprocessing where wish to read in profile
0026 info from some other process is it approriate to SProf::Clear before
0027 reading.
0028 
0029 
0030 Usage
0031 -------
0032 
0033 ::
0034 
0035     (ok) A[blyth@localhost CSGOptiX]$ opticks-f SProf::Write
0036     ./CSGOptiX/CSGOptiX.cc:    SProf::Write();
0037     ./qudarap/QSim.cc:    SProf::Write(); // per-event write, so have something in case of crash
0038     ./sysrap/SEvt.cc:    SProf::Write();
0039     ./sysrap/SEvt.cc:    SProf::Write();
0040     ./sysrap/SProf.hh:    SProf::Write("run_meta.txt", true );
0041     ./sysrap/SProf.hh:inline void SProf::Write(bool append)
0042     ./sysrap/SProf.hh:    if(!WRITE) std::cerr << "SProf::Write DISABLED, enable[export SProf__WRITE=1] disable[unset SProf__WRITE]\n" ;
0043     ./sysrap/tests/SProfTest.cc:        SProf::Write();      // frequent write to have something in case of crash
0044     ./sysrap/tests/SProfTest.cc:    SProf::Write();
0045     ./u4/tests/U4HitTest.cc:    SProf::Write(append);
0046     (ok) A[blyth@localhost opticks]$
0047 
0048 
0049 
0050 Config via envvars
0051 -------------------
0052 
0053 Enable writing of profile txt file with::
0054 
0055     export SProf__WRITE=1
0056 
0057 Default path to write profile info is "SProf.txt", to override that::
0058 
0059     export SProf__PATH=SProf_%0.5d.txt
0060     export SProf__PATH_INDEX=0
0061 
0062 If the PATH provided contains "%" it is treated as a format string
0063 which is expected to take one integer index provided from the PATH_INDEX.
0064 
0065 
0066 Slurm array running without overwriting SProf.txt and other logs
0067 -----------------------------------------------------------------
0068 
0069 ::
0070 
0071     ID=$(printf "J%0.6d" "${SLURM_ARRAY_TASK_ID:-0}")
0072     LOGDIR=logs/$ID
0073     mkdir -p $LOGDIR
0074     pushd $LOGDIR
0075     ...invoke executable...
0076     popd
0077 
0078 
0079 Former Kludge, now removed
0080 ---------------------------
0081 
0082 Formerly shared output from SProf into the run_meta.txt, using::
0083 
0084     SProf::Write("run_meta.txt", true );
0085     // HMM: this relying on relative path, ie on the invoking directory
0086 
0087 HMM Combining run metadata in run_meta.txt
0088 (from SEvt::RUN_META) together with profiling info from here
0089 was a kludge that was removed as it complicates things.
0090 
0091 **/
0092 
0093 #include <vector>
0094 #include <fstream>
0095 #include <sstream>
0096 #include "sprof.h"
0097 #include "ssys.h"
0098 #include "sstr.h"
0099 
0100 #include "SYSRAP_API_EXPORT.hh"
0101 
0102 struct SYSRAP_API SProf
0103 {
0104     static constexpr const char* SProf__WRITE      = "SProf__WRITE" ;
0105 
0106     static constexpr const char* SProf__PATH       = "SProf__PATH" ;
0107     static constexpr const char* PATH_DEFAULT      = "SProf.txt" ;
0108     //static constexpr const char* PATH_DEFAULT    = "SProf_%0.5d.txt" ;
0109 
0110     static constexpr const char* SProf__PATH_INDEX = "SProf__PATH_INDEX" ;
0111     static constexpr const int PATH_INDEX_DEFAULT = 0 ;
0112 
0113     static constexpr const char* FMT = "%0.3d" ;
0114     static constexpr const int N = 10 ;
0115     static char TAG[N] ;
0116     static int  SetTag(int idx, const char* fmt=FMT ); // used to distinguish profiles from multiple events
0117     static bool HasTag();
0118     static const char* Tag();
0119     static void UnsetTag();
0120 
0121     static std::vector<sprof>       PROF ;   // sprof struct of 3 integers
0122     static std::vector<std::string> NAME ;
0123     static std::vector<std::string> META ;
0124 
0125     static int64_t Add(const char* name, const char* meta=nullptr);
0126     static void    Add(const char* name, const sprof& prof, const char* meta=nullptr );
0127 
0128     static int32_t Delta_RS();  // RS difference of last two stamps, or -1 when do not have more that one stamp
0129     static int32_t Range_RS();  // RS range between first and last stamps
0130 
0131     static void Clear();
0132 
0133     static std::string Serialize() ;
0134     static std::string Desc() ;
0135 
0136     static const char* Path();
0137     static void Write(bool append=false);
0138     static void Read();
0139 
0140     static std::string Annotation(const char* l0, size_t n0, const char* l1=nullptr, size_t n1=0, const char* l2=nullptr, size_t n2=0);
0141 };
0142 
0143 
0144 /**
0145 SProf::SetTag
0146 ---------------
0147 
0148 Canonically invoked from CSGOptiX::simulate
0149 
0150 **/
0151 
0152 
0153 inline int SProf::SetTag(int idx, const char* fmt)
0154 {
0155     return snprintf(TAG, N, fmt, idx );
0156 }
0157 inline bool SProf::HasTag()
0158 {
0159     return TAG[0] != '\0' ;
0160 }
0161 inline const char* SProf::Tag()
0162 {
0163     return TAG[0] == '\0' ? nullptr : TAG ;
0164 }
0165 inline void SProf::UnsetTag()
0166 {
0167     TAG[0] = '\0' ;
0168 }
0169 
0170 
0171 
0172 
0173 
0174 inline int64_t SProf::Add(const char* name, const char* meta)
0175 {
0176     sprof prof ;
0177     sprof::Stamp(prof);
0178     Add(name, prof, meta);
0179     return prof.st ;
0180 }
0181 
0182 inline void SProf::Add( const char* _name, const sprof& prof, const char* meta)
0183 {
0184     std::stringstream ss ;
0185     ss << ( HasTag() ? TAG : "" ) << _name ;
0186     std::string name = ss.str();
0187     NAME.push_back(name);
0188     PROF.push_back(prof);
0189     META.push_back(meta ? meta : "");
0190 }
0191 
0192 inline int32_t SProf::Delta_RS()
0193 {
0194     int num_prof = PROF.size();
0195     const sprof* p1 = num_prof > 0 ? &PROF.back() : nullptr ;
0196     const sprof* p0 = num_prof > 1 ? p1 - 1 : nullptr ;
0197     return p0 && p1 ? sprof::Delta_RS(p0, p1) : -1  ;
0198 }
0199 
0200 inline int32_t SProf::Range_RS()
0201 {
0202     int num_prof = PROF.size();
0203     const sprof* p0 = num_prof > 0 ? PROF.data() : nullptr ;
0204     const sprof* p1 = num_prof > 0 ? PROF.data() + num_prof - 1 : nullptr ;
0205     return p0 && p1 ? sprof::Delta_RS(p0, p1) : -1  ;
0206 }
0207 
0208 
0209 
0210 
0211 
0212 
0213 inline void SProf::Clear()
0214 {
0215     PROF.clear();
0216     NAME.clear();
0217     META.clear();
0218 }
0219 
0220 inline std::string SProf::Desc() // static
0221 {
0222     int num_prof = PROF.size() ;
0223 
0224     std::stringstream ss ;
0225     for(int i=0 ; i < num_prof  ; i++)
0226     {
0227         const std::string& name = NAME[i] ;
0228         const sprof& prof = PROF[i] ;
0229         const std::string& meta = META[i] ;
0230         ss
0231             << std::setw(30) << name
0232             << " : "
0233             << std::setw(50) << sprof::Desc_(prof)
0234             << ( meta.empty() ? "" : " # " )
0235             << ( meta.empty() ? "" : meta  )
0236             << std::endl
0237             ;
0238     }
0239 
0240     std::string str = ss.str() ;
0241     return str ;
0242 }
0243 
0244 inline std::string SProf::Serialize() // static
0245 {
0246     int num = PROF.size() ;
0247     std::stringstream ss ;
0248     for(int i=0 ; i < num ; i++)
0249     {
0250         const std::string& name = NAME[i] ;
0251         const sprof& prof = PROF[i] ;
0252         const std::string& meta = META[i] ;
0253         ss
0254             << name
0255             << ":"
0256             << sprof::Serialize(prof)
0257             << ( meta.empty() ? "" : " # " )
0258             << ( meta.empty() ? "" : meta  )
0259             << std::endl
0260             ;
0261     }
0262     std::string str = ss.str() ;
0263     return str ;
0264 }
0265 
0266 
0267 inline const char* SProf::Path()  // static
0268 {
0269     const char* PATH = ssys::getenvvar(SProf__PATH,       PATH_DEFAULT);
0270     int INDEX        = ssys::getenvint(SProf__PATH_INDEX, PATH_INDEX_DEFAULT);
0271     bool looks_like_fmt = strstr(PATH,"%") != nullptr ;
0272     const char* path = looks_like_fmt ? sstr::Format(PATH, INDEX) : PATH ;
0273     return path ;
0274 }
0275 
0276 inline void SProf::Write(bool append)
0277 {
0278     bool WRITE = ssys::getenvbool(SProf__WRITE) ;
0279     if(!WRITE) std::cerr << "SProf::Write DISABLED, enable[export SProf__WRITE=1] disable[unset SProf__WRITE]\n" ;
0280     if(!WRITE) return ;
0281 
0282     const char* path = Path();
0283     if(!path) return ;
0284     std::ios_base::openmode mode = std::ios::out|std::ios::binary ;
0285     if(append) mode |= std::ios::app ;
0286     std::ofstream fp(path, mode );
0287     fp << Serialize() ;
0288     fp.close();
0289 }
0290 
0291 /**
0292 
0293 A000_QSim__simulate_HEAD:1760593677804471,7316440,1220224
0294 A000_QSim__simulate_HEAD:1760593677804471,7316440,1220224   # metadata
0295 
0296 **/
0297 
0298 
0299 inline void SProf::Read()
0300 {
0301     const char* path = Path();
0302     if(!path) return ;
0303 
0304     Clear();
0305     bool dump = false ;
0306     std::ifstream fp(path);
0307 
0308     if(fp.fail()) std::cerr
0309         << "SProf::Read failed to read from"
0310         << " [" << ( path ? path : "-" )  << "]"
0311         << std::endl
0312         ;
0313 
0314     char delim0 = ':' ;
0315     char delim1 = '#' ;
0316 
0317     std::string str;
0318     while (std::getline(fp, str))
0319     {
0320         if(dump) std::cout << "str[" << str << "]" << std::endl ;
0321         char* s = (char*)str.c_str() ;
0322         char* p = (char*)strchr(s, delim0 );
0323         char* h = (char*)strchr(s, delim1 );
0324 
0325         if(p == nullptr) continue ;
0326         *p = '\0' ;
0327         std::string name = s ;  // string prior to delim0 ":"
0328 
0329         bool with_meta = h != nullptr ;
0330         if(with_meta) *h = '\0' ;
0331         std::string meta = with_meta ? h + 2 : "" ;
0332 
0333         sprof prof ;
0334         int rc = sprof::Import(prof, p+1 );
0335         if( rc == 0 ) Add( name.c_str(), prof, meta.c_str() );
0336         if(dump) std::cout << "name:[" << name << "]" << " Desc_:[" << sprof::Desc_(prof) << "]" << " rc " << rc  <<  std::endl ;
0337     }
0338     fp.close();
0339 }
0340 
0341 
0342 inline std::string SProf::Annotation(const char* l0, size_t n0, const char* l1, size_t n1, const char* l2, size_t n2) // static
0343 {
0344     std::stringstream ss ;
0345     if(l0) ss << l0 << "=" << n0 ;
0346     if(l1) ss << "," << l1 << "=" << n1 ;
0347     if(l2) ss << "," << l2 << "=" << n2 ;
0348     std::string str = ss.str();
0349     return str ;
0350 }
0351 
0352