ATLAS Offline Software
Loading...
Searching...
No Matches
TriggerEDMSerialiserTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6#include "TriggerEDMCLIDs.h"
7
8#include "Gaudi/Interfaces/IOptionsSvc.h"
9#include "GaudiKernel/System.h"
15#include "AthContainers/debug.h"
21
22#include <ranges>
23#include <string>
24#include <numeric>
25
26namespace {
27 // Special module ID used internally to store total result size limit in the truncation threshold map
28 constexpr uint16_t fullResultTruncationID = std::numeric_limits<uint16_t>::max();
29}
30
32 const std::string& name,
33 const IInterface* parent )
34 : base_class( type, name, parent ),
35 m_dynAuxAddress(AuxIdTypeMap_t::Updater_t()) {}
36
38 // Initialise tools and services
39 ATH_CHECK( m_serializerSvc.retrieve() );
40 ATH_CHECK( m_clidSvc.retrieve() );
41 ATH_CHECK( m_debugInfoWHKey.initialize() );
43 if (!m_monTool.empty()) ATH_CHECK(m_monTool.retrieve());
44 // Parse the list of collections to serialise
45 for ( const std::string& typeKeyAuxIDs : m_collectionsToSerialize.value() ) {
47 }
48
49 // Retrieve the total result size limit from DataFlowConfig which is a special object
50 // used online to hold DF properties passed from TDAQ to HLT as run parameters
51 auto jobOptionsSvc = service<Gaudi::Interfaces::IOptionsSvc>("JobOptionsSvc", /*createIf=*/ false);
52 if (!jobOptionsSvc.isValid()) {
53 ATH_MSG_WARNING("Could not retrieve JobOptionsSvc, will not update the EventSizeHardLimitMB property");
54 }
55 else {
56 if (jobOptionsSvc->has("DataFlowConfig.DF_MaxEventSizeMB")) {
57 if (m_eventSizeHardLimitMB.fromString(jobOptionsSvc->get("DataFlowConfig.DF_MaxEventSizeMB")).isSuccess()) {
58 ATH_MSG_DEBUG("Updated EventSizeHardLimitMB to " << m_eventSizeHardLimitMB.value()
59 << " from DataFlowConfig.DF_MaxEventSizeMB");
60 }
61 else {
62 ATH_MSG_ERROR("Could not convert DataFlowConfig.DF_MaxEventSizeMB to integer. Leaving EventSizeHardLimitMB="
63 << m_eventSizeHardLimitMB.value());
64 }
65 }
66 else {
67 ATH_MSG_DEBUG("Could not retrieve DataFlowConfig.DF_MaxEventSizeMB from JobOptionsSvc. This is fine if running "
68 << "offline, but should not happen online. Leaving EventSizeHardLimitMB="
69 << m_eventSizeHardLimitMB.value());
70 }
71 }
72
73 // Add the total result size limit to truncation threshold map
74 if (m_eventSizeHardLimitMB >= 0) {
76 ATH_MSG_ERROR("Fraction cannot be > 1.0, but FullResultTruncationFrac is set to " << m_fullResultTruncationFrac);
77 return StatusCode::FAILURE;
78 }
79 float totalResultSizeLimitBytes = m_fullResultTruncationFrac * m_eventSizeHardLimitMB * 1024. * 1024.;
80 m_truncationThresholds[fullResultTruncationID] = static_cast<uint32_t>(totalResultSizeLimitBytes);
81 }
82 else {
83 m_truncationThresholds[fullResultTruncationID] = std::numeric_limits<uint32_t>::max();
84 }
85
86 return StatusCode::SUCCESS;
87}
88
89StatusCode TriggerEDMSerialiserTool::addCollectionToSerialise(const std::string& typeKeyAuxIDs, std::vector<Address>& addressVec) const {
90 ATH_MSG_DEBUG("Parsing " << typeKeyAuxIDs);
91
92 // Syntax: 'collectionKeyType;module1,module2,...[;allowTruncation]'
93 std::vector<std::string_view> def = CxxUtils::tokenize<std::string_view, char>(typeKeyAuxIDs, ';');
94
95 if ( def.size() < 2 ) {
96 ATH_MSG_ERROR("Invalid EDM collection specification: " << typeKeyAuxIDs);
97 return StatusCode::FAILURE;
98 }
99
100 const std::string_view typeKeyAux = def[0];
101 const std::string_view configuredType = typeKeyAux.substr( 0, typeKeyAux.find('#') );
102 const std::string_view key = typeKeyAux.substr( typeKeyAux.find('#')+1, typeKeyAux.find('.')-typeKeyAux.find('#') );
103
105
106 const size_t pos = configuredType.find('_');
107 const std::string transientType{ pos==std::string::npos ? configuredType : configuredType.substr(0, pos) };
108
109 CLID clid{0};
110 std::string persistentType;
111 if ( m_clidSvc->getIDOfTypeName(transientType, clid).isFailure() ) {
112 ATH_MSG_ERROR( "Can not find CLID for " << transientType << " that is needed for serialisation " << key );
113 return StatusCode::FAILURE;
114 }
115 ATH_MSG_VERBOSE("Decoded transient type: " << transientType << " with the CLID " << clid );
116
117 if ( transientType == configuredType ) {
118 std::string realTypeName;
119 if( m_clidSvc->getTypeInfoNameOfID( clid, realTypeName ).isFailure() ) {
120 ATH_MSG_ERROR( "Can not find real type name for " << transientType << " that is needed for serialisation " << key );
121 return StatusCode::FAILURE;
122 }
123 persistentType = transientType + version( realTypeName );
124 ATH_MSG_VERBOSE(transientType << " = "<< configuredType << " thus obtained real type name from clid svc " << realTypeName << " forming persistent type name "<< persistentType );
125 } else {
126 persistentType = configuredType;
127 }
128
129 ATH_MSG_DEBUG( "Persistent type: " << persistentType );
130
131 RootType classDesc = RootType::ByNameNoQuiet( persistentType );
132 if ( ! classDesc.IsComplete() ) {
133 ATH_MSG_ERROR( "The type " << persistentType << " is not known to ROOT serialiser" );
134 return StatusCode::FAILURE;
135 }
136
137 // Set truncation mode
138 if ( def.size() > 2 && def[2].contains("allowTruncation") ) {
139 ATH_MSG_DEBUG("Truncation allowed for " << configuredType << "#" << key);
140 truncationMode = Address::Truncation::Allowed;
141 }
142
143 std::vector<uint16_t> moduleIdVec = CxxUtils::tokenize<uint16_t, char>(def[1], ',');
144 std::sort(moduleIdVec.begin(), moduleIdVec.end());
145
146 if (moduleIdVec.empty()) {
147 ATH_MSG_ERROR( "No HLT result module IDs given for " << typeKeyAux );
148 return StatusCode::FAILURE;
149 }
150
151 ATH_MSG_DEBUG( "Transient type " << transientType << " persistent type " << persistentType << " will be written to " << moduleIdVec.size() << " result ROBFragments with IDs: "
152 << moduleIdVec << "" );
153
154 if ( persistentType.starts_with("xAOD") ) { // xAOD - either interface of Aux
156 if ( typeKeyAux.contains('.') ) { // Aux, possibly with selection of variables
157 ATH_MSG_DEBUG( "with aux content: " );
158 const std::string allVars = std::string(typeKeyAux.substr( typeKeyAux.find('.')+1 ));
159 if (!allVars.empty()) {
160 const auto variableNames = allVars | std::views::split('.') | std::ranges::to<std::set<std::string>>();
161 if (msgLvl(MSG::DEBUG)) {
162 for ( const auto& el: variableNames ) {
163 ATH_MSG_DEBUG( " \"" << el << "\"" );
164 }
165 }
166 sel.selectAux( variableNames );
167 }
168 addressVec.push_back( {transientType, std::move(persistentType), std::move(classDesc), clid,
169 std::string(key), std::move(moduleIdVec), Address::Category::xAODAux, truncationMode, std::move(sel)} );
170 } else {
171 addressVec.push_back( {transientType, std::move(persistentType), std::move(classDesc), clid,
172 std::string(key), std::move(moduleIdVec), Address::Category::xAODInterface, truncationMode} );
173 }
174 } else { // an old T/P type
175 addressVec.push_back( {transientType, std::move(persistentType), std::move(classDesc), clid,
176 std::string(key), std::move(moduleIdVec), Address::Category::OldTP, truncationMode} );
177 }
178 return StatusCode::SUCCESS;
179}
180
181StatusCode TriggerEDMSerialiserTool::makeHeader(const Address& address, std::vector<uint32_t>& buffer ) {
182 buffer.push_back(0); // fragment size placeholder
183 buffer.push_back( address.clid ); // type info via CLID
184
185 std::vector<uint32_t> serializedLabel;
187 std::vector<std::string> descr({address.persType, address.key});
188 ss.serialize( descr, serializedLabel );
189 buffer.push_back( serializedLabel.size() );
190 buffer.insert( buffer.end(), serializedLabel.begin(), serializedLabel.end() ); // plain SG key
191 return StatusCode::SUCCESS;
192}
193
194StatusCode TriggerEDMSerialiserTool::fillPayload( const void* data, size_t sz, std::vector<uint32_t>& buffer ) const {
195 ATH_CHECK( sz != 0 );
196 ATH_CHECK( data != nullptr );
197
198 buffer.push_back( sz ); // size in bytes
199 const size_t neededSize = std::ceil( double(sz)/sizeof(uint32_t) );
200 const size_t existingSize = buffer.size();
201 buffer.resize(existingSize + neededSize);
202 std::memcpy(buffer.data() + existingSize, data, sz);
203 return StatusCode::SUCCESS;
204}
205
206
207
208StatusCode TriggerEDMSerialiserTool::serialiseDynAux( DataObject* dObj, const Address& address, std::vector<uint32_t>& buffer, size_t& nDynWritten ) const {
209 ATH_MSG_DEBUG( "About to start streaming aux data of " << address.key );
210 DataBucketBase* dObjAux = dynamic_cast<DataBucketBase*>(dObj);
211 ATH_CHECK( dObjAux != nullptr );
212 //coverity[FORWARD_NULL:FALSE]
213 const SG::IAuxStoreIO* auxStoreIO = dObjAux->template cast<SG::IAuxStoreIO> (nullptr, true);
214 if ( auxStoreIO == nullptr ) {
215 ATH_MSG_DEBUG( "Can't obtain AuxContainerBase of " << address.key << " no dynamic variables presumably" );
216 return StatusCode::SUCCESS;
217 }
218
219 const SG::auxid_set_t& selected = address.sel.getSelectedAuxIDs( auxStoreIO->getDynamicAuxIDs() );
220
221 if ( selected.empty() ) {
222 ATH_MSG_VERBOSE( "Empty set of dynamic variables to store, do nothing" );
223 return StatusCode::SUCCESS;
224 }
225 ATH_MSG_DEBUG("Ready for serialisation of " << selected.size() << " dynamic variables");
226
227 for (SG::auxid_t auxVarID : selected ) {
228
229 const Address* auxAddress{};
230
231 // Find type information for dynamic variable
232 const auto itr = m_dynAuxAddress.find(auxVarID);
233 if ( itr != m_dynAuxAddress.end() ) {
234 auxAddress = &(itr->second);
235 }
236 // Or create and cache it on first encounter. We cannot do this during addCollectionToSerialise
237 // because variables with AuxDataOptions set (e.g. PackedContainer) don't report their actual
238 // type through the AuxTypeRegistry (see ATR-32953).
239 else {
240 const std::string decorationName = SG::AuxTypeRegistry::instance().getName(auxVarID);
241 const std::string typeName = SG::AuxTypeRegistry::instance().getVecTypeName(auxVarID);
242 const std::type_info* tinfo = auxStoreIO->getIOType (auxVarID);
243
244 ATH_CHECK( tinfo != nullptr );
245 TClass* cls = TClass::GetClass (*tinfo);
246 ATH_CHECK( cls != nullptr );
247
248 CLID clid{0};
249 if ( m_clidSvc->getIDOfTypeName(typeName, clid).isFailure() ) { // First try
250 const std::string fullTypeName = System::typeinfoName( *tinfo );
251 if ( m_clidSvc->getIDOfTypeInfoName(fullTypeName, clid).isFailure() ) { // Second try
252 ATH_MSG_ERROR("Unable to obtain CLID for either typeName:" << typeName << " or fullTypeName:" << fullTypeName);
253 ATH_MSG_ERROR("Please check if this is something which should obtain a CLID via TriggerEDMCLIDs.h");
254 return StatusCode::FAILURE;
255 }
256 }
257
258 // Create the type information for the dynamic variable
259 Address addr { typeName, cls->GetName(), RootType(cls), clid,
260 decorationName, address.moduleIdVec, Address::Category::xAODDecoration };
261
262 // Store type and get pointer to it
263 const auto& [itr, inserted] = m_dynAuxAddress.emplace( auxVarID, std::move(addr) );
264 auxAddress = &(itr->second);
265 }
266
267 ATH_MSG_DEBUG( "Streaming '" << auxAddress->key << "' of type '" << auxAddress->transType <<
268 "', aux ID " << auxVarID << ", class '" << auxAddress->classDesc.Class()->GetName() <<
269 "'" << ", CLID " << auxAddress->clid );
270
271 const void* rawptr = auxStoreIO->getIOData( auxVarID );
272 ATH_CHECK( rawptr != nullptr );
273
274 size_t sz=0;
275 void* mem = m_serializerSvc->serialize( rawptr, auxAddress->classDesc, sz );
276
277 if ( mem == nullptr or sz == 0 ) {
278 ATH_MSG_ERROR( "Serialisation of " << address.persTypeName() << "."<< auxAddress->key << " unsuccessful" );
279 return StatusCode::FAILURE;
280 }
281 ATH_MSG_DEBUG( "Serialised " << address.persTypeName() << "."<< auxAddress->key << " memory size " << sz );
282
283 std::vector<uint32_t> fragment;
284 ATH_CHECK( makeHeader( *auxAddress, fragment ) );
285 ATH_CHECK( fillPayload( mem, sz, fragment ) );
286 fragment[0] = fragment.size();
287
288 delete [] static_cast<const char*>( mem );
289
290 buffer.insert( buffer.end(), fragment.begin(), fragment.end() );
291 ++nDynWritten;
292 }
293 return StatusCode::SUCCESS;
294}
295
296
297StatusCode TriggerEDMSerialiserTool::serialiseContainer( void* data, const Address& address, std::vector<uint32_t>& buffer ) const {
298
299 size_t sz=0;
300 void* mem = m_serializerSvc->serialize( data, address.classDesc, sz );
301
302 ATH_MSG_DEBUG( "Streamed to buffer at address " << mem << " of " << sz << " bytes" );
303
304 if ( mem == nullptr or sz == 0 ) {
305 ATH_MSG_ERROR( "Serialisation of " << address.persType << " " << address.key << " unsuccessful" );
306 return StatusCode::FAILURE;
307 }
308
309 // prepare fragment
310 std::vector<uint32_t> fragment;
311 ATH_CHECK( makeHeader( address, fragment ) );
312 ATH_CHECK( fillPayload( mem, sz, fragment ) );
313 if ( mem != nullptr ) delete [] static_cast<const char*>( mem );
314
315
316 ATH_MSG_DEBUG( address.transType << "#" << address.key << " Fragment size: " << fragment.size()*sizeof(uint32_t) << " bytes");
317 fragment[0] = fragment.size();
318 buffer.insert( buffer.end(), fragment.begin(), fragment.end() );
319
320 return StatusCode::SUCCESS;
321}
322
324 void* data,
325 const Address& address,
326 std::vector<uint32_t>& buffer,
327 SGImplSvc* evtStore) const
328{
329 ATH_MSG_DEBUG("xAOD Aux Container");
330
331 void* copy = data;
332 //Get the Base Info given clid.
333 const SG::BaseInfoBase* bib = SG::BaseInfoBase::find (address.clid);
334 //cast data to xAOD::AuxContainerBase
335 void* data_interface = bib->cast (data, ClassID_traits<xAOD::AuxContainerBase>::ID());
336 if (data_interface != nullptr) {
337 const xAOD::AuxContainerBase* store = reinterpret_cast<const xAOD::AuxContainerBase*> (data_interface);
338 copy = address.classDesc.Construct();
339 //cast copy to xAOD::AuxContainerBase
340 void* copy_interface = bib->cast (copy, ClassID_traits<xAOD::AuxContainerBase>::ID());
341 xAOD::AuxContainerBase* copy_store = reinterpret_cast<xAOD::AuxContainerBase*> (copy_interface);
343 *copy_store,
344 nullptr);
345 }
346
347 ATH_CHECK( serialiseContainer( copy, address, buffer ) );
348
349 if (copy != data) {
350 address.classDesc.Destruct (copy);
351 }
352
353 size_t baseSize = buffer.size();
354 if ( not m_saveDynamic )
355 return StatusCode::SUCCESS;
356
357 DataObject* dObj = evtStore->accessData( address.clid, address.key );
358 ATH_CHECK( dObj != nullptr );
359 size_t nDynWritten = 0;
360 ATH_CHECK( serialiseDynAux( dObj, address, buffer, nDynWritten ) );
361 if ( nDynWritten > 0 ) {
362 ATH_MSG_DEBUG( " Fragment size including " << (buffer.size() - baseSize)*sizeof(uint32_t) << " bytes from "
363 << nDynWritten << "x DynAux : " << buffer.size()*sizeof(uint32_t) );
364 }
365 return StatusCode::SUCCESS;
366}
367
368StatusCode TriggerEDMSerialiserTool::serialiseTPContainer( void* data, const Address& address, std::vector<uint32_t>& buffer ) const {
369
370 ATH_MSG_DEBUG("TP Container, converting from: " << address.transType << " to " << address.persType );
371 std::string converterPersistentType;
372 void * persistent = m_tpTool->convertTP( address.transType, data, converterPersistentType );
373 ATH_CHECK( persistent != nullptr );
374 ATH_CHECK ( converterPersistentType == address.persType );
375 ATH_CHECK( serialiseContainer( persistent, address, buffer ) );
376
377 address.classDesc.Destruct( persistent );
378
379 return StatusCode::SUCCESS;
380}
381
382StatusCode TriggerEDMSerialiserTool::serialise( const Address& address, std::vector<uint32_t>& buffer, SGImplSvc* evtStore ) const {
383 DataObject* dObj = evtStore->accessData( address.clid, address.key );
384 if ( dObj == nullptr ) {
385 ATH_MSG_DEBUG("Data Object with the CLID " << address.clid << " and the key " << address.key << " is missing");
386 return StatusCode::SUCCESS;
387 }
388
389 void* rawptr = SG::fromStorable( dObj, address.clid, nullptr, msgLvl(MSG::DEBUG) );
390 if ( rawptr == nullptr ) {
391 ATH_MSG_DEBUG( "Data Object with key " << address.key << " can not be converted to void* for streaming" );
392 return StatusCode::SUCCESS;
393 }
394 ATH_MSG_DEBUG("Obtained raw pointer " << rawptr );
395
397 return serialiseContainer( rawptr, address, buffer );
398 }
399 if ( address.category == Address::Category::xAODAux ) {
400 return serialisexAODAuxContainer( rawptr, address, buffer, evtStore );
401 }
402 if ( address.category == Address::Category::OldTP ) {
403 return serialiseTPContainer( rawptr, address, buffer );
404 }
405 ATH_MSG_ERROR("Unknown Address category - neither of xAODInterface, xAODAux, OldTP");
406 return StatusCode::FAILURE;
407}
408
409StatusCode TriggerEDMSerialiserTool::fill( HLT::HLTResultMT& resultToFill, const EventContext& ctx ) const {
410
411 // Leave this check until there is a justified case for appending data to an existing result
412 if (not resultToFill.getSerialisedData().empty()) {
413 ATH_MSG_ERROR("Trying to fill a result which is not empty! Likely misconfiguration, returning a FAILURE");
414 return StatusCode::FAILURE;
415 }
416
417 SGImplSvc* evtStore = dynamic_cast<SGImplSvc*>(Atlas::getExtendedEventContext(ctx).proxy());
418 ATH_CHECK( evtStore != nullptr );
419
420 // Map storing information to be written out in case of truncation for each module
421 TruncationInfoMap truncationInfoMap;
422
423 // Record debug info container to be filled in case of truncation
424 auto debugInfo = SG::makeHandle(m_debugInfoWHKey, ctx);
425 auto debugInfoData = std::make_unique<xAOD::TrigCompositeContainer>();
426 auto debugInfoAux = std::make_unique<xAOD::TrigCompositeAuxContainer>();
427 debugInfoData->setStore(debugInfoAux.get());
428 ATH_CHECK(debugInfo.record(std::move(debugInfoData), std::move(debugInfoAux)));
429
430 // Find a list of active moduleIDs in this event to skip inactive ones
431 std::set<uint16_t> activeModules = activeModuleIDs(resultToFill);
432 if (activeModules.empty()) {
433 ATH_MSG_DEBUG("No active module IDs in this event. This is normal for events accepted "
434 << "only to calibration streams. Skip all EDM serialisation.");
435 return StatusCode::SUCCESS;
436 }
437
438 // Create buffer for serialised data
439 std::vector<uint32_t> buffer;
440 buffer.reserve(1000);
441
442 std::unordered_map<uint16_t, std::vector<uint32_t>> deferredInterfaceBuffer;
443 for ( const Address& address: m_toSerialise ) {
444 // Check if we need to serialise this object for this event
445 std::vector<uint16_t> addressActiveModuleIds;
446 std::set_intersection(address.moduleIdVec.begin(), address.moduleIdVec.end(),
447 activeModules.begin(), activeModules.end(),
448 std::back_inserter(addressActiveModuleIds));
449 if (addressActiveModuleIds.empty()) {
450 ATH_MSG_DEBUG("Streaming of " << address.persTypeName() << " is skipped "
451 << "because its module IDs are not active in this event");
452 continue;
453 }
454
455 buffer.clear();
456 ATH_MSG_DEBUG( "Streaming " << address.persTypeName() );
457 //coverity[FORWARD_NULL:FALSE]
458 ATH_CHECK( serialise(address, buffer, evtStore) );
459 if (buffer.empty()) {
460 ATH_MSG_DEBUG("Streaming of " << address.persTypeName() << " is skipped");
461 continue;
462 }
463
464 const size_t thisFragmentSize = buffer.size()*sizeof(uint32_t);
465 ATH_MSG_DEBUG( "Serialised size of " << address.persTypeName() << " is " << thisFragmentSize << " bytes" );
466 for (const uint16_t id : addressActiveModuleIds) {
467 // If result not yet truncated, try adding the serialised data
468 if (resultToFill.getTruncatedModuleIds().count(id)==0) {
469 // for truncation allowed collections, save the interface for a deferred addition
470 if (address.truncationMode==Address::Truncation::Allowed &&
471 address.category == Address::Category::xAODInterface){
472 deferredInterfaceBuffer[id]=buffer;
473 continue;
474 }
475 else {
476 ATH_CHECK(tryAddData(resultToFill, id, buffer, address.truncationMode, deferredInterfaceBuffer));
477 // clean up the deferred interface buffer, if used
478 deferredInterfaceBuffer.erase(id);
479 }
480 }
481 // Check for truncation after adding data
482 if (resultToFill.getTruncatedModuleIds().count(id)==0) {
483 ATH_MSG_DEBUG("Module " << id << " payload after inserting " << address.persTypeName() << " has "
484 << resultToFill.getSerialisedData().at(id).size()*sizeof(uint32_t) << " bytes");
485 truncationInfoMap[id].push_back({&address, thisFragmentSize, true});
486 }
487 else {
488 ATH_MSG_WARNING("HLTResult with module ID " << id <<
489 " truncated - could not add " << address.persTypeName() <<
490 (address.truncationMode==Address::Truncation::Allowed ? " (truncation allowed)" : ""));
491 truncationInfoMap[id].push_back({&address, thisFragmentSize, false});
492 }
493 }
494 }
495
496 // Handle truncation
497 ATH_CHECK(fillDebugInfo(truncationInfoMap, *debugInfo, resultToFill, evtStore));
498
499 return StatusCode::SUCCESS;
500}
501
503 const uint16_t id,
504 const std::vector<uint32_t>& data,
505 Address::Truncation truncationMode,
506 const std::unordered_map<uint16_t, std::vector<uint32_t>> & deferredInterfaceBuffer) const {
507 if (m_truncationThresholds.value().count(id)==0) {
508 ATH_MSG_ERROR("Module ID " << id << " missing from TruncationThresholds map. Cannot determine if result needs truncation");
509 return StatusCode::FAILURE;
510 }
511
512 // Size in this module
513 const uint32_t currentSizeBytes = hltResult.getSerialisedData().count(id)==0
514 ? 0 : hltResult.getSerialisedData().at(id).size()*sizeof(uint32_t);
515 // Total size
516 size_t currentTotalSizeWords = 0;
517 for (const auto& [i, d] : hltResult.getSerialisedData()) currentTotalSizeWords += d.size();
518 const uint32_t currentTotalSizeBytes = currentTotalSizeWords*sizeof(uint32_t);
519 // Size to be added
520 const uint32_t extraSizeBytes = data.size()*sizeof(uint32_t);
521
522 bool severeTruncation = truncationMode==Address::Truncation::Error;
523 if (currentTotalSizeBytes+extraSizeBytes > m_truncationThresholds.value().at(fullResultTruncationID)) {
524 // The data doesn't fit, flag the full result as truncated
525 ATH_MSG_DEBUG("Skipping adding data to result with module ID " << id << " because of full-result truncation");
526 hltResult.addTruncatedModuleId(fullResultTruncationID, severeTruncation);
527 hltResult.addTruncatedModuleId(id, severeTruncation);
528 }
529 else if (currentSizeBytes+extraSizeBytes > m_truncationThresholds.value().at(id)) {
530 // The data doesn't fit, flag this module's result as truncated
531 ATH_MSG_DEBUG("Skipping adding data to truncated result with module ID " << id);
532 hltResult.addTruncatedModuleId(id, severeTruncation);
533 }
534 else {
535 // for truncation allowed collections, add first the interface, only if the Aux is can be stored
536 if (truncationMode==Address::Truncation::Allowed){
537 hltResult.addSerialisedData(id, deferredInterfaceBuffer.at(id));
538 }
539 // The data fits, so add it to the result
540 ATH_MSG_DEBUG("Adding data to result with module ID " << id);
541 hltResult.addSerialisedData(id, data);
542 }
543 return StatusCode::SUCCESS;
544}
545
547 xAOD::TrigCompositeContainer& debugInfoCont,
548 HLT::HLTResultMT& resultToFill,
549 SGImplSvc* evtStore) const {
550 // If full result truncation happened, flag all results as truncated to produce debug info for all
551 if (resultToFill.getTruncatedModuleIds().count(fullResultTruncationID)>0) {
552 ATH_MSG_ERROR("HLT result truncation on total size! Limit of "
553 << m_truncationThresholds.value().at(fullResultTruncationID)/1024./1024.
554 << " MB exceeded. Flagging all module IDs as truncated.");
555 for (const auto& [id, data] : resultToFill.getSerialisedData()) {
556 resultToFill.addTruncatedModuleId(id);
557 }
558 }
559 // Loop over truncation info and fill histograms and debug info objects
560 for (const auto& [id, truncationInfoVec] : truncationInfoMap) {
561 if (resultToFill.getTruncatedModuleIds().count(id)>0) {
562 // Create and fill a debug info object
563 xAOD::TrigComposite* debugInfoThisModule = new xAOD::TrigComposite;
564 debugInfoCont.push_back(debugInfoThisModule); // the container in event store takes ownership of debugInfoThisModule
565 xAOD::TrigComposite::Accessor<uint16_t> moduleId("moduleId");
566 xAOD::TrigComposite::Accessor<uint32_t> totalSize("totalSize");
567 xAOD::TrigComposite::Accessor<std::vector<std::string>> typeNameVec("typeName");
568 xAOD::TrigComposite::Accessor<std::vector<uint32_t>> sizeVec("size");
569 xAOD::TrigComposite::Accessor<std::vector<char>> isRecordedVec("isRecorded");
570 std::pair<std::string, size_t> largestRecorded{"None", 0};
571 std::pair<std::string, size_t> largestDropped{"None", 0};
572 std::pair<std::string, size_t> firstDropped{"None", 0};
573 moduleId(*debugInfoThisModule) = id;
574 uint32_t sizeSum = 0;
575 bool severeTruncation = false;
576 bool truncated = false;
577 for (const TruncationInfo& truncationInfo : truncationInfoVec) {
578 // Store typeName and size information
579 sizeSum += truncationInfo.size;
580 typeNameVec(*debugInfoThisModule).push_back(truncationInfo.addrPtr->persTypeName());
581 sizeVec(*debugInfoThisModule).push_back(truncationInfo.size);
582 isRecordedVec(*debugInfoThisModule).push_back(static_cast<char>(truncationInfo.recorded));
583 if (truncationInfo.recorded && truncationInfo.size > largestRecorded.second) {
584 largestRecorded = {truncationInfo.addrPtr->persTypeName(), truncationInfo.size};
585 }
586 if (!truncationInfo.recorded && truncationInfo.size > largestDropped.second) {
587 largestDropped = {truncationInfo.addrPtr->persTypeName(), truncationInfo.size};
588 }
589 if (!truncationInfo.recorded && !truncated) {
590 firstDropped = {truncationInfo.addrPtr->persTypeName(), truncationInfo.size};
591 truncated = true;
592 }
593 // Decide if this was a severe truncation (event goes to debug stream)
594 if (!truncationInfo.recorded) {
595 severeTruncation |= (truncationInfo.addrPtr->truncationMode==Address::Truncation::Error);
596 }
597 }
598 totalSize(*debugInfoThisModule) = sizeSum;
599 msg(severeTruncation ? MSG::ERROR : MSG::WARNING)
600 << "HLT result truncation" << (severeTruncation ? "." : " in low priority collections.")
601 << " Module ID: " << id << ", limit: "
602 << m_truncationThresholds.value().at(id)/1024. << " kB, total size: "
603 << sizeSum/1024. << " kB, largest recorded collection: " << largestRecorded.first
604 << " (" << largestRecorded.second/1024. << " kB), largest dropped collection: "
605 << largestDropped.first << " (" << largestDropped.second/1024. << " kB), "
606 << " first dropped collection: " <<firstDropped.first << " (" << firstDropped.second/1024. << " kB)"
607 << endmsg;
608 // Give more information on the chains which accepted this event
609 using namespace TrigCompositeUtils;
610 SG::ReadHandle<DecisionContainer> navigation(m_debugNavigationSummaryRHKey); // Implicit ctx lookup - OK, rare code path
611 const Decision* terminus = getTerminusNode(navigation);
612 if (terminus) {
613 std::stringstream ss;
614 ss << "Passing chains in this event: ";
615 for (const DecisionID chainID : decisionIDs(terminus)) {
616 ss << HLT::Identifier(chainID).name() << ", ";
617 addDecisionID(chainID, debugInfoThisModule); // Save this list also into the output, it is then accessible offline too
618 }
619 ATH_MSG_WARNING(ss.str());
620 }
621 // Monitoring
622 const std::string prefix = severeTruncation ? "" : "Allowed";
623 auto monModuleId = Monitored::Scalar<int>(prefix+"Truncation_ModuleId", id);
624 auto monTotalSize = Monitored::Scalar<float>(prefix+"Truncation_TotalSize", sizeSum/1024.);
625 auto monLargestName = Monitored::Scalar<std::string>(
626 prefix+"Truncation_LargestName",
627 largestRecorded.second > largestDropped.second ? largestRecorded.first : largestDropped.first);
628 auto monLargestSize = Monitored::Scalar<float>(
629 prefix+"Truncation_LargestSize",
630 largestRecorded.second > largestDropped.second ? largestRecorded.second/1024. : largestDropped.second/1024.);
631 auto mon = Monitored::Group(m_monTool, monModuleId, monTotalSize, monLargestName, monLargestSize);
632 }
633 }
634 // Serialise and write the debug info only in case of truncation
635 if (!debugInfoCont.empty()) {
636 std::vector<Address> debugInfoAddressVec;
637 const std::string debugInfoID = std::string("xAOD::TrigCompositeContainer#")+m_debugInfoWHKey.key()+";0";
638 const std::string debugInfoAuxID = std::string("xAOD::TrigCompositeAuxContainer#")+m_debugInfoWHKey.key()+"Aux.;0";
639 ATH_CHECK(addCollectionToSerialise(debugInfoID, debugInfoAddressVec));
640 ATH_CHECK(addCollectionToSerialise(debugInfoAuxID, debugInfoAddressVec));
641 std::vector<uint32_t> buffer;
642 for (const Address& address : debugInfoAddressVec) {
643 buffer.clear();
644 ATH_CHECK( serialise(address, buffer, evtStore) );
645 resultToFill.addSerialisedData(0, buffer); // 0 is the main result ID
646 // It would be better to avoid hard-coding main result ID but it should not be configurable either
647 }
648 }
649 return StatusCode::SUCCESS;
650}
651
652std::string TriggerEDMSerialiserTool::version( const std::string& name ) {
653 if ( name.contains("DataVector") ) {
654 const size_t start = name.find('_');
655 return name.substr( start, name.find('>') - start );
656 }
657 const size_t pos = name.find('_');
658 return (pos == std::string::npos ? std::string{} : name.substr( pos ));
659}
660
662 std::set<uint16_t> activeIDs;
663 for (const eformat::helper::StreamTag& st : result.getStreamTags()) {
664 if (st.robs.empty() && st.dets.empty()) { // Full Event Building stream
665 activeIDs.insert(0); // 0 is the main result ID
666 continue;
667 }
668 for (const uint32_t robid : st.robs) {
669 eformat::helper::SourceIdentifier sid(robid);
670 if (sid.subdetector_id() != eformat::SubDetector::TDAQ_HLT) {
671 continue;
672 }
673 activeIDs.insert(sid.module_id());
674 }
675 }
676 return activeIDs;
677}
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
Handle mappings between names and auxid_t.
Helper functions intended to be called from the debugger.
Provide an interface for finding inheritance information at run time.
uint32_t CLID
The Class ID type.
Interface providing I/O for a generic auxiliary store.
static Double_t sz
static Double_t ss
unsigned int DecisionID
xAOD::TrigComposite Decision
void decisionIDs(const Decision *d, DecisionIDContainer &id)
Extracts DecisionIDs stored in the Decision object.
static unsigned int totalSize(const MultiDimArray< T, N > &ht)
TTypeAdapter RootType
Definition RootType.h:211
convert to and from a SG storable
void addDecisionID(DecisionID id, Decision *d)
Appends the decision (given as ID) to the decision object.
A non-templated base class for DataBucket, allows to access the transient object address as a void*.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
bool empty() const noexcept
Returns true if the collection is empty.
A container class for data required to build online output from HLT.
Definition HLTResultMT.h:38
const std::set< uint16_t > & getTruncatedModuleIds() const
Getter for the truncation information.
void addTruncatedModuleId(const uint16_t moduleId, bool severeTruncation=true)
Add module ID to the list of truncated results.
void addSerialisedData(const uint16_t moduleId, const std::vector< uint32_t > &data)
Append serialised data (copy of input) for a given moduleId, doesn't remove existing data.
const std::unordered_map< uint16_t, std::vector< uint32_t > > & getSerialisedData() const
Serialised data getter.
std::string name() const
reports human redable name
Group of local monitoring quantities and retain correlation when filling histograms
Declare a monitored scalar variable.
The Athena Transient Store API.
Definition SGImplSvc.h:109
DataObject * accessData(const CLID &id) const
find proxy and access its data. Returns 0 to flag failure
std::string getName(SG::auxid_t auxid) const
Return the name of an aux data item.
std::string getVecTypeName(SG::auxid_t auxid) const
Return the type of the STL vector used to hold an aux data item.
static AuxTypeRegistry & instance()
Return the singleton registry instance.
The non-template portion of the BaseInfo implementation.
static const BaseInfoBase * find(CLID clid)
Find the BaseInfoBase instance for clid.
Definition BaseInfo.cxx:570
void * cast(void *p, CLID clid) const
Cast to a base pointer.
Definition BaseInfo.cxx:166
Interface providing I/O for a generic auxiliary store.
Definition IAuxStoreIO.h:44
virtual const std::type_info * getIOType(SG::auxid_t auxid) const =0
Return the type of the data to be stored for one aux data item.
virtual const void * getIOData(SG::auxid_t auxid) const =0
Return a pointer to the data to be stored for one aux data item.
virtual const SG::auxid_set_t & getDynamicAuxIDs() const =0
Get the list of all dynamically created variables.
A set of aux data identifiers.
Definition AuxTypes.h:47
Utility class (not a tool or so) to serialize strings into stream of 32bit integers.
static TScopeAdapter ByNameNoQuiet(const std::string &name, Bool_t load=kTRUE)
Definition RootType.cxx:586
void Destruct(void *place) const
Definition RootType.cxx:677
Bool_t IsComplete() const
Definition RootType.cxx:895
TClass * Class() const
Definition RootType.h:183
void * Construct() const
Definition RootType.cxx:666
Gaudi::Property< bool > m_saveDynamic
static StatusCode makeHeader(const TriggerEDMSerialiserTool::Address &address, std::vector< uint32_t > &buffer)
Given the ID of the collection (in address arg) insert basic streaming info into the buffer.
Gaudi::Property< int > m_eventSizeHardLimitMB
StatusCode serialiseTPContainer(void *data, const Address &address, std::vector< uint32_t > &buffer) const
Place inside the buffer the serialised old type of container involves T/P conversion.
SG::ReadHandleKey< TrigCompositeUtils::DecisionContainer > m_debugNavigationSummaryRHKey
StoreGate key for the navigation summary object - with this we can print which chains accepted the ev...
std::vector< Address > m_toSerialise
ToolHandle< TrigSerTPTool > m_tpTool
CxxUtils::ConcurrentToValMap< SG::auxid_t, Address, CxxUtils::SimpleUpdater, std::hash< SG::auxid_t >, std::equal_to< SG::auxid_t >, SG::null_auxid > AuxIdTypeMap_t
A thread-safe map to store the AuxId to Address mapping for dynamic variables.
StatusCode fillDebugInfo(const TruncationInfoMap &truncationInfoMap, xAOD::TrigCompositeContainer &debugInfoCont, HLT::HLTResultMT &resultToFill, SGImplSvc *evtStore) const
Parse the truncation debug information, fill monitoring histograms, fill and record the debug info co...
static std::string version(const std::string &name)
Obtain version from the actual type name.
TriggerEDMSerialiserTool(const std::string &type, const std::string &name, const IInterface *parent)
StatusCode fillPayload(const void *data, size_t sz, std::vector< uint32_t > &buffer) const
Copy bytes from the memory into the buffer converting from char[] to uint32_t[] This function is cand...
Gaudi::Property< std::vector< std::string > > m_collectionsToSerialize
virtual StatusCode fill(HLT::HLTResultMT &resultToFill, const EventContext &ctx) const override
StatusCode serialiseContainer(void *data, const Address &address, std::vector< uint32_t > &buffer) const
Place inside the buffer the serialised container (can be either TP, xAOD) involves simple invocation ...
StatusCode serialise(const Address &address, std::vector< uint32_t > &buffer, SGImplSvc *evtStore) const
Retrieve data from event store, serialise and fill the buffer using one of the specific serialise met...
std::unordered_map< uint16_t, std::vector< TruncationInfo > > TruncationInfoMap
Typedef for collection of TruncationInfo objects for full event.
SG::WriteHandleKey< xAOD::TrigCompositeContainer > m_debugInfoWHKey
StoreGate key for the truncation debug info object.
ServiceHandle< IAthenaSerializeSvc > m_serializerSvc
Gaudi::Property< std::map< uint16_t, uint32_t > > m_truncationThresholds
StatusCode addCollectionToSerialise(const std::string &typeKeyAuxIDs, std::vector< Address > &addressVec) const
Parse entry from m_collectionsToSerialize and add it to m_toSerialise.
StatusCode serialisexAODAuxContainer(void *data, const Address &address, std::vector< uint32_t > &buffer, SGImplSvc *evtStore) const
Place inside the buffer serialised the xAOD Aux container involves selection and recording of dynamic...
ServiceHandle< IClassIDSvc > m_clidSvc
StatusCode serialiseDynAux(DataObject *dObject, const Address &address, std::vector< uint32_t > &buffer, size_t &nDynWritten) const
Add dynamic variables to the payload.
StatusCode tryAddData(HLT::HLTResultMT &hltResult, const uint16_t id, const std::vector< uint32_t > &data, Address::Truncation truncationMode, const std::unordered_map< uint16_t, std::vector< uint32_t > > &deferredInterfaceBuffer) const
Try appending serialised data to HLT result.
ToolHandle< GenericMonitoringTool > m_monTool
static std::set< uint16_t > activeModuleIDs(const HLT::HLTResultMT &result)
Build a list of module IDs to serialise based on the stream tags.
Gaudi::Property< float > m_fullResultTruncationFrac
virtual StatusCode initialize() override
Common base class for the auxiliary containers.
Class helping in dealing with dynamic branch selection.
virtual SG::auxid_set_t getSelectedAuxIDs(const SG::auxid_set_t &fullset) const
Return which variables were selected to be written out.
Helper to copy an aux store while applying thinning.
const ExtendedEventContext & getExtendedEventContext(const EventContext &ctx)
Retrieve an extended context from a context object.
std::vector< std::string > tokenize(std::string_view the_str, std::string_view delimiters)
Splits the string into smaller substrings.
void copyAuxStoreThinned(const SG::IConstAuxStore &orig, SG::IAuxStore &copy, const SG::ThinningInfo *info)
Helper to copy an aux store while applying thinning.
bool fromStorable(DataObject *pDObj, T *&pTrans, bool quiet=false, IRegisterTransient *irt=0, bool isConst=true)
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
size_t auxid_t
Identifier for a particular aux data item.
Definition AuxTypes.h:27
const Decision * getTerminusNode(SG::ReadHandle< DecisionContainer > &container)
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
TrigCompositeContainer_v1 TrigCompositeContainer
Declare the latest version of the container.
TrigComposite_v1 TrigComposite
Declare the latest version of the class.
setWord1 uint16_t
Internal structure to keep configuration organised conveniently.
xAOD::AuxSelection sel
xAOD dynamic variables selection, relevant only for xAODAux category
Internal structure to keep information for truncation debugging.
MsgStream & msg
Definition testRead.cxx:32