Skip to content

Commit d8091df

Browse files
authored
[QC-421] Allow to check PP tasks results in CheckRunners (#506)
* [QC-421] Allow to check PP tasks results in CheckRunners * fix infrastructuregenerator test
1 parent 6fce345 commit d8091df

11 files changed

Lines changed: 96 additions & 15 deletions

Framework/postprocessing.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@
2222
"url": "ccdb-test.cern.ch:8080"
2323
}
2424
},
25+
"checks": {
26+
"ExamplePPCheck": {
27+
"active": "true",
28+
"className": "o2::quality_control_modules::skeleton::SkeletonCheck",
29+
"moduleName": "QcSkeleton",
30+
"policy": "OnAny",
31+
"detectorName": "TST",
32+
"dataSource": [{
33+
"type": "PostProcessing",
34+
"name": "ExampleTrend",
35+
"MOs": ["mean_of_histogram"]
36+
}]
37+
}
38+
},
2539
"postprocessing": {
2640
"ExamplePostprocessing": {
2741
"active": "true",

Framework/src/Check.cxx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "QualityControl/TaskRunner.h"
2626
#include "QualityControl/InputUtils.h"
2727
#include "QualityControl/RootClassFactory.h"
28+
#include "QualityControl/PostProcessingDevice.h"
2829
// Fairlogger
2930
#include <fairlogger/Logger.h>
3031

@@ -34,6 +35,7 @@ using namespace o2::configuration;
3435

3536
using namespace o2::quality_control::checker;
3637
using namespace o2::quality_control::core;
38+
using namespace o2::quality_control::postprocessing;
3739
using namespace std;
3840

3941
/// Static functions
@@ -88,12 +90,15 @@ void Check::initConfig(std::string checkName)
8890
mNumberOfTaskSources = 0;
8991
for (const auto& [_key, dataSource] : checkConfig.get_child("dataSource")) {
9092
(void)_key;
91-
if (dataSource.get<std::string>("type") == "Task" || dataSource.get<std::string>("type") == "ExternalTask") {
93+
if (auto sourceType = dataSource.get<std::string>("type");
94+
sourceType == "Task" || sourceType == "ExternalTask" || sourceType == "PostProcessing") {
9295
auto taskName = dataSource.get<std::string>("name");
9396
mNumberOfTaskSources++;
9497

9598
if (dataSource.get<std::string>("type") == "Task") {
9699
mInputs.push_back({ taskName, TaskRunner::createTaskDataOrigin(), TaskRunner::createTaskDataDescription(taskName) });
100+
} else if (dataSource.get<std::string>("type") == "PostProcessing") {
101+
mInputs.push_back({ taskName, PostProcessingDevice::createPostProcessingDataOrigin(), PostProcessingDevice::createPostProcessingDataDescription(taskName) });
97102
} else if (dataSource.get<std::string>("type") == "ExternalTask") {
98103
auto query = config->getString("qc.externalTasks." + taskName + ".query").get();
99104
framework::Inputs input = o2::framework::DataDescriptorQueryBuilder::parse(query.c_str());

Framework/src/CheckRunner.cxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ void CheckRunner::prepareCacheData(framework::InputRecord& inputRecord)
274274
void CheckRunner::sendPeriodicMonitoring()
275275
{
276276
if (mTimer.isTimeout()) {
277-
mTimer.reset(1000000); // 10 s.
277+
mTimer.reset(10000000); // 10 s.
278278
mCollector->send({ mTotalNumberObjectsReceived, "qc_objects_received" }, DerivedMetricMode::RATE);
279279
mCollector->send({ mTotalNumberCheckExecuted, "qc_checks_executed" }, DerivedMetricMode::RATE);
280280
mCollector->send({ mTotalNumberQOStored, "qc_qo_stored" }, DerivedMetricMode::RATE);
@@ -397,7 +397,7 @@ void CheckRunner::initMonitoring()
397397
mCollector->enableProcessMonitoring();
398398
mCollector->addGlobalTag(tags::Key::Subsystem, tags::Value::QC);
399399
mCollector->addGlobalTag("CheckRunnerName", mDeviceName);
400-
mTimer.reset(1000000); // 10 s.
400+
mTimer.reset(10000000); // 10 s.
401401
}
402402

403403
void CheckRunner::initServiceDiscovery()

Framework/src/InfrastructureGenerator.cxx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,15 @@ void InfrastructureGenerator::generateCheckRunners(framework::WorkflowSpec& work
367367
}
368368
}
369369

370+
if (config->getRecursive("qc").count("postprocessing")) {
371+
for (const auto& [ppTaskName, ppTaskConfig] : config->getRecursive("qc.postprocessing")) {
372+
if (ppTaskConfig.get<bool>("active", true)) {
373+
InputSpec taskOutput{ ppTaskName, PostProcessingDevice::createPostProcessingDataOrigin(), PostProcessingDevice::createPostProcessingDataDescription(ppTaskName) };
374+
tasksOutputMap.insert({ DataSpecUtils::label(taskOutput), taskOutput });
375+
}
376+
}
377+
}
378+
370379
// For each external task prepare the InputSpec to be stored in tasksoutputMap
371380
if (config->getRecursive("qc").count("externalTasks")) {
372381
for (const auto& [taskName, taskConfig] : config->getRecursive("qc.externalTasks")) {
@@ -467,7 +476,7 @@ void InfrastructureGenerator::generatePostProcessing(WorkflowSpec& workflow, std
467476
ppTask.getOptions()
468477
};
469478

470-
ppTaskSpec.algorithm = std::move(adaptFromTask<PostProcessingDevice>(std::move(ppTask)));
479+
ppTaskSpec.algorithm = adaptFromTask<PostProcessingDevice>(std::move(ppTask));
471480

472481
workflow.emplace_back(std::move(ppTaskSpec));
473482
}

Framework/src/PostProcessingDevice.cxx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,9 @@ void PostProcessingDevice::init(framework::InitContext& ctx)
5252

5353
void PostProcessingDevice::run(framework::ProcessingContext& ctx)
5454
{
55-
// todo: enable once check runners can store the results.
56-
// Now we still choose the default option - storing data directly to the repo.
5755
// we set the publication callback each time, because we cannot be sure that
5856
// the reference to DataAllocator does not change
59-
// mRunner.setPublicationCallback(publishToDPL(ctx.outputs(), outputBinding));
57+
mRunner->setPublicationCallback(publishToDPL(ctx.outputs(), outputBinding));
6058

6159
// When run returns false, it has done its processing.
6260
if (!mRunner->run()) {

Framework/test/testCheck.cxx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,22 @@ BOOST_AUTO_TEST_CASE(test_check_dont_invoke_beautify)
116116
// Beautify should not run - more than one MO declared
117117
BOOST_CHECK(!testCheck.mBeautify);
118118
}
119+
120+
BOOST_AUTO_TEST_CASE(test_check_postprocessing)
121+
{
122+
std::string configFilePath = std::string("json://") + getTestDataDirectory() + "testSharedConfig.json";
123+
124+
Check check("checkAnyPP", configFilePath);
125+
check.init();
126+
127+
TestCheck testCheck;
128+
check.setCheckInterface(dynamic_cast<CheckInterface*>(&testCheck));
129+
130+
std::map<std::string, std::shared_ptr<MonitorObject>> moMap = { { "SkeletonPostProcessing/example", std::shared_ptr<MonitorObject>(new MonitorObject()) } };
131+
132+
check.check(moMap);
133+
// Check should run
134+
BOOST_CHECK(testCheck.mCheck);
135+
// Beautify should run - single MO declared
136+
BOOST_CHECK(testCheck.mBeautify);
137+
}

Framework/test/testInfrastructureGenerator.cxx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ BOOST_AUTO_TEST_CASE(qc_factory_remote_test)
8181

8282
// the infrastructure should consist of a proxy, merger and checker for the 'skeletonTask' (its taskRunner is declared to be
8383
// local) and also taskRunner and checker for the 'abcTask' and 'xyzTask'.
84-
BOOST_REQUIRE_EQUAL(workflow.size(), 9);
84+
// Post processing adds one process for the task and one for checks.
85+
BOOST_REQUIRE_EQUAL(workflow.size(), 10);
8586

8687
auto tcpclustProxy = std::find_if(
8788
workflow.begin(), workflow.end(),
@@ -142,7 +143,7 @@ BOOST_AUTO_TEST_CASE(qc_factory_remote_test)
142143
return d.name.find("QC-CHECK-RUNNER") != std::string::npos &&
143144
d.inputs.size() == 1;
144145
});
145-
BOOST_REQUIRE_EQUAL(checkRunnerCount, 3);
146+
BOOST_REQUIRE_EQUAL(checkRunnerCount, 4);
146147

147148
auto postprocessingTask = std::find_if(
148149
workflow.begin(), workflow.end(),
@@ -159,8 +160,8 @@ BOOST_AUTO_TEST_CASE(qc_factory_standalone_test)
159160
std::string configFilePath = std::string("json://") + getTestDataDirectory() + "testSharedConfig.json";
160161
auto workflow = InfrastructureGenerator::generateStandaloneInfrastructure(configFilePath);
161162

162-
// the infrastructure should consist of 3 TaskRunners, 3 CheckRunners, 1 PostProcessingRunner
163-
BOOST_REQUIRE_EQUAL(workflow.size(), 7);
163+
// the infrastructure should consist of 3 TaskRunners, 1 PostProcessingRunner, 4 CheckRunners (including one for PP)
164+
BOOST_REQUIRE_EQUAL(workflow.size(), 8);
164165

165166
auto taskRunnerSkeleton = std::find_if(
166167
workflow.begin(), workflow.end(),
@@ -195,7 +196,7 @@ BOOST_AUTO_TEST_CASE(qc_factory_standalone_test)
195196
return d.name.find("QC-CHECK-RUNNER") != std::string::npos &&
196197
d.inputs.size() == 1;
197198
});
198-
BOOST_REQUIRE_EQUAL(checkRunnerCount, 3);
199+
BOOST_REQUIRE_EQUAL(checkRunnerCount, 4);
199200

200201
auto postprocessingTask = std::find_if(
201202
workflow.begin(), workflow.end(),

Framework/test/testSharedConfig.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,19 @@
147147
"test2"
148148
]
149149
}]
150+
},
151+
"checkAnyPP": {
152+
"active": "true",
153+
"className": "o2::quality_control_modules::skeleton::SkeletonCheck",
154+
"moduleName": "QcSkeleton",
155+
"policy": "OnAny",
156+
"dataSource": [{
157+
"type": "PostProcessing",
158+
"name": "SkeletonPostProcessing",
159+
"MOs": [
160+
"example"
161+
]
162+
}]
150163
}
151164
},
152165
"postprocessing": {

Modules/Skeleton/src/SkeletonCheck.cxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ void SkeletonCheck::beautify(std::shared_ptr<MonitorObject> mo, Quality checkRes
6262
if (checkResult == Quality::Good) {
6363
h->SetFillColor(kGreen);
6464
} else if (checkResult == Quality::Bad) {
65-
ILOG(Info, Support) << "Quality::Bad, setting to red";
65+
ILOG(Info, Support) << "Quality::Bad, setting to red" << ENDM;
6666
h->SetFillColor(kRed);
6767
} else if (checkResult == Quality::Medium) {
68-
ILOG(Info, Support) << "Quality::medium, setting to orange";
68+
ILOG(Info, Support) << "Quality::medium, setting to orange" << ENDM;
6969
h->SetFillColor(kOrange);
7070
}
7171
h->SetLineColor(kBlack);

doc/Advanced.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ Below the full QC Checks configuration structure is described. Note that more th
600600
"policy": "OnAny", "": ["Policy which determines when MOs should be checked. See the documentation",
601601
"of Checks for the list of available policies and their behaviour."],
602602
"dataSource": [{ "": "List of data source of the Check.",
603-
"type": "Task", "": "Type of the data source, only \"Task\" up to this date",
603+
"type": "Task", "": "Type of the data source, \"Task\", \"ExternalTask\" or \"PostProcessing\"",
604604
"name": "myTask_1", "": "Name of the Task",
605605
"MOs": [ "example" ], "": ["List of MOs to be checked. Use \"all\" (not as a list) to check each MO ",
606606
"which is produced by the Task"]

0 commit comments

Comments
 (0)