diff --git a/.gitignore b/.gitignore index 7b4fc60..eb3db83 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ /Makefile /Makefile.in +/compile + /aclocal.m4 /ar-lib /autom4te.cache @@ -62,3 +64,4 @@ out*.json # Eclipse CDT project files /.cproject /.project +/.settings diff --git a/doc/examples/mca-calib.json b/doc/examples/mca-calib.json index 4aa26a9..a14b886 100644 --- a/doc/examples/mca-calib.json +++ b/doc/examples/mca-calib.json @@ -48,7 +48,8 @@ "type": "dbrx::RootTreeReader", "input": "&mcaFileReader.content.mcaEvents", "nEntries": -1, - "firstEntry": 0 + "firstEntry": 0, + "progressUpdateTime": 0.5 }, "calib": { diff --git a/src/dbrx.cxx b/src/dbrx.cxx index 555cb7c..b6d263d 100644 --- a/src/dbrx.cxx +++ b/src/dbrx.cxx @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -184,8 +185,12 @@ int main(int argc, char *argv[], char *envp[]) { // Have to create an application to activate ROOT's on-demand class loader // (still true for ROOT-6?): +// g_rootApplication = unique_ptr(new TApplication("dbrx", &nArgs, args)); g_rootApplication = unique_ptr(new TApplication("dbrx", 0, 0)); + // Disable ROOT on-screen graphics output: + gROOT->SetBatch(true); + // Set ROOT program name (necessary / useful ?): gSystem->SetProgname("dbrx"); @@ -222,4 +227,5 @@ int main(int argc, char *argv[], char *envp[]) { } dbrx_log_info("Done."); + return 0; } diff --git a/src/rootiobrics.cxx b/src/rootiobrics.cxx index 0c13a09..5ba6077 100644 --- a/src/rootiobrics.cxx +++ b/src/rootiobrics.cxx @@ -66,6 +66,13 @@ void RootTreeReader::processInput() { index = firstEntry - 1; size = m_chain->GetEntries() - firstEntry.get(); if (ssize_t(nEntries) > 0) size = std::min(ssize_t(nEntries), size.get()); + + gettimeofday(&m_StartTime, NULL); + + m_LastTime.tv_sec = m_StartTime.tv_sec; + m_LastTime.tv_usec = m_StartTime.tv_usec; + + m_PreviousNEntries = index.get(); } @@ -73,6 +80,57 @@ bool RootTreeReader::nextOutput() { if (index.get() + 1 < firstEntry.get() + size.get()) { ++index; m_chain->GetEntry(index); + + // Update progress infos: + + if (pProgressUpdateTime.get() != pProgressUpdateTime.get()) return true; // No progress update + + gettimeofday(&m_CurrentTime, NULL); + + double timeDiff = m_CurrentTime.tv_sec - m_LastTime.tv_sec + 1.0e-6*(m_CurrentTime.tv_usec - m_LastTime.tv_usec); + + if (timeDiff < pProgressUpdateTime.get()) return true; + + double averageTimeDiff = m_CurrentTime.tv_sec - m_StartTime.tv_sec + 1.0e-6*(m_CurrentTime.tv_usec - m_StartTime.tv_usec); + + double percentage = 100. * (index.get()-firstEntry.get())/size.get(); + + int64_t nEntries = index.get() - m_PreviousNEntries; + m_PreviousNEntries = index.get()-firstEntry.get(); + + dbrx_log_info("Reading from chain %s ...", m_chain->GetName()); + dbrx_log_info(" %5.1f %% done (%u/%u pulses read)", + percentage, + (unsigned int) index.get()-firstEntry.get(), + (unsigned int) size.get()); + + double rate = (nEntries)/timeDiff; + double averageRate = (index.get()-firstEntry.get())/averageTimeDiff; + + dbrx_log_info(" Rate: %5.1f Entries/s (average rate: %5.1f Entries/s)", rate, averageRate); + + double eta = (size.get() - (index.get()-firstEntry.get()))/averageRate; + + int fullSeconds = eta; + int usecs = (eta-fullSeconds)*1.0e6; + + int hours = eta/(3600.); + int minutes = (eta - hours*3600.)/60.; + double seconds = eta - hours*3600. - minutes*60.; + + time_t finishTime; + finishTime = m_CurrentTime.tv_sec+fullSeconds; + struct tm* finishtm; + finishtm = localtime(&finishTime); + + char tmbuf[64]; + strftime(tmbuf, sizeof tmbuf, "%a %b %d - %H:%M:%S", finishtm); + + dbrx_log_info("ETA: %i:%i:%5.2f (%s)", hours, minutes, seconds, tmbuf); + + m_LastTime.tv_sec = m_CurrentTime.tv_sec; + m_LastTime.tv_usec = m_CurrentTime.tv_usec; + return true; } else return false; } @@ -348,7 +406,7 @@ void RootFileWriter::ContentGroup::processInput() { // Need to clone inputObject to own it: dbrx_log_trace("Cloning object \"%s\" to content group \"%s\"", inputObject->GetName(), absolutePath()); TNamed *outputObject = (TNamed*) inputObject->Clone(); - writeObject(outputObject); + writeObject(outputObject, m_writer->overwrite.get()); } } } @@ -420,7 +478,7 @@ RootFileWriter::ContentGroup::ContentGroup(RootFileWriter *writer, Bric *parentB -void RootFileWriter::writeObject(TNamed *obj) { +void RootFileWriter::writeObject(TNamed *obj, bool overwrite) { if (string(obj->GetName()).empty()) throw invalid_argument("Refusing to add object with empty name to TDirectory"); @@ -431,10 +489,19 @@ void RootFileWriter::writeObject(TNamed *obj) { TDirectory::AddDirectoryStatus() && (obj->IsA()->GetDirectoryAutoAdd() != nullptr) ); - if (!autoAdded) obj->Write(); + if (!autoAdded) + { + if (overwrite) + { + obj->Write(obj->GetName(), TObject::kOverwrite); + } + else + { + obj->Write(); + } + } } - void RootFileWriter::connectInputs() { dbrx_log_trace("Setting up content groups for bric \"%s\"", absolutePath()); inputs.addContent(content); @@ -466,7 +533,21 @@ void RootFileWriter::openOutputForWrite() { const char *outFileName = fileName->c_str(); const char *outFileTitle = title->c_str(); dbrx_log_debug("Creating TFile \"%s\" with title \"%s\" in bric \"%s\""_format(outFileName, outFileTitle, absolutePath())); - TFile *tfile = TFile::Open(outFileName, "RECREATE", outFileTitle); + + // Open tfile in update mode if chosen that way + TFile *tfile = nullptr; + if (recreateFile.get()) + { + dbrx_log_debug("Recreate file %s", outFileName); + tfile = TFile::Open(outFileName, "RECREATE", outFileTitle); + } + else + { + dbrx_log_debug("Update file %s", outFileName); + tfile = TFile::Open(outFileName, "UPDATE", outFileTitle); + } + + if (tfile == nullptr) throw runtime_error("Could not create TFile \"%s\""_format(outFileName)); outputFile.value() = unique_ptr(tfile); @@ -481,7 +562,8 @@ void RootFileWriter::finalizeOutput() { if (! m_outputReadyForWrite) return; dbrx_log_debug("Writing TFile \"%s\" in bric \"%s\""_format(outputFile->GetName(), absolutePath())); - outputFile->Write(); + if (overwrite.get()) outputFile->Write(0, TObject::kOverwrite); + else outputFile->Write(); outputFile->ReOpen("READ"); diff --git a/src/rootiobrics.h b/src/rootiobrics.h index 7e1103b..96583dc 100644 --- a/src/rootiobrics.h +++ b/src/rootiobrics.h @@ -19,6 +19,7 @@ #define DBRX_ROOTIOBRICS_H #include +#include #include "Bric.h" @@ -27,6 +28,9 @@ #include #include +#include +#include + namespace dbrx { @@ -34,6 +38,16 @@ class RootTreeReader: public MapperBric { protected: std::unique_ptr m_chain; + // Additional members for progress informations + //! Previously printed progress + int64_t m_PreviousNEntries; + //! CPU time at begin of reading + struct timeval m_StartTime; + //! CPU time from last event + struct timeval m_LastTime; + //! Current CPU time + struct timeval m_CurrentTime; + public: class Entry final: public DynOutputGroup { public: @@ -47,6 +61,9 @@ class RootTreeReader: public MapperBric { Param nEntries{this, "nEntries", "Number of entries to read (-1 for all)", -1}; Param firstEntry{this, "firstEntry", "First entry to read", 0}; + //! Parameter: Time to update the progress information + Param pProgressUpdateTime {this, "progressUpdateTime", "Time to update the progress information [s]", std::numeric_limits::quiet_NaN()}; + Entry entry{this, "entry"}; Output size{this, "size", "Number of entries"}; @@ -157,7 +174,8 @@ class RootFileWriter: public AsyncReducerBric { protected: static const PropKey s_thisDirName; - static void writeObject(TNamed *obj); + // Additional argument to choose if the object is overwritten + static void writeObject(TNamed *obj, bool overwrite = false); bool m_outputReadyForWrite = false; @@ -204,6 +222,11 @@ class RootFileWriter: public AsyncReducerBric { Param title{this, "title", "Title"}; Param content{this, "content", "Content"}; + // Is used to choose the mode for opening the root file + Param recreateFile{this, "recreate", "Recreate file", true}; + // Is used to choose if the contents of the root file are overwritten + Param overwrite{this, "overwrite", "Overwrite objects in file", false}; + Output output{this, "output", "Output File Name"}; Output outputFile{this, "outputFile", "Output TFile"};