diff --git a/Modules/Example/CMakeLists.txt b/Modules/Example/CMakeLists.txt index c6fb049998..628e7be0de 100644 --- a/Modules/Example/CMakeLists.txt +++ b/Modules/Example/CMakeLists.txt @@ -2,6 +2,7 @@ add_library(O2QcExample src/BenchmarkTask.cxx + src/EveryObject.cxx src/ExampleTask.cxx src/AnalysisTask.cxx src/FakeCheck.cxx @@ -19,6 +20,7 @@ target_link_libraries(O2QcExample PUBLIC O2QualityControl) add_root_dictionary(O2QcExample HEADERS include/Example/BenchmarkTask.h + include/Example/EveryObject.h include/Example/AnalysisTask.h include/Example/ExampleTask.h include/Example/FakeCheck.h diff --git a/Modules/Example/etc/every-object.json b/Modules/Example/etc/every-object.json new file mode 100644 index 0000000000..1a8fcc6b10 --- /dev/null +++ b/Modules/Example/etc/every-object.json @@ -0,0 +1,52 @@ +{ + "qc": { + "config": { + "database": { + "implementation": "CCDB", + "host": "ccdb-test.cern.ch:8080", + "username": "not_applicable", + "password": "not_applicable", + "name": "not_applicable" + }, + "Activity": { + "number": "42", + "type": "2", + "periodName": "", "": "Period name - e.g. LHC22c, LHC22c1b_test", + "passName": "", "": "Pass type - e.g. spass, cpass1", + "provenance": "qc", "": "Provenance - qc or qc_mc depending whether it is normal data or monte carlo data" + }, + "monitoring": { + "url": "infologger:///debug?qc" + }, + "consul": { + "url": "" + }, + "conditionDB": { + "url": "ccdb-test.cern.ch:8080" + }, + "infologger": { "": "Configuration of the Infologger (optional).", + "filterDiscardDebug": "false", "": "Set to true to discard debug and trace messages (default: false)", + "filterDiscardLevel": "21", "": "Message at this level or above are discarded (default: 21 - Trace)" + } + }, + "tasks": { + "EveryObject": { + "active": "true", + "className": "o2::quality_control_modules::example::EveryObject", + "moduleName": "QcExample", + "detectorName": "TST", + "cycleDurationSeconds": "10", "": "10 seconds minimum", + "maxNumberCycles": "-1", + "": "The other type of dataSource is \"direct\", see basic-no-sampling.json.", + "dataSource": { + "type": "direct", + "query": "random:TST/RAWDATA/0" + } + } + }, + "checks": { + } + }, + "dataSamplingPolicies": [ + ] +} diff --git a/Modules/Example/include/Example/EveryObject.h b/Modules/Example/include/Example/EveryObject.h new file mode 100644 index 0000000000..0ee966231f --- /dev/null +++ b/Modules/Example/include/Example/EveryObject.h @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file EveryObject.h +/// \author Piotr Konopka +/// + +#ifndef QC_MODULE_EXAMPLE_EXAMPLEEVERYOBJECT_H +#define QC_MODULE_EXAMPLE_EXAMPLEEVERYOBJECT_H + +#include "QualityControl/TaskInterface.h" +#include + +class TH1F; +class TH2F; +class TH3F; +class THnSparse; +class TCanvas; + +using namespace o2::quality_control::core; + +namespace o2::quality_control_modules::example +{ + +/// \brief Task which publishes (not exactly) every class object used as MO. Can be used to test memory leaks. +/// \author Piotr Konopka +class EveryObject final : public TaskInterface +{ + public: + /// \brief Constructor + EveryObject() = default; + /// Destructor + ~EveryObject() override; + + // Definition of the methods for the template method pattern + void initialize(o2::framework::InitContext& ctx) override; + void startOfActivity(Activity& activity) override; + void startOfCycle() override; + void monitorData(o2::framework::ProcessingContext& ctx) override; + void endOfCycle() override; + void endOfActivity(Activity& activity) override; + void reset() override; + + private: + TH1F* mTH1F = nullptr; + TH2F* mTH2F = nullptr; + TH3F* mTH3F = nullptr; + THnSparse* mTHnSparseF = nullptr; + TCanvas* mTCanvas = nullptr; + std::array mTCanvasMembers = { nullptr }; +}; + +} // namespace o2::quality_control_modules::example + +#endif // QC_MODULE_EXAMPLE_EXAMPLEEVERYOBJECT_H diff --git a/Modules/Example/include/Example/LinkDef.h b/Modules/Example/include/Example/LinkDef.h index ff544d7c58..cb49469443 100644 --- a/Modules/Example/include/Example/LinkDef.h +++ b/Modules/Example/include/Example/LinkDef.h @@ -8,6 +8,6 @@ #pragma link C++ class o2::quality_control_modules::example::BenchmarkTask + ; #pragma link C++ class o2::quality_control_modules::example::ExampleCondition + ; #pragma link C++ class o2::quality_control_modules::example::CustomTH2F + ; - #pragma link C++ class o2::quality_control_modules::example::AnalysisTask + ; +#pragma link C++ class o2::quality_control_modules::example::EveryObject+; #endif diff --git a/Modules/Example/src/EveryObject.cxx b/Modules/Example/src/EveryObject.cxx new file mode 100644 index 0000000000..940a1c93cf --- /dev/null +++ b/Modules/Example/src/EveryObject.cxx @@ -0,0 +1,162 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file EveryObject.cxx +/// \author Piotr Konopka +/// + +#include +#include + +#include "QualityControl/QcInfoLogger.h" +#include "Example/EveryObject.h" +#include +#include + +#include +#include +#include +#include +#include + +constexpr Double_t rangeLimiter = 16 * 64000; + +namespace o2::quality_control_modules::example +{ + +EveryObject::~EveryObject() +{ + delete mTH1F; + delete mTH2F; + delete mTH3F; + delete mTHnSparseF; + delete mTCanvas; // TCanvas should delete the contained plots, given that we set kCanDelete +} + +void EveryObject::initialize(o2::framework::InitContext& /*ctx*/) +{ + ILOG(Info, Support) << "initialize EveryObject" << ENDM; // QcInfoLogger is used. FairMQ logs will go to there as well. + + // todo: enable/disable with config flags (this is why objects are always accessed after checking if not null) + // todo: ttree, tefficiency, tprofile + + mTH1F = new TH1F("th1f", "th1f", 64000, 0, rangeLimiter); + getObjectsManager()->startPublishing(mTH1F); + + mTH2F = new TH2F("th2f", "th2f", 250, 0, rangeLimiter, 250, 0, rangeLimiter); + getObjectsManager()->startPublishing(mTH2F); + + mTH3F = new TH3F("th3f", "th3f", 40, 0, rangeLimiter, 40, 0, rangeLimiter, 40, 0, rangeLimiter); + getObjectsManager()->startPublishing(mTH3F); + { + const size_t bins = 1000; + const size_t dim = 5; + const Double_t min = 0.0; + const Double_t max = rangeLimiter; + + const std::vector binsDims(dim, bins); + const std::vector mins(dim, min); + const std::vector maxs(dim, max); + mTHnSparseF = new THnSparseF("thnsparsef", "thnsparsef", dim, binsDims.data(), mins.data(), maxs.data()); + getObjectsManager()->startPublishing(mTHnSparseF); + } + { + mTCanvas = new TCanvas("tcanvas", "tcanvas", 1000, 1000); + mTCanvas->Clear(); + mTCanvas->Divide(2, 2); + for (size_t i = 0; i < 4; i++) { + auto name = std::string("tcanvas_th2f_") + std::to_string(i); + mTCanvasMembers[i] = new TH2F(name.c_str(), name.c_str(), 250, 0, rangeLimiter, 250, 0, rangeLimiter); + + mTCanvas->cd(i + 1); + mTCanvasMembers[i]->Draw(); + mTCanvasMembers[i]->SetBit(TObject::kCanDelete); + } + getObjectsManager()->startPublishing(mTCanvas); + } +} + +void EveryObject::startOfActivity(Activity& activity) +{ + ILOG(Info, Support) << "startOfActivity " << activity.mId << ENDM; +} + +void EveryObject::startOfCycle() +{ + ILOG(Info, Support) << "startOfCycle" << ENDM; +} + +void EveryObject::monitorData(o2::framework::ProcessingContext& ctx) +{ + for (auto&& input : framework::InputRecordWalker(ctx.inputs())) { + const auto* header = header::get(input.header); + auto value1 = (Float_t)(header->payloadSize % (size_t)rangeLimiter); + auto value2 = (Float_t)((header->tfCounter + header->payloadSize) % (size_t)rangeLimiter); + auto value3 = (Float_t)((header->tfCounter * header->payloadSize) % (size_t)rangeLimiter); + + if (mTH1F) { + mTH1F->Fill(value1); + } + if (mTH2F) { + mTH2F->Fill(value1, value3); + } + if (mTH3F) { + mTH3F->Fill(value1, value2, value3); + } + if (mTHnSparseF) { + std::array values{ value1, value2, value3, value2 / (value1 + 1), value2 / (value3 + 1) }; + mTHnSparseF->Fill(values.data()); + } + if (mTCanvas) { + mTCanvasMembers[0]->Fill(value1, value3); + mTCanvasMembers[1]->Fill(value3, value1); + mTCanvasMembers[2]->Fill(value2, value3); + mTCanvasMembers[3]->Fill(value3, value2); + } + } +} + +void EveryObject::endOfCycle() +{ + ILOG(Info, Support) << "endOfCycle" << ENDM; +} + +void EveryObject::endOfActivity(Activity& /*activity*/) +{ + ILOG(Info, Support) << "endOfActivity" << ENDM; +} + +void EveryObject::reset() +{ + ILOG(Info, Support) << "Resetting the objects" << ENDM; + if (mTH1F) { + mTH1F->Reset(); + } + if (mTH2F) { + mTH2F->Reset(); + } + if (mTH3F) { + mTH3F->Reset(); + } + if (mTHnSparseF) { + mTHnSparseF->Reset(); + } + if (mTCanvas) { + for (const auto member : mTCanvasMembers) { + if (member) { + member->Reset(); + } + } + } +} + +} // namespace o2::quality_control_modules::example