//-------------------------------------------------------------------------------- // Programme de test des classes NTuple/DataTable/ ... en multi-threads (SOPHYA) // R. Ansari - C. Magneville , Novembre 2007 // (C) UPS+LAL IN2P3/CNRS (C) DAPNIA/SPP CEA - 2007 // // Exemples de commandes pour test (renvoie Rc=0 si OK) // csh> tmtdt // tmtdt SEL TotSize NThreads [NOTHS] // csh> tmtdt NT 50000 2 // csh> tmtdt DT 50000 2 // csh> tmtdt SWPPF 50000 2 // Le fits ne semble pas etre thread-safe, uniquement avec NTH=1 // csh> tmtdt SWFITS 50000 1 //-------------------------------------------------------------------------------- #include "sopnamsp.h" #include "sspvflags.h" #include "zthread.h" #include "resusage.h" #include "ctimer.h" #include "timing.h" #include #include #include #include #include #include "tvector.h" #include "fioarr.h" #include "matharr.h" #include "tarrinit.h" // Pour tester la gestion multi-thread de Fill NTuple/DataTable #include "ntuple.h" #include "datatable.h" #include "swppfdtable.h" #ifndef SOPHYA_NO_FitsIOServer #include "fitsinoutfile.h" #include "swfitsdtable.h" #include "fitshdtable.h" #endif #include "histinit.h" //--------------------------------------------------------------------------------- // Definition d'une classe heritant de ZThread, pour remplir ou lire NTuple/DataTable // des aleatoires class MTntdt : public ZThread { public: MTntdt(bool fgc, sa_size_t sz, sa_size_t start, sa_size_t end); inline void SetNTDTable(NTuple* nt=NULL, BaseDataTable* dt=NULL) { nt_ = nt; dt_ = dt; } inline uint_8 NErr() { return nerr_; } virtual void run(); protected: bool fgc_; // true -> fill , false -> read sa_size_t size_, start_, end_; NTuple* nt_; // A remplir si != NULL BaseDataTable* dt_; // A remplir si != NULL string nom_; int tid_; uint_8 nerr_; }; static int mtrandId = 0; // Pour donner un identificateur a chaque thread MTntdt::MTntdt(bool fgc, sa_size_t sz, sa_size_t start, sa_size_t end) : fgc_(fgc) , size_(sz), start_(start) , end_(end) , nerr_(0) { SetNTDTable(); char buff[32]; sprintf(buff, "MTntdt-Id=%d", mtrandId); tid_ = mtrandId; mtrandId++; nom_ = buff; cout << " Thread MTntdt(" << nom_ << " ) Created ... " << endl; } // Le travail fait dans chaque thread (appele par start()) void MTntdt::run() { Timer tm(nom_.c_str()); char buff[128]; cout << "MTntdt::run() - Nom= " << nom_ << " TotSize " << size_ << " Start=" << start_ << " End=" << end_ << endl; double x,cx,sx; double xnt[10]; uint_8 nok = 0; if (fgc_) { // Creation if (nt_) { for(sa_size_t k=start_; k<=end_; k++) { x = k*0.013; cx = cos(x); sx = sin(x); xnt[0] = tid_; xnt[1] = k; xnt[2] = x; xnt[3] = cx; xnt[4] = sx; nt_->Fill(xnt); } } if (dt_) { DataTableRow dtr = dt_->EmptyRow(); for(sa_size_t k=start_; k<=end_; k++) { x = k*0.013; cx = cos(x); sx = sin(x); dtr[0] = tid_; dtr[1] = k; dtr[2] = x; dtr[3] = cx; dtr[4] = sx; dt_->AddRow(dtr); } } sprintf(buff, "%s : EndOf NT/DT Creation", nom_.c_str()); tm.Split(buff); } else { // lecture - verification if (nt_) { for(sa_size_t k=start_; k<=end_; k++) { nt_->GetVecD(k, xnt); sa_size_t kk = (sa_size_t)(xnt[1]+0.01); x = kk*0.013; if (fabs(x-xnt[2])>1.e-9) { nerr_++; continue; } cx = cos(x); if (fabs(cx-xnt[3])>1.e-9) { nerr_++; continue; } sx = sin(x); if (fabs(sx-xnt[4])>1.e-9) { nerr_++; continue; } nok++; } } if (dt_) { DataTableRow dtr = dt_->EmptyRow(); for(sa_size_t k=start_; k<=end_; k++) { dt_->GetRow(k, dtr); sa_size_t kk = (int_8)(dtr[1]); x = kk*0.013; xnt[2] = (r_8)(dtr[2]); if (fabs(x-xnt[2])>1.e-9) { nerr_++; continue; } xnt[3] = (r_8)(dtr[3]); cx = cos(x); if (fabs(cx-xnt[3])>1.e-9) { nerr_++; continue; } xnt[4] = (r_8)(dtr[4]); sx = sin(x); if (fabs(sx-xnt[4])>1.e-9) { nerr_++; continue; } nok++; } } sprintf(buff, "%s : EndOf NT/DT Check NOk= %ld NErr=%ld ", nom_.c_str(), (long)nok, (long)nerr_); tm.Split(buff); } } // ----- Fin de la definition de la classe MTntdt ---- //--------------------------------------------------------------------------------- //------- f3_tmtdt() int f3_tmtdt(sa_size_t SZ, int NTH, bool fgnt=true, bool fgdt=false, bool fgswppf=false, bool fgswfits=false, bool fgthsafe=true) { cout << "[1] f3_tmtdt/starting, SZ= " << SZ << " NTH= " << NTH << endl; if (fgthsafe) cout << " ... Running NTuple/DataTable Thread-safe " << endl; else cout << " ... WARNING Running NTuple/DataTable NOT Thread-safe " << endl; ResourceUsage res(ResourceUsage::RU_All); vector vth; sa_size_t csz = SZ / NTH; sa_size_t first, last; int rc = 0; // Verification des flags if (!fgnt && !fgdt && !fgswppf && !fgswfits) fgnt = true; if (fgnt) fgdt = fgswppf = fgswfits = false; else if (fgdt) fgswppf = fgswfits = false; else if (fgswppf) fgswfits = false; #ifdef SOPHYA_NO_FitsIOServer if (fgswfits) { cout << " SOPHYA compiled without FitsIOServer --> SwPPFDataTable " << endl; fgswppf = true; fgswfits = false; } #endif char* nomnt[5]={"tid","k","x","cx","sx"}; NTuple* nt = NULL; BaseDataTable* dt = NULL; DataTable* dtmem = NULL; SwPPFDataTable* dtswppf = NULL; POutPersist* pond = new POutPersist("mtdt.ppf"); if (fgnt) { nt = new NTuple(5, nomnt); if (fgthsafe) nt->SetThreadSafe(true); } else if (fgdt) { dtmem = new DataTable; dt = dtmem; } else if (fgswppf) { dtswppf = new SwPPFDataTable(*pond); dt = dtswppf; } #ifndef SOPHYA_NO_FitsIOServer SwFitsDataTable* dtswfits = NULL; FitsInOutFile* fio = NULL; if (fgswfits) { // SwFitsDataTable creation fio = new FitsInOutFile("!mtdt.fits",FitsInOutFile::Fits_Create); dtswfits = new SwFitsDataTable(*fio, 512, true); dt = dtswfits; } #endif if (dt) { if (fgthsafe) dt->SetThreadSafe(true); dt->AddIntegerColumn("tid"); dt->AddLongColumn("k"); dt->AddDoubleColumn("x"); dt->AddDoubleColumn("cx"); dt->AddDoubleColumn("sx"); } Timer tm("f2_tmtdt-NTupleDTable/MultiThreads"); cout << "[2] f3_tmtdt/creating fill threads " << endl; for(int kt=0; ktSetNTDTable(nt, dt); vth.push_back(throp); } cout << "[3] f3_tmtdt/starting fill threads " << endl; for(int kt=0; ktstart(); cout << "[4] f3_tmtdt/waiting for all threads to finish " << endl; sleep(2); for(int kt=0; ktjoin(); tm.Split(); cout << "[5] f3_tmtdt/deleting thread objects " << endl; for(int kt=0; kt> PPFNameTag("DT") >> (*dtswppf); dt = dtswppf; if (fgthsafe) dt->SetThreadSafe(true); } // Si c'est un SwFITSDataTable, on le relit sur le fichier FITS #ifndef SOPHYA_NO_FitsIOServer if (dtswfits) { delete dtswfits; delete fio; fio = NULL; // fio = new FitsInOutFile("mtdt.fits",FitsInOutFile::Fits_RO); // fio->MoveAbsToHDU(2); // SwFitsDataTable creation/readin in from fits file string finame = "mtdt.fits"; dtswfits = new SwFitsDataTable(finame); dt = dtswfits; } #endif tm.Split(); cout << "[7] f3_tmtdt/creating read/check threads " << endl; for(int kt=0; ktSetNTDTable(nt, dt); vth.push_back(throp); } cout << "[8] f3_tmtdt/starting read/check threads " << endl; for(int kt=0; ktstart(); cout << "[8] f3_tmtdt/waiting for all threads to finish " << endl; sleep(2); for(int kt=0; ktjoin(); tm.Split(); cout << "[9] f3_tmtdt/deleting thread objects " << endl; for(int kt=0; ktNTuple , =DT->DataTable, =SWPPF , =SWFITS SwPPF.SwFits DataTable" << endl; cout << " TotSize: Totale NTuple/DataTable NRows, NThreads= Number of Threads" << endl; cout << " if arg[4]==NOTHS -> NO call tp SetThreadSafe(true)" << endl; return 1; } string sel = arg[1]; bool fgnt,fgdt,fgswppf,fgswfits; fgnt = fgdt = fgswppf = fgswfits= false; if (sel == "NT") fgnt = true; else if (sel == "DT") fgdt = true; else if (sel == "SWPPF") fgswppf = true; else if (sel == "SWFITS") fgswfits = true; bool fgths = true; if ((narg > 4) && (strcmp(arg[4],"NOTHS")==0)) fgths = false; sa_size_t SZ = atoi(arg[2]); int NTH = atoi(arg[3]); try { rc = f3_tmtdt(SZ, NTH, fgnt, fgdt, fgswppf, fgswfits, fgths); } catch (PThrowable exc) { cerr << "zthr: catched Exception " << exc.Msg() << endl; rc = 77; } catch (...) { cerr << " catched unknown (...) exception (tmtdt.cc) " << endl; rc = 78; } cout << "----------- tmtdt/END (Rc= " << rc << " ) ------------ " << endl; PrtTim("---END tmtdt---"); return(rc); }