From afee8925937bcc17658d30e6092d1bf4a604a99f Mon Sep 17 00:00:00 2001
From: "P.-A. Loizeau" <p.-a.loizeau@gsi.de>
Date: Fri, 8 Jul 2022 16:57:11 +0200
Subject: [PATCH] [MQ] in RepReqSampler and DigiEventSink, add option adding
 suffix to histos name and folder

=> needed to collect histo and canvases from multiple instances of the devices (e.g. multiple nodes) in a single histo server
=> Same cannot easily be in processing classes like Unpack and BuildEvent as both name and folder need to be changed to avoid collisions
---
 MQ/mcbm/CbmDeviceBuildDigiEvents.cxx | 12 +++---
 MQ/mcbm/CbmDeviceDigiEventSink.cxx   | 55 ++++++++++++++++++----------
 MQ/mcbm/CbmDeviceDigiEventSink.h     | 10 +++--
 MQ/mcbm/runDigiEventSink.cxx         |  2 +
 MQ/source/CbmMQTsSamplerRepReq.cxx   | 47 +++++++++++++++++-------
 MQ/source/CbmMQTsSamplerRepReq.h     |  1 +
 MQ/source/runTsSamplerRepReq.cxx     |  2 +
 7 files changed, 86 insertions(+), 43 deletions(-)

diff --git a/MQ/mcbm/CbmDeviceBuildDigiEvents.cxx b/MQ/mcbm/CbmDeviceBuildDigiEvents.cxx
index 772c18451f..ce20891f33 100644
--- a/MQ/mcbm/CbmDeviceBuildDigiEvents.cxx
+++ b/MQ/mcbm/CbmDeviceBuildDigiEvents.cxx
@@ -695,7 +695,8 @@ bool CbmDeviceBuildDigiEvents::SendDigiEvents(FairMQParts& partsIn)
     /// Get the proper order for block selection as TRD1D and TRD2D may insert indices in separate loops
     /// => Needed to ensure that the start and stop of the block copy do not trigger a vector size exception
     event->SortIndices();
-        /// for each detector, find the data in the Digi vectors and copy them
+
+    /// for each detector, find the data in the Digi vectors and copy them
     /// TODO: Template + loop on list of data types?
     /// ==> T0
     uint32_t uNbDigis = (0 < event->GetNofData(ECbmDataType::kT0Digi) ? event->GetNofData(ECbmDataType::kT0Digi) : 0);
@@ -769,10 +770,11 @@ bool CbmDeviceBuildDigiEvents::SendDigiEvents(FairMQParts& partsIn)
   boost::archive::binary_oarchive oaEvt(ossEvt);
   oaEvt << vOutEvents;
   std::string* strMsgEvt = new std::string(ossEvt.str());
-  FairMQMessagePtr message(NewMessage(const_cast<char*>(strMsgEvt->c_str()),  // data
-                                      strMsgEvt->length(),                    // size
-                                      [](void*, void* object) { delete static_cast<std::string*>(object); },
-                                      strMsgEvt));  // object that manages the data
+  FairMQMessagePtr message(NewMessage(
+    const_cast<char*>(strMsgEvt->c_str()),  // data
+    strMsgEvt->length(),                    // size
+    [](void*, void* object) { delete static_cast<std::string*>(object); },
+    strMsgEvt));  // object that manages the data
   LOG(debug) << "Serializing done";
 
   /// Make a new composed messaged with TsHeader + vector of Digi Event + TsMetaData
diff --git a/MQ/mcbm/CbmDeviceDigiEventSink.cxx b/MQ/mcbm/CbmDeviceDigiEventSink.cxx
index c184d93abf..cdf99c95fc 100644
--- a/MQ/mcbm/CbmDeviceDigiEventSink.cxx
+++ b/MQ/mcbm/CbmDeviceDigiEventSink.cxx
@@ -35,9 +35,9 @@
 #include "TCanvas.h"
 #include "TFile.h"
 #include "TH1.h"
-#include "TProfile.h"
 #include "TList.h"
 #include "TNamed.h"
+#include "TProfile.h"
 
 #include <boost/archive/binary_iarchive.hpp>
 #include <boost/serialization/utility.hpp>
@@ -80,6 +80,7 @@ try {
   fuPublishFreqTs          = fConfig->GetValue<uint32_t>("PubFreqTs");
   fdMinPublishTime         = fConfig->GetValue<double_t>("PubTimeMin");
   fdMaxPublishTime         = fConfig->GetValue<double_t>("PubTimeMax");
+  fsHistosSuffix           = fConfig->GetValue<std::string>("HistosSuffix");
   fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
 
   /// Associate the MissedTs Channel to the corresponding handler
@@ -217,26 +218,40 @@ bool CbmDeviceDigiEventSink::InitHistograms()
   // ALGO: std::vector<std::pair<TNamed*, std::string>> vHistos = fMonitorAlgo->GetHistoVector();
   std::vector<std::pair<TNamed*, std::string>> vHistos = {};
 
-  fhFullTsBuffSizeEvo =
-    new TProfile("hFullTsBuffSizeEvo", "Evo. of the full TS buffer size; Time in run [s]; Size []", 720, 0, 7200);
-  fhMissTsBuffSizeEvo =
-    new TProfile("hMissTsBuffSizeEvo", "Evo. of the missed TS buffer size; Time in run [s]; Size []", 720, 0, 7200);
-  fhFullTsProcEvo  = new TH1I("hFullTsProcEvo", "Processed full TS; Time in run [s]; # []", 720, 0, 7200);
-  fhMissTsProcEvo  = new TH1I("hMissTsProcEvo", "Processed missing TS; Time in run [s]; # []", 720, 0, 7200);
-  fhTotalTsProcEvo = new TH1I("hTotalTsProcEvo", "Total processed TS; Time in run [s]; # []", 720, 0, 7200);
-  fhTotalEventsEvo = new TH1I("hTotalEventsEvo", "Processed events; Time in run [s]; # []", 720, 0, 7200);
-  vHistos.push_back(std::pair<TNamed*, std::string>(fhFullTsBuffSizeEvo, "EvtSink"));
-  vHistos.push_back(std::pair<TNamed*, std::string>(fhMissTsBuffSizeEvo, "EvtSink"));
-  vHistos.push_back(std::pair<TNamed*, std::string>(fhFullTsProcEvo, "EvtSink"));
-  vHistos.push_back(std::pair<TNamed*, std::string>(fhMissTsProcEvo, "EvtSink"));
-  vHistos.push_back(std::pair<TNamed*, std::string>(fhTotalTsProcEvo, "EvtSink"));
-  vHistos.push_back(std::pair<TNamed*, std::string>(fhTotalEventsEvo, "EvtSink"));
+  /* clang-format off */
+  fhFullTsBuffSizeEvo = new TProfile(Form("hFullTsBuffSizeEvo%s", fsHistosSuffix.data()),
+                                     "Evo. of the full TS buffer size; Time in run [s]; Size []",
+                                     720, 0, 7200);
+  fhMissTsBuffSizeEvo = new TProfile(Form("hMissTsBuffSizeEvo%s", fsHistosSuffix.data()),
+                                     "Evo. of the missed TS buffer size; Time in run [s]; Size []",
+                                     720, 0, 7200);
+  fhFullTsProcEvo  = new TH1I(Form("hFullTsProcEvo%s", fsHistosSuffix.data()),
+                              "Processed full TS; Time in run [s]; # []",
+                              720, 0, 7200);
+  fhMissTsProcEvo  = new TH1I(Form("hMissTsProcEvo%s", fsHistosSuffix.data()),
+                              "Processed missing TS; Time in run [s]; # []",
+                              720, 0, 7200);
+  fhTotalTsProcEvo = new TH1I(Form("hTotalTsProcEvo%s", fsHistosSuffix.data()),
+                              "Total processed TS; Time in run [s]; # []",
+                              720, 0, 7200);
+  fhTotalEventsEvo = new TH1I(Form("hTotalEventsEvo%s", fsHistosSuffix.data()),
+                              "Processed events; Time in run [s]; # []",
+                              720, 0, 7200);
+  /* clang-format on */
+
+  std::string sFolder = std::string("EvtSink") + fsHistosSuffix;
+  vHistos.push_back(std::pair<TNamed*, std::string>(fhFullTsBuffSizeEvo, sFolder));
+  vHistos.push_back(std::pair<TNamed*, std::string>(fhMissTsBuffSizeEvo, sFolder));
+  vHistos.push_back(std::pair<TNamed*, std::string>(fhFullTsProcEvo, sFolder));
+  vHistos.push_back(std::pair<TNamed*, std::string>(fhMissTsProcEvo, sFolder));
+  vHistos.push_back(std::pair<TNamed*, std::string>(fhTotalTsProcEvo, sFolder));
+  vHistos.push_back(std::pair<TNamed*, std::string>(fhTotalEventsEvo, sFolder));
 
   /// Obtain vector of pointers on each canvas from the algo (+ optionally desired folder) or create them locally
   // ALGO: std::vector<std::pair<TCanvas*, std::string>> vCanvases = fMonitorAlgo->GetCanvasVector();
   std::vector<std::pair<TCanvas*, std::string>> vCanvases = {};
 
-  fcEventSinkAllHist = new TCanvas("cEventSinkAllHist", "Event Sink Monitoring");
+  fcEventSinkAllHist = new TCanvas(Form("cEventSinkAllHist%s", fsHistosSuffix.data()), "Event Sink Monitoring");
   fcEventSinkAllHist->Divide(3, 2);
 
   fcEventSinkAllHist->cd(1);
@@ -270,7 +285,7 @@ bool CbmDeviceDigiEventSink::InitHistograms()
   gPad->SetLogy();
   fhTotalEventsEvo->Draw("hist");
 
-  vCanvases.push_back(std::pair<TCanvas*, std::string>(fcEventSinkAllHist, "canvases"));
+  vCanvases.push_back(std::pair<TCanvas*, std::string>(fcEventSinkAllHist, std::string("canvases") + fsHistosSuffix));
 
   /// Add pointers to each histo in the histo array
   /// Create histo config vector
@@ -425,9 +440,9 @@ bool CbmDeviceDigiEventSink::HandleData(FairMQParts& parts, int /*index*/)
       fhMissTsProcEvo->Fill(secInRun.count(), (fulMissedTsCounter - fulLastMissTsCounter));
       fhTotalTsProcEvo->Fill(secInRun.count(),
                              (fulTsCounter - fulLastFullTsCounter + fulMissedTsCounter - fulLastMissTsCounter));
-      fhTotalEventsEvo->Fill(secInRun.count(), fulProcessedEvents -fulLastProcessedEvents);
+      fhTotalEventsEvo->Fill(secInRun.count(), fulProcessedEvents - fulLastProcessedEvents);
 
-      fLastFillTime = currentTime;
+      fLastFillTime          = currentTime;
       fulLastFullTsCounter   = fulTsCounter;
       fulLastMissTsCounter   = fulMissedTsCounter;
       fulLastProcessedEvents = fulProcessedEvents;
@@ -785,7 +800,7 @@ void CbmDeviceDigiEventSink::Finish()
 
 CbmEventTimeslice::CbmEventTimeslice(FairMQParts& parts, bool bDigiEvtInput)
 {
-  fbDigiEvtInput =bDigiEvtInput;
+  fbDigiEvtInput = bDigiEvtInput;
 
   uint32_t uPartIdx = 0;
 
diff --git a/MQ/mcbm/CbmDeviceDigiEventSink.h b/MQ/mcbm/CbmDeviceDigiEventSink.h
index a91e38280e..958fdc1a7e 100644
--- a/MQ/mcbm/CbmDeviceDigiEventSink.h
+++ b/MQ/mcbm/CbmDeviceDigiEventSink.h
@@ -56,7 +56,8 @@ public:
   ~CbmEventTimeslice();
 
   void ExtractSelectedData();
-  std::vector<CbmDigiEvent>& GetSelectedData(){
+  std::vector<CbmDigiEvent>& GetSelectedData()
+  {
     if (!fbDigiEvtInput) ExtractSelectedData();
     return fvDigiEvents;
   }
@@ -116,9 +117,10 @@ private:
   /// Output file/tree management
   int64_t fiTreeFileMaxSize = 10000000000LL;  //! Default value: ~10 GB
   /// Histograms management
-  uint32_t fuPublishFreqTs  = 100;
-  double_t fdMinPublishTime = 0.5;
-  double_t fdMaxPublishTime = 5.0;
+  uint32_t fuPublishFreqTs   = 100;
+  double_t fdMinPublishTime  = 0.5;
+  double_t fdMaxPublishTime  = 5.0;
+  std::string fsHistosSuffix = "";
 
   /// List of MQ channels names
   std::vector<std::string> fsAllowedChannels = {fsChannelNameDataInput};
diff --git a/MQ/mcbm/runDigiEventSink.cxx b/MQ/mcbm/runDigiEventSink.cxx
index c6df0f8088..ade9d4a6e5 100644
--- a/MQ/mcbm/runDigiEventSink.cxx
+++ b/MQ/mcbm/runDigiEventSink.cxx
@@ -42,6 +42,8 @@ void addCustomOptions(bpo::options_description& options)
                         "Minimal time between two publishing");
   options.add_options()("PubTimeMax", bpo::value<double_t>()->default_value(10.0),
                         "Maximal time between two publishing");
+  options.add_options()("HistosSuffix", bpo::value<std::string>()->default_value(""),
+                        "Suffix added to folders, histos and canvases names, e.g. for multiple nodes usages");
   options.add_options()("ChNameIn", bpo::value<std::string>()->default_value("histogram-in"),
                         "MQ channel name for histos");
 }
diff --git a/MQ/source/CbmMQTsSamplerRepReq.cxx b/MQ/source/CbmMQTsSamplerRepReq.cxx
index 1524507c43..b8fa2f6a50 100644
--- a/MQ/source/CbmMQTsSamplerRepReq.cxx
+++ b/MQ/source/CbmMQTsSamplerRepReq.cxx
@@ -75,6 +75,7 @@ try {
   fuPublishFreqTs          = fConfig->GetValue<uint32_t>("PubFreqTs");
   fdMinPublishTime         = fConfig->GetValue<double_t>("PubTimeMin");
   fdMaxPublishTime         = fConfig->GetValue<double_t>("PubTimeMax");
+  fsHistosSuffix           = fConfig->GetValue<std::string>("HistosSuffix");
   fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
 
   if (fbNoSplitTs) {
@@ -252,6 +253,9 @@ bool CbmMQTsSamplerRepReq::InitHistograms()
   LOG(info) << "Histograms publication frequency in TS:    " << fuPublishFreqTs;
   LOG(info) << "Histograms publication min. interval in s: " << fdMinPublishTime;
   LOG(info) << "Histograms publication max. interval in s: " << fdMaxPublishTime;
+  if ("" != fsHistosSuffix) {  //
+    LOG(info) << "Suffix added to folders, histograms and canvas names: " << fsHistosSuffix;
+  }
 
   /// Vector of pointers on each histo (+ optionally desired folder)
   std::vector<std::pair<TNamed*, std::string>> vHistos = {};
@@ -259,25 +263,40 @@ bool CbmMQTsSamplerRepReq::InitHistograms()
   std::vector<std::pair<TCanvas*, std::string>> vCanvases = {};
 
   /// Histos creation and obtain pointer on them
-  fhTsRate       = new TH1I("TsRate", "TS rate; t [s]", 1800, 0., 1800.);
-  fhTsSize       = new TH1I("TsSize", "Size of TS; Size [MB]", 15000, 0., 15000.);
-  fhTsSizeEvo    = new TProfile("TsSizeEvo", "Evolution of the TS Size; t [s]; Mean size [MB]", 1800, 0., 1800.);
-  fhTsMaxSizeEvo = new TH1F("TsMaxSizeEvo", "Evolution of maximal TS Size; t [s]; Max size [MB]", 1800, 0., 1800.);
-  fhMissedTS     = new TH1I("Missed_TS", "Missed TS", 2, -0.5, 1.5);
-  fhMissedTSEvo  = new TProfile("Missed_TS_Evo", "Missed TS evolution; t [s]", 1800, 0., 1800.);
+  /* clang-format off */
+  fhTsRate       = new TH1I(Form("TsRate%s", fsHistosSuffix.data()),
+                            "TS rate; t [s]",
+                            1800, 0., 1800.);
+  fhTsSize       = new TH1I(Form("TsSize%s", fsHistosSuffix.data()),
+                           "Size of TS; Size [MB]",
+                           15000, 0., 15000.);
+  fhTsSizeEvo    = new TProfile(Form("TsSizeEvo%s", fsHistosSuffix.data()),
+                                "Evolution of the TS Size; t [s]; Mean size [MB]",
+                                1800, 0., 1800.);
+  fhTsMaxSizeEvo = new TH1F(Form("TsMaxSizeEvo%s", fsHistosSuffix.data()),
+                            "Evolution of maximal TS Size; t [s]; Max size [MB]",
+                            1800, 0., 1800.);
+  fhMissedTS     = new TH1I(Form("MissedTs%s", fsHistosSuffix.data()),
+                            "Missed TS",
+                            2, -0.5, 1.5);
+  fhMissedTSEvo  = new TProfile(Form("MissedTsEvo%s", fsHistosSuffix.data()),
+                                "Missed TS evolution; t [s]",
+                                1800, 0., 1800.);
+  /* clang-format on */
 
   /// Add histo pointers to the histo vector
-  vHistos.push_back(std::pair<TNamed*, std::string>(fhTsRate, "Sampler"));
-  vHistos.push_back(std::pair<TNamed*, std::string>(fhTsSize, "Sampler"));
-  vHistos.push_back(std::pair<TNamed*, std::string>(fhTsSizeEvo, "Sampler"));
-  vHistos.push_back(std::pair<TNamed*, std::string>(fhTsMaxSizeEvo, "Sampler"));
-  vHistos.push_back(std::pair<TNamed*, std::string>(fhMissedTS, "Sampler"));
-  vHistos.push_back(std::pair<TNamed*, std::string>(fhMissedTSEvo, "Sampler"));
+  std::string sFolder = std::string("Sampler") + fsHistosSuffix;
+  vHistos.push_back(std::pair<TNamed*, std::string>(fhTsRate, sFolder));
+  vHistos.push_back(std::pair<TNamed*, std::string>(fhTsSize, sFolder));
+  vHistos.push_back(std::pair<TNamed*, std::string>(fhTsSizeEvo, sFolder));
+  vHistos.push_back(std::pair<TNamed*, std::string>(fhTsMaxSizeEvo, sFolder));
+  vHistos.push_back(std::pair<TNamed*, std::string>(fhMissedTS, sFolder));
+  vHistos.push_back(std::pair<TNamed*, std::string>(fhMissedTSEvo, sFolder));
 
   /// Canvases creation
   Double_t w = 10;
   Double_t h = 10;
-  fcSummary  = new TCanvas("cSampSummary", "Sampler monitoring plots", w, h);
+  fcSummary  = new TCanvas(Form("cSampSummary%s", fsHistosSuffix.data()), "Sampler monitoring plots", w, h);
   fcSummary->Divide(2, 3);
 
   fcSummary->cd(1);
@@ -313,7 +332,7 @@ bool CbmMQTsSamplerRepReq::InitHistograms()
   fhMissedTSEvo->Draw("el");
 
   /// Add canvas pointers to the canvas vector
-  vCanvases.push_back(std::pair<TCanvas*, std::string>(fcSummary, "canvases"));
+  vCanvases.push_back(std::pair<TCanvas*, std::string>(fcSummary, std::string("canvases") + fsHistosSuffix));
 
   /// Add pointers to each histo in the histo array
   /// Create histo config vector
diff --git a/MQ/source/CbmMQTsSamplerRepReq.h b/MQ/source/CbmMQTsSamplerRepReq.h
index b12b6a268c..21d9426148 100644
--- a/MQ/source/CbmMQTsSamplerRepReq.h
+++ b/MQ/source/CbmMQTsSamplerRepReq.h
@@ -58,6 +58,7 @@ protected:
   uint32_t fuPublishFreqTs             = 0;
   double_t fdMinPublishTime            = 0.5;
   double_t fdMaxPublishTime            = 5;
+  std::string fsHistosSuffix           = "";
 
   uint64_t fulFirstTsIndex   = 0;
   uint64_t fulPrevTsIndex    = 0;
diff --git a/MQ/source/runTsSamplerRepReq.cxx b/MQ/source/runTsSamplerRepReq.cxx
index 0663ad70a3..69bb37c408 100644
--- a/MQ/source/runTsSamplerRepReq.cxx
+++ b/MQ/source/runTsSamplerRepReq.cxx
@@ -43,6 +43,8 @@ void addCustomOptions(bpo::options_description& options)
                         "Minimal time between two publishing");
   options.add_options()("PubTimeMax", bpo::value<double_t>()->default_value(10.0),
                         "Maximal time between two publishing");
+  options.add_options()("HistosSuffix", bpo::value<std::string>()->default_value(""),
+                        "Suffix added to folders, histos and canvases names, e.g. for multiple nodes usages");
   options.add_options()("ChNameIn", bpo::value<std::string>()->default_value("histogram-in"),
                         "MQ channel name for histos");
 }
-- 
GitLab