From 5336eeda8196ddc2f0c66880ac2a526d9ad5201b Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 24 Sep 2025 12:21:48 +0200 Subject: [PATCH 1/2] DPL: allow closing a signpost interval with an error The error will be printed regardless of the signposts being enabled. In case the signposts are actually enabled, the error will be the closing message of the signpost interval. In case the signposts are not enabled, the error will be printed as a standard error. --- Framework/Foundation/include/Framework/Signpost.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Framework/Foundation/include/Framework/Signpost.h b/Framework/Foundation/include/Framework/Signpost.h index 7ed544c529303..51d1b0433b0de 100644 --- a/Framework/Foundation/include/Framework/Signpost.h +++ b/Framework/Foundation/include/Framework/Signpost.h @@ -611,6 +611,16 @@ void o2_debug_log_set_stacktrace(_o2_log_t* log, int stacktrace) } else if (O2_BUILTIN_UNLIKELY(private_o2_log_##log->stacktrace)) { \ _o2_signpost_interval_end(private_o2_log_##log, id, name, remove_engineering_type(format).data(), ##__VA_ARGS__); \ } +// Print out a message at error level in any case even if the signpost is not enable. +// If it is enabled, behaves like O2_SIGNPOST_END. +#define O2_SIGNPOST_END_WITH_ERROR(log, id, name, format, ...) \ + if (O2_BUILTIN_UNLIKELY(O2_SIGNPOST_ENABLED_MAC(log))) { \ + O2_SIGNPOST_END_MAC(log, id, name, format, ##__VA_ARGS__); \ + } else if (O2_BUILTIN_UNLIKELY(private_o2_log_##log->stacktrace)) { \ + _o2_signpost_interval_end(private_o2_log_##log, id, name, remove_engineering_type(format).data(), ##__VA_ARGS__); \ + } else { \ + O2_LOG_MACRO_RAW(error, remove_engineering_type(format).data(), ##__VA_ARGS__); \ + } #else // This is the release implementation, it does nothing. #define O2_DECLARE_DYNAMIC_LOG(x) #define O2_DECLARE_DYNAMIC_STACKTRACE_LOG(x) From 18ce36bd66668db83754d188d38caba10dba6ed8 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 25 Sep 2025 11:31:50 +0200 Subject: [PATCH 2/2] DPL Analysis: write HistogramRegistry incrementally This should reduce big spikes at the end of the processing when a large HistogramRegistry is serialised. --- .../AnalysisSupport/src/AODWriterHelpers.cxx | 137 ++++++++++++------ .../Core/include/Framework/AnalysisManagers.h | 6 +- .../include/Framework/HistogramRegistry.h | 14 +- .../Core/include/Framework/OutputObjHeader.h | 2 + Framework/Core/src/HistogramRegistry.cxx | 94 +++--------- .../TestWorkflows/src/o2TestHistograms.cxx | 46 ++++++ 6 files changed, 167 insertions(+), 132 deletions(-) diff --git a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx index 475e65bf9212b..27dad43480913 100644 --- a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx @@ -22,14 +22,20 @@ #include "Framework/DataOutputDirector.h" #include "Framework/TableTreeHelpers.h" #include "Framework/Monitoring.h" +#include "Framework/Signpost.h" #include +#include #include #include #include #include #include #include +#include +#include + +O2_DECLARE_DYNAMIC_LOG(histogram_registry); namespace o2::framework::writers { @@ -46,6 +52,7 @@ struct InputObjectRoute { struct InputObject { TClass* kind = nullptr; void* obj = nullptr; + std::string container; std::string name; int count = -1; }; @@ -273,24 +280,30 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) callbacks.set(endofdatacb); return [inputObjects, objmap, tskmap](ProcessingContext& pc) mutable -> void { auto mergePart = [&inputObjects, &objmap, &tskmap, &pc](DataRef const& ref) { + O2_SIGNPOST_ID_GENERATE(hid, histogram_registry); + O2_SIGNPOST_START(histogram_registry, hid, "mergePart", "Merging histogram"); if (!ref.header) { - LOG(error) << "Header not found"; + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "Header not found."); return; } auto datah = o2::header::get(ref.header); if (!datah) { - LOG(error) << "No data header in stack"; + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "No data header in stack"); return; } if (!ref.payload) { - LOGP(error, "Payload not found for {}/{}/{}", datah->dataOrigin.as(), datah->dataDescription.as(), datah->subSpecification); + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "Payload not found for %{public}s/%{public}s/%d", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); return; } auto objh = o2::header::get(ref.header); if (!objh) { - LOGP(error, "No output object header in stack of {}/{}/{}", datah->dataOrigin.as(), datah->dataDescription.as(), datah->subSpecification); + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "No output object header in stack of %{public}s/%{public}s/%d.", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); return; } @@ -300,48 +313,73 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) obj.kind = tm.ReadClass(); tm.SetBufferOffset(0); tm.ResetMap(); + O2_SIGNPOST_ID_GENERATE(did, histogram_registry); + O2_SIGNPOST_START(histogram_registry, did, "initialising root", "Starting deserialization of %{public}s/%{public}s/%d", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); if (obj.kind == nullptr) { - LOGP(error, "Cannot read class info from buffer of {}/{}/{}", datah->dataOrigin.as(), datah->dataDescription.as(), datah->subSpecification); + O2_SIGNPOST_END(histogram_registry, did, "initialising root", "Failed to deserialise"); + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "Cannot read class info from buffer of %{public}s/%{public}s/%d.", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); return; } + O2_SIGNPOST_END(histogram_registry, did, "initialising root", "Done init."); auto policy = objh->mPolicy; auto sourceType = objh->mSourceType; auto hash = objh->mTaskHash; + O2_SIGNPOST_START(histogram_registry, did, "deserialization", "Starting deserialization of %{public}s/%{public}s/%d", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); obj.obj = tm.ReadObjectAny(obj.kind); auto* named = static_cast(obj.obj); obj.name = named->GetName(); + O2_SIGNPOST_END(histogram_registry, did, "deserialization", "Done deserialization."); + // If we have a folder, we assume the first element of the path + // to be the name of the registry. + if (sourceType == HistogramRegistrySource) { + obj.container = objh->containerName; + } else { + obj.container = obj.name; + } auto hpos = std::find_if(tskmap.begin(), tskmap.end(), [&](auto&& x) { return x.id == hash; }); if (hpos == tskmap.end()) { - LOG(error) << "No task found for hash " << hash; + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "No task found for hash %d.", hash); return; } auto taskname = hpos->name; auto opos = std::find_if(objmap.begin(), objmap.end(), [&](auto&& x) { return x.id == hash; }); if (opos == objmap.end()) { - LOG(error) << "No object list found for task " << taskname << " (hash=" << hash << ")"; + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "No object list found for task %{public}s (hash=%d).", + taskname.c_str(), hash); return; } auto objects = opos->bindings; - if (std::find(objects.begin(), objects.end(), obj.name) == objects.end()) { - LOG(error) << "No object " << obj.name << " in map for task " << taskname; + if (std::find(objects.begin(), objects.end(), obj.container) == objects.end()) { + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "No container %{public}s in map for task %{public}s.", + obj.container.c_str(), taskname.c_str()); return; } auto nameHash = runtime_hash(obj.name.c_str()); InputObjectRoute key{obj.name, nameHash, taskname, hash, policy, sourceType}; auto existing = std::find_if(inputObjects->begin(), inputObjects->end(), [&](auto&& x) { return (x.first.uniqueId == nameHash) && (x.first.taskHash == hash); }); // If it's the first one, we just add it to the list. + O2_SIGNPOST_START(histogram_registry, did, "merging", "Starting merging of %{public}s/%{public}s/%d", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); if (existing == inputObjects->end()) { obj.count = objh->mPipelineSize; - inputObjects->push_back(std::make_pair(key, obj)); + inputObjects->emplace_back(key, obj); existing = inputObjects->end() - 1; } else { obj.count = existing->second.count; // Otherwise, we merge it with the existing one. auto merger = existing->second.kind->GetMerge(); if (!merger) { - LOG(error) << "Already one unmergeable object found for " << obj.name; + O2_SIGNPOST_END(histogram_registry, did, "merging", "Unabled to merge"); + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "merging", "Already one unmergeable object found for %{public}s", obj.name.c_str()); return; } TList coll; @@ -353,15 +391,22 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) existing->second.count -= 1; if (existing->second.count != 0) { + O2_SIGNPOST_END(histogram_registry, did, "merging", "Done partial merging."); + O2_SIGNPOST_END(histogram_registry, hid, "mergePart", "Pipeline lanes still missing."); return; } + O2_SIGNPOST_END(histogram_registry, did, "merging", "Done merging."); // Write the object here. auto route = existing->first; auto entry = existing->second; auto file = ROOTfileNames.find(route.policy); if (file == ROOTfileNames.end()) { + O2_SIGNPOST_END(histogram_registry, hid, "mergePart", "Not matching any file."); return; } + O2_SIGNPOST_START(histogram_registry, did, "writing", "Starting writing of %{public}s/%{public}s/%d", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); auto filename = file->second; if (f[route.policy] == nullptr) { f[route.policy] = TFile::Open(filename.c_str(), "RECREATE"); @@ -375,53 +420,53 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) currentFile = filename; } - // translate the list-structure created by the registry into a directory structure within the file - std::function writeListToFile; - writeListToFile = [&](TList* list, TDirectory* parentDir) { - TIter next(list); - TObject* object = nullptr; - while ((object = next())) { - if (object->InheritsFrom(TList::Class())) { - writeListToFile(static_cast(object), parentDir->mkdir(object->GetName(), object->GetName(), true)); + // FIXME: handle folders + f[route.policy]->cd("/"); + auto* currentDir = f[route.policy]->GetDirectory(currentDirectory.c_str()); + // The name contains a path... + int objSize = 0; + if (sourceType == HistogramRegistrySource) { + TDirectory* currentFolder = currentDir; + O2_SIGNPOST_EVENT_EMIT(histogram_registry, hid, "mergePart", "Toplevel folder is %{public}s.", + currentDir->GetName()); + std::string objName = entry.name; + auto lastSlash = entry.name.rfind('/'); + + if (lastSlash != std::string::npos) { + auto dirname = entry.name.substr(0, lastSlash); + objName = entry.name.substr(lastSlash + 1); + currentFolder = currentDir->GetDirectory(dirname.c_str()); + if (!currentFolder) { + O2_SIGNPOST_EVENT_EMIT(histogram_registry, hid, "mergePart", "Creating folder %{public}s", + dirname.c_str()); + currentFolder = currentDir->mkdir(dirname.c_str(), "", kTRUE); } else { - int objSize = parentDir->WriteObjectAny(object, object->Class(), object->GetName()); - static int maxSizeWritten = 0; - if (objSize > maxSizeWritten) { - auto& monitoring = pc.services().get(); - maxSizeWritten = objSize; - monitoring.send(Metric{fmt::format("{}/{}:{}", object->ClassName(), object->GetName(), objSize), "aod-largest-object-written"}.addTag(tags::Key::Subsystem, tags::Value::DPL)); - } - auto* written = list->Remove(object); - delete written; + O2_SIGNPOST_EVENT_EMIT(histogram_registry, hid, "mergePart", "Folder %{public}s already there.", + currentFolder->GetName()); } } - }; - - TDirectory* currentDir = f[route.policy]->GetDirectory(currentDirectory.c_str()); - if (route.sourceType == OutputObjSourceType::HistogramRegistrySource) { - auto* outputList = static_cast(entry.obj); - outputList->SetOwner(false); - - // if registry should live in dedicated folder a TNamed object is appended to the list - if (outputList->Last() && outputList->Last()->IsA() == TNamed::Class()) { - delete outputList->Last(); - outputList->RemoveLast(); - currentDir = currentDir->mkdir(outputList->GetName(), outputList->GetName(), true); - } - - writeListToFile(outputList, currentDir); - outputList->SetOwner(); - delete outputList; + O2_SIGNPOST_EVENT_EMIT(histogram_registry, hid, "mergePart", "Writing %{public}s of kind %{public}s in %{public}s", + entry.name.c_str(), entry.kind->GetName(), currentDir->GetName()); + objSize = currentFolder->WriteObjectAny(entry.obj, entry.kind, objName.c_str()); + O2_SIGNPOST_END(histogram_registry, did, "writing", "End writing %{public}s", entry.name.c_str()); + delete (TObject*)entry.obj; entry.obj = nullptr; } else { - currentDir->WriteObjectAny(entry.obj, entry.kind, entry.name.c_str()); + O2_SIGNPOST_EVENT_EMIT(histogram_registry, hid, "mergePart", "Writing %{public}s of kind %{public}s in %{public}s", + entry.name.c_str(), entry.kind->GetName(), currentDir->GetName()); + objSize = currentDir->WriteObjectAny(entry.obj, entry.kind, entry.name.c_str()); + O2_SIGNPOST_END(histogram_registry, did, "writing", "End writing %{public}s", entry.name.c_str()); delete (TObject*)entry.obj; entry.obj = nullptr; } + O2_SIGNPOST_END(histogram_registry, hid, "mergePart", "Done merging object of %d bytes.", objSize); }; + O2_SIGNPOST_ID_GENERATE(rid, histogram_registry); + O2_SIGNPOST_START(histogram_registry, rid, "processParts", "Start merging %zu parts received together.", pc.inputs().getNofParts(0)); for (int pi = 0; pi < pc.inputs().getNofParts(0); ++pi) { mergePart(pc.inputs().get("x", pi)); } + O2_SIGNPOST_END(histogram_registry, rid, "processParts", "Done histograms in multipart message."); }; }}; } diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h index 6c43bf3eebebb..596f3da6a557a 100644 --- a/Framework/Core/include/Framework/AnalysisManagers.h +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -11,6 +11,7 @@ #ifndef FRAMEWORK_ANALYSISMANAGERS_H #define FRAMEWORK_ANALYSISMANAGERS_H +#include "DataAllocator.h" #include "Framework/AnalysisHelpers.h" #include "Framework/DataSpecUtils.h" #include "Framework/GroupedCombinations.h" @@ -247,7 +248,10 @@ template bool postRunOutput(EndOfStreamContext& context, T& hr) { auto& deviceSpec = context.services().get(); - context.outputs().snapshot(hr.ref(deviceSpec.inputTimesliceId, deviceSpec.maxInputTimeslices), *(hr.getListOfHistograms())); + auto sendHistos = [deviceSpec, &context](HistogramRegistry const& self, TNamed* obj) mutable { + context.outputs().snapshot(self.ref(deviceSpec.inputTimesliceId, deviceSpec.maxInputTimeslices), *obj); + }; + hr.apply(sendHistos); hr.clean(); return true; } diff --git a/Framework/Core/include/Framework/HistogramRegistry.h b/Framework/Core/include/Framework/HistogramRegistry.h index 6db4bd0a2d0e2..49ef006f84a79 100644 --- a/Framework/Core/include/Framework/HistogramRegistry.h +++ b/Framework/Core/include/Framework/HistogramRegistry.h @@ -173,16 +173,15 @@ class HistogramRegistry template std::shared_ptr operator()(const HistName& histName); + // Apply @a callback on every single entry in the registry + void apply(std::function callback) const; // return the OutputSpec associated to the HistogramRegistry OutputSpec const spec(); - OutputRef ref(uint16_t idx, uint16_t pipelineSize); + OutputRef ref(uint16_t idx, uint16_t pipelineSize) const; void setHash(uint32_t hash); - /// returns the list of histograms, properly sorted for writing. - TList* getListOfHistograms(); - /// deletes all the histograms from the registry void clean(); @@ -220,16 +219,13 @@ class HistogramRegistry // helper function to find the histogram position in the registry template - uint32_t getHistIndex(const T& histName); + uint32_t getHistIndex(const T& histName) const; constexpr uint32_t imask(uint32_t i) const { return i & REGISTRY_BITMASK; } - // helper function to create resp. find the subList defined by path - TList* getSubList(TList* list, std::deque& path); - // helper function to split user defined path/to/hist/name string std::deque splitPath(const std::string& pathAndNameUser); @@ -431,7 +427,7 @@ std::shared_ptr HistogramRegistry::operator()(const HistName& histName) } template -uint32_t HistogramRegistry::getHistIndex(const T& histName) +uint32_t HistogramRegistry::getHistIndex(const T& histName) const { if (O2_BUILTIN_LIKELY(histName.hash == mRegistryKey[histName.idx])) { return histName.idx; diff --git a/Framework/Core/include/Framework/OutputObjHeader.h b/Framework/Core/include/Framework/OutputObjHeader.h index 6e665bb697572..f1c284d564f15 100644 --- a/Framework/Core/include/Framework/OutputObjHeader.h +++ b/Framework/Core/include/Framework/OutputObjHeader.h @@ -44,6 +44,8 @@ struct OutputObjHeader : public BaseHeader { uint32_t mTaskHash; uint16_t mPipelineIndex = 0; uint16_t mPipelineSize = 1; + // Name of the actual container for the object, e.g. the HistogramRegistry name + char containerName[64] = {0}; constexpr OutputObjHeader() : BaseHeader(sizeof(OutputObjHeader), sHeaderType, sSerializationMethod, sVersion), diff --git a/Framework/Core/src/HistogramRegistry.cxx b/Framework/Core/src/HistogramRegistry.cxx index 0a0cc1fc3a690..5e39fbe7181e7 100644 --- a/Framework/Core/src/HistogramRegistry.cxx +++ b/Framework/Core/src/HistogramRegistry.cxx @@ -51,9 +51,12 @@ OutputSpec const HistogramRegistry::spec() return OutputSpec{OutputLabel{mName}, "ATSK", desc, 0, Lifetime::QA}; } -OutputRef HistogramRegistry::ref(uint16_t pipelineIndex, uint16_t pipelineSize) +OutputRef HistogramRegistry::ref(uint16_t pipelineIndex, uint16_t pipelineSize) const { - return OutputRef{std::string{mName}, 0, o2::header::Stack{OutputObjHeader{mPolicy, OutputObjSourceType::HistogramRegistrySource, mTaskHash, pipelineIndex, pipelineSize}}}; + OutputObjHeader header{mPolicy, OutputObjSourceType::HistogramRegistrySource, mTaskHash, pipelineIndex, pipelineSize}; + // Copy the name of the registry to the haeder. + strncpy(header.containerName, mName.data(), 64); + return OutputRef{std::string{mName}, 0, o2::header::Stack{header}}; } void HistogramRegistry::setHash(uint32_t hash) @@ -282,87 +285,26 @@ void HistogramRegistry::print(bool showAxisDetails) LOGF(info, ""); } -// create output structure will be propagated to file-sink -TList* HistogramRegistry::getListOfHistograms() +void HistogramRegistry::apply(std::function callback) const { - TList* list = new TList(); - list->SetName(mName.data()); - + // Keep the list sorted as originally done to avoid hidden dependency on the order, for now , for now. + auto finalList = mRegisteredNames; + auto caseInsensitiveCompare = [](const std::string& s1, const std::string& s2) { + return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), + [](char c1, char c2) { return std::tolower(static_cast(c1)) < std::tolower(static_cast(c2)); }); + }; if (mSortHistos) { - auto caseInsensitiveCompare = [](const std::string& s1, const std::string& s2) { - return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), - [](char c1, char c2) { return std::tolower(static_cast(c1)) < std::tolower(static_cast(c2)); }); - }; - std::sort(mRegisteredNames.begin(), mRegisteredNames.end(), caseInsensitiveCompare); + std::sort(finalList.begin(), finalList.end(), caseInsensitiveCompare); } - - for (auto& curHistName : mRegisteredNames) { + for (auto& curHistName : finalList) { TNamed* rawPtr = nullptr; std::visit([&](const auto& sharedPtr) { rawPtr = (TNamed*)sharedPtr.get(); }, mRegistryValue[getHistIndex(HistName{curHistName.data()})]); - if (rawPtr) { - std::deque path = splitPath(rawPtr->GetName()); - std::string name = path.back(); - path.pop_back(); - TList* targetList{getSubList(list, path)}; - if (targetList) { - rawPtr->SetName(name.data()); - targetList->Add(rawPtr); - } else { - LOGF(fatal, "Specified subfolder could not be created."); - } - } - } - - // place lists always at the top - std::function moveListsToTop; - moveListsToTop = [&](TList* list) { - TIter next(list); - TNamed* subList = nullptr; - std::vector subLists; - while ((subList = (TNamed*)next())) { - if (subList->InheritsFrom(TList::Class())) { - subLists.push_back(subList); - moveListsToTop((TList*)subList); - } - } - std::reverse(subLists.begin(), subLists.end()); - for (auto curList : subLists) { - list->Remove(curList); - list->AddFirst(curList); - } - }; - moveListsToTop(list); - - // create dedicated directory containing all of the registrys histograms - if (mCreateRegistryDir) { - // propagate this to the writer by adding a 'flag' to the output list - list->AddLast(new TNamed("createFolder", "")); - } - return list; -} - -// helper function to create resp. find the subList defined by path -TList* HistogramRegistry::getSubList(TList* list, std::deque& path) -{ - if (path.empty()) { - return list; - } - TList* targetList{nullptr}; - std::string nextList = path[0]; - path.pop_front(); - if (auto subList = (TList*)list->FindObject(nextList.data())) { - if (subList->InheritsFrom(TList::Class())) { - targetList = getSubList((TList*)subList, path); - } else { - return nullptr; + if (!rawPtr) { + // Skipping empty histograms + continue; } - } else { - subList = new TList(); - subList->SetName(nextList.data()); - list->Add(subList); - targetList = getSubList(subList, path); + callback(*this, rawPtr); } - return targetList; } // helper function to split user defined path/to/hist/name string diff --git a/Framework/TestWorkflows/src/o2TestHistograms.cxx b/Framework/TestWorkflows/src/o2TestHistograms.cxx index 61710e1f63d5f..ae3610ca01e67 100644 --- a/Framework/TestWorkflows/src/o2TestHistograms.cxx +++ b/Framework/TestWorkflows/src/o2TestHistograms.cxx @@ -43,6 +43,16 @@ struct EtaAndClsHistogramsSimple { Configurable trackFilterString{"track-filter", "o2::aod::track::pt < 10.f", "Track filter string"}; Filter trackFilter = o2::aod::track::pt < 10.f; + HistogramRegistry registry{ + "registry", + { + {"a/b/eta", "#Eta", {HistType::kTH1F, {{100, -2.0, 2.0}}}}, // + {"a/phi", "#Phi", {HistType::kTH1D, {{102, 0, 2 * M_PI}}}}, // + {"c/pt", "p_{T}", {HistType::kTH1D, {{1002, -0.01, 50.1}}}}, // + {"ptToPt", "#ptToPt", {HistType::kTH2F, {{100, -0.01, 10.01}, {100, -0.01, 10.01}}}} // + } // + }; + void init(InitContext&) { if (!trackFilterString->empty()) { @@ -56,6 +66,11 @@ struct EtaAndClsHistogramsSimple { for (auto& track : tracks) { etaClsH->Fill(track.eta(), track.pt()); skimEx(track.pt(), track.eta()); + + registry.fill(HIST("a/b/eta"), track.eta()); + registry.fill(HIST("a/phi"), track.phi()); + registry.fill(HIST("c/pt"), track.pt()); + registry.fill(HIST("ptToPt"), track.pt(), track.signed1Pt()); } } }; @@ -66,6 +81,16 @@ struct EtaAndClsHistogramsIUSimple { Configurable trackFilterString{"track-filter", "o2::aod::track::pt < 10.f", "Track filter string"}; Filter trackFilter = o2::aod::track::pt < 10.f; + HistogramRegistry registry{ + "registry", + { + {"a/b/eta", "#Eta", {HistType::kTH1F, {{100, -2.0, 2.0}}}}, // + {"a/phi", "#Phi", {HistType::kTH1D, {{102, 0, 2 * M_PI}}}}, // + {"c/pt", "p_{T}", {HistType::kTH1D, {{1002, -0.01, 50.1}}}}, // + {"ptToPt", "#ptToPt", {HistType::kTH2F, {{100, -0.01, 10.01}, {100, -0.01, 10.01}}}} // + } // + }; + void init(InitContext&) { if (!trackFilterString->empty()) { @@ -79,12 +104,28 @@ struct EtaAndClsHistogramsIUSimple { for (auto& track : tracks) { etaClsH->Fill(track.eta(), track.pt()); skimEx(track.pt(), track.eta()); + + registry.fill(HIST("a/b/eta"), track.eta()); + registry.fill(HIST("a/phi"), track.phi()); + registry.fill(HIST("c/pt"), track.pt()); + registry.fill(HIST("ptToPt"), track.pt(), track.signed1Pt()); } } }; struct EtaAndClsHistogramsFull { OutputObj etaClsH{TH3F("eta_vs_cls_vs_sigmapT", "#eta vs N_{cls} vs sigma_{1/pT}", 102, -2.01, 2.01, 160, -0.5, 159.5, 100, 0, 10)}; + + HistogramRegistry registry{ + "registry", + { + {"a/b/eta", "#Eta", {HistType::kTH1F, {{100, -2.0, 2.0}}}}, // + {"a/phi", "#Phi", {HistType::kTH1D, {{102, 0, 2 * M_PI}}}}, // + {"c/pt", "p_{T}", {HistType::kTH1D, {{1002, -0.01, 50.1}}}}, // + {"ptToPt", "#ptToPt", {HistType::kTH2F, {{100, -0.01, 10.01}, {100, -0.01, 10.01}}}} // + } // + }; + Configurable trackFilterString{"track-filter", "o2::aod::track::pt < 10.f", "Track filter string"}; Filter trackFilter = o2::aod::track::pt < 10.f; @@ -100,6 +141,11 @@ struct EtaAndClsHistogramsFull { LOGP(info, "Invoking the run 3 one"); for (auto& track : tracks) { etaClsH->Fill(track.eta(), track.tpcNClsFindable(), track.sigma1Pt()); + + registry.fill(HIST("a/b/eta"), track.eta()); + registry.fill(HIST("a/phi"), track.phi()); + registry.fill(HIST("c/pt"), track.pt()); + registry.fill(HIST("ptToPt"), track.pt(), track.signed1Pt()); } } };