Skip to content
Snippets Groups Projects
Commit 05c9008f authored by Rosen Matev's avatar Rosen Matev :sunny:
Browse files

Add signal handler that dumps the raw event

parent 1fb679d4
No related branches found
No related tags found
4 merge requests!4553Fix UT Decoder,!4539Synchronize master branch with 2024-patches,!4525Draft: Synchronize master branch with 2024-patches,!3883Error event handling
......@@ -8,14 +8,15 @@
* granted to it by virtue of its status as an Intergovernmental Organization *
* or submit itself to any jurisdiction. *
\*****************************************************************************/
#include <memory>
#include "Gaudi/Algorithm.h"
#include "GaudiAlg/FunctionalDetails.h"
#include "GaudiKernel/DataObjectHandle.h"
#include "GaudiKernel/FunctionalFilterDecision.h"
#include "GaudiKernel/RegistryEntry.h"
#include <csignal>
#include <memory>
class ConfigurableDummy : public Gaudi::Algorithm {
using Algorithm::Algorithm;
......@@ -28,6 +29,7 @@ public:
private:
Gaudi::Property<int> m_CFD{this, "CFD", 1, "ControlFlowDecision is true every Nth events"};
Gaudi::Property<bool> m_decisionWarning{this, "DecisionWarning", false, "Emit a warning for false decisions"};
Gaudi::Property<int> m_signal{this, "Signal", 0, "Raise signal"};
Gaudi::Property<std::vector<std::string>> m_inpKeys{this, "inpKeys", {}, ""};
Gaudi::Property<std::vector<std::string>> m_outKeys{this, "outKeys", {}, ""};
......@@ -96,5 +98,7 @@ StatusCode ConfigurableDummy::execute( EventContext const& context ) const // th
bool decision = m_CFD > 0 && context.evt() % m_CFD == 0;
if ( m_decisionWarning && !decision ) { warning() << "Event did not pass" << endmsg; }
if ( m_signal > 0 ) { std::raise( m_signal ); }
return decision ? Gaudi::Functional::FilterDecision::PASSED : Gaudi::Functional::FilterDecision::FAILED;
}
......@@ -58,6 +58,7 @@ gaudi_add_module(LHCbAlgs
src/ProcessPhase.cpp
src/RunChangeTest.cpp
src/ServiceStarter.cpp
src/SignalMDFWriter.cpp
src/TESCheck.cpp
src/TESFingerPrint.cpp
src/TESMerger.cpp
......
/*****************************************************************************\
* (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration *
* *
* This software is distributed under the terms of the GNU General Public *
* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". *
* *
* In applying this licence, 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. *
\*****************************************************************************/
#include "Event/RawEvent.h"
#include "LHCbAlgs/Consumer.h"
#include <csignal>
#include <fcntl.h>
#include <fmt/format.h>
#include <stdio.h>
/** @class SignalMDFWriter
*
* PrepareMDFSignalHandler
*
* Register signal handler that writes the raw event.
*
* The behavior is undefined if any signal handler performs any of the following:
* ...
* - access to an object with thread storage duration
*
* https://maskray.me/blog/2021-02-14-all-about-thread-local-storage
*
*/
namespace {
using DataHandle = DataObjectReadHandle<LHCb::RawEvent>;
constexpr size_t OUTPUT_PATH_SIZE = 1024;
DataHandle* s_rawEventHandle = nullptr;
char s_outputPath[OUTPUT_PATH_SIZE] = "";
void signal_handler( int ) {
auto f = ::open( s_outputPath, O_WRONLY | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH );
if ( f == -1 ) { std::_Exit( EXIT_FAILURE ); }
const auto* rawEvent = s_rawEventHandle->getIfExists();
if ( rawEvent ) {
// MDF event header
LHCb::RawBank const* const daqBank = rawEvent->banks( LHCb::RawBank::DAQ )[0];
::write( f, daqBank->data(), daqBank->totalSize() - daqBank->hdrSize() );
// MDF raw banks
constexpr auto types = LHCb::RawBank::types();
for ( const auto type : types ) {
if ( type != LHCb::RawBank::DAQ ) {
for ( LHCb::RawBank const* const bank : rawEvent->banks( type ) ) { ::write( f, bank, bank->totalSize() ); }
}
}
}
::close( f );
std::_Exit( EXIT_FAILURE );
}
} // namespace
class SignalMDFWriter : public LHCb::Algorithm::Consumer<void()> {
public:
SignalMDFWriter( const std::string& name, ISvcLocator* pSvcLocator ) : Consumer( name, pSvcLocator ) {}
StatusCode start() override;
StatusCode stop() override;
void operator()() const override;
private:
Gaudi::Property<std::string> m_outputPrefix{this, "OutputPrefix", "signal"};
Gaudi::Property<std::vector<int>> m_signals{this, "Signals", {SIGILL, SIGABRT, SIGBUS, SIGSEGV}};
DataHandle m_rawEvent{this, "RawEvent", ""};
};
DECLARE_COMPONENT( SignalMDFWriter )
StatusCode SignalMDFWriter::start() {
return Consumer::start().andThen( [&] {
s_rawEventHandle = &m_rawEvent;
for ( auto signal : m_signals ) std::signal( signal, signal_handler );
} );
}
StatusCode SignalMDFWriter::stop() { return Consumer::stop(); }
void SignalMDFWriter::operator()() const {
// 1. Make sure the transient MapView is allocated and initialized.
// 2. Obtain the ODIN raw data to construct the name of the output.
auto const* rawEvent = m_rawEvent.get();
auto const banks = rawEvent->banks( LHCb::RawBank::ODIN );
if ( banks.size() != 1 ) {
throw GaudiException( "Unexpected number of ODIN banks: " + std::to_string( banks.size() ), __PRETTY_FUNCTION__,
StatusCode::FAILURE );
}
// Assume ODIN v7
auto s = fmt::format( "{}_{:010}_{:020}.mdf", m_outputPrefix.value(), banks[0]->data()[0],
static_cast<uint64_t>( banks[0]->data()[8] ) +
( static_cast<uint64_t>( banks[0]->data()[9] ) << 32 ) );
if ( s.size() + 1 > OUTPUT_PATH_SIZE ) {
throw GaudiException( "OutputPrefix property is too long", __PRETTY_FUNCTION__, StatusCode::FAILURE );
}
std::strcpy( s_outputPath, s.c_str() );
}
###############################################################################
# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration #
# #
# This software is distributed under the terms of the GNU General Public #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". #
# #
# In applying this licence, 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. #
###############################################################################
from PyConf.Algorithms import (
SignalMDFWriter,
ConfigurableDummy,
)
from PyConf.application import (
ApplicationOptions,
configure,
configure_input,
default_raw_event,
)
from PyConf.control_flow import CompositeNode, NodeLogic
options = ApplicationOptions(_enabled=False)
options.set_input_and_conds_from_testfiledb('2023_raw_hlt1_269939')
options.n_threads = 1
options.n_event_slots = 4
options.evt_max = 50
# options.use_iosvc = True
options.event_store = 'EvtStoreSvc'
options.scheduler_legacy_mode = False
configure_input(options)
ensure_event = SignalMDFWriter(
OutputPrefix="signal", RawEvent=default_raw_event(["VP"]))
prescaler = ConfigurableDummy(CFD=20)
crash = ConfigurableDummy(Signal=11)
top = CompositeNode(
"top", [ensure_event, prescaler, crash],
combine_logic=NodeLogic.LAZY_AND,
force_order=True)
configure(options, top)
from Configurables import LHCb__DetDesc__ReserveDetDescForEvent as reserveIOV
reserveIOV("reserveIOV").PreloadGeometry = False
<?xml version="1.0" ?><!DOCTYPE extension PUBLIC '-//QM/2.3/Extension//EN' 'http://www.codesourcery.com/qm/dtds/2.3/-//qm/2.3/extension//en.dtd'>
<!--
(c) Copyright 2000-2024 CERN for the benefit of the LHCb Collaboration
This software is distributed under the terms of the GNU General Public
Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".
In applying this licence, 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.
-->
<extension class="GaudiTest.GaudiExeTest" kind="test">
<argument name="program"><text>gaudirun.py</text></argument>
<argument name="args"><set>
<text>../options/signal_writer.py</text>
</set></argument>
<argument name="use_temp_dir"><enumeral>per-test</enumeral></argument>
<argument name="exit_code"><integer>1</integer></argument>
<argument name="validator">
<text>
countErrorLines({"FATAL": 0, "ERROR": 0, "WARNING": 0})
import os
expected_fn = "signal_0000269939_00000000000001450050.mdf"
expected_size = 28032
try:
size = os.path.getsize(expected_fn)
if size != expected_size:
causes.append(f"size {size} != expected {expected_size}")
except Exception as e:
causes.append(str(e))
</text>
</argument>
</extension>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment