File indexing completed on 2026-04-09 07:49:33
0001 #pragma once
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #include "SCurandChunk.h"
0043 #include "SCurandSpec.h"
0044 #include "SYSRAP_API_EXPORT.hh"
0045 #include "SCU_.h"
0046
0047 struct SYSRAP_API SCurandState
0048 {
0049 typedef unsigned long long ULL ;
0050 static constexpr const ULL M = 1000000ull ;
0051
0052 const char* dir ;
0053 std::vector<ULL> spec = {} ;
0054 std::vector<SCurandChunk> chunk = {} ;
0055 scurandref<curandStateXORWOW> all = {} ;
0056
0057 const char* getDir() const ;
0058
0059 SCurandState(const char* dir=nullptr);
0060
0061 void init();
0062 void initFromSpec();
0063 void initFromDir();
0064 void addChunk(ULL num);
0065
0066 ULL num_total() const ;
0067 std::string desc() const ;
0068
0069 bool is_complete() const ;
0070
0071 template<typename T>
0072 T* loadAndUpload( unsigned rngmax ) ;
0073
0074 };
0075
0076
0077 inline const char* SCurandState::getDir() const
0078 {
0079 return SCurandChunk::Dir(dir);
0080 }
0081
0082 inline SCurandState::SCurandState(const char* _dir)
0083 :
0084 dir( _dir ? strdup(_dir) : nullptr )
0085 {
0086 init();
0087 }
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103 inline void SCurandState::init()
0104 {
0105 all = {} ;
0106 all.chunk_idx = 0 ;
0107 all.chunk_offset = 0 ;
0108 all.num = 0 ;
0109 all.states = nullptr ;
0110
0111 const char* SEED_OFFSET = ssys::getenvvar("SCurandState__init_SEED_OFFSET");
0112 const char* CHUNKSIZES = ssys::getenvvar("SCurandState__init_CHUNKSIZES");
0113
0114 SCurandSpec::ParseSeedOffset( all.seed, all.offset, SEED_OFFSET );
0115 SCurandSpec::ParseChunkSizes( spec, CHUNKSIZES );
0116
0117 SCurandChunk::ParseDir(chunk, dir);
0118
0119 int num_spec = spec.size() ;
0120 int num_chunk = chunk.size() ;
0121
0122 if(num_chunk == 0)
0123 {
0124 initFromSpec();
0125 }
0126 else if( num_chunk > 0 )
0127 {
0128 initFromDir();
0129 }
0130
0131 all.num = num_total();
0132
0133 assert( spec.size() == chunk.size() );
0134 }
0135
0136
0137
0138
0139 inline void SCurandState::initFromSpec()
0140 {
0141 long num_spec = spec.size() ;
0142 for(long i=0 ; i < num_spec ; i++)
0143 {
0144 ULL num = spec[i];
0145 addChunk(num);
0146 }
0147 }
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175 inline void SCurandState::initFromDir()
0176 {
0177 ULL num_spec = spec.size() ;
0178
0179 for(ULL i=0 ; i < num_spec ; i++)
0180 {
0181 scurandref<curandStateXORWOW>* r = SCurandChunk::Find(chunk, i );
0182 ULL num_cumulative = SCurandChunk::NumTotal_InRange(chunk, 0, i );
0183 bool already_have_chunk = r != nullptr ;
0184
0185 if(already_have_chunk)
0186 {
0187 bool r_chunk_follows_spec =
0188 r->chunk_idx == i &&
0189 r->chunk_offset == num_cumulative &&
0190 r->num == spec[i] &&
0191 r->seed == all.seed &&
0192 r->offset == all.offset
0193 ;
0194
0195 assert(r_chunk_follows_spec);
0196 if(!r_chunk_follows_spec) std::cerr
0197 << "SCurandState::initFromDir"
0198 << " r_chunk_follows_spec " << ( r_chunk_follows_spec ? "YES" : "NO " ) << "\n"
0199 << " r.chunk_idx " << r->chunk_idx << " i " << i << "\n"
0200 << " r.chunk_offset " << r->chunk_offset << " num_cumulative " << num_cumulative << "\n"
0201 << " r.num " << r->num << " spec[i] " << spec[i] << "\n"
0202 << " r.seed " << r->seed << " all.seed " << all.seed << "\n"
0203 << " r.offset " << r->offset << " all.offset " << all.offset << "\n"
0204 ;
0205
0206 if(!r_chunk_follows_spec) return ;
0207 }
0208 else
0209 {
0210 addChunk(spec[i]);
0211 }
0212 }
0213 }
0214
0215
0216
0217
0218 inline void SCurandState::addChunk(ULL num)
0219 {
0220 int num_chunk = chunk.size();
0221 ULL num_cumulative = SCurandChunk::NumTotal_InRange(chunk, 0, num_chunk );
0222
0223 SCurandChunk c = {} ;
0224
0225 c.ref.chunk_idx = num_chunk ;
0226 c.ref.chunk_offset = num_cumulative ;
0227 c.ref.num = num ;
0228 c.ref.seed = all.seed ;
0229 c.ref.offset = all.offset ;
0230 c.ref.states = nullptr ;
0231
0232 chunk.push_back(c);
0233 }
0234
0235 inline unsigned long long SCurandState::num_total() const
0236 {
0237 return SCurandChunk::NumTotal_SpecCheck(chunk, spec);
0238 }
0239
0240
0241 inline std::string SCurandState::desc() const
0242 {
0243 const char* _dir = getDir();
0244
0245 int num_spec = spec.size();
0246 int num_chunk = chunk.size();
0247 int num_valid = SCurandChunk::CountValid(chunk, dir );
0248 bool complete = is_complete();
0249
0250 std::stringstream ss;
0251 ss
0252 << "[SCurandState::desc\n"
0253 << " dir " << ( dir ? dir : "-" ) << "\n"
0254 << " getDir " << ( _dir ? _dir : "-" ) << "\n"
0255 << " num_spec " << num_spec << "\n"
0256 << " num_chunk " << num_chunk << "\n"
0257 << " num_valid " << num_valid << "\n"
0258 << " is_complete " << ( complete ? "YES" : "NO " ) << "\n"
0259 << " num_total " << SCurandChunk::FormatNum(num_total()) << "\n"
0260 << SCurandSpec::Desc(spec)
0261 << "\n"
0262 << SCurandChunk::Desc(chunk, dir)
0263 << "]SCurandState::desc\n"
0264 ;
0265 std::string str = ss.str();
0266 return str ;
0267 }
0268
0269 inline bool SCurandState::is_complete() const
0270 {
0271 int num_spec = spec.size();
0272 int num_valid = SCurandChunk::CountValid(chunk, dir );
0273 return num_spec == num_valid ;
0274 }
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286 template<typename T>
0287 inline T* SCurandState::loadAndUpload( unsigned rngmax )
0288 {
0289 T* d0 = SCU_::device_alloc<T>( rngmax, "SCurandState::loadAndUpload" );
0290 T* d = d0 ;
0291
0292 ULL available_chunk = chunk.size();
0293 ULL count = 0 ;
0294
0295 std::cout
0296 << " rngmax " << rngmax
0297 << " rngmax/M " << rngmax/M
0298 << " available_chunk " << available_chunk
0299 << " all.num/M " << all.num/M
0300 << " rngmax/M " << rngmax/M
0301 << " d0 " << d0
0302 << "\n"
0303 ;
0304
0305
0306 sdigest dig ;
0307
0308 for(ULL i=0 ; i < available_chunk ; i++)
0309 {
0310 ULL remaining = rngmax - count ;
0311
0312 const SCurandChunk& ck = chunk[i];
0313
0314 bool partial_read = remaining < ck.ref.num ;
0315
0316 ULL num = partial_read ? remaining : ck.ref.num ;
0317
0318 std::cout
0319 << " i " << std::setw(3) << i
0320 << " ck.ref.num/M " << std::setw(4) << ck.ref.num/M
0321 << " count/M " << std::setw(4) << count/M
0322 << " remaining/M " << std::setw(4) << remaining/M
0323 << " partial_read " << ( partial_read ? "YES" : "NO " )
0324 << " num/M " << std::setw(4) << num/M
0325 << " d " << d
0326 << "\n"
0327 ;
0328
0329 scurandref<curandStateXORWOW> cr = ck.load(num, dir, &dig ) ;
0330
0331 assert( cr.states != nullptr);
0332
0333 bool num_match = cr.num == num ;
0334
0335 if(!num_match) std::cerr
0336 << "SCurandState::loadAndUpload"
0337 << " num_match " << ( num_match ? "YES" : "NO " )
0338 << " cr.num/M " << cr.num/M
0339 << " num/M " << num/M
0340 << "\n"
0341 ;
0342
0343 assert(num_match);
0344
0345 SCU_::copy_host_to_device<T>( d , cr.states , num );
0346
0347 free(cr.states);
0348
0349 d += num ;
0350 count += num ;
0351
0352 if(count > rngmax) assert(0);
0353 if(count == rngmax) break ;
0354 }
0355
0356 bool complete = count == rngmax ;
0357 assert( complete );
0358 std::string digest = dig.finalize();
0359
0360 std::cout
0361 << "SCurandState::loadAndUpload"
0362 << " complete " << ( complete ? "YES" : "NO ")
0363 << " rngmax/M " << rngmax/M
0364 << " rngmax " << rngmax
0365 << " digest " << digest << "(cf md5sum of cat-ed chunk(s))"
0366 << "\n"
0367 ;
0368
0369 return complete ? d0 : nullptr ;
0370 }
0371
0372
0373