Back to home page

EIC code displayed by LXR

 
 

    


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

0001 #pragma once
0002 /**
0003 SCurandChunk.h  NB NOT GENERAL : THIS IS SPECIFIC TO curandStateXORWOW
0004 ========================================================================
0005 
0006 
0007 The Load_ and Save methods are specific to curandStateXORWOW, most 
0008 of the rest is more general. But there is no need 
0009 for saving states for counter based RNG such as Philox 
0010 
0011 ::
0012 
0013     ~/o/sysrap/tests/SCurandState_test.sh
0014 
0015 **/
0016 
0017 #include <iomanip>
0018 
0019 #include "sdirectory.h"
0020 #include "spath.h"
0021 #include "sstr.h"
0022 #include "ssys.h"
0023 #include "scurandref.h"
0024 #include "sdigest.h"
0025 
0026 #include "SYSRAP_API_EXPORT.hh"
0027 
0028 struct SYSRAP_API SCurandChunk
0029 {
0030     typedef unsigned long long ULL ; 
0031     scurandref<curandStateXORWOW> ref = {} ; 
0032 
0033     std::string desc() const ;
0034     std::string meta() const ;
0035     std::string name() const ;
0036     const char* path(const char* _dir=nullptr) const ;
0037     bool path_exists(const char* _dir=nullptr) const ; 
0038 
0039     static constexpr const long STATE_SIZE = 44 ;  
0040     static constexpr const char* RNGDIR = "${RNGDir:-$HOME/.opticks/rngcache/RNG}" ; 
0041     static constexpr const ULL M = 1000000 ; 
0042     static constexpr const char* PREFIX = "SCurandChunk_" ; 
0043     static constexpr const char* EXT = ".bin" ; 
0044     static constexpr char DELIM = '_' ;
0045     static constexpr const long NUM_ELEM = 5 ;  
0046 
0047     static const char* Dir( const char* _dir=nullptr ); 
0048     static std::string Desc(const SCurandChunk& chunk, const char* _dir=nullptr ); 
0049     static std::string Desc(const std::vector<SCurandChunk>& chunk, const char* _dir=nullptr ); 
0050     static int ParseDir( std::vector<SCurandChunk>& chunk, const char* _dir=nullptr );
0051 
0052     static constexpr const char* ParseName_DEBUG = "SCurandChunk__ParseName_DEBUG" ; 
0053     static int ParseName( SCurandChunk& chunk, const char* name ); 
0054     static long ParseNum(const char* num); 
0055 
0056     static std::string FormatIdx(ULL idx);
0057     static std::string FormatNum(ULL num);
0058     static std::string FormatMeta(const scurandref<curandStateXORWOW>& d ); 
0059     static std::string FormatName(const scurandref<curandStateXORWOW>& d ); 
0060 
0061     static ULL NumFromFilesize(const char* name, const char* _dir=nullptr); 
0062     static bool IsValid(const SCurandChunk& chunk, const char* _dir=nullptr);
0063     static int CountValid(const std::vector<SCurandChunk>& chunk, const char* _dir=nullptr );
0064     static scurandref<curandStateXORWOW>* Find(std::vector<SCurandChunk>& chunk, long idx );
0065     static ULL NumTotal_SpecCheck(const std::vector<SCurandChunk>& chunk, const std::vector<ULL>& spec );
0066     static ULL NumTotal_InRange(  const std::vector<SCurandChunk>& chunk, ULL i0, ULL i1 ); 
0067 
0068     scurandref<curandStateXORWOW> load(ULL read_num=0, const char* _dir=nullptr, sdigest* dig=nullptr ) const ; 
0069     static int OldLoad( SCurandChunk& chunk, const char* name, ULL q_num=0, const char* _dir=nullptr );
0070     static curandStateXORWOW* Load_( ULL& file_num, const char* path, ULL read_num, sdigest* dig ); 
0071 
0072     static int Save( curandStateXORWOW* states, unsigned num_states, const char* path ) ; 
0073     int save( const char* _dir=nullptr ) const ; 
0074 };
0075 
0076 inline std::string SCurandChunk::desc() const
0077 {
0078     std::stringstream ss ; 
0079     ss << Desc(*this) << "\n" ; 
0080     std::string str = ss.str() ; 
0081     return str ;  
0082 }
0083 
0084 inline std::string SCurandChunk::meta() const
0085 {
0086     return FormatMeta(ref); 
0087 }
0088 inline std::string SCurandChunk::name() const
0089 {
0090     return FormatName(ref); 
0091 }
0092 inline const char* SCurandChunk::path(const char* _dir) const
0093 {
0094     std::string n = name(); 
0095     const char* dir = _dir ? _dir : RNGDIR ; 
0096     return spath::Resolve( dir, n.c_str() );  
0097 }
0098 
0099 inline bool SCurandChunk::path_exists(const char* _dir) const
0100 {
0101     const char* pth = path(_dir) ; 
0102     return spath::Exists(pth); 
0103 } 
0104 
0105 inline const char* SCurandChunk::Dir( const char* _dir )
0106 {
0107     const char* dir = _dir ? _dir : RNGDIR ; 
0108     return spath::Resolve(dir); 
0109 } 
0110 
0111 inline std::string SCurandChunk::Desc(const SCurandChunk& chunk, const char* _dir )
0112 {
0113     bool exists = chunk.path_exists(_dir); 
0114     std::stringstream ss ; 
0115     ss << chunk.path(_dir) << " exists " <<  ( exists ? "YES" : "NO " ) ; 
0116     std::string str = ss.str() ; 
0117     return str ;  
0118 }
0119 
0120 inline std::string SCurandChunk::Desc(const std::vector<SCurandChunk>& chunk, const char* _dir )
0121 {
0122     int num_chunk = chunk.size(); 
0123     std::stringstream ss ; 
0124     ss << "SCurandChunk::Desc\n" ; 
0125     for(int i=0 ; i < num_chunk ; i++) ss << Desc(chunk[i], _dir) << "\n" ;  
0126     std::string str = ss.str() ; 
0127     return str ;  
0128 } 
0129 
0130 /**
0131 SCurandChunk::ParseDir
0132 -----------------------
0133 
0134 Populate chunk vector based on matching file names within directory 
0135 
0136 **/
0137 
0138 
0139 inline int SCurandChunk::ParseDir(std::vector<SCurandChunk>& chunk, const char* _dir )
0140 {
0141     const char* dir = spath::Resolve(_dir ? _dir : RNGDIR) ; 
0142     std::vector<std::string> names ; 
0143     sdirectory::DirList( names, dir, PREFIX, EXT ); 
0144 
0145     int num_names = names.size(); 
0146     int count = 0 ; 
0147 
0148     for(int i=0 ; i < num_names ; i++) 
0149     {
0150         const std::string& n = names[i] ; 
0151         SCurandChunk c = {} ; 
0152         if(SCurandChunk::ParseName(c, n.c_str())==0) 
0153         {
0154             ULL chunk_offset = NumTotal_InRange(chunk, 0, chunk.size() ); 
0155             assert( c.ref.chunk_offset == chunk_offset );
0156             assert( c.ref.chunk_idx == count ); // chunk files must be in idx order 
0157             chunk.push_back(c);
0158             count += 1 ; 
0159         }
0160     }
0161     return 0 ; 
0162 }
0163 
0164 /**
0165 SCurandChunk::ParseName
0166 -------------------------
0167 
0168 ::
0169 
0170     SCurandChunk_0000_0000M_0001M_0_0.bin
0171     SCurandChunk_0001_0001M_0001M_0_0.bin
0172     SCurandChunk_0002_0002M_0001M_0_0.bin
0173     SCurandChunk_0003_0003M_0001M_0_0.bin
0174     SCurandChunk_0004_0004M_0001M_0_0.bin
0175     SCurandChunk_0005_0005M_0001M_0_0.bin
0176     ^^^^^^^^^^^^^....................^^^^
0177     PREFIX             meta          EXT
0178 
0179 **/
0180 
0181 
0182 inline int SCurandChunk::ParseName( SCurandChunk& chunk, const char* name )
0183 {
0184     if(name == nullptr ) return 1 ;  
0185     size_t other = strlen(PREFIX)+strlen(EXT) ; 
0186     if( strlen(name) <= other ) return 2 ; 
0187 
0188     std::string n = name ; 
0189     std::string meta = n.substr( strlen(PREFIX), strlen(name) - other ); 
0190 
0191     std::vector<std::string> elem ; 
0192     sstr::Split(meta.c_str(), DELIM, elem ); 
0193 
0194     unsigned num_elem = elem.size(); 
0195     if( num_elem != NUM_ELEM )  return 3 ; 
0196 
0197     chunk.ref.chunk_idx    = std::atoll(elem[0].c_str()) ; 
0198     chunk.ref.chunk_offset = ParseNum(elem[1].c_str()) ;
0199     chunk.ref.num          = ParseNum(elem[2].c_str()) ; 
0200     chunk.ref.seed         = std::atoll(elem[3].c_str()) ; 
0201     chunk.ref.offset       = std::atoll(elem[4].c_str()) ; 
0202     chunk.ref.states       = nullptr ; 
0203 
0204     int DEBUG = ssys::getenvint(ParseName_DEBUG,0); 
0205 
0206     if(DEBUG > 0) std::cout 
0207          << ParseName_DEBUG  
0208          << " " << std::setw(30) << n 
0209          << " : [" << meta << "][" 
0210          << chunk.name() 
0211          << "]\n" 
0212          ; 
0213     return 0 ; 
0214 }
0215 
0216 
0217 
0218 inline long SCurandChunk::ParseNum(const char* num)
0219 {
0220     char* n = strdup(num); 
0221     char last = n[strlen(n)-1] ; 
0222     ULL scale = last == 'M' ? M : 1 ; 
0223     if(scale > 1) n[strlen(n)-1] = '\0' ; 
0224     ULL value = scale*std::atoll(num) ; 
0225     return value ; 
0226 }
0227 
0228 
0229 
0230 inline std::string SCurandChunk::FormatMeta(const scurandref<curandStateXORWOW>& d)
0231 {
0232     std::stringstream ss ; 
0233     ss 
0234        << FormatIdx(d.chunk_idx) 
0235        << DELIM
0236        << FormatNum(d.chunk_offset) 
0237        << DELIM
0238        << FormatNum(d.num)
0239        << DELIM
0240        << d.seed
0241        << DELIM
0242        << d.offset
0243        ; 
0244     std::string str = ss.str(); 
0245     return str ;   
0246 }
0247 inline std::string SCurandChunk::FormatName(const scurandref<curandStateXORWOW>& d)
0248 {
0249     std::stringstream ss ; 
0250     ss << PREFIX << FormatMeta(d) << EXT ; 
0251     std::string str = ss.str(); 
0252     return str ;   
0253 }
0254  
0255 inline std::string SCurandChunk::FormatIdx(ULL idx)
0256 {
0257     std::stringstream ss; 
0258     ss << std::setw(4) << std::setfill('0') << idx ;
0259     std::string str = ss.str(); 
0260     return str ;   
0261 }
0262 inline std::string SCurandChunk::FormatNum(ULL num)
0263 {
0264     ULL scale = M  ; 
0265 
0266     bool intmul = num % scale == 0 ; 
0267     if(!intmul) std::cerr
0268          << "SCurandChunk::FormatNum"
0269          << " num [" << num << "]"
0270          << " intmul " << ( intmul ? "YES" : "NO " )
0271          << "\n"
0272          ; 
0273     assert( intmul && "integer multiples of 1000000 are required" ); 
0274     ULL value = num/scale ; 
0275 
0276     std::stringstream ss; 
0277     ss << std::setw(4) << std::setfill('0') << value << 'M' ; 
0278     std::string str = ss.str(); 
0279     return str ;   
0280 }
0281 
0282 inline unsigned long long SCurandChunk::NumFromFilesize(const char* name, const char* _dir)
0283 {
0284     const char* dir = _dir ? _dir : RNGDIR ; 
0285     ULL file_size = spath::Filesize(dir, name); 
0286 
0287     bool expected_file_size = file_size % STATE_SIZE == 0 ; 
0288     ULL file_num = file_size/STATE_SIZE ;
0289 
0290     if(0) std::cerr
0291         << "SCurandChunk::NumFromFilesize"
0292         << " dir " << ( dir ? dir : "-" )
0293         << " name " << ( name ? name : "-" )
0294         << " file_size " << file_size
0295         << " STATE_SIZE " << STATE_SIZE
0296         << " file_num " << file_num
0297         << " expected_file_size " << ( expected_file_size ? "YES" : "NO" )
0298         << "\n"
0299         ;
0300 
0301     assert( expected_file_size );
0302     return file_num ; 
0303 }
0304 
0305 inline bool SCurandChunk::IsValid(const SCurandChunk& chunk, const char* _dir )
0306 {
0307     bool exists = chunk.path_exists(_dir) ;  
0308     if(!exists) return false ; 
0309 
0310     std::string n = chunk.name(); 
0311 
0312 
0313     ULL chunk_num = chunk.ref.num ; 
0314     ULL file_num = NumFromFilesize(n.c_str(), _dir) ;  
0315     bool valid = chunk_num == file_num ; 
0316 
0317     if(!valid) std::cerr   
0318         << "SCurandChunk::IsValid"
0319         << " chunk file exists [" << n << "]"
0320         << " but filesize does not match name metadata "
0321         << " chunk_num " << chunk_num
0322         << " file_num " << file_num
0323         << " valid " << ( valid ? "YES" : "NO " )
0324         << "\n"
0325         ;
0326     return valid ; 
0327 }
0328 
0329 inline int SCurandChunk::CountValid(const std::vector<SCurandChunk>& chunk, const char* _dir )
0330 {
0331     int num_chunk = chunk.size(); 
0332     int count = 0 ; 
0333     for(int i=0 ; i < num_chunk ; i++)
0334     {
0335         const SCurandChunk& c = chunk[i];     
0336         bool valid = IsValid(c, _dir); 
0337         if(!valid) continue ;  
0338         count += 1 ;          
0339     }
0340     return count ; 
0341 }
0342 
0343 inline scurandref<curandStateXORWOW>* SCurandChunk::Find(std::vector<SCurandChunk>& chunk, long q_idx )
0344 {
0345     int num_chunk = chunk.size(); 
0346     int count = 0 ; 
0347     scurandref<curandStateXORWOW>* p = nullptr ; 
0348     for(int i=0 ; i < num_chunk ; i++)
0349     {
0350         SCurandChunk& c = chunk[i] ;     
0351         if( c.ref.chunk_idx == q_idx ) 
0352         {
0353             p = &(c.ref) ;  
0354             count += 1 ; 
0355         }
0356     }
0357     assert( count == 0 || count == 1 ); 
0358     return count == 1 ? p : nullptr ; 
0359 }
0360 
0361 
0362 /**
0363 SCurandChunk::NumTotal_SpecCheck
0364 ---------------------------------
0365 
0366 Total number of states in the chunks 
0367 
0368 **/
0369 
0370 
0371 inline unsigned long long SCurandChunk::NumTotal_SpecCheck(const std::vector<SCurandChunk>& chunk, const std::vector<ULL>& spec )
0372 {
0373     assert( chunk.size() == spec.size() ) ;
0374     ULL tot = 0 ; 
0375     ULL num_chunk = chunk.size(); 
0376     for(ULL i=0 ; i < num_chunk ; i++)
0377     {
0378         const scurandref<curandStateXORWOW>& d = chunk[i].ref ;     
0379         assert( d.chunk_idx == i );  
0380         assert( d.num == spec[i] );  
0381         tot += d.num ; 
0382     }
0383     return tot ; 
0384 }
0385 
0386 inline unsigned long long SCurandChunk::NumTotal_InRange( const std::vector<SCurandChunk>& chunk, ULL i0, ULL i1 )
0387 {
0388     ULL num_chunk = chunk.size(); 
0389     assert( i0 <= num_chunk ); 
0390     assert( i1 <= num_chunk ); 
0391 
0392     ULL num_tot = 0ull ; 
0393     for(ULL i=i0 ; i < i1 ; i++) 
0394     {
0395         const scurandref<curandStateXORWOW>& d = chunk[i].ref ;     
0396         num_tot += d.num ; 
0397     } 
0398     return num_tot ; 
0399 }
0400 
0401 
0402 
0403 
0404 
0405 
0406 
0407 
0408 
0409 inline scurandref<curandStateXORWOW> SCurandChunk::load( ULL read_num, const char* _dir, sdigest* dig ) const
0410 {
0411     scurandref<curandStateXORWOW> lref(ref); 
0412     const char* p = path(_dir); 
0413 
0414     ULL file_num = 0 ; 
0415     lref.states = Load_(file_num, p, read_num, dig );
0416     lref.num = read_num ; 
0417 
0418     return lref ;
0419 }
0420 
0421 
0422 /**
0423 SCurandChunk::OldLoad
0424 ---------------------
0425 
0426 **/
0427 
0428 
0429 inline int SCurandChunk::OldLoad( SCurandChunk& chunk, const char* name, ULL read_num, const char* _dir )
0430 {
0431     int prc = ParseName(chunk, name); 
0432     if( prc > 0) std::cerr
0433         << "SCurandChunk::Load"
0434         << " chunk name not allowed "
0435         << "\n"
0436         ;
0437     if(prc > 0) return 1 ; 
0438     
0439     const char* dir = _dir ? _dir : RNGDIR ; 
0440     const char* p = spath::Resolve(dir, name); 
0441 
0442     ULL name_num = chunk.ref.num ;         // from ParseName
0443 
0444     ULL file_num = 0 ; 
0445     curandStateXORWOW* h_states = Load_( file_num, p, read_num, nullptr ) ; 
0446 
0447     if( h_states )
0448     {
0449         chunk.ref.num = read_num ; 
0450         chunk.ref.states = h_states ; 
0451         bool name_filesize_consistent = file_num == name_num ; 
0452 
0453         std::cerr
0454             << "SCurandChunk::Load"
0455             << " path " << p 
0456             << " name_num " << FormatNum(name_num) << "(from parsing filename) "
0457             << " file_num " << FormatNum(file_num) << "(from file_size/STATE_SIZE) "
0458             << " name_filesize_consistent " << ( name_filesize_consistent ? "YES" : "NO " )
0459             << " read_num " << FormatNum(read_num)
0460             << "\n"
0461             ; 
0462     }
0463     return h_states ? 0 : 2  ; 
0464 }
0465 
0466 
0467 inline curandStateXORWOW* SCurandChunk::Load_( ULL& file_num, const char* path, ULL read_num, sdigest* dig )
0468 {
0469     FILE *fp = fopen(path,"rb");
0470 
0471     bool open_failed = fp == nullptr ; 
0472     if(open_failed) std::cerr 
0473         << "SCurandChunk::Load_"
0474         << " unable to open file "
0475         << "[" << path << "]" 
0476         << "\n" 
0477         ; 
0478 
0479     if(open_failed) return nullptr ; 
0480 
0481     fseek(fp, 0L, SEEK_END);
0482     ULL file_size = ftell(fp);
0483     rewind(fp);
0484 
0485     bool expected_size = file_size % STATE_SIZE == 0 ; 
0486     if(!expected_size) std::cerr 
0487         << "SCurandChunk::Load_"
0488         << " expected_size " << ( expected_size ? "YES" : "NO " )
0489         << "\n" 
0490         ;  
0491 
0492     if(!expected_size) return nullptr ; 
0493 
0494     file_num = file_size/STATE_SIZE;   // NB  STATE_SIZE not same as type_size
0495 
0496     bool read_num_toobig = read_num > file_num ; 
0497     if(read_num_toobig) std::cerr 
0498         << "SCurandChunk::Load_"
0499         << " read_num_toobig " << ( read_num_toobig ? "YES" : "NO " )
0500         << "\n" 
0501         ;  
0502 
0503     if(read_num_toobig) return nullptr ; 
0504     if(read_num == 0) read_num = file_num ;  // 0 means all 
0505 
0506     curandStateXORWOW* h_states = (curandStateXORWOW*)malloc(sizeof(curandStateXORWOW)*read_num);
0507 
0508 /**
0509 /usr/local/cuda-11.7/include/curand_kernel.h::
0510 
0511      140 struct curandStateXORWOW {
0512      141     unsigned int d, v[5];
0513      142     int boxmuller_flag;
0514      143     int boxmuller_flag_double;
0515      144     float boxmuller_extra;
0516      145     double boxmuller_extra_double;
0517      146 };
0518 
0519 
0520 **/
0521 
0522 
0523     for(ULL i = 0 ; i < read_num ; ++i )
0524     {   
0525         curandStateXORWOW& rng = h_states[i] ;
0526         fread(&rng.d,                     sizeof(unsigned),1,fp);  if(dig) dig->add_<unsigned>(&rng.d, 1 ); 
0527         fread(&rng.v,                     sizeof(unsigned),5,fp);  if(dig) dig->add_<unsigned>( rng.v, 5 );
0528         fread(&rng.boxmuller_flag,        sizeof(int)     ,1,fp);  if(dig) dig->add_<int>(&rng.boxmuller_flag,1); 
0529         fread(&rng.boxmuller_flag_double, sizeof(int)     ,1,fp);  if(dig) dig->add_<int>(&rng.boxmuller_flag_double,1);
0530         fread(&rng.boxmuller_extra,       sizeof(float)   ,1,fp);  if(dig) dig->add_<float>(&rng.boxmuller_extra,1);
0531         fread(&rng.boxmuller_extra_double,sizeof(double)  ,1,fp);  if(dig) dig->add_<double>(&rng.boxmuller_extra_double,1);
0532     }   
0533     fclose(fp);
0534     return h_states ; 
0535 }
0536 
0537 
0538 inline int SCurandChunk::Save( curandStateXORWOW* states, unsigned num_states, const char* path ) // static
0539 {
0540     sdirectory::MakeDirsForFile(path);
0541     FILE *fp = fopen(path,"wb");
0542     bool open_fail = fp == nullptr ; 
0543 
0544     if(open_fail) std::cerr 
0545         << "SCurandChunk::Save"
0546         << " FAILED to open file for writing" 
0547         << ( path ? path : "-" ) 
0548         << "\n" 
0549         ;
0550 
0551     if( open_fail ) return 3 ; 
0552 
0553     for(unsigned i = 0 ; i < num_states ; ++i )
0554     {
0555         curandStateXORWOW& rng = states[i] ;
0556         fwrite(&rng.d,                     sizeof(unsigned int),1,fp);
0557         fwrite(&rng.v,                     sizeof(unsigned int),5,fp);
0558         fwrite(&rng.boxmuller_flag,        sizeof(int)         ,1,fp);
0559         fwrite(&rng.boxmuller_flag_double, sizeof(int)         ,1,fp);
0560         fwrite(&rng.boxmuller_extra,       sizeof(float)       ,1,fp);
0561         fwrite(&rng.boxmuller_extra_double,sizeof(double)      ,1,fp);
0562     }   
0563     fclose(fp);
0564     return 0 ; 
0565 }
0566 
0567 inline int SCurandChunk::save( const char* _dir ) const
0568 {
0569     const char* p = path(_dir);  
0570     bool exists = spath::Exists(p); 
0571     std::cerr 
0572         << "SCurandChunk::save"
0573         << " p " << ( p ? p : "-" )
0574         << " exists " << ( exists ? "YES" : "NO " )
0575         << "\n"
0576         ;  
0577 
0578     if(exists) return 1 ; 
0579 
0580     int rc = Save( ref.states, ref.num, p ); 
0581     return rc ;
0582 }
0583