ROOT logo
// @(#)root/proofplayer:$Id: TPerfStats.cxx 31296 2009-11-18 20:35:00Z rdm $
// Author: Kristjan Gulbrandsen   11/05/04

/*************************************************************************
 * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TPerfStats                                                           //
//                                                                      //
// Provides the interface for the PROOF internal performance measurment //
// and event tracing.                                                   //
//                                                                      //
//////////////////////////////////////////////////////////////////////////


#include "TPerfStats.h"

#include "Riostream.h"
#include "TCollection.h"
#include "TEnv.h"
#include "TError.h"
#include "TFile.h"
#include "TH1.h"
#include "TH2.h"
#include "TProofDebug.h"
#include "TProof.h"
#include "TProofServ.h"
#include "TSlave.h"
#include "TTree.h"
#include "TSQLServer.h"
#include "TSQLResult.h"
#include "TParameter.h"
#include "TPluginManager.h"
#include "TROOT.h"
#include "TTimeStamp.h"
#include "TVirtualMonitoring.h"


ClassImp(TPerfEvent)
ClassImp(TPerfStats)


//------------------------------------------------------------------------------

//______________________________________________________________________________
TPerfEvent::TPerfEvent(TTimeStamp *offset)
   : fEvtNode("-3"), fType(TVirtualPerfStats::kUnDefined), fSlave(),
     fEventsProcessed(0), fBytesRead(0), fLen(0), fLatency(0.0), fProcTime(0.0), fCpuTime(0.0),
     fIsStart(kFALSE), fIsOk(kFALSE)
{
   // Constructor

   if (gProofServ != 0) {
      fEvtNode = gProofServ->GetOrdinal();
   } else {
      if (gProof && gProof->IsLite())
         fEvtNode = "0";
      else
         fEvtNode = "-2"; // not on a PROOF server
   }

   if (offset != 0) {
      fTimeStamp = TTimeStamp(fTimeStamp.GetSec() - offset->GetSec(),
                     fTimeStamp.GetNanoSec() - offset->GetNanoSec());
   }
}

//______________________________________________________________________________
Int_t TPerfEvent::Compare(const TObject *obj) const
{
   // Compare method. Must return -1 if this is smaller than obj,
   // 0 if objects are equal and 1 if this is larger than obj.

   const TPerfEvent *pe = dynamic_cast<const TPerfEvent*>(obj);

   R__ASSERT(pe != 0);

   if (fTimeStamp < pe->fTimeStamp) {
      return -1;
   } else if (fTimeStamp == pe->fTimeStamp) {
      return 0;
   } else {
      return 1;
   }
}

//______________________________________________________________________________
void TPerfEvent::Print(Option_t *) const
{
   // Dump content of this instance

   cout << "TPerfEvent: ";

   if ( fEvtNode == -2 ) {
      cout << "StandAlone ";
   } else if ( fEvtNode == -1 ) {
      cout << "Master ";
   } else {
      cout << "Slave " << fEvtNode << " ";
   }
   cout << TVirtualPerfStats::EventType(fType) << " "
        << double(fTimeStamp)
        << endl;
}


//------------------------------------------------------------------------------

//______________________________________________________________________________
TPerfStats::TPerfStats(TList *input, TList *output)
   : fTrace(0), fPerfEvent(0), fPacketsHist(0), fEventsHist(0), fLatencyHist(0),
      fProcTimeHist(0), fCpuTimeHist(0), fBytesRead(0),
      fTotCpuTime(0.), fTotBytesRead(0), fTotEvents(0), fNumEvents(0),
      fSlaves(0), fDoHist(kFALSE),
      fDoTrace(kFALSE), fDoTraceRate(kFALSE), fDoSlaveTrace(kFALSE), fDoQuota(kFALSE),
      fMonitoringWriter(0)
{
   // Normal constructor.

   TProof *proof = (gProofServ) ? gProofServ->GetProof() : gProof;

   // Master flag
   Bool_t isMaster = ((proof && proof->TestBit(TProof::kIsMaster)) ||
                      (gProofServ && gProofServ->IsMaster())) ? kTRUE : kFALSE;

   TList *l = proof ? proof->GetListOfSlaveInfos() : 0 ;
   TIter nextslaveinfo(l);
   while (TSlaveInfo *si = dynamic_cast<TSlaveInfo*>(nextslaveinfo()))
      if (si->fStatus == TSlaveInfo::kActive) fSlaves++;

   PDB(kGlobal,1) Info("TPerfStats", "Statistics for %d slave(s)", fSlaves);

   fDoHist = (input->FindObject("PROOF_StatsHist") != 0);
   fDoTrace = (input->FindObject("PROOF_StatsTrace") != 0);
   fDoTraceRate = (input->FindObject("PROOF_RateTrace") != 0);
   fDoSlaveTrace = (input->FindObject("PROOF_SlaveStatsTrace") != 0);

   if ((isMaster && (fDoTrace || fDoTraceRate)) || (!isMaster && fDoSlaveTrace)) {
      // Construct tree
      gDirectory->RecursiveRemove(gDirectory->FindObject("PROOF_PerfStats"));
      fTrace = new TTree("PROOF_PerfStats", "PROOF Statistics");
      fTrace->SetDirectory(0);
      fTrace->Bronch("PerfEvents", "TPerfEvent", &fPerfEvent, 64000, 0);
      output->Add(fTrace);
   }

   if (fDoHist && isMaster) {
      // Make Histograms
      Double_t time_per_bin = 1e-3; // 10ms
      Double_t min_time = 0;
      Int_t ntime_bins = 1000;

      gDirectory->RecursiveRemove(gDirectory->FindObject("PROOF_PacketsHist"));
      fPacketsHist = new TH1D("PROOF_PacketsHist", "Packets processed per Worker",
                              fSlaves, 0, fSlaves);
      fPacketsHist->SetDirectory(0);
      fPacketsHist->SetMinimum(0);
      output->Add(fPacketsHist);

      gDirectory->RecursiveRemove(gDirectory->FindObject("PROOF_EventsHist"));
      fEventsHist = new TH1D("PROOF_EventsHist", "Events processed per Worker",
                             fSlaves, 0, fSlaves);
      fEventsHist->SetFillColor(kGreen);
      fEventsHist->SetDirectory(0);
      fEventsHist->SetMinimum(0);
      output->Add(fEventsHist);

      gDirectory->RecursiveRemove(gDirectory->FindObject("PROOF_NodeHist"));
      fNodeHist = new TH1D("PROOF_NodeHist", "Slaves per Fileserving Node",
                           fSlaves, 0, fSlaves);
      fNodeHist->SetDirectory(0);
      fNodeHist->SetMinimum(0);
      fNodeHist->SetBit(TH1::kCanRebin);
      output->Add(fNodeHist);

      gDirectory->RecursiveRemove(gDirectory->FindObject("PROOF_LatencyHist"));
      fLatencyHist = new TH2D("PROOF_LatencyHist", "GetPacket Latency per Worker",
                              fSlaves, 0, fSlaves,
                              ntime_bins, min_time, time_per_bin);
      fLatencyHist->SetDirectory(0);
      fLatencyHist->SetMarkerStyle(4);
      fLatencyHist->SetBit(TH1::kCanRebin);
      output->Add(fLatencyHist);

      gDirectory->RecursiveRemove(gDirectory->FindObject("PROOF_ProcTimeHist"));
      fProcTimeHist = new TH2D("PROOF_ProcTimeHist", "Packet Processing Time per Worker",
                               fSlaves, 0, fSlaves,
                               ntime_bins, min_time, time_per_bin);
      fProcTimeHist->SetDirectory(0);
      fProcTimeHist->SetMarkerStyle(4);
      fProcTimeHist->SetBit(TH1::kCanRebin);
      output->Add(fProcTimeHist);

      gDirectory->RecursiveRemove(gDirectory->FindObject("PROOF_CpuTimeHist"));
      fCpuTimeHist = new TH2D("PROOF_CpuTimeHist", "Packet CPU Time per Worker",
                              fSlaves, 0, fSlaves,
                              ntime_bins, min_time, time_per_bin);
      fCpuTimeHist->SetDirectory(0);
      fCpuTimeHist->SetMarkerStyle(4);
      fCpuTimeHist->SetBit(TH1::kCanRebin);
      output->Add(fCpuTimeHist);

      nextslaveinfo.Reset();
      Int_t slavebin=1;
      while (TSlaveInfo *si = dynamic_cast<TSlaveInfo*>(nextslaveinfo())) {
         if (si->fStatus == TSlaveInfo::kActive) {
            fPacketsHist->GetXaxis()->SetBinLabel(slavebin, si->GetOrdinal());
            fEventsHist->GetXaxis()->SetBinLabel(slavebin, si->GetOrdinal());
            fNodeHist->GetXaxis()->SetBinLabel(slavebin, si->GetOrdinal());
            fLatencyHist->GetXaxis()->SetBinLabel(slavebin, si->GetOrdinal());
            fProcTimeHist->GetXaxis()->SetBinLabel(slavebin, si->GetOrdinal());
            fCpuTimeHist->GetXaxis()->SetBinLabel(slavebin, si->GetOrdinal());
            slavebin++;
         }
      }
   }

   if (isMaster) {
      // Monitoring for query performances using SQL DB
      TString sqlserv = gEnv->GetValue("ProofServ.QueryLogDB", "");
      if (sqlserv != "") {
         PDB(kGlobal,1) Info("TPerfStats", "store monitoring data in SQL DB: %s", sqlserv.Data());
         fDoQuota = kTRUE;
      }

      // Monitoring for query performances using monitoring system (e.g. Monalisa)
      TString mon = gEnv->GetValue("ProofServ.Monitoring", "");
      if (mon != "") {
         // Extract arguments (up to 9 'const char *')
         TString a[10];
         Int_t from = 0;
         TString tok;
         Int_t na = 0;
         while (mon.Tokenize(tok, from, " "))
            a[na++] = tok;
         na--;
         // Get monitor object from the plugin manager
         TPluginHandler *h = 0;
         if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualMonitoringWriter", a[0]))) {
            if (h->LoadPlugin() != -1) {
               fMonitoringWriter =
                  (TVirtualMonitoringWriter *) h->ExecPlugin(na, a[1].Data(), a[2].Data(), a[3].Data(),
                                                                 a[4].Data(), a[5].Data(), a[6].Data(),
                                                                 a[7].Data(), a[8].Data(), a[9].Data());
               if (fMonitoringWriter && fMonitoringWriter->IsZombie()) {
                  delete fMonitoringWriter;
                  fMonitoringWriter = 0;
               }
            }
         }
      }

      if (fMonitoringWriter) {
         PDB(kGlobal,1) Info("TPerfStats", "created monitoring object: %s", mon.Data());
         fDoQuota = kTRUE;
      }
   }
}

//______________________________________________________________________________
void TPerfStats::SimpleEvent(EEventType type)
{
   // Simple event.

   if (type == kStop && fPacketsHist != 0) {
      fNodeHist->LabelsDeflate("X");
      fNodeHist->LabelsOption("auv","X");
   }

   if (type == kStop && fDoQuota)
      WriteQueryLog();

   if (fTrace == 0) return;

   TPerfEvent pe(&fTzero);
   pe.fType = type;

   fPerfEvent = &pe;
   fTrace->SetBranchAddress("PerfEvents",&fPerfEvent);
   fTrace->Fill();
   fPerfEvent = 0;
}

//______________________________________________________________________________
void TPerfStats::PacketEvent(const char *slave, const char* slavename, const char* filename,
                             Long64_t eventsprocessed, Double_t latency, Double_t proctime,
                             Double_t cputime, Long64_t bytesRead)
{
   // Packet event.

   if (fDoTrace && fTrace != 0) {
      TPerfEvent pe(&fTzero);

      pe.fType = kPacket;
      pe.fSlaveName = slavename;
      pe.fFileName = filename;
      pe.fSlave = slave;
      pe.fEventsProcessed = eventsprocessed;
      pe.fBytesRead = bytesRead;
      pe.fLatency = latency;
      pe.fProcTime = proctime;
      pe.fCpuTime = cputime;

      fPerfEvent = &pe;
      fTrace->SetBranchAddress("PerfEvents",&fPerfEvent);
      fTrace->Fill();
      fPerfEvent = 0;
   }

   PDB(kGlobal,1)
      Info("PacketEvent","%s: fDoHist: %d, fPacketsHist: %p, eventsprocessed: %lld",
                         slave, fDoHist, fPacketsHist, eventsprocessed);

   if (fDoHist && fPacketsHist != 0) {
      fPacketsHist->Fill(slave, 1);
      fEventsHist->Fill(slave, eventsprocessed);
      fLatencyHist->Fill(slave, latency, 1);
      fProcTimeHist->Fill(slave, proctime, 1);
      fCpuTimeHist->Fill(slave, cputime, 1);
   }

   if (fDoQuota) {
      fTotCpuTime += cputime;
      fTotBytesRead += bytesRead;
      fTotEvents += eventsprocessed;
   }

   // Write to monitoring system, if requested
   if (fMonitoringWriter) {
      if (!gProofServ || !gProofServ->GetSessionTag() || !gProofServ->GetProof() ||
          !gProofServ->GetProof()->GetQueryResult()) {
         Error("PacketEvent", "some required object are undefined (0x%lx 0x%lx 0x%lx 0x%lx)",
               gProofServ, (gProofServ ? gProofServ->GetSessionTag() : 0),
              (gProofServ ? gProofServ->GetProof() : 0),
              ((gProofServ && gProofServ->GetProof()) ?
                gProofServ->GetProof()->GetQueryResult() : 0));
         return;
      }

      TTimeStamp stop;
      TString identifier;
      identifier.Form("Progress-%s-%d", gProofServ->GetSessionTag(),
                      gProofServ->GetProof()->GetQueryResult()->GetSeqNum());

      TList values;
      values.SetOwner();
      values.Add(new TParameter<int>("id", 0));
      values.Add(new TNamed("user", gProofServ->GetUser()));
      values.Add(new TNamed("group", gProofServ->GetGroup()));
      values.Add(new TNamed("begin", fTzero.AsString("s")));
      values.Add(new TParameter<int>("walltime", stop.GetSec()-fTzero.GetSec()));
      values.Add(new TParameter<Long64_t>("bytesread", fTotBytesRead));
      values.Add(new TParameter<Long64_t>("events", fTotEvents));
      values.Add(new TParameter<Long64_t>("totevents", fNumEvents));
      values.Add(new TParameter<int>("workers", fSlaves));
      if (!fMonitoringWriter->SendParameters(&values, identifier))
         Error("PacketEvent", "sending of monitoring info failed");
   }
}

//______________________________________________________________________________
void TPerfStats::FileEvent(const char *slave, const char *slavename, const char *nodename,
                            const char *filename, Bool_t isStart)
{
   // File event.

   if (fDoTrace && fTrace != 0) {
      TPerfEvent pe(&fTzero);

      pe.fType = kFile;
      pe.fSlaveName = slavename;
      pe.fNodeName = nodename;
      pe.fFileName = filename;
      pe.fSlave = slave;
      pe.fIsStart = isStart;

      fPerfEvent = &pe;
      fTrace->SetBranchAddress("PerfEvents",&fPerfEvent);
      fTrace->Fill();
      fPerfEvent = 0;
   }

   if (fDoHist && fPacketsHist != 0) {
      fNodeHist->Fill(nodename, isStart ? 1 : -1);
   }
}

//______________________________________________________________________________
void TPerfStats::FileOpenEvent(TFile *file, const char *filename, Double_t start)
{
   // Open file event.

   if (fDoTrace && fTrace != 0) {
      TPerfEvent pe(&fTzero);

      pe.fType = kFileOpen;
      pe.fFileName = filename;
      pe.fFileClass = file != 0 ? file->ClassName() : "none";
      pe.fProcTime = double(TTimeStamp())-start;
      pe.fIsOk = (file != 0);

      fPerfEvent = &pe;
      fTrace->SetBranchAddress("PerfEvents",&fPerfEvent);
      fTrace->Fill();
      fPerfEvent = 0;
   }
}

//______________________________________________________________________________
void TPerfStats::FileReadEvent(TFile *file, Int_t len, Double_t start)
{
   // Read file event.

   if (fDoTrace && fTrace != 0) {
      TPerfEvent pe(&fTzero);

      pe.fType = kFileRead;
      pe.fFileName = file->GetName();
      pe.fFileClass = file->ClassName();
      pe.fLen = len;
      pe.fProcTime = double(TTimeStamp())-start;

      fPerfEvent = &pe;
      fTrace->SetBranchAddress("PerfEvents",&fPerfEvent);
      fTrace->Fill();
      fPerfEvent = 0;
   }
}

//______________________________________________________________________________
void TPerfStats::RateEvent(Double_t proctime, Double_t deltatime,
                           Long64_t eventsprocessed, Long64_t bytesRead)
{
   // Rate event.

   if ((fDoTrace || fDoTraceRate) && fTrace != 0) {
      TPerfEvent pe(&fTzero);

      pe.fType = kRate;
      pe.fEventsProcessed = eventsprocessed;
      pe.fBytesRead = bytesRead;
      pe.fProcTime = proctime;
      pe.fLatency = deltatime;

      fPerfEvent = &pe;
      fTrace->SetBranchAddress("PerfEvents",&fPerfEvent);
      fTrace->Fill();
      fPerfEvent = 0;
   }
}

//______________________________________________________________________________
void TPerfStats::SetBytesRead(Long64_t num)
{
   // Set number of bytes read.

   fBytesRead = num;
}

//______________________________________________________________________________
Long64_t TPerfStats::GetBytesRead() const
{
   // Get number of bytes read.

   return fBytesRead;
}

//______________________________________________________________________________
void TPerfStats::WriteQueryLog()
{
   // Connect to SQL server and register query log used for quotas.
   // The proofquerylog table has the format:
   // CREATE TABLE proofquerylog (
   //   id            INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
   //   user          VARCHAR(32) NOT NULL,
   //   group         VARCHAR(32),
   //   begin         DATETIME,
   //   end           DATETIME,
   //   walltime      INT,
   //   cputime       FLOAT,
   //   bytesread     BIGINT,
   //   events        BIGINT,
   //   workers       INT
   //)
   // The same info is send to Monalisa (or other monitoring systems) in the
   // form of a list of name,value pairs.

   TTimeStamp stop;

   TString sqlserv = gEnv->GetValue("ProofServ.QueryLogDB","");
   TString sqluser = gEnv->GetValue("ProofServ.QueryLogUser","");
   TString sqlpass = gEnv->GetValue("ProofServ.QueryLogPasswd","");

   // write to SQL DB
   if (sqlserv != "" && sqluser != "" && sqlpass != "" && gProofServ) {
      TString sql;
      sql.Form("INSERT INTO proofquerylog VALUES (0, '%s', '%s', "
               "'%s', '%s', %d, %.2f, %lld, %lld, %d)",
               gProofServ->GetUser(), gProofServ->GetGroup(),
               fTzero.AsString("s"), stop.AsString("s"),
               stop.GetSec()-fTzero.GetSec(), fTotCpuTime,
               fTotBytesRead, fTotEvents, fSlaves);

      // open connection to SQL server
      TSQLServer *db =  TSQLServer::Connect(sqlserv, sqluser, sqlpass);

      if (!db || db->IsZombie()) {
         Error("WriteQueryLog", "failed to connect to SQL server %s as %s %s",
               sqlserv.Data(), sqluser.Data(), sqlpass.Data());
         printf("%s\n", sql.Data());
      } else {
         TSQLResult *res = db->Query(sql);

         if (!res) {
            Error("WriteQueryLog", "insert into proofquerylog failed");
            printf("%s\n", sql.Data());
         }
         delete res;
      }
      delete db;
   }

   // write to monitoring system
   if (fMonitoringWriter) {
      if (!gProofServ || !gProofServ->GetSessionTag() || !gProofServ->GetProof() ||
          !gProofServ->GetProof()->GetQueryResult()) {
         Error("WriteQueryLog", "some required object are undefined (0x%lx 0x%lx 0x%lx 0x%lx)",
               gProofServ, (gProofServ ? gProofServ->GetSessionTag() : 0),
              (gProofServ ? gProofServ->GetProof() : 0),
              ((gProofServ && gProofServ->GetProof()) ?
                gProofServ->GetProof()->GetQueryResult() : 0));
         return;
      }

      TString identifier;
      identifier.Form("%s-%d", gProofServ->GetSessionTag(),
                      gProofServ->GetProof()->GetQueryResult()->GetSeqNum());

      TList values;
      values.SetOwner();
      values.Add(new TParameter<int>("id", 0));
      values.Add(new TNamed("user", gProofServ->GetUser()));
      values.Add(new TNamed("group", gProofServ->GetGroup()));
      values.Add(new TNamed("begin", fTzero.AsString("s")));
      values.Add(new TNamed("end", stop.AsString("s")));
      values.Add(new TParameter<int>("walltime", stop.GetSec()-fTzero.GetSec()));
      values.Add(new TParameter<float>("cputime", fTotCpuTime));
      values.Add(new TParameter<Long64_t>("bytesread", fTotBytesRead));
      values.Add(new TParameter<Long64_t>("events", fTotEvents));
      values.Add(new TParameter<int>("workers", fSlaves));
      if (!fMonitoringWriter->SendParameters(&values, identifier))
         Error("WriteQueryLog", "sending of monitoring info failed");
   }
}

//______________________________________________________________________________
void TPerfStats::Setup(TList *input)
{
   // Setup the PROOF input list with requested statistics and tracing options.

   const Int_t ntags=3;
   const Char_t *tags[ntags] = {"StatsHist",
                                "StatsTrace",
                                "SlaveStatsTrace"};

   for (Int_t i=0; i<ntags; i++) {
      TString envvar = "Proof.";
      envvar += tags[i];
      TString inputname = "PROOF_";
      inputname += tags[i];
      TObject* obj = input->FindObject(inputname.Data());
      if (gEnv->GetValue(envvar.Data(), 0)) {
         if (!obj)
            input->Add(new TNamed(inputname.Data(),""));
      } else {
         if (obj) {
            input->Remove(obj);
            delete obj;
         }
      }
   }
}

//______________________________________________________________________________
void TPerfStats::Start(TList *input, TList *output)
{
   // Initialize PROOF statistics run.

   if (gPerfStats)
      delete gPerfStats;

   gPerfStats = new TPerfStats(input, output);
   if (gPerfStats && !gPerfStats->TestBit(TObject::kInvalidObject)) {
      gPerfStats->SimpleEvent(TVirtualPerfStats::kStart);
   } else {
      SafeDelete(gPerfStats);
   }
}

//______________________________________________________________________________
void TPerfStats::Stop()
{
   // Terminate the PROOF statistics run.

   if (!gPerfStats) return;

   gPerfStats->SimpleEvent(TVirtualPerfStats::kStop);

   delete gPerfStats;
   gPerfStats = 0;
}
 TPerfStats.cxx:1
 TPerfStats.cxx:2
 TPerfStats.cxx:3
 TPerfStats.cxx:4
 TPerfStats.cxx:5
 TPerfStats.cxx:6
 TPerfStats.cxx:7
 TPerfStats.cxx:8
 TPerfStats.cxx:9
 TPerfStats.cxx:10
 TPerfStats.cxx:11
 TPerfStats.cxx:12
 TPerfStats.cxx:13
 TPerfStats.cxx:14
 TPerfStats.cxx:15
 TPerfStats.cxx:16
 TPerfStats.cxx:17
 TPerfStats.cxx:18
 TPerfStats.cxx:19
 TPerfStats.cxx:20
 TPerfStats.cxx:21
 TPerfStats.cxx:22
 TPerfStats.cxx:23
 TPerfStats.cxx:24
 TPerfStats.cxx:25
 TPerfStats.cxx:26
 TPerfStats.cxx:27
 TPerfStats.cxx:28
 TPerfStats.cxx:29
 TPerfStats.cxx:30
 TPerfStats.cxx:31
 TPerfStats.cxx:32
 TPerfStats.cxx:33
 TPerfStats.cxx:34
 TPerfStats.cxx:35
 TPerfStats.cxx:36
 TPerfStats.cxx:37
 TPerfStats.cxx:38
 TPerfStats.cxx:39
 TPerfStats.cxx:40
 TPerfStats.cxx:41
 TPerfStats.cxx:42
 TPerfStats.cxx:43
 TPerfStats.cxx:44
 TPerfStats.cxx:45
 TPerfStats.cxx:46
 TPerfStats.cxx:47
 TPerfStats.cxx:48
 TPerfStats.cxx:49
 TPerfStats.cxx:50
 TPerfStats.cxx:51
 TPerfStats.cxx:52
 TPerfStats.cxx:53
 TPerfStats.cxx:54
 TPerfStats.cxx:55
 TPerfStats.cxx:56
 TPerfStats.cxx:57
 TPerfStats.cxx:58
 TPerfStats.cxx:59
 TPerfStats.cxx:60
 TPerfStats.cxx:61
 TPerfStats.cxx:62
 TPerfStats.cxx:63
 TPerfStats.cxx:64
 TPerfStats.cxx:65
 TPerfStats.cxx:66
 TPerfStats.cxx:67
 TPerfStats.cxx:68
 TPerfStats.cxx:69
 TPerfStats.cxx:70
 TPerfStats.cxx:71
 TPerfStats.cxx:72
 TPerfStats.cxx:73
 TPerfStats.cxx:74
 TPerfStats.cxx:75
 TPerfStats.cxx:76
 TPerfStats.cxx:77
 TPerfStats.cxx:78
 TPerfStats.cxx:79
 TPerfStats.cxx:80
 TPerfStats.cxx:81
 TPerfStats.cxx:82
 TPerfStats.cxx:83
 TPerfStats.cxx:84
 TPerfStats.cxx:85
 TPerfStats.cxx:86
 TPerfStats.cxx:87
 TPerfStats.cxx:88
 TPerfStats.cxx:89
 TPerfStats.cxx:90
 TPerfStats.cxx:91
 TPerfStats.cxx:92
 TPerfStats.cxx:93
 TPerfStats.cxx:94
 TPerfStats.cxx:95
 TPerfStats.cxx:96
 TPerfStats.cxx:97
 TPerfStats.cxx:98
 TPerfStats.cxx:99
 TPerfStats.cxx:100
 TPerfStats.cxx:101
 TPerfStats.cxx:102
 TPerfStats.cxx:103
 TPerfStats.cxx:104
 TPerfStats.cxx:105
 TPerfStats.cxx:106
 TPerfStats.cxx:107
 TPerfStats.cxx:108
 TPerfStats.cxx:109
 TPerfStats.cxx:110
 TPerfStats.cxx:111
 TPerfStats.cxx:112
 TPerfStats.cxx:113
 TPerfStats.cxx:114
 TPerfStats.cxx:115
 TPerfStats.cxx:116
 TPerfStats.cxx:117
 TPerfStats.cxx:118
 TPerfStats.cxx:119
 TPerfStats.cxx:120
 TPerfStats.cxx:121
 TPerfStats.cxx:122
 TPerfStats.cxx:123
 TPerfStats.cxx:124
 TPerfStats.cxx:125
 TPerfStats.cxx:126
 TPerfStats.cxx:127
 TPerfStats.cxx:128
 TPerfStats.cxx:129
 TPerfStats.cxx:130
 TPerfStats.cxx:131
 TPerfStats.cxx:132
 TPerfStats.cxx:133
 TPerfStats.cxx:134
 TPerfStats.cxx:135
 TPerfStats.cxx:136
 TPerfStats.cxx:137
 TPerfStats.cxx:138
 TPerfStats.cxx:139
 TPerfStats.cxx:140
 TPerfStats.cxx:141
 TPerfStats.cxx:142
 TPerfStats.cxx:143
 TPerfStats.cxx:144
 TPerfStats.cxx:145
 TPerfStats.cxx:146
 TPerfStats.cxx:147
 TPerfStats.cxx:148
 TPerfStats.cxx:149
 TPerfStats.cxx:150
 TPerfStats.cxx:151
 TPerfStats.cxx:152
 TPerfStats.cxx:153
 TPerfStats.cxx:154
 TPerfStats.cxx:155
 TPerfStats.cxx:156
 TPerfStats.cxx:157
 TPerfStats.cxx:158
 TPerfStats.cxx:159
 TPerfStats.cxx:160
 TPerfStats.cxx:161
 TPerfStats.cxx:162
 TPerfStats.cxx:163
 TPerfStats.cxx:164
 TPerfStats.cxx:165
 TPerfStats.cxx:166
 TPerfStats.cxx:167
 TPerfStats.cxx:168
 TPerfStats.cxx:169
 TPerfStats.cxx:170
 TPerfStats.cxx:171
 TPerfStats.cxx:172
 TPerfStats.cxx:173
 TPerfStats.cxx:174
 TPerfStats.cxx:175
 TPerfStats.cxx:176
 TPerfStats.cxx:177
 TPerfStats.cxx:178
 TPerfStats.cxx:179
 TPerfStats.cxx:180
 TPerfStats.cxx:181
 TPerfStats.cxx:182
 TPerfStats.cxx:183
 TPerfStats.cxx:184
 TPerfStats.cxx:185
 TPerfStats.cxx:186
 TPerfStats.cxx:187
 TPerfStats.cxx:188
 TPerfStats.cxx:189
 TPerfStats.cxx:190
 TPerfStats.cxx:191
 TPerfStats.cxx:192
 TPerfStats.cxx:193
 TPerfStats.cxx:194
 TPerfStats.cxx:195
 TPerfStats.cxx:196
 TPerfStats.cxx:197
 TPerfStats.cxx:198
 TPerfStats.cxx:199
 TPerfStats.cxx:200
 TPerfStats.cxx:201
 TPerfStats.cxx:202
 TPerfStats.cxx:203
 TPerfStats.cxx:204
 TPerfStats.cxx:205
 TPerfStats.cxx:206
 TPerfStats.cxx:207
 TPerfStats.cxx:208
 TPerfStats.cxx:209
 TPerfStats.cxx:210
 TPerfStats.cxx:211
 TPerfStats.cxx:212
 TPerfStats.cxx:213
 TPerfStats.cxx:214
 TPerfStats.cxx:215
 TPerfStats.cxx:216
 TPerfStats.cxx:217
 TPerfStats.cxx:218
 TPerfStats.cxx:219
 TPerfStats.cxx:220
 TPerfStats.cxx:221
 TPerfStats.cxx:222
 TPerfStats.cxx:223
 TPerfStats.cxx:224
 TPerfStats.cxx:225
 TPerfStats.cxx:226
 TPerfStats.cxx:227
 TPerfStats.cxx:228
 TPerfStats.cxx:229
 TPerfStats.cxx:230
 TPerfStats.cxx:231
 TPerfStats.cxx:232
 TPerfStats.cxx:233
 TPerfStats.cxx:234
 TPerfStats.cxx:235
 TPerfStats.cxx:236
 TPerfStats.cxx:237
 TPerfStats.cxx:238
 TPerfStats.cxx:239
 TPerfStats.cxx:240
 TPerfStats.cxx:241
 TPerfStats.cxx:242
 TPerfStats.cxx:243
 TPerfStats.cxx:244
 TPerfStats.cxx:245
 TPerfStats.cxx:246
 TPerfStats.cxx:247
 TPerfStats.cxx:248
 TPerfStats.cxx:249
 TPerfStats.cxx:250
 TPerfStats.cxx:251
 TPerfStats.cxx:252
 TPerfStats.cxx:253
 TPerfStats.cxx:254
 TPerfStats.cxx:255
 TPerfStats.cxx:256
 TPerfStats.cxx:257
 TPerfStats.cxx:258
 TPerfStats.cxx:259
 TPerfStats.cxx:260
 TPerfStats.cxx:261
 TPerfStats.cxx:262
 TPerfStats.cxx:263
 TPerfStats.cxx:264
 TPerfStats.cxx:265
 TPerfStats.cxx:266
 TPerfStats.cxx:267
 TPerfStats.cxx:268
 TPerfStats.cxx:269
 TPerfStats.cxx:270
 TPerfStats.cxx:271
 TPerfStats.cxx:272
 TPerfStats.cxx:273
 TPerfStats.cxx:274
 TPerfStats.cxx:275
 TPerfStats.cxx:276
 TPerfStats.cxx:277
 TPerfStats.cxx:278
 TPerfStats.cxx:279
 TPerfStats.cxx:280
 TPerfStats.cxx:281
 TPerfStats.cxx:282
 TPerfStats.cxx:283
 TPerfStats.cxx:284
 TPerfStats.cxx:285
 TPerfStats.cxx:286
 TPerfStats.cxx:287
 TPerfStats.cxx:288
 TPerfStats.cxx:289
 TPerfStats.cxx:290
 TPerfStats.cxx:291
 TPerfStats.cxx:292
 TPerfStats.cxx:293
 TPerfStats.cxx:294
 TPerfStats.cxx:295
 TPerfStats.cxx:296
 TPerfStats.cxx:297
 TPerfStats.cxx:298
 TPerfStats.cxx:299
 TPerfStats.cxx:300
 TPerfStats.cxx:301
 TPerfStats.cxx:302
 TPerfStats.cxx:303
 TPerfStats.cxx:304
 TPerfStats.cxx:305
 TPerfStats.cxx:306
 TPerfStats.cxx:307
 TPerfStats.cxx:308
 TPerfStats.cxx:309
 TPerfStats.cxx:310
 TPerfStats.cxx:311
 TPerfStats.cxx:312
 TPerfStats.cxx:313
 TPerfStats.cxx:314
 TPerfStats.cxx:315
 TPerfStats.cxx:316
 TPerfStats.cxx:317
 TPerfStats.cxx:318
 TPerfStats.cxx:319
 TPerfStats.cxx:320
 TPerfStats.cxx:321
 TPerfStats.cxx:322
 TPerfStats.cxx:323
 TPerfStats.cxx:324
 TPerfStats.cxx:325
 TPerfStats.cxx:326
 TPerfStats.cxx:327
 TPerfStats.cxx:328
 TPerfStats.cxx:329
 TPerfStats.cxx:330
 TPerfStats.cxx:331
 TPerfStats.cxx:332
 TPerfStats.cxx:333
 TPerfStats.cxx:334
 TPerfStats.cxx:335
 TPerfStats.cxx:336
 TPerfStats.cxx:337
 TPerfStats.cxx:338
 TPerfStats.cxx:339
 TPerfStats.cxx:340
 TPerfStats.cxx:341
 TPerfStats.cxx:342
 TPerfStats.cxx:343
 TPerfStats.cxx:344
 TPerfStats.cxx:345
 TPerfStats.cxx:346
 TPerfStats.cxx:347
 TPerfStats.cxx:348
 TPerfStats.cxx:349
 TPerfStats.cxx:350
 TPerfStats.cxx:351
 TPerfStats.cxx:352
 TPerfStats.cxx:353
 TPerfStats.cxx:354
 TPerfStats.cxx:355
 TPerfStats.cxx:356
 TPerfStats.cxx:357
 TPerfStats.cxx:358
 TPerfStats.cxx:359
 TPerfStats.cxx:360
 TPerfStats.cxx:361
 TPerfStats.cxx:362
 TPerfStats.cxx:363
 TPerfStats.cxx:364
 TPerfStats.cxx:365
 TPerfStats.cxx:366
 TPerfStats.cxx:367
 TPerfStats.cxx:368
 TPerfStats.cxx:369
 TPerfStats.cxx:370
 TPerfStats.cxx:371
 TPerfStats.cxx:372
 TPerfStats.cxx:373
 TPerfStats.cxx:374
 TPerfStats.cxx:375
 TPerfStats.cxx:376
 TPerfStats.cxx:377
 TPerfStats.cxx:378
 TPerfStats.cxx:379
 TPerfStats.cxx:380
 TPerfStats.cxx:381
 TPerfStats.cxx:382
 TPerfStats.cxx:383
 TPerfStats.cxx:384
 TPerfStats.cxx:385
 TPerfStats.cxx:386
 TPerfStats.cxx:387
 TPerfStats.cxx:388
 TPerfStats.cxx:389
 TPerfStats.cxx:390
 TPerfStats.cxx:391
 TPerfStats.cxx:392
 TPerfStats.cxx:393
 TPerfStats.cxx:394
 TPerfStats.cxx:395
 TPerfStats.cxx:396
 TPerfStats.cxx:397
 TPerfStats.cxx:398
 TPerfStats.cxx:399
 TPerfStats.cxx:400
 TPerfStats.cxx:401
 TPerfStats.cxx:402
 TPerfStats.cxx:403
 TPerfStats.cxx:404
 TPerfStats.cxx:405
 TPerfStats.cxx:406
 TPerfStats.cxx:407
 TPerfStats.cxx:408
 TPerfStats.cxx:409
 TPerfStats.cxx:410
 TPerfStats.cxx:411
 TPerfStats.cxx:412
 TPerfStats.cxx:413
 TPerfStats.cxx:414
 TPerfStats.cxx:415
 TPerfStats.cxx:416
 TPerfStats.cxx:417
 TPerfStats.cxx:418
 TPerfStats.cxx:419
 TPerfStats.cxx:420
 TPerfStats.cxx:421
 TPerfStats.cxx:422
 TPerfStats.cxx:423
 TPerfStats.cxx:424
 TPerfStats.cxx:425
 TPerfStats.cxx:426
 TPerfStats.cxx:427
 TPerfStats.cxx:428
 TPerfStats.cxx:429
 TPerfStats.cxx:430
 TPerfStats.cxx:431
 TPerfStats.cxx:432
 TPerfStats.cxx:433
 TPerfStats.cxx:434
 TPerfStats.cxx:435
 TPerfStats.cxx:436
 TPerfStats.cxx:437
 TPerfStats.cxx:438
 TPerfStats.cxx:439
 TPerfStats.cxx:440
 TPerfStats.cxx:441
 TPerfStats.cxx:442
 TPerfStats.cxx:443
 TPerfStats.cxx:444
 TPerfStats.cxx:445
 TPerfStats.cxx:446
 TPerfStats.cxx:447
 TPerfStats.cxx:448
 TPerfStats.cxx:449
 TPerfStats.cxx:450
 TPerfStats.cxx:451
 TPerfStats.cxx:452
 TPerfStats.cxx:453
 TPerfStats.cxx:454
 TPerfStats.cxx:455
 TPerfStats.cxx:456
 TPerfStats.cxx:457
 TPerfStats.cxx:458
 TPerfStats.cxx:459
 TPerfStats.cxx:460
 TPerfStats.cxx:461
 TPerfStats.cxx:462
 TPerfStats.cxx:463
 TPerfStats.cxx:464
 TPerfStats.cxx:465
 TPerfStats.cxx:466
 TPerfStats.cxx:467
 TPerfStats.cxx:468
 TPerfStats.cxx:469
 TPerfStats.cxx:470
 TPerfStats.cxx:471
 TPerfStats.cxx:472
 TPerfStats.cxx:473
 TPerfStats.cxx:474
 TPerfStats.cxx:475
 TPerfStats.cxx:476
 TPerfStats.cxx:477
 TPerfStats.cxx:478
 TPerfStats.cxx:479
 TPerfStats.cxx:480
 TPerfStats.cxx:481
 TPerfStats.cxx:482
 TPerfStats.cxx:483
 TPerfStats.cxx:484
 TPerfStats.cxx:485
 TPerfStats.cxx:486
 TPerfStats.cxx:487
 TPerfStats.cxx:488
 TPerfStats.cxx:489
 TPerfStats.cxx:490
 TPerfStats.cxx:491
 TPerfStats.cxx:492
 TPerfStats.cxx:493
 TPerfStats.cxx:494
 TPerfStats.cxx:495
 TPerfStats.cxx:496
 TPerfStats.cxx:497
 TPerfStats.cxx:498
 TPerfStats.cxx:499
 TPerfStats.cxx:500
 TPerfStats.cxx:501
 TPerfStats.cxx:502
 TPerfStats.cxx:503
 TPerfStats.cxx:504
 TPerfStats.cxx:505
 TPerfStats.cxx:506
 TPerfStats.cxx:507
 TPerfStats.cxx:508
 TPerfStats.cxx:509
 TPerfStats.cxx:510
 TPerfStats.cxx:511
 TPerfStats.cxx:512
 TPerfStats.cxx:513
 TPerfStats.cxx:514
 TPerfStats.cxx:515
 TPerfStats.cxx:516
 TPerfStats.cxx:517
 TPerfStats.cxx:518
 TPerfStats.cxx:519
 TPerfStats.cxx:520
 TPerfStats.cxx:521
 TPerfStats.cxx:522
 TPerfStats.cxx:523
 TPerfStats.cxx:524
 TPerfStats.cxx:525
 TPerfStats.cxx:526
 TPerfStats.cxx:527
 TPerfStats.cxx:528
 TPerfStats.cxx:529
 TPerfStats.cxx:530
 TPerfStats.cxx:531
 TPerfStats.cxx:532
 TPerfStats.cxx:533
 TPerfStats.cxx:534
 TPerfStats.cxx:535
 TPerfStats.cxx:536
 TPerfStats.cxx:537
 TPerfStats.cxx:538
 TPerfStats.cxx:539
 TPerfStats.cxx:540
 TPerfStats.cxx:541
 TPerfStats.cxx:542
 TPerfStats.cxx:543
 TPerfStats.cxx:544
 TPerfStats.cxx:545
 TPerfStats.cxx:546
 TPerfStats.cxx:547
 TPerfStats.cxx:548
 TPerfStats.cxx:549
 TPerfStats.cxx:550
 TPerfStats.cxx:551
 TPerfStats.cxx:552
 TPerfStats.cxx:553
 TPerfStats.cxx:554
 TPerfStats.cxx:555
 TPerfStats.cxx:556
 TPerfStats.cxx:557
 TPerfStats.cxx:558
 TPerfStats.cxx:559
 TPerfStats.cxx:560
 TPerfStats.cxx:561
 TPerfStats.cxx:562
 TPerfStats.cxx:563
 TPerfStats.cxx:564
 TPerfStats.cxx:565
 TPerfStats.cxx:566
 TPerfStats.cxx:567
 TPerfStats.cxx:568
 TPerfStats.cxx:569
 TPerfStats.cxx:570
 TPerfStats.cxx:571
 TPerfStats.cxx:572
 TPerfStats.cxx:573
 TPerfStats.cxx:574
 TPerfStats.cxx:575
 TPerfStats.cxx:576
 TPerfStats.cxx:577
 TPerfStats.cxx:578
 TPerfStats.cxx:579
 TPerfStats.cxx:580
 TPerfStats.cxx:581
 TPerfStats.cxx:582
 TPerfStats.cxx:583
 TPerfStats.cxx:584
 TPerfStats.cxx:585
 TPerfStats.cxx:586
 TPerfStats.cxx:587
 TPerfStats.cxx:588
 TPerfStats.cxx:589
 TPerfStats.cxx:590
 TPerfStats.cxx:591
 TPerfStats.cxx:592
 TPerfStats.cxx:593
 TPerfStats.cxx:594
 TPerfStats.cxx:595
 TPerfStats.cxx:596
 TPerfStats.cxx:597
 TPerfStats.cxx:598
 TPerfStats.cxx:599
 TPerfStats.cxx:600
 TPerfStats.cxx:601
 TPerfStats.cxx:602
 TPerfStats.cxx:603
 TPerfStats.cxx:604
 TPerfStats.cxx:605
 TPerfStats.cxx:606
 TPerfStats.cxx:607
 TPerfStats.cxx:608
 TPerfStats.cxx:609
 TPerfStats.cxx:610
 TPerfStats.cxx:611
 TPerfStats.cxx:612
 TPerfStats.cxx:613
 TPerfStats.cxx:614
 TPerfStats.cxx:615
 TPerfStats.cxx:616
 TPerfStats.cxx:617