#include #include #define MAX_EVEC_PRINT_NORM 8 #define FP16_WIDTH_24 2.0833333333333 #define FP16_COEF_EXP_SHARE_FLOATS 10 #define FP16_WIDTH_COEF (2.0*(1.0 + 1.0 / (double)FP16_COEF_EXP_SHARE_FLOATS)) // Adopting eig-comp from C. Lehner, based on multi-grid lanczos arxiv:1710.06884 CPS_START_NAMESPACE // prec = sizeof(float or double) int EvecWriter::writeCompressedVector ( const char *dir, OPT *V, struct evec_write &warg, std::vector &evals){ // const char *cname=""; const char *fname=""; static Timer timer (cname,fname); timer.start(); int neig = evals.size(); int ID = UniqueID(); #pragma omp parallel { #pragma omp single { nthreads = omp_get_num_threads(); } } float *raw_in = (float*)V; VRB.Result(cname,fname,"%s\n%d threads\n\n",header,nthreads); // size_t vol4d, vol5d; size_t f_size, f_size_coef_block, nkeep_fp16; //, f_size_block, // fprintf(stderr,"Arguments: sx sy sz st s5 bx by bz bt b5 nkeep fileindex filesperdir bigendian nkeep_single_prec vrb_nkeep_res vrb_evec_res\n"); { for(int i=0;i<5;i++) args.s[i]=GJP.NodeSites(i); for(int i=0;i<5;i++) args.b[i]=warg.b[i]; args.nkeep=warg.nkeep; args.nkeep_single=warg.nkeep_single; // args.filesperdir=warg.filesperdir; warg.findex=ID; if(warg.bigendian) bigendian=true; VRB.Result(cname,fname,"Parameters:\n"); for (int i=0;i<5;i++) VRB.Result(cname,fname,"s[%d] = %d\n",i,args.s[i]); for (int i=0;i<5;i++) VRB.Result(cname,fname,"b[%d] = %d\n",i,args.b[i]); VRB.Result(cname,fname,"nkeep = %d\n",args.nkeep); VRB.Result(cname,fname,"file_index = %10.10d\n",warg.findex); VRB.Result(cname,fname,"n_dir = %d\n",warg.n_dir); VRB.Result(cname,fname,"big_endian = %d\n",warg.bigendian); VRB.Result(cname,fname,"nkeep_single = %d\n",args.nkeep_single); vol4d = args.s[0] * args.s[1] * args.s[2] * args.s[3]; vol5d = vol4d * args.s[4]; f_size = vol5d / 2 * 24; VRB.Result(cname,fname,"f_size = %d\n",f_size); // sanity check args.blocks = 1; for (int i=0;i<5;i++) { if (args.s[i] % args.b[i]) { fprintf(stderr,"Invalid blocking in dimension %d\n",i); return 72; } args.nb[i] = args.s[i] / args.b[i]; args.blocks *= args.nb[i]; } f_size_block = f_size / args.blocks; VRB.Result(cname,fname,"number of blocks = %d\n",args.blocks); VRB.Result(cname,fname,"f_size_block = %d\n",f_size_block); VRB.Result(cname,fname,"Internally using sizeof(OPT) = %d\n",sizeof(OPT)); } { // off_t size = ftello(f); // if ( size % (sizeof(float)*f_size) ) { // fprintf(stderr,"Invalid file size\n"); // return 2; // } // neig = ( size / sizeof(float) / f_size ); size_t size = f_size*sizeof(float)*neig; f_size_coef_block = neig * 2 * args.nkeep; VRB.Result(cname,fname,"We have %d eigenvectors \n",neig); printf("Size of operating coefficient data in GB: %g\n", (double)f_size_coef_block * (double)args.blocks / 1024./1024./1024. * sizeof(OPT)); nkeep_fp16 = args.nkeep - args.nkeep_single; if (nkeep_fp16 < 0) nkeep_fp16 = 0; VRB.Result(cname,fname,"neig nkeep_single nkee_fp16=%d %d %d\n",neig, args.nkeep_single, nkeep_fp16); // estimate of compression { double size_of_coef_data = (neig * (double)args.blocks * (args.nkeep_single * 4 + nkeep_fp16 * FP16_WIDTH_COEF)*2) / 1024. / 1024. / 1024.; double size_of_evec_data = ((args.nkeep - nkeep_fp16)* f_size * 4 + nkeep_fp16 * f_size * FP16_WIDTH_24) / 1024. / 1024. / 1024.; double size_orig = (double)size / 1024. / 1024. / 1024.; double size_of_comp = size_of_coef_data+size_of_evec_data; printf("--------------------------------------------------------------------------------\n"); // printf("Original size: %g GB\n",size_orig); printf("Compressed size: %g GB (%g GB coef, %g GB evec)\n",size_of_comp,size_of_coef_data,size_of_evec_data); printf("Compressed to %.4g%% of original\n",size_of_comp / size_orig * 100.); printf("--------------------------------------------------------------------------------\n"); } double t1 = dclock(); // double size_in_gb = f_size * (double)neig * sizeof(float) / 1024. / 1024. / 1024.; // printf("Read %.4g GB in %.4g seconds at %.4g GB/s\n", size_in_gb, t1-t0,size_in_gb / (t1-t0) ); // uint32_t crc_comp = crc32_fast(raw_in,(size_t)f_size * neig * sizeof(float),0); uint32_t crc_comp = crc32_loop(0,(unsigned char *)raw_in,(size_t)f_size * neig * sizeof(float)); double t2 = dclock(); printf("Node %d: Computed CRC32: %X (in %.4g seconds)\n",ID,crc_comp,t2-t1); // fclose(f); VRB.Result(cname,fname,"Fixing endian-ness\n"); // fix endian if needed // turning off threading for sum testing. Eventually unnecessary //#pragma omp parallel for for (int j=0;j 1e-5) { fprintf(stderr,"Unexpected error in creating blocks\n"); // return 91; } } } // Now do Gram-Schmidt { // create block memory block_data_ortho.resize(args.blocks); for (int i=0;i - |j> // std::complex res_j = sp_single(ev_j,res,f_size_block); COUNT_FLOPS_BYTES(8 / 2 * f_size_block, 2*f_size_block*sizeof(OPT)); // 6 per complex multiply, 2 per complex add -> 8 / 2 = 4 caxpy_single(res,- res_j,ev_j,res,f_size_block); COUNT_FLOPS_BYTES(8 / 2 * f_size_block, 3*f_size_block*sizeof(OPT)); } // normalize std::complex nrm = sp_single(res,res,f_size_block); COUNT_FLOPS_BYTES(8 / 2 * f_size_block,2*f_size_block*sizeof(OPT)); scale_single(res, (OPT)(1.0 / sqrt(nrm.real())),f_size_block); COUNT_FLOPS_BYTES(f_size_block,2*f_size_block*sizeof(OPT)); } } #pragma omp critical { flops += flopsl + 1; bytes += bytesl + 2; } } double t1 = dclock(); printf("Gram-Schmidt took %.4g seconds (%g Gflops/s, %g GB/s)\n",t1-t0,flops / (t1-t0) / 1000./1000./1000., bytes / (t1-t0) / 1024./1024./1024.); } // Get coefficients and create graphs { // create block memory block_coef.resize(args.blocks); for (int i=0;i