Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TProofBench.cxx
Go to the documentation of this file.
1 // @(#)root/proof:$Id$
2 // Author: G.Ganis, S.Ryu Feb 2011
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 /**
12  \defgroup proofbench PROOF benchmark utilities
13  \ingroup proof
14 
15  Set of utilities to benchmark a PROOF facility.
16  See also https://root.cern.ch/proof-benchmark-framework-tproofbench .
17 
18 */
19 
20 /** \class TProofBench
21 \ingroup proofbench
22 
23  Steering class for PROOF benchmarks
24 
25 */
26 
27 #include "RConfigure.h"
28 
29 #include "TProofBench.h"
30 #include "Getline.h"
31 #include "TProofBenchRunCPU.h"
32 #include "TProofBenchRunDataRead.h"
33 #include "TProofBenchDataSet.h"
34 #include "TProofNodes.h"
35 #include "TClass.h"
36 #include "TFile.h"
37 #include "TFileCollection.h"
38 #include "TFileInfo.h"
39 #include "THashList.h"
40 #include "TKey.h"
41 #include "TObjString.h"
42 #include "TProof.h"
43 #include "TROOT.h"
44 #include "TSortedList.h"
45 #include "TTimeStamp.h"
46 #include "TUrl.h"
47 
48 #include "TCanvas.h"
49 #include "TF1.h"
50 #include "TGraphErrors.h"
51 #include "TH1F.h"
52 #include "TMath.h"
53 #include "TProfile.h"
54 #include "TStyle.h"
55 #include "TLegend.h"
56 #ifdef WIN32
57 #include <io.h>
58 #endif
59 
60 ClassImp(TProofBench);
61 
62 // Functions for fitting
63 
64 TF1 *TProofBench::fgFp1 = 0;
65 TF1 *TProofBench::fgFp1n = 0;
66 TF1 *TProofBench::fgFp2 = 0;
67 TF1 *TProofBench::fgFp2n = 0;
68 TF1 *TProofBench::fgFp3 = 0;
69 TF1 *TProofBench::fgFp3n = 0;
70 TF1 *TProofBench::fgFio = 0;
71 TF1 *TProofBench::fgFioV = 0;
72 static Int_t gFioVn0 = -1; // Number of real cores for fgFioV
73 static Int_t gFioVn1 = -1; // Number of real+hyper cores for fgFioV
74 
75 TList *TProofBench::fgGraphs = new TList;
76 
77 ////////////////////////////////////////////////////////////////////////////////
78 /// Simple polynomial 1st degree
79 
80 Double_t funp1(Double_t *xx, Double_t *par)
81 {
82  Double_t res = par[0] + par[1] * xx[0];
83  return res;
84 }
85 
86 ////////////////////////////////////////////////////////////////////////////////
87 /// Simple polynomial 2nd degree
88 
89 Double_t funp2(Double_t *xx, Double_t *par)
90 {
91  Double_t res = par[0] + par[1] * xx[0] + par[2] * xx[0] * xx[0];
92  return res;
93 }
94 
95 ////////////////////////////////////////////////////////////////////////////////
96 /// Normalized 1st degree
97 
98 Double_t funp1n(Double_t *xx, Double_t *par)
99 {
100  Double_t res = par[0] / xx[0] + par[1];
101  return res;
102 }
103 
104 ////////////////////////////////////////////////////////////////////////////////
105 /// Normalized 2nd degree
106 
107 Double_t funp2n(Double_t *xx, Double_t *par)
108 {
109  Double_t res = par[0] / xx[0] + par[1] + par[2] * xx[0];
110  return res;
111 }
112 
113 ////////////////////////////////////////////////////////////////////////////////
114 /// I/O saturated rate function
115 
116 Double_t funio(Double_t *xx, Double_t *par)
117 {
118  Double_t sat = par[0] / par[1] * (xx[0] * par[1] / par[2] - 1.);
119  if (xx[0] < par[2] / par[1]) sat = 0.;
120  Double_t res = par[0] * xx[0] / (1. + sat);
121  return res;
122 }
123 
124 ////////////////////////////////////////////////////////////////////////////////
125 /// I/O saturated rate function with varying Rcpu
126 
127 Double_t funiov(Double_t *xx, Double_t *par)
128 {
129  // par[0] = rio
130  // par[1] = b1
131  // par[2] = b2
132  // par[3] = nc
133  // par[4] = ri
134 
135  Double_t rio = par[0] / par[3] * xx[0];
136  if (xx[0] > par[3]) rio = par[0];
137 
138  Double_t rcpu = par[1] * xx[0];
139  if (xx[0] > gFioVn0) rcpu = par[1]*gFioVn0 + par[2]*(xx[0] - gFioVn0);
140  if (xx[0] > gFioVn1) rcpu = par[1]*gFioVn0 + par[2]*(gFioVn1 - gFioVn0);
141 
142  Double_t res = 1. / (1./par[4] + 1./rio + 1./rcpu);
143 
144  return res;
145 }
146 
147 ////////////////////////////////////////////////////////////////////////////////
148 /// Function with varying Rcpu
149 
150 Double_t funcpuv(Double_t *xx, Double_t *par)
151 {
152  // par[0] = offset
153  // par[1] = rate contribution from real cores
154  // par[2] = rate contribution from hyper cores
155 
156  Double_t n = (xx[0] - par[0]);
157  Double_t rcpu = par[1] * n;
158  if (xx[0] > gFioVn0) rcpu = par[1]*gFioVn0 + par[2]*(n - gFioVn0);
159  if (xx[0] > gFioVn1) rcpu = par[1]*gFioVn0 + par[2]*(gFioVn1 - gFioVn0);
160 
161  return rcpu;
162 }
163 
164 ////////////////////////////////////////////////////////////////////////////////
165 /// Function with varying Rcpu normalized
166 
167 Double_t funcpuvn(Double_t *xx, Double_t *par)
168 {
169  // par[0] = offset
170  // par[1] = rate contribution from real cores
171  // par[2] = rate contribution from hyper cores
172 
173  Double_t n = (xx[0] - par[0]);
174  Double_t rcpu = par[1] * n;
175  if (xx[0] > gFioVn0) rcpu = par[1]*gFioVn0 + par[2]*(n - gFioVn0);
176  if (xx[0] > gFioVn1) rcpu = par[1]*gFioVn0 + par[2]*(gFioVn1 - gFioVn0);
177 
178  return rcpu / xx[0];
179 }
180 
181 ////////////////////////////////////////////////////////////////////////////////
182 /// Constructor: check PROOF and load selectors PAR
183 
184 TProofBench::TProofBench(const char *url, const char *outfile, const char *proofopt)
185  : fUnlinkOutfile(kFALSE), fProofDS(0), fOutFile(0),
186  fNtries(4), fHistType(0), fNHist(16), fReadType(0),
187  fDataSet("BenchDataSet"), fNFilesWrk(2), fReleaseCache(kTRUE),
188  fDataGenSel(kPROOF_BenchSelDataGenDef),
189  fRunCPU(0), fRunDS(0), fDS(0), fDebug(kFALSE), fDescription(0)
190 {
191  SetBit(kInvalidObject);
192  if (!url) {
193  Error("TProofBench", "specifying a PROOF master url is mandatory - cannot continue");
194  return;
195  }
196  if (!(fProof = TProof::Open(url, proofopt)) || (fProof && !fProof->IsValid())) {
197  Error("TProofBench", "could not open a valid PROOF session - cannot continue");
198  return;
199  }
200  // Get the size of the cluster
201  fNumWrkMax = fProof->GetParallel();
202  if (fProof->UseDynamicStartup() && TProof::GetEnvVars()) {
203  // It must be passed as PROOF option 'workers=N' and recorded in the envs vars
204  TNamed *n = (TNamed *) TProof::GetEnvVars()->FindObject("PROOF_NWORKERS");
205  if (!n) {
206  Error("TProofBench", "dynamic mode: you must specify the max number of workers");
207  fProof->Close();
208  SafeDelete(fProof);
209  return;
210  }
211  TString sn(n->GetTitle());
212  if (sn.IsDigit()) fNumWrkMax = sn.Atoi();
213  if (!sn.IsDigit()) {
214  Error("TProofBench", "dynamic mode: wrong specification of the max number of"
215  " workers ('%s')", n->GetTitle());
216  fProof->Close();
217  SafeDelete(fProof);
218  return;
219  }
220  }
221  if (fNumWrkMax <= 0) {
222  Error("TProofBench", "wrong max number of workers ('%d')", fNumWrkMax);
223  fProof->Close();
224  SafeDelete(fProof);
225  return;
226  }
227  // By default we use the same instance for dataset actions
228  fProofDS = fProof;
229  // The object is now valid
230  ResetBit(kInvalidObject);
231  // Identifying string
232  TUrl u(url);
233  TString host(TString::Format("PROOF at %s", u.GetHost()));
234  if (!strcmp(u.GetProtocol(), "lite")) host.Form("PROOF-Lite on %s", gSystem->HostName());
235  fDescription = new TNamed("PB_description",
236  TString::Format("%s, %d workers", host.Data(), fNumWrkMax).Data());
237  Printf(" Run description: %s", fDescription->GetTitle());
238  // Set output file
239  if (SetOutFile(outfile, kFALSE) != 0)
240  Warning("TProofBench", "problems opening '%s' - ignoring: use SetOutFile to try"
241  " again or with another file", outfile);
242 }
243 
244 ////////////////////////////////////////////////////////////////////////////////
245 /// Destructor
246 
247 TProofBench::~TProofBench()
248 {
249  CloseOutFile();
250  if (fUnlinkOutfile) gSystem->Unlink(fOutFileName);
251  SafeDelete(fReadType);
252  SafeDelete(fRunCPU);
253  SafeDelete(fRunDS);
254  SafeDelete(fDescription);
255 }
256 
257 ////////////////////////////////////////////////////////////////////////////////
258 /// Set the otuput file
259 /// Return 0 on success, -1 on error
260 
261 Int_t TProofBench::OpenOutFile(Bool_t wrt, Bool_t verbose)
262 {
263  // Remove any bad file
264  if (fOutFile && fOutFile->IsZombie()) SafeDelete(fOutFile);
265 
266  Int_t rc = 0;
267  if (!fOutFile && fOutFileName.Length() > 0) {
268  const char *mode = 0;
269  if (wrt)
270  mode = gSystem->AccessPathName(fOutFileName) ? "RECREATE" : "UPDATE";
271  else
272  mode = "READ";
273  if (!(fOutFile = TFile::Open(fOutFileName, mode)) || (fOutFile && fOutFile->IsZombie())) {
274  if (verbose)
275  Warning("OpenOutFile", "problems opening '%s' - ignoring: use SetOutFile to try"
276  " again or with another file", fOutFileName.Data());
277  rc = -1;
278  }
279  if (fOutFile) {
280  gROOT->GetListOfFiles()->Remove(fOutFile);
281  if (!strcmp(mode, "RECREATE")) {
282  // Save the description string
283  fOutFile->cd();
284  fDescription->Write();
285  }
286  }
287  }
288  return rc;
289 }
290 
291 ////////////////////////////////////////////////////////////////////////////////
292 /// Set the output file
293 /// Return 0 on success, -1 on error
294 
295 Int_t TProofBench::SetOutFile(const char *outfile, Bool_t verbose)
296 {
297  Int_t rc = 0;
298  // Close existing file, if any
299  if (fOutFile) {
300  if (!fOutFile->IsZombie()) fOutFile->Close();
301  SafeDelete(fOutFile);
302  }
303 
304  fOutFileName = outfile;
305  if (fOutFileName == "<default>") {
306  // Default output file: proofbench-<master>-<DayMonthYear-hhmm>.root
307  TDatime dat;
308  const char *lite = (fProof->IsLite()) ? "-lite" : "";
309  fOutFileName.Form("proofbench-%s%s-%dw-%d-%.2d%.2d.root",
310  fProof->GetMaster(), lite, fNumWrkMax,
311  dat.GetDate(), dat.GetHour(), dat.GetMinute());
312  Info("SetOutFile", "using default output file: '%s'", fOutFileName.Data());
313  fUnlinkOutfile = kTRUE;
314  }
315  if (!fOutFileName.IsNull()) {
316  if ((rc = OpenOutFile(kTRUE, kFALSE)) != 0 && verbose)
317  Warning("SetOutFile", "problems opening '%s' - ignoring: use SetOutFile to try"
318  " again or with another file", outfile);
319  }
320  return rc;
321 }
322 
323 ////////////////////////////////////////////////////////////////////////////////
324 /// Close output file
325 
326 void TProofBench::CloseOutFile()
327 {
328  if (SetOutFile(0) != 0)
329  Warning("CloseOutFile", "problems closing '%s'", fOutFileName.Data());
330 }
331 
332 ////////////////////////////////////////////////////////////////////////////////
333 /// Perform the CPU run
334 /// Return 0 on success, -1 on error
335 
336 Int_t TProofBench::RunCPU(Long64_t nevents, Int_t start, Int_t stop, Int_t step)
337 {
338  // Open the file for the results
339  if (OpenOutFile(kTRUE) != 0) {
340  Error("RunCPU", "problems opening '%s' to save the result", fOutFileName.Data());
341  return -1;
342  }
343  fUnlinkOutfile = kFALSE;
344 
345  SafeDelete(fRunCPU);
346  TPBHistType *htype = new TPBHistType(TPBHistType::kHist1D); // Owned by the input list
347  fRunCPU = new TProofBenchRunCPU(htype, fNHist, fOutFile);
348  if (!fCPUSel.IsNull()) fRunCPU->SetSelName(fCPUSel);
349  if (!fSelOption.IsNull()) fRunDS->SetSelOption(fSelOption);
350  if (!fCPUPar.IsNull()) fRunCPU->SetParList(fCPUPar);
351  fRunCPU->Run(nevents, start, stop, step, fNtries, fDebug, -1);
352 
353  // Close the file
354  if (SetOutFile(0) != 0)
355  Warning("RunCPU", "problems closing '%s'", fOutFileName.Data());
356 
357  // Done
358  return 0;
359 }
360 
361 ////////////////////////////////////////////////////////////////////////////////
362 /// Perform the CPU run scanning over the number of workers per node
363 /// Return 0 on success, -1 on error
364 
365 Int_t TProofBench::RunCPUx(Long64_t nevents, Int_t start, Int_t stop)
366 {
367  // Open the file for the results
368  if (OpenOutFile(kTRUE) != 0) {
369  Error("RunCPUx", "problems opening '%s' to save the result", fOutFileName.Data());
370  return -1;
371  }
372  fUnlinkOutfile = kFALSE;
373 
374  SafeDelete(fRunCPU);
375  TPBHistType *htype = new TPBHistType(TPBHistType::kHist1D); // Owned by the input list
376  fRunCPU = new TProofBenchRunCPU(htype, fNHist, fOutFile);
377  if (!fCPUSel.IsNull()) fRunCPU->SetSelName(fCPUSel);
378  if (!fSelOption.IsNull()) fRunDS->SetSelOption(fSelOption);
379  if (!fCPUPar.IsNull()) fRunCPU->SetParList(fCPUPar);
380  fRunCPU->Run(nevents, start, stop, -2, fNtries, fDebug, -1);
381 
382  // Close the file
383  if (SetOutFile(0) != 0)
384  Warning("RunCPUx", "problems closing '%s'", fOutFileName.Data());
385 
386  // Done
387  return 0;
388 }
389 
390 ////////////////////////////////////////////////////////////////////////////////
391 /// Draw the CPU speedup plot.
392 /// opt = 'typewhat', e.g. 'std:max:'
393 /// type = 'std:' draw standard evt/s plot
394 /// 'stdx:' draw standard evt/s plot, 1 worker per node
395 /// 'norm:' draw normalized plot
396 /// 'normx:' draw normalized plot, 1 worker per node
397 /// what = 'max:' draw max rate
398 /// 'avg:' draw average rate
399 /// 'all:' draw max and average rate on same plot (default)
400 /// dofit = 0 no fit
401 /// 1 fit with the relevant '1st degree related' function
402 /// 2 fit with the relevant '2nd degree related' function
403 /// 3 fit with varying rcpu function
404 /// n0 = for dofit == 3, number of real cores
405 /// n1 = for dofit == 3, number of total cores (real + hyperthreaded)
406 ///
407 
408 void TProofBench::DrawCPU(const char *outfile, const char *opt, Bool_t verbose,
409  Int_t dofit, Int_t n0, Int_t n1)
410 {
411  // Get the TProfile an create the graphs
412  TFile *fout = TFile::Open(outfile, "READ");
413  if (!fout || (fout && fout->IsZombie())) {
414  ::Error("DrawCPU", "could not open file '%s' ...", outfile);
415  return;
416  }
417 
418  // Get description
419  TString description("<not available>");
420  TNamed *nmdesc = (TNamed *) fout->Get("PB_description");
421  if (nmdesc) description = nmdesc->GetTitle();
422 
423  // Parse option
424  TString oo(opt);
425  Bool_t isNorm = (oo.Contains("norm")) ? kTRUE : kFALSE;
426  Bool_t isX = (oo.Contains("stdx:") || oo.Contains("normx:")) ? kTRUE : kFALSE;
427  Bool_t doAvg = kTRUE, doMax = kTRUE;
428  if (oo.Contains("avg:")) doMax = kFALSE;
429  if (oo.Contains("max:")) doAvg = kFALSE;
430 
431  const char *dirn = (isX) ? "RunCPUx" : "RunCPU";
432  TDirectory *d = (TDirectory *) fout->Get(dirn);
433  if (!d) {
434  ::Error("DrawCPU", "could not find directory '%s' ...", dirn);
435  fout->Close();
436  delete fout;
437  return;
438  }
439  d->cd();
440 
441  TString hprofn, hmaxn;
442  const char *lx = (isX) ? "_x" : "";
443  const char *ln = (isNorm) ? "Norm" : "Prof";
444  hprofn.Form("%s%s_CPU_QR_Evts", ln, lx);
445  hmaxn.Form("%s%s_CPU_PS_MaxEvts", ln, lx);
446 
447  Double_t xmin = -1., xmax = -1.;
448  Double_t ami = -1., amx = -1., mmi = -1., mmx = -1.;
449  Int_t kamx = -1, kmmx = -1, nbins = -1;
450  Double_t ymx = -1., ymi = -1.;
451 
452  TProfile *pf = 0;
453  Int_t kmx = -1;
454 
455  TProfile *pfav = 0;
456  TGraphErrors *grav = 0;
457  if (doAvg) {
458  if (!(grav = GetGraph(d, hprofn, nbins, xmin, xmax, ami, amx, kamx, pfav))) {
459  ::Error("DrawCPU", "could not find '%s' ...", hprofn.Data());
460  fout->Close();
461  delete fout;
462  return;
463  }
464  ymx = amx;
465  ymi = ami;
466  pf = pfav;
467  kmx = kamx;
468  }
469  TProfile *pfmx = 0;
470  TGraphErrors *grmx = 0;
471  if (doMax) {
472  if (!(grmx = GetGraph(d, hmaxn, nbins, xmin, xmax, mmi, mmx, kmmx, pfmx))) {
473  ::Warning("DrawCPU", "could not find '%s': feature added in 5.34/11", hmaxn.Data());
474  if (!grav) {
475  // Nothing to do if not asked for the average
476  fout->Close();
477  delete fout;
478  return;
479  }
480  doMax = kFALSE;
481  }
482  if (mmx > ymx) ymx = mmx;
483  if ((ymi > 0 && mmi < ymi) || (ymi < 0.)) ymi = mmi;
484  pf = pfmx;
485  kmx = kmmx;
486  }
487 
488  // Create the canvas
489  TCanvas *cpu = new TCanvas("cpu", "Rate vs wrks",204,69,1050,502);
490  cpu->Range(-3.106332,0.7490716,28.1362,1.249867);
491 
492  TH1F *hgr = new TH1F("Graph-CPU"," CPU speed-up", nbins*4, xmin, xmax);
493  hgr->SetMaximum(ymx + (ymx-ymi)*0.2);
494  hgr->SetMinimum(0);
495  if (isNorm) hgr->SetMaximum(ymx*1.2);
496  hgr->SetDirectory(0);
497  hgr->SetStats(0);
498  hgr->GetXaxis()->SetTitle(pf->GetXaxis()->GetTitle());
499  hgr->GetXaxis()->CenterTitle(true);
500  hgr->GetXaxis()->SetLabelSize(0.05);
501  hgr->GetXaxis()->SetTitleSize(0.06);
502  hgr->GetXaxis()->SetTitleOffset(0.62);
503  hgr->GetYaxis()->SetTitleSize(0.08);
504  hgr->GetYaxis()->SetTitleOffset(0.52);
505  hgr->GetYaxis()->SetTitle("Rate (events/s)");
506 
507  TLegend *leg = 0;
508  if (isNorm) {
509  leg = new TLegend(0.7, 0.8, 0.9, 0.9);
510  } else {
511  leg = new TLegend(0.1, 0.8, 0.3, 0.9);
512  }
513 
514  gStyle->SetOptTitle(0);
515  TGraphErrors *gr = 0;
516  if (doAvg) {
517  grav->SetFillColor(1);
518  grav->SetLineColor(13);
519  grav->SetMarkerColor(4);
520  grav->SetMarkerStyle(21);
521  grav->SetMarkerSize(1.2);
522  grav->SetHistogram(hgr);
523 
524  if (verbose) grav->Print();
525  grav->Draw("alp");
526  leg->AddEntry(grav, "Average", "P");
527  gr = grav;
528  }
529  if (doMax) {
530  grmx->SetFillColor(1);
531  grmx->SetLineColor(13);
532  grmx->SetMarkerColor(2);
533  grmx->SetMarkerStyle(29);
534  grmx->SetMarkerSize(1.8);
535  grmx->SetHistogram(hgr);
536 
537  if (verbose) grmx->Print();
538  if (doAvg) {
539  grmx->Draw("lpSAME");
540  } else {
541  grmx->Draw("alp");
542  }
543  leg->AddEntry(grmx, "Maximum", "P");
544  gr = grmx;
545  }
546  leg->Draw();
547  gPad->Update();
548 
549  if (dofit > 0) {
550  // Make sure the fitting functions are defined
551  Double_t xmi = 0.9;
552  if (nbins > 5) xmi = 1.5;
553  AssertFittingFun(xmi, nbins + .1);
554 
555  // Starting point for the parameters and fit
556  Double_t normrate = -1.;
557  if (dofit == 1) {
558  if (isNorm) {
559  fgFp1n->SetParameter(0, pf->GetBinContent(1));
560  fgFp1n->SetParameter(1, pf->GetBinContent(nbins-1));
561  gr->Fit(fgFp1n);
562  if (verbose) fgFp1n->Print();
563  normrate = fgFp1n->GetParameter(1);
564  } else {
565  fgFp1->SetParameter(0, 0.);
566  fgFp1->SetParameter(1, pf->GetBinContent(1));
567  gr->Fit(fgFp1);
568  if (verbose) fgFp1->Print();
569  normrate = fgFp1->Derivative(1.);
570  }
571  } else if (dofit == 2) {
572  if (isNorm) {
573  fgFp2n->SetParameter(0, pf->GetBinContent(1));
574  fgFp2n->SetParameter(1, pf->GetBinContent(nbins-1));
575  fgFp2n->SetParameter(2, 0.);
576  gr->Fit(fgFp2n);
577  if (verbose) fgFp2n->Print();
578  normrate = fgFp2n->GetParameter(1);
579  } else {
580  fgFp2->SetParameter(0, 0.);
581  fgFp2->SetParameter(1, pf->GetBinContent(1));
582  fgFp2->SetParameter(2, 0.);
583  gr->Fit(fgFp2);
584  if (verbose) fgFp2->Print();
585  normrate = fgFp2->Derivative(1.);
586  }
587  } else {
588  // Starting point for the parameters and fit
589  gFioVn0 = (n0 > 0) ? n0 : (Int_t) (nbins + .1)/2.;
590  gFioVn1 = (n1 > 0) ? n1 : (Int_t) (nbins + .1);
591  if (isNorm) {
592  fgFp3n->SetParameter(0, 0.);
593  fgFp3n->SetParameter(1, pf->GetBinContent(1));
594  fgFp3n->SetParameter(2, pf->GetBinContent(nbins-1));
595  gr->Fit(fgFp3n);
596  if (verbose) fgFp3n->Print();
597  normrate = pf->GetBinContent(1);
598  } else {
599  fgFp3->SetParameter(0, 0.);
600  fgFp3->SetParameter(1, 0.);
601  fgFp3->SetParameter(2, pf->GetBinContent(1));
602  gr->Fit(fgFp3);
603  if (verbose) fgFp3->Print();
604  normrate = fgFp3->Derivative(1.);
605  }
606  }
607 
608  // Notify the cluster performance parameters
609  if (!isNorm) {
610  printf("* ************************************************************ *\n");
611  printf("* *\r");
612  printf("* Cluster: %s\n", description.Data());
613  printf("* Performance measurement from scalability plot: *\n");
614  printf("* *\r");
615  printf("* rate max: %.3f\tmegaRNGPS (@ %d workers)\n", ymx/1000000, kmx);
616  printf("* *\r");
617  printf("* per-worker rate: %.3f\tmegaRNGPS \n", normrate/1000000);
618  printf("* ************************************************************ *\n");
619  } else {
620  printf("* ************************************************************ *\n");
621  printf("* *\r");
622  printf("* Cluster: %s\n", description.Data());
623  printf("* *\r");
624  printf("* Per-worker rate from normalized plot: %.3f\tmegaRNGPS\n", normrate/1000000);
625  printf("* ************************************************************ *\n");
626  }
627  }
628  // Close the file
629  fout->Close();
630  if (grav) fgGraphs->Add(grav);
631  if (grmx) fgGraphs->Add(grmx);
632 }
633 
634 ////////////////////////////////////////////////////////////////////////////////
635 /// Get from TDirectory 'd' the TProfile named 'pfn' and create the graph.
636 /// Return also the max y in mx.
637 
638 TGraphErrors *TProofBench::GetGraph(TDirectory *d, const char *pfn, Int_t &nb,
639  Double_t &xmi, Double_t &xmx,
640  Double_t &ymi, Double_t &ymx, Int_t &kmx, TProfile *&pf)
641 {
642  // Sanity checks
643  if (!d || !pfn || (pfn && strlen(pfn) <= 0)) {
644  ::Error("TProofBench::GetGraph", "directory or name not defined!");
645  return (TGraphErrors *)0;
646  }
647 
648  TList *keylist = d->GetListOfKeys();
649  TKey *key = 0;
650  TIter nxk(keylist);
651  while ((key = (TKey *) nxk())) {
652  if (TString(key->GetName()).BeginsWith(pfn)) {
653  pf = (TProfile *) d->Get(key->GetName());
654  break;
655  }
656  }
657  // Sanity checks
658  if (!pf) {
659  ::Error("TProofBench::GetGraph", "TProfile for '%s' not found in directory '%s'", pfn, d->GetName());
660  return (TGraphErrors *)0;
661  }
662 
663  nb = pf->GetNbinsX();
664  TGraphErrors *gr = new TGraphErrors(nb);
665  gr->SetName(TString::Format("Graph_%s", pfn));
666  Double_t xx, ex, yy, ey;
667  ymi = pf->GetBinContent(1);
668  ymx = ymi;
669  xmi = pf->GetBinCenter(1) - pf->GetBinWidth(1)/2. ;
670  xmx = pf->GetBinCenter(nb) + pf->GetBinWidth(nb)/2. ;
671  kmx = -1;
672  for (Int_t k = 1;k <= nb; k++) {
673  xx = pf->GetBinCenter(k);
674  ex = pf->GetBinWidth(k) * .001;
675  yy = pf->GetBinContent(k);
676  ey = pf->GetBinError(k);
677  if (k == 1) {
678  ymi = yy;
679  ymx = yy;
680  kmx = k;
681  } else {
682  if (yy < ymi) ymi = yy;
683  if (yy > ymx) { ymx = yy; kmx = k; }
684  }
685  gr->SetPoint(k-1, xx, yy);
686  gr->SetPointError(k-1, ex, ey);
687  }
688 
689  // Done
690  return gr;
691 }
692 
693 ////////////////////////////////////////////////////////////////////////////////
694 /// Make sure that the fitting functions are defined
695 
696 void TProofBench::AssertFittingFun(Double_t mi, Double_t mx)
697 {
698  if (!fgFp1) {
699  fgFp1 = new TF1("funp1", funp1, mi, mx, 2);
700  fgFp1->SetParNames("offset", "slope");
701  }
702 
703  if (!fgFp1n) {
704  fgFp1n = new TF1("funp1n", funp1n, mi, mx, 2);
705  fgFp1n->SetParNames("decay", "norm rate");
706  }
707 
708  if (!fgFp2) {
709  fgFp2 = new TF1("funp2", funp2, mi, mx, 3);
710  fgFp2->SetParNames("offset", "slope", "deviation");
711  }
712 
713  if (!fgFp2n) {
714  fgFp2n = new TF1("funp2n", funp2n, mi, mx, 3);
715  fgFp2n->SetParNames("decay", "norm rate", "deviation");
716  }
717 
718  if (!fgFp3) {
719  fgFp3 = new TF1("funcpuv", funcpuv, mi, mx, 3);
720  fgFp3->SetParNames("offset", "slope real", "slope hyper");
721  }
722 
723  if (!fgFp3n) {
724  fgFp3n = new TF1("funcpuvn", funcpuvn, mi, mx, 3);
725  fgFp3n->SetParNames("offset", "slope real", "slope hyper");
726  }
727 
728  if (!fgFio) {
729  fgFio = new TF1("funio", funio, mi, mx, 3);
730  fgFio->SetParNames("R1", "RIO", "TotIO");
731  }
732  if (!fgFioV) {
733  fgFioV = new TF1("funiov", funiov, mi, mx, 5);
734  fgFioV->SetParNames("rio", "b1", "b2", "nc", "ri");
735  }
736 
737 }
738 
739 ////////////////////////////////////////////////////////////////////////////////
740 
741 class fileDesc : public TNamed {
742 public:
743  Long_t fMtime; // Modification time
744  TString fDesc; // Test description string, if any
745  fileDesc(const char *n, const char *o,
746  Long_t t, const char *d) : TNamed(n, o), fMtime(t), fDesc(d) { }
747  Int_t Compare(const TObject *o) const {
748  const fileDesc *fd = static_cast<const fileDesc *>(o);
749  if (!fd || (fd && fd->fMtime == fMtime)) return 0;
750  if (fMtime < fd->fMtime) return -1;
751  return 1;
752  }
753 };
754 
755 ////////////////////////////////////////////////////////////////////////////////
756 /// Get performance specs. Check file 'path', or files in directory 'path'
757 /// (default current directory).
758 /// The degree of the polynomial used for the fit is 'degfit' (default 1).
759 
760 void TProofBench::GetPerfSpecs(const char *path, Int_t degfit)
761 {
762  // Locate the file (ask if many)
763  TString pp(path), fn, oo;
764  if (pp.IsNull()) pp = gSystem->WorkingDirectory();
765  FileStat_t st;
766  if (gSystem->GetPathInfo(pp.Data(), st) != 0) {
767  ::Error("TProofBench::GetPerfSpecs", "path '%s' could not be stat'ed - abort", pp.Data());
768  return;
769  }
770  TSortedList filels;
771  if (R_ISDIR(st.fMode)) {
772  // Scan the directory
773  void *dirp = gSystem->OpenDirectory(pp.Data());
774  if (!dirp) {
775  ::Error("TProofBench::GetPerfSpecs", "directory path '%s' could nto be open - abort", pp.Data());
776  return;
777  }
778  const char *ent = 0;
779  while ((ent = gSystem->GetDirEntry(dirp))) {
780  if (!strcmp(ent, ".") || !strcmp(ent, "..")) continue;
781  fn.Form("%s/%s", pp.Data(), ent);
782  if (gSystem->GetPathInfo(fn.Data(), st) != 0) continue;
783  if (!R_ISREG(st.fMode)) continue;
784  fn += "?filetype=raw";
785  TFile *f = TFile::Open(fn);
786  if (!f) continue;
787  char rr[5] = {0};
788  if (!f->ReadBuffer(rr, 4)) {
789  if (!strncmp(rr, "root", 4)) {
790  SafeDelete(f);
791  fn.ReplaceAll("?filetype=raw", "");
792  if ((f = TFile::Open(fn))) {
793  TString desc("<no decription>");
794  TNamed *nmdesc = (TNamed *) f->Get("PB_description");
795  if (nmdesc) desc = nmdesc->GetTitle();
796  if (f->GetListOfKeys()->FindObject("RunCPU"))
797  filels.Add(new fileDesc(fn, "std:", st.fMtime, desc.Data()));
798  if (f->GetListOfKeys()->FindObject("RunCPUx"))
799  filels.Add(new fileDesc(fn, "stdx:", st.fMtime, desc.Data()));
800  } else {
801  ::Warning("TProofBench::GetPerfSpecs", "problems opening '%s'", fn.Data());
802  }
803  }
804  }
805  SafeDelete(f);
806  }
807  } else if (!R_ISREG(st.fMode)) {
808  ::Error("TProofBench::GetPerfSpecs",
809  "path '%s' not a regular file nor a directory - abort", pp.Data());
810  return;
811  } else {
812  // This is the file
813  fn = pp;
814  // Check it
815  TString emsg;
816  Bool_t isOk = kFALSE;
817  if (gSystem->GetPathInfo(fn.Data(), st) == 0) {
818  fn += "?filetype=raw";
819  TFile *f = TFile::Open(fn);
820  if (f) {
821  char rr[5] = {0};
822  if (!(f->ReadBuffer(rr, 4))) {
823  if (!strncmp(rr, "root", 4)) {
824  fn.ReplaceAll("?filetype=raw", "");
825  if ((f = TFile::Open(fn))) {
826  if (f->GetListOfKeys()->FindObject("RunCPU")) oo = "std:";
827  if (f->GetListOfKeys()->FindObject("RunCPUx")) oo = "stdx:";
828  SafeDelete(f);
829  if (!oo.IsNull()) {
830  isOk = kTRUE;
831  } else {
832  emsg.Form("path '%s' does not contain the relevant dirs - abort", fn.Data());
833  }
834  } else {
835  emsg.Form("path '%s' cannot be open - abort", fn.Data());
836  }
837  } else {
838  emsg.Form("'%s' is not a ROOT file - abort", fn.Data());
839  }
840  } else {
841  emsg.Form("could not read first 4 bytes from '%s' - abort", fn.Data());
842  }
843  SafeDelete(f);
844  } else {
845  emsg.Form("path '%s' cannot be open in raw mode - abort", fn.Data());
846  }
847  } else {
848  emsg.Form("path '%s' cannot be stated - abort", fn.Data());
849  }
850  if (!isOk) {
851  ::Error("TProofBench::GetPerfSpecs", "%s", emsg.Data());
852  return;
853  }
854  }
855 
856  fileDesc *nm = 0;
857  // Ask the user, if more then 1
858  if (filels.GetSize() == 1) {
859  nm = (fileDesc *) filels.First();
860  fn = nm->GetName();
861  oo = nm->GetTitle();
862  } else if (filels.GetSize() > 1) {
863  TIter nxf(&filels);
864  Int_t idx = 0;
865  Printf("Several possible files found:");
866  while ((nm = (fileDesc *) nxf())) {
867  Printf(" %d\t%s\t%s\t%s (file: %s)", idx++, nm->GetTitle(),
868  TTimeStamp(nm->fMtime).AsString("s"), nm->fDesc.Data(), nm->GetName());
869  }
870  TString a(Getline(TString::Format("Make your choice [%d] ", idx-1)));
871  if (a.IsNull() || a[0] == '\n') a.Form("%d", idx-1);
872  idx = a.Atoi();
873  if ((nm = (fileDesc *) filels.At(idx))) {
874  fn = nm->GetName();
875  oo = nm->GetTitle();
876  } else {
877  ::Error("TProofBench::GetPerfSpecs", "chosen index '%d' does not exist - abort", idx);
878  return;
879  }
880  } else {
881  if (fn.IsNull()) {
882  ::Error("TProofBench::GetPerfSpecs",
883  "path '%s' is a directory but no ROOT file found in it - abort", pp.Data());
884  return;
885  }
886  }
887 
888  // Now get the specs
889  TProofBench::DrawCPU(fn.Data(), oo.Data(), kFALSE, degfit);
890 }
891 
892 ////////////////////////////////////////////////////////////////////////////////
893 /// Perform a test using dataset 'dset'
894 /// Return 0 on success, -1 on error
895 /// Open the file for the results
896 
897 Int_t TProofBench::RunDataSet(const char *dset,
898  Int_t start, Int_t stop, Int_t step)
899 {
900  if (OpenOutFile(kTRUE) != 0) {
901  Error("RunDataSet", "problems opening '%s' to save the result", fOutFileName.Data());
902  return -1;
903  }
904  fUnlinkOutfile = kFALSE;
905 
906  if (fReleaseCache) ReleaseCache(dset);
907  SafeDelete(fRunDS);
908  TPBReadType *readType = fReadType;
909  if (!readType) readType = new TPBReadType(TPBReadType::kReadOpt);
910  fRunDS = new TProofBenchRunDataRead(fDS, readType, fOutFile);
911  if (!fDataSel.IsNull()) fRunDS->SetSelName(fDataSel);
912  if (!fSelOption.IsNull()) fRunDS->SetSelOption(fSelOption);
913  if (!fDataPar.IsNull()) fRunDS->SetParList(fDataPar);
914  fRunDS->SetReleaseCache(fReleaseCache);
915  fRunDS->Run(dset, start, stop, step, fNtries, fDebug, -1);
916  SafeDelete(readType);
917 
918  // Close the file
919  if (SetOutFile(0) != 0)
920  Warning("RunDataSet", "problems closing '%s'", fOutFileName.Data());
921 
922  // Done
923  return 0;
924 }
925 
926 ////////////////////////////////////////////////////////////////////////////////
927 /// Perform a test using dataset 'dset' scanning over the number of workers
928 /// per node.
929 /// Return 0 on success, -1 on error
930 /// Open the file for the results
931 
932 Int_t TProofBench::RunDataSetx(const char *dset, Int_t start, Int_t stop)
933 {
934  if (OpenOutFile(kTRUE) != 0) {
935  Error("RunDataSetx", "problems opening '%s' to save the result", fOutFileName.Data());
936  return -1;
937  }
938  fUnlinkOutfile = kFALSE;
939 
940  ReleaseCache(dset);
941  SafeDelete(fRunDS);
942  TPBReadType *readType = fReadType;
943  if (!readType) readType = new TPBReadType(TPBReadType::kReadOpt);
944  fRunDS = new TProofBenchRunDataRead(fDS, readType, fOutFile);
945  if (!fDataSel.IsNull()) fRunDS->SetSelName(fDataSel);
946  if (!fSelOption.IsNull()) fRunDS->SetSelOption(fSelOption);
947  if (!fDataPar.IsNull()) fRunDS->SetParList(fDataPar);
948  fRunDS->Run(dset, start, stop, -2, fNtries, fDebug, -1);
949  SafeDelete(readType);
950 
951  // Close the file
952  if (SetOutFile(0) != 0)
953  Warning("RunDataSetx", "problems closing '%s'", fOutFileName.Data());
954 
955  // Done
956  return 0;
957 }
958 
959 ////////////////////////////////////////////////////////////////////////////////
960 /// Draw the CPU speedup plot.
961 /// opt = 'typewhat', e.g. 'std:max:'
962 /// type = 'std:' draw standard plot
963 /// 'stdx:' draw standard plot, 1 worker per node
964 /// 'norm:' draw normalized plot
965 /// 'normx:' draw normalized plot, 1 worker per node
966 /// what = 'max:' draw max rate
967 /// 'avg:' draw average rate
968 /// 'all:' draw max and average rate on same plot (default)
969 /// type = 'mbs' MB/s scaling plots (default)
970 /// 'evts' Event/s scaling plots
971 /// dofit = 0 no fit
972 /// 1 fit with default 3 parameter saturated I/O formula
973 /// 2 fit with 4 parameter saturated I/O formula (varying Rcpu)
974 /// n0 = for dofit == 2, number of real cores
975 /// n1 = for dofit == 2, number of total cores (real + hyperthreaded)
976 ///
977 
978 void TProofBench::DrawDataSet(const char *outfile,
979  const char *opt, const char *type, Bool_t verbose,
980  Int_t dofit, Int_t n0, Int_t n1)
981 {
982  // Get the TProfile an create the graphs
983  TFile *fout = TFile::Open(outfile, "READ");
984  if (!fout || (fout && fout->IsZombie())) {
985  ::Error("DrawDataSet", "could not open file '%s' ...", outfile);
986  return;
987  }
988 
989  // Get description
990  TString description("<not available>");
991  TNamed *nmdesc = (TNamed *) fout->Get("PB_description");
992  if (nmdesc) description = nmdesc->GetTitle();
993 
994  // Parse option
995  TString oo(opt);
996  Bool_t isNorm = (oo.Contains("norm")) ? kTRUE : kFALSE;
997  Bool_t isX = (oo.Contains("stdx:") || oo.Contains("normx:")) ? kTRUE : kFALSE;
998  Bool_t doAvg = (oo.Contains("all:") || oo.Contains("avg:")) ? kTRUE : kFALSE;
999  Bool_t doMax = (oo.Contains("all:") || oo.Contains("max:")) ? kTRUE : kFALSE;
1000 
1001  const char *dirn = (isX) ? "RunDataReadx" : "RunDataRead";
1002  TDirectory *d = (TDirectory *) fout->Get(dirn);
1003  if (!d) {
1004  ::Error("DrawCPU", "could not find directory '%s' ...", dirn);
1005  fout->Close();
1006  delete fout;
1007  return;
1008  }
1009  d->cd();
1010 
1011  TString hprofn, hmaxn;
1012  const char *lx = (isX) ? "_x" : "";
1013  const char *ln = (isNorm) ? "Norm" : "Prof";
1014  Bool_t isIO = kTRUE;
1015  if (type && !strcmp(type, "evts")) {
1016  hprofn.Form("%s%s_DataRead_QR_Evts", ln, lx);
1017  hmaxn.Form("%s%s_DataRead_PS_MaxEvts", ln, lx);
1018  isIO = kFALSE;
1019  } else {
1020  hprofn.Form("%s%s_DataRead_QR_IO", ln, lx);
1021  hmaxn.Form("%s%s_DataRead_PS_MaxIO", ln, lx);
1022  }
1023 
1024  Double_t xmin = -1., xmax = -1.;
1025  Double_t ami = -1., amx = -1., mmi = -1., mmx = -1.;
1026  Int_t kamx = -1, kmmx = -1, nbins = -1;
1027  Double_t ymx = -1., ymi = -1.;
1028 
1029  TProfile *pf = 0;
1030  Int_t kmx = -1;
1031 
1032  TProfile *pfav = 0;
1033  TGraphErrors *grav = 0;
1034  if (doAvg) {
1035  if (!(grav = GetGraph(d, hprofn, nbins, xmin, xmax, ami, amx, kamx, pfav))) {
1036  ::Error("DrawCPU", "could not find '%s' ...", hprofn.Data());
1037  fout->Close();
1038  delete fout;
1039  return;
1040  }
1041  ymx = amx;
1042  ymi = ami;
1043  pf = pfav;
1044  kmx = kamx;
1045  }
1046 
1047  TProfile *pfmx = 0;
1048  TGraphErrors *grmx = 0;
1049  if (doMax) {
1050  if (!(grmx = GetGraph(d, hmaxn, nbins, xmin, xmax, mmi, mmx, kmmx, pfmx))) {
1051  ::Warning("DrawCPU", "could not find '%s': feature added in 5.34/11", hmaxn.Data());
1052  if (!grav) {
1053  // Nothing to do if not asked for the average
1054  fout->Close();
1055  delete fout;
1056  return;
1057  }
1058  doMax = kFALSE;
1059  }
1060  if (mmx > ymx) ymx = mmx;
1061  if ((ymi > 0 && mmi < ymi) || (ymi < 0.)) ymi = mmi;
1062  pf = pfmx;
1063  kmx = kmmx;
1064  }
1065 
1066  // Create the canvas
1067  TCanvas *cpu = new TCanvas("dataset", "Rate vs wrks",204,69,1050,502);
1068  cpu->Range(-3.106332,0.7490716,28.1362,1.249867);
1069 
1070  TH1F *hgr = new TH1F("Graph-DataSet"," Data Read speed-up", nbins*4, xmin, xmax);
1071  hgr->SetMaximum(ymx + (ymx-ymi)*0.2);
1072  hgr->SetMinimum(0);
1073  if (isNorm) hgr->SetMaximum(ymx*1.2);
1074  hgr->SetDirectory(0);
1075  hgr->SetStats(0);
1076  hgr->GetXaxis()->SetTitle(pf->GetXaxis()->GetTitle());
1077  hgr->GetXaxis()->CenterTitle(true);
1078  hgr->GetXaxis()->SetLabelSize(0.05);
1079  hgr->GetXaxis()->SetTitleSize(0.06);
1080  hgr->GetXaxis()->SetTitleOffset(0.62);
1081  hgr->GetYaxis()->SetLabelSize(0.06);
1082  hgr->GetYaxis()->SetTitleSize(0.08);
1083  hgr->GetYaxis()->SetTitleOffset(0.52);
1084  if (isIO) {
1085  hgr->GetYaxis()->SetTitle("Rate (MB/s)");
1086  } else {
1087  hgr->GetYaxis()->SetTitle("Rate (events/s)");
1088  }
1089 
1090  TLegend *leg = 0;
1091  if (isNorm) {
1092  leg = new TLegend(0.7, 0.8, 0.9, 0.9);
1093  } else {
1094  leg = new TLegend(0.1, 0.8, 0.3, 0.9);
1095  }
1096 
1097  TGraphErrors *gr = 0;
1098  if (doAvg) {
1099  grav->SetFillColor(1);
1100  grav->SetLineColor(13);
1101  grav->SetMarkerColor(4);
1102  grav->SetMarkerStyle(21);
1103  grav->SetMarkerSize(1.2);
1104  grav->SetHistogram(hgr);
1105 
1106  if (verbose) grav->Print();
1107  grav->Draw("alp");
1108  leg->AddEntry(grav, "Average", "P");
1109  gr = grav;
1110  }
1111  if (doMax) {
1112  grmx->SetFillColor(1);
1113  grmx->SetLineColor(13);
1114  grmx->SetMarkerColor(2);
1115  grmx->SetMarkerStyle(29);
1116  grmx->SetMarkerSize(1.8);
1117  grmx->SetHistogram(hgr);
1118 
1119  if (verbose) grmx->Print();
1120  if (doAvg) {
1121  grmx->Draw("lpSAME");
1122  } else {
1123  grmx->Draw("alp");
1124  }
1125  leg->AddEntry(grmx, "Maximum", "P");
1126  gr = grmx;
1127  }
1128  leg->Draw();
1129  gPad->Update();
1130 
1131  Double_t normrate = -1.;
1132  if (dofit > 0) {
1133  // Make sure the fitting functions are defined
1134  Double_t xmi = 0.9;
1135  if (nbins > 5) xmi = 1.5;
1136  AssertFittingFun(xmi, nbins + .1);
1137 
1138  if (dofit == 1) {
1139  // Starting point for the parameters and fit
1140  fgFio->SetParameter(0, pf->GetBinContent(1));
1141  fgFio->SetParameter(1, pf->GetBinContent(nbins-1));
1142  fgFio->SetParameter(2, pf->GetBinContent(nbins-1));
1143  gr->Fit(fgFio);
1144  if (verbose) fgFio->Print();
1145  normrate = fgFio->Derivative(1.);
1146  } else if (dofit > 1) {
1147  // Starting point for the parameters and fit
1148  gFioVn0 = (n0 > 0) ? n0 : (Int_t) (nbins + .1)/2.;
1149  gFioVn1 = (n1 > 0) ? n1 : (Int_t) (nbins + .1);
1150  fgFioV->SetParameter(0, 20.);
1151  fgFioV->SetParameter(1, pf->GetBinContent(1));
1152  fgFioV->SetParameter(2, pf->GetBinContent(1));
1153  fgFioV->SetParameter(3, 4.);
1154  fgFioV->SetParameter(4, 1000.);
1155 
1156  gr->Fit(fgFioV);
1157  if (verbose) fgFio->Print();
1158  normrate = fgFioV->Derivative(1.);
1159  }
1160  }
1161 
1162  // Notify the cluster performance parameters
1163  if (!isNorm) {
1164  printf("* ************************************************************ *\n");
1165  printf("* *\r");
1166  printf("* Cluster: %s\n", description.Data());
1167  printf("* Performance measurement from scalability plot: *\n");
1168  printf("* *\r");
1169  if (isIO) {
1170  printf("* rate max: %.3f\tMB/s (@ %d workers)\n", ymx, kmx);
1171  printf("* *\r");
1172  printf("* per-worker rate: %.3f\tMB/s \n", normrate);
1173  } else {
1174  printf("* rate max: %.3f\tevts/s (@ %d workers)\n", ymx, kmx);
1175  }
1176  printf("* ************************************************************ *\n");
1177  }
1178  // Close the file
1179  fout->Close();
1180  if (grav) fgGraphs->Add(grav);
1181  if (grmx) fgGraphs->Add(grmx);
1182 }
1183 
1184 ////////////////////////////////////////////////////////////////////////////////
1185 /// Draw the efficiency plot.
1186 /// opt = 'cpu' or 'data' (default the first found)
1187 ///
1188 
1189 void TProofBench::DrawEfficiency(const char *outfile,
1190  const char *opt, Bool_t verbose)
1191 {
1192  // Get the TProfile an create the graphs
1193  TFile *fout = TFile::Open(outfile, "READ");
1194  if (!fout || (fout && fout->IsZombie())) {
1195  ::Error("DrawEfficiency", "could not open file '%s' ...", outfile);
1196  return;
1197  }
1198 
1199  // Get description
1200  TString description("<not available>");
1201  TNamed *nmdesc = (TNamed *) fout->Get("PB_description");
1202  if (nmdesc) description = nmdesc->GetTitle();
1203 
1204  // Parse option
1205  TString oo(opt), ln("CPU");
1206  const char *dirs[4] = { "RunCPU", "RunCPUx", "RunDataRead", "RunDataReadx"};
1207  const char *labs[4] = { "CPU", "CPU", "DataRead", "DataRead"};
1208  Int_t fst = 0, lst = 3;
1209  if (oo == "cpu") {
1210  lst = 0;
1211  } else if (oo == "cpux") {
1212  fst = 1;
1213  lst = 1;
1214  } else if (oo.BeginsWith("data")) {
1215  if (oo.EndsWith("x")) {
1216  fst = 3;
1217  lst = 3;
1218  } else {
1219  fst = 2;
1220  lst = 2;
1221  }
1222  }
1223  const char *dirn = 0;
1224  TDirectory *d = 0;
1225  for (Int_t i = fst; i <= lst; i++) {
1226  if ((d = (TDirectory *) fout->Get(dirs[i]))) {
1227  dirn = dirs[i];
1228  ln = labs[i];
1229  break;
1230  }
1231  }
1232  if (!d && !dirn) {
1233  ::Error("DrawEfficiency", "could not find directory ...");
1234  fout->Close();
1235  delete fout;
1236  return;
1237  }
1238  d->cd();
1239 
1240  TString hprof;
1241  hprof.Form("Prof_%s_CPU_eff", ln.Data());
1242 
1243  Double_t xmin = -1., xmax = -1.;
1244  Int_t kmx = -1, nbins = -1;
1245  Double_t ymx = -1., ymi = -1.;
1246 
1247  TProfile *pf = 0;
1248  TGraphErrors *gr = 0;
1249  if (!(gr = GetGraph(d, hprof, nbins, xmin, xmax, ymi, ymx, kmx, pf))) {
1250  ::Error("DrawEfficiency", "could not find '%s' ...", hprof.Data());
1251  fout->Close();
1252  delete fout;
1253  return;
1254  }
1255 
1256  // Create the canvas
1257  TCanvas *cpu = new TCanvas("efficiency", "efficiency vs wrks",204,69,1050,502);
1258  cpu->Range(-3.106332,0.7490716,28.1362,1.249867);
1259 
1260  TH1F *hgr = new TH1F("Graph-Efficiency","CPU effectiveness", nbins*4, xmin, xmax);
1261  hgr->SetMaximum(1.2);
1262  hgr->SetMinimum(0);
1263  hgr->SetDirectory(0);
1264  hgr->SetStats(0);
1265  hgr->GetXaxis()->SetTitle(pf->GetXaxis()->GetTitle());
1266  hgr->GetXaxis()->CenterTitle(true);
1267  hgr->GetXaxis()->SetLabelSize(0.05);
1268  hgr->GetXaxis()->SetTitleSize(0.06);
1269  hgr->GetXaxis()->SetTitleOffset(0.62);
1270  hgr->GetYaxis()->SetLabelSize(0.06);
1271  hgr->GetYaxis()->SetTitleSize(0.08);
1272  hgr->GetYaxis()->SetTitleOffset(0.52);
1273  hgr->GetYaxis()->SetTitle("CPU effectiveness");
1274 
1275  gr->SetFillColor(1);
1276  gr->SetLineColor(13);
1277  gr->SetMarkerColor(4);
1278  gr->SetMarkerStyle(21);
1279  gr->SetMarkerSize(1.2);
1280  gr->SetHistogram(hgr);
1281 
1282  if (verbose) gr->Print();
1283  gr->Draw("alp");
1284 
1285  // Notify the cluster performance parameters
1286  printf("* ************************************************************ *\n");
1287  printf("* *\r");
1288  printf("* Cluster: %s\n", description.Data());
1289  printf("* CPU effectiveness measurement: *\n");
1290  printf("* *\r");
1291  printf("* effectiveness max: %.3f (@ %d workers)\n", ymx, kmx);
1292  printf("* *\r");
1293  printf("* ************************************************************ *\n");
1294  // Close the file
1295  fout->Close();
1296  if (gr) fgGraphs->Add(gr);
1297 }
1298 
1299 ////////////////////////////////////////////////////////////////////////////////
1300 /// Release memory cache for dataset 'dset'
1301 /// Return 0 on success, -1 on error
1302 
1303 Int_t TProofBench::ReleaseCache(const char *dset)
1304 {
1305  // Do it via the dataset handler
1306  if (!fDS) fDS = new TProofBenchDataSet(fProofDS);
1307  return fDS ? fDS->ReleaseCache(dset) : -1;
1308 }
1309 
1310 ////////////////////////////////////////////////////////////////////////////////
1311 /// Physically remove the dataset 'dset', i.e. remove the dataset and the files
1312 /// it describes
1313 /// Return 0 on success, -1 on error
1314 
1315 Int_t TProofBench::RemoveDataSet(const char *dset)
1316 {
1317  // Do it via the dataset handler
1318  if (!fDS) fDS = new TProofBenchDataSet(fProofDS);
1319  return fDS ? fDS->RemoveFiles(dset) : -1;
1320 }
1321 
1322 ////////////////////////////////////////////////////////////////////////////////
1323 /// Create the largest dataset for the run.
1324 /// Defaults for
1325 /// dataset name, filename root
1326 /// are
1327 /// "BenchDataSet", "event"
1328 /// respectively.
1329 /// These can be changed via dset and fnroot, respectively.
1330 /// The string 'fnroot' defines the location of the files, interpreted as an URL.
1331 /// Examples:
1332 /// fnroot files
1333 /// 'event' <datadir>/event_<ord>_<#>.root
1334 /// '/mss/event' /mss/event_<ord>_<#>.root
1335 /// 'root://srv//mss/event?remote=1'
1336 /// root://srv//mss/event_<ord>_<#>?remote=1.root
1337 /// Default selector is TSelEventGen. Use SetDataGenSel and SetDataGenPar to change it
1338 /// and to pass the list of PARs defining the alternative selector.
1339 /// The argument 'nevt' controls the number of events per file (-1 for the default,
1340 /// which is 30000).
1341 /// Return 0 on success, -1 on error
1342 
1343 Int_t TProofBench::MakeDataSet(const char *dset, Long64_t nevt, const char *fnroot,
1344  Bool_t regenerate)
1345 {
1346  if (dset && strlen(dset) > 0) fDataSet = dset;
1347 
1348  // Load the selector, if needed
1349  if (!TClass::GetClass(fDataGenSel)) {
1350  // Is it the default selector?
1351  if (fDataGenSel == kPROOF_BenchSelDataGenDef) {
1352  // Load the parfile
1353  TString par = TString::Format("%s/%s%s.par", TROOT::GetEtcDir().Data(), kPROOF_BenchParDir, kPROOF_BenchDataSelPar);
1354  Info("MakeDataSet", "uploading '%s' ...", par.Data());
1355  if (fProof->UploadPackage(par) != 0) {
1356  Error("MakeDataSet", "problems uploading '%s' - cannot continue", par.Data());
1357  return -1;
1358  }
1359  Info("MakeDataSet", "enabling '%s' ...", kPROOF_BenchDataSelPar);
1360  if (fProof->EnablePackage(kPROOF_BenchDataSelPar) != 0) {
1361  Error("MakeDataSet", "problems enabling '%s' - cannot continue", kPROOF_BenchDataSelPar);
1362  return -1;
1363  }
1364  } else {
1365  if (fDataGenPar.IsNull()) {
1366  Error("MakeDataSet", "you should load the class '%s' before running the benchmark", fDataGenSel.Data());
1367  return -1;
1368  }
1369  }
1370  // Load additional PAR files, if any or required by the alternative selector
1371  TString par;
1372  Int_t from = 0;
1373  while (fDataGenPar.Tokenize(par, from, ",")) {
1374  Info("MakeDataSet", "Uploading '%s' ...", par.Data());
1375  if (fProof->UploadPackage(par) != 0) {
1376  Error("MakeDataSet", "problems uploading '%s' - cannot continue", par.Data());
1377  return -1;
1378  }
1379  Info("MakeDataSet", "Enabling '%s' ...", par.Data());
1380  if (fProof->EnablePackage(par) != 0) {
1381  Error("MakeDataSet", "problems enabling '%s' - cannot continue", par.Data());
1382  return -1;
1383  }
1384  }
1385  // Check
1386  if (!TClass::GetClass(fDataGenSel)) {
1387  Error("MakeDataSet", "failed to load '%s'", fDataGenSel.Data());
1388  return -1;
1389  }
1390  }
1391 
1392  // For files, 30000 evst each (about 600 MB total) per worker
1393  TString fn, fnr("event");
1394  Bool_t remote = kFALSE;
1395  if (fnroot && strlen(fnroot) > 0) {
1396  TUrl ur(fnroot, kTRUE);
1397  if (!strcmp(ur.GetProtocol(), "file") &&
1398  !gSystem->IsAbsoluteFileName(ur.GetFile())) {
1399  fnr = fnroot;
1400  } else {
1401  fnr = gSystem->BaseName(ur.GetFile());
1402  // We need to set the basedir
1403  TString bdir(gSystem->DirName(fnroot));
1404  bdir += "/<fn>";
1405  fProof->SetParameter("PROOF_BenchmarkBaseDir", bdir.Data());
1406  // Flag as remote, if so
1407  if (strcmp(ur.GetProtocol(), "file")) remote = kTRUE;
1408  }
1409  }
1410  TProofNodes pn(fProof);
1411  TMap *filesmap = new TMap;
1412  TMap *nodesmap = pn.GetMapOfNodes();
1413  TIter nxnd(nodesmap);
1414  TList *wli = 0;
1415  TObject *obj = 0;
1416  Int_t kf = 1;
1417  while ((obj = nxnd()) != 0) {
1418  if ((wli = dynamic_cast<TList *>(nodesmap->GetValue(obj)))) {
1419  THashList *fli = new THashList;
1420  Int_t nf = wli->GetSize() * fNFilesWrk;
1421  TSlaveInfo *wi = (TSlaveInfo *) wli->First();
1422  while (nf--) {
1423  fn.Form("%s-%s-%d.root", fnr.Data(), wi->GetName(), kf++);
1424  // Add to the node list for generation
1425  fli->Add(new TObjString(fn));
1426  }
1427  filesmap->Add(new TObjString(obj->GetName()), fli);
1428  }
1429  }
1430  filesmap->Print();
1431  // Prepare for file generation ... add map in the input list
1432  filesmap->SetName("PROOF_FilesToProcess");
1433  fProof->AddInput(filesmap);
1434 
1435  // Set parameters for processing
1436  TString oldpack;
1437  if (TProof::GetParameter(fProof->GetInputList(), "PROOF_Packetizer", oldpack) != 0) oldpack = "";
1438  fProof->SetParameter("PROOF_Packetizer", "TPacketizerFile");
1439  Int_t oldnotass = -1;
1440  if (TProof::GetParameter(fProof->GetInputList(), "PROOF_ProcessNotAssigned", oldnotass) != 0) oldnotass = -1;
1441  fProof->SetParameter("PROOF_ProcessNotAssigned", (Int_t)0);
1442 
1443  // Process
1444  Long64_t ne = (nevt > 0) ? nevt : 30000;
1445  fProof->SetParameter("PROOF_BenchmarkNEvents", ne);
1446  fProof->SetParameter("PROOF_BenchmarkRegenerate", Int_t(regenerate));
1447  fProof->Process(fDataGenSel, (Long64_t) 1);
1448  fProof->DeleteParameters("PROOF_BenchmarkNEvents");
1449  fProof->DeleteParameters("PROOF_BenchmarkRegenerate");
1450  fProof->DeleteParameters("PROOF_BenchmarkBaseDir");
1451 
1452  // Restore parameters
1453  if (!oldpack.IsNull())
1454  fProof->SetParameter("PROOF_Packetizer", oldpack);
1455  else
1456  fProof->DeleteParameters("PROOF_Packetizer");
1457  if (oldnotass != -1)
1458  fProof->SetParameter("PROOF_ProcessNotAssigned", oldnotass);
1459  else
1460  fProof->DeleteParameters("PROOF_ProcessNotAssigned");
1461 
1462  // Cleanup
1463  if (fProof->GetInputList()) fProof->GetInputList()->Remove(filesmap);
1464  filesmap->SetOwner(kTRUE);
1465  delete filesmap;
1466 
1467  // The dataset to be registered in the end with proper port
1468  TFileCollection *fc = new TFileCollection("dum", "dum");
1469 
1470  if (fProof->GetOutputList()) {
1471  fProof->GetOutputList()->Print();
1472  TIter nxout(fProof->GetOutputList());
1473  while ((obj = nxout())) {
1474  TList *fli = dynamic_cast<TList *>(obj);
1475  if (fli && TString(fli->GetName()).BeginsWith("PROOF_FilesGenerated_")) {
1476  TIter nxfg(fli);
1477  TFileInfo *fi = 0;
1478  while ((fi = (TFileInfo *) nxfg()))
1479  fc->Add(fi);
1480  fli->SetOwner(kFALSE);
1481  }
1482  }
1483  // Register the new dataset, overwriting any existing dataset wth the same name
1484  // trusting the existing information
1485  fc->Update();
1486  if (fc->GetNFiles() > 0) {
1487  if (remote) fc->SetBit(TFileCollection::kRemoteCollection);
1488  if (!(fProof->RegisterDataSet(fDataSet, fc, "OT")))
1489  Warning("MakeDataSet", "problems registering '%s'", dset);
1490  } else {
1491  Warning("MakeDataSet", "dataset '%s' is empty!", dset);
1492  }
1493  } else {
1494  Warning("MakeDataSet", "PROOF output list is empty!");
1495  }
1496 
1497  SafeDelete(fc);
1498 
1499  // Get updated information
1500  fc = fProof->GetDataSet(fDataSet);
1501  if (fc) {
1502  fc->Print("F");
1503  } else {
1504  Warning("MakeDataSet", "dataset '%s' was not generated!", fDataSet.Data());
1505  }
1506 
1507  SafeDelete(fc);
1508 
1509  // Done
1510  return 0;
1511 }
1512 
1513 ////////////////////////////////////////////////////////////////////////////////
1514 /// Copy the files of dataset 'dset' to 'destdir' and create a new dataset named 'dsetdst'
1515 /// decribing them.
1516 /// Return 0 on success, -1 on error
1517 
1518 Int_t TProofBench::CopyDataSet(const char *dset, const char *dsetdst, const char *destdir)
1519 {
1520  // Make some checks
1521  if (!fProof) {
1522  Error("CopyDataSet", "no PROOF found - cannot continue");
1523  return -1;
1524  }
1525  if (!dset || (dset && !fProof->ExistsDataSet(dset))) {
1526  Error("CopyDataSet", "dataset '%s' does not exist", dset);
1527  return -1;
1528  }
1529  if (!dsetdst || (dsetdst && fProof->ExistsDataSet(dsetdst))) {
1530  if (isatty(0) != 0 && isatty(1) != 0) {
1531  Printf("Target dataset '%s' exists already:"
1532  " do you want to remove it first?", dsetdst);
1533  const char *a = Getline("[Y,n] ");
1534  Printf("a: %s", a);
1535  if (a[0] == 'Y' || a[0] == 'y' || a[0] == '\n') {
1536  Info("CopyDataSet", "removing dataset '%s' ...", dsetdst);
1537  RemoveDataSet(dsetdst);
1538  } else {
1539  return -1;
1540  }
1541  } else {
1542  Error("CopyDataSet", "destination dataset '%s' does already exist: remove it first", dsetdst);
1543  return -1;
1544  }
1545  }
1546 
1547  // The TFileCollection object for the new dataset
1548  TFileCollection *fc = fProof->GetDataSet(dset);
1549  if (!fc) {
1550  Error("CopyDataSet", "problems retrieving TFileCollection for dataset '%s'", dset);
1551  return -1;
1552  }
1553  TFileCollection *fcn = new TFileCollection(dsetdst, "");
1554  TString fn;
1555  TFileInfo *fi = 0;
1556  TIter nxfi(fc->GetList());
1557  while ((fi = (TFileInfo *) nxfi())) {
1558  fn.Form("%s/%s", destdir, gSystem->BaseName(fi->GetCurrentUrl()->GetFile()));
1559  Info("CopyDataSet", "adding info for file '%s'", fn.Data());
1560  fcn->Add(new TFileInfo(fn));
1561  }
1562  delete fc;
1563 
1564  // Do it via the dataset handler
1565  if (!fDS) fDS = new TProofBenchDataSet(fProofDS);
1566  if (fDS->CopyFiles(dset, destdir) != 0) {
1567  Error("CopyDataSet", "problems copying files of dataset '%s' to dest dir '%s'", dset, destdir);
1568  delete fcn;
1569  return -1;
1570  }
1571 
1572  // Register the new dataset, overwriting any existing dataset wth the same name
1573  // trusting the existing information
1574  Int_t rc = 0;
1575  if (!(fProof->RegisterDataSet(dsetdst, fcn, "OT"))) {
1576  Error("CopyDataSet", "problems registering and verifying '%s'", dsetdst);
1577  rc = -1;
1578  }
1579  delete fcn;
1580 
1581  // Done
1582  return rc;
1583 }
1584 
1585 ////////////////////////////////////////////////////////////////////////////////
1586 /// Set the PROOF instance to be used for dataset operations, like releasing
1587 /// cache ...
1588 /// Use SetProofDS(0) to reset and using the default PROOF
1589 
1590 void TProofBench::SetProofDS(TProof *pds)
1591 {
1592  if (pds && !pds->IsValid()) {
1593  Error("SetProofDS", "trying to set an invalid PROOF instance");
1594  return;
1595  }
1596  fProofDS = pds ? pds : fProof;
1597  if (fProofDS) {
1598  SafeDelete(fDS);
1599  fDS = new TProofBenchDataSet(fProofDS);
1600  }
1601  // Done
1602  return;
1603 }
1604