Skip to content

Commit 50a9d5b

Browse files
committed
Merge pull request #890 in B2/basf2 from feature/BII-8925-r61 to release/06-01
* commit '5e1784529d1e65584537a612dc1f259d80bf6b2d': Move the DQM files under the directory for output ROOT files because RbTupleManager does not do it for us Merge pull request #534 in B2/basf2 from feature/BII-8925-lz4 to main
2 parents 268128c + 5e17845 commit 50a9d5b

File tree

7 files changed

+210
-15
lines changed

7 files changed

+210
-15
lines changed

hlt/softwaretrigger/scripts/softwaretrigger/test_support.py

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
# See git log for contributors and copyright holders. #
66
# This file is licensed under LGPL-3.0, see LICENSE.md. #
77
##########################################################################
8+
9+
import os
810
import random
911
import shutil
1012
import subprocess
11-
import os
1213
import sys
13-
import tempfile
1414
from glob import glob
1515

16+
import b2test_utils
1617
import basf2
1718
import generators
1819
from simulation import add_simulation
@@ -148,29 +149,44 @@ def test_script(script_location, input_file_name, temp_dir):
148149

149150
random_seed = "".join(random.choices("abcdef", k=4))
150151

151-
histos_file_name = os.path.join(temp_dir, f"{random_seed}_histos.root")
152+
histos_file_name = f"{random_seed}_histos.root"
152153
output_file_name = os.path.join(temp_dir, f"{random_seed}_output.root")
153154
# TODO: should we use the default global tag here?
154155
globaltags = list(basf2.conditions.default_globaltags)
155156
num_processes = 1
156157

158+
# Because the script name is hard-coded in the run control GUI,
159+
# we must jump into the script directory
160+
cwd = os.getcwd()
157161
os.chdir(os.path.dirname(script_location))
158-
cmd = [sys.executable, script_location,
159-
"--central-db-tag"] + globaltags + [
162+
cmd1 = [sys.executable, script_location, "--central-db-tag"] + globaltags + [
160163
"--input-file", os.path.abspath(input_file_name),
161-
"--histo-output-file", os.path.abspath(histos_file_name),
164+
"--histo-output-file", f"./{histos_file_name}",
162165
"--output-file", os.path.abspath(output_file_name),
163166
"--number-processes", str(num_processes),
164-
input_buffer, output_buffer, str(histo_port)]
167+
input_buffer, output_buffer, str(histo_port)
168+
]
169+
subprocess.check_call(cmd1)
165170

166-
subprocess.check_call(cmd)
171+
# Move the output file with DQM histograms under the expected location:
172+
# for reasons we don't want to know, they are saved under the current directory
173+
# even if a valid and existing working directory is specified
174+
if os.path.exists(histos_file_name):
175+
final_histos_file_name = os.path.join(temp_dir, histos_file_name)
176+
shutil.move(histos_file_name, os.path.join(temp_dir, final_histos_file_name))
167177

168-
test_path = basf2.Path()
169-
test_path.add_module("RootInput", inputFileName=output_file_name)
170-
test_path.add_module(CheckForCorrectHLTResults())
178+
# Go back to the original directory for safety
179+
os.chdir(cwd)
171180

172181
if "expressreco" not in script_location and "beam_reco" in script_location:
173-
basf2.process(test_path)
182+
# Check the integrity of HLT result
183+
test_path = basf2.Path()
184+
test_path.add_module("RootInput", inputFileName=output_file_name)
185+
test_path.add_module(CheckForCorrectHLTResults())
186+
assert(b2test_utils.safe_process(test_path) == 0)
187+
# Check the size of DQM histograms
188+
cmd2 = ["hlt-check-dqm-size", final_histos_file_name]
189+
subprocess.check_call(cmd2)
174190

175191

176192
def test_folder(location, run_type, exp_number, phase, passthrough=False):
@@ -194,7 +210,9 @@ def test_folder(location, run_type, exp_number, phase, passthrough=False):
194210
express reco if hlt is in passthrough mode
195211
196212
"""
197-
temp_dir = tempfile.mkdtemp()
213+
214+
# The test is already run in a clean, temporary directory
215+
temp_dir = os.getcwd()
198216
output_file_name = os.path.join(temp_dir, f"{location.name}_{run_type.name}.root")
199217
generate_input_file(run_type=run_type, location=location,
200218
output_file_name=output_file_name, exp_number=exp_number,
@@ -207,5 +225,3 @@ def test_folder(location, run_type, exp_number, phase, passthrough=False):
207225
test_script(script_location, input_file_name=output_file_name, temp_dir=temp_dir)
208226

209227
assert run_at_least_one
210-
211-
shutil.rmtree(temp_dir)

hlt/tests/release_validation/automatic-01-reconstructrawdata-hlt.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,7 @@ ${PARENT} basf2 ${PROCESSES} \
3131
--output-file ${OUTPUT_ROOT_DIR}/beam_reco_monitor-hlt-out.root \
3232
--histo-output-file ${OUTPUT_ROOT_DIR}/beam_reco_monitor-hlt-dqm.root \
3333
--local-db-path cdb
34+
35+
# For weird reasons, RbTupleManager does not create the ROOT file with DQM histograms
36+
# in ${OUTPUT_ROOT_DIR}, so we must manually move it there.
37+
mv beam_reco_monitor-hlt-dqm.root ${OUTPUT_ROOT_DIR}/beam_reco_monitor-hlt-dqm.root
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
3+
##########################################################################
4+
# basf2 (Belle II Analysis Software Framework) #
5+
# Author: The Belle II Collaboration #
6+
# #
7+
# See git log for contributors and copyright holders. #
8+
# This file is licensed under LGPL-3.0, see LICENSE.md. #
9+
##########################################################################
10+
11+
# Check the size of the DQM histograms produced by HLT
12+
hlt-check-dqm-size ${OUTPUT_ROOT_DIR}/beam_reco_monitor-hlt-dqm.root

hlt/tests/release_validation/automatic-04-reconstructrawdata-expressreco.sh renamed to hlt/tests/release_validation/automatic-05-reconstructrawdata-expressreco.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,7 @@ ${PARENT} basf2 ${PROCESSES} \
3232
--output-file ${OUTPUT_ROOT_DIR}/beam_reco_monitor-expressreco-out.root \
3333
--histo-output-file ${OUTPUT_ROOT_DIR}/beam_reco_monitor-expressreco-dqm.root \
3434
--local-db-path cdb
35+
36+
#For weird reasons, RbTupleManager does not create the ROOT file with DQM histograms
37+
# in ${OUTPUT_ROOT_DIR}, so we must manually move it there.
38+
mv beam_reco_monitor-expressreco-dqm.root ${OUTPUT_ROOT_DIR}/beam_reco_monitor-expressreco-dqm.root

hlt/tools/SConscript

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Import('env')
2+
3+
env['TOOLS_LIBS']['hlt-check-dqm-size'] = ['framework',
4+
'zmq',
5+
'stdc++',
6+
'$ROOT_LIBS']
7+
8+
Return('env')

hlt/tools/hlt-check-dqm-size.cc

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/**************************************************************************
2+
* basf2 (Belle II Analysis Software Framework) *
3+
* Author: The Belle II Collaboration *
4+
* *
5+
* See git log for contributors and copyright holders. *
6+
* This file is licensed under LGPL-3.0, see LICENSE.md. *
7+
**************************************************************************/
8+
9+
/* Belle 2 headers. */
10+
#include <framework/logging/Logger.h>
11+
#include <framework/pcore/EvtMessage.h>
12+
#include <framework/pcore/MsgHandler.h>
13+
14+
/* ROOT headers. */
15+
#include <TClass.h>
16+
#include <TCollection.h>
17+
#include <TDirectory.h>
18+
#include <TFile.h>
19+
#include <TH1.h>
20+
#include <TList.h>
21+
#include <TObject.h>
22+
#include <TKey.h>
23+
#include <TSystem.h>
24+
25+
/* C++ headers. */
26+
#include <iostream>
27+
#include <memory>
28+
#include <string>
29+
#include <vector>
30+
31+
/* LZ4 headers. */
32+
#include <lz4.h>
33+
34+
/* ZeroMQ headers. */
35+
#include <zmq.hpp>
36+
37+
namespace {
38+
39+
/** Stream the histograms. */
40+
unsigned int streamHistograms(TDirectory* directory, Belle2::MsgHandler& msgHandler, const std::string& directoryName = "")
41+
{
42+
TList* keylist{directory->GetListOfKeys()};
43+
TIter nextkey{keylist};
44+
TKey* key{nullptr};
45+
unsigned int counter{0};
46+
while ((key = dynamic_cast<TKey*>(nextkey()))) {
47+
TObject* object{directory->Get(key->GetName())};
48+
TClass* objectClass{object->IsA()};
49+
std::string objectName{directoryName};
50+
if (not objectName.empty()) {
51+
objectName += "/";
52+
}
53+
objectName += object->GetName();
54+
if (objectClass->InheritsFrom(TH1::Class())) {
55+
TH1* histogram{dynamic_cast<TH1*>(object)};
56+
msgHandler.add(histogram, objectName);
57+
counter++;
58+
} else if (objectClass->InheritsFrom(TDirectory::Class())) {
59+
TDirectory* subDirectory{dynamic_cast<TDirectory*>(object)};
60+
// Apparently the dqm server does not understand multi-layer directory structures,
61+
// therefore the original author broke this down to only show the last directory
62+
counter += streamHistograms(subDirectory, msgHandler, object->GetName());
63+
}
64+
}
65+
return counter;
66+
}
67+
}
68+
69+
int main(int argc, char* argv[])
70+
{
71+
if (argc == 1 or std::string(argv[1]) == "--help" or std::string(argv[1]) == "-h") {
72+
std::cout << "Usage: " << argv[0] << " INPUT_FILE\n\n"
73+
" This tool checks if the online systems can handle the size of the DQM histograms\n"
74+
" by compressing and decompressing them with LZ4 as done within our ZeroMQ framework.\n";
75+
return 1;
76+
}
77+
std::string inputFileName{argv[1]};
78+
if (inputFileName.find(".root") == std::string::npos) {
79+
B2ERROR("The input file is not a .root file!");
80+
return 1;
81+
}
82+
if (gSystem->AccessPathName(inputFileName.c_str())) {
83+
B2ERROR("The input file does not exist!");
84+
return 1;
85+
}
86+
std::unique_ptr<TFile> inputFile{
87+
std::unique_ptr<TFile>(TFile::Open(inputFileName.c_str(), "READ"))
88+
};
89+
if (!inputFile or !inputFile->IsOpen() or inputFile->IsZombie()) {
90+
B2ERROR("The input file is not working!");
91+
return 1;
92+
}
93+
Belle2::MsgHandler msgHandler;
94+
unsigned int streamedHistograms{streamHistograms(gDirectory, msgHandler)};
95+
std::unique_ptr<Belle2::EvtMessage> evtMessage{
96+
std::unique_ptr<Belle2::EvtMessage>(msgHandler.encode_msg(Belle2::ERecordType::MSG_EVENT))
97+
};
98+
size_t maximalCompressedSize{100000000};
99+
std::vector<char> compressedBuffer;
100+
compressedBuffer.resize(maximalCompressedSize, 0);
101+
int compressedSize{
102+
LZ4_compress_default(evtMessage->buffer(), &compressedBuffer[0],
103+
evtMessage->size(), maximalCompressedSize)
104+
};
105+
if (compressedSize <= 0) {
106+
B2ERROR("LZ4_compress_default failed"
107+
<< LogVar("file name", inputFileName)
108+
<< LogVar("streamed histograms", streamedHistograms)
109+
<< LogVar("original size", evtMessage->size())
110+
<< LogVar("compressed size", compressedSize));
111+
inputFile->Close();
112+
return 1;
113+
}
114+
zmq::message_t message{&compressedBuffer[0], static_cast<size_t>(compressedSize)};
115+
size_t maximalUncompressedSize{128000000};
116+
std::vector<char> uncompressedBuffer;
117+
uncompressedBuffer.reserve(maximalUncompressedSize);
118+
int uncompressedSize{
119+
LZ4_decompress_safe(message.data<char>(), &uncompressedBuffer[0],
120+
message.size(), maximalUncompressedSize)
121+
};
122+
if (uncompressedSize <= 0) {
123+
B2ERROR("LZ4_decompress_safe failed"
124+
<< LogVar("file name", inputFileName)
125+
<< LogVar("streamed histograms", streamedHistograms)
126+
<< LogVar("original size", evtMessage->size())
127+
<< LogVar("compressed size", compressedSize)
128+
<< LogVar("uncompressed size", uncompressedSize));
129+
inputFile->Close();
130+
return 1;
131+
}
132+
if (evtMessage->size() != uncompressedSize) {
133+
B2ERROR("Original size and decompressed size differ"
134+
<< LogVar("file name", inputFileName)
135+
<< LogVar("streamed histograms", streamedHistograms)
136+
<< LogVar("original size", evtMessage->size())
137+
<< LogVar("compressed size", compressedSize)
138+
<< LogVar("uncompressed size", uncompressedSize));
139+
inputFile->Close();
140+
return 1;
141+
}
142+
B2INFO("The compression/decompression cycle with LZ4 is successfully completed"
143+
<< LogVar("file name", inputFileName)
144+
<< LogVar("streamed histograms", streamedHistograms)
145+
<< LogVar("original size", evtMessage->size())
146+
<< LogVar("compressed size", compressedSize)
147+
<< LogVar("uncompressed size", uncompressedSize)
148+
<< LogVar("compressed/uncompressed ratio", (compressedSize * 1.) / uncompressedSize));
149+
inputFile->Close();
150+
return 0;
151+
}

0 commit comments

Comments
 (0)