ATLAS Offline Software
Loading...
Searching...
No Matches
TriggerEDMSerialiserTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include <cstring>
6#include <boost/core/demangle.hpp>
7#include <boost/algorithm/string.hpp>
8#include "Gaudi/Interfaces/IOptionsSvc.h"
9#include "GaudiKernel/IToolSvc.h"
10#include "GaudiKernel/System.h"
16#include "AthContainers/debug.h"
21
23#include "TriggerEDMCLIDs.h"
25#include <numeric>
26
27namespace {
28 // Special module ID used internally to store total result size limit in the truncation threshold map
29 constexpr uint16_t fullResultTruncationID = std::numeric_limits<uint16_t>::max();
30}
31
33 const std::string& name,
34 const IInterface* parent )
35 : base_class( type, name, parent ) {}
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
104 std::string transientType;
105 std::string persistentType;
107
108 if ( configuredType.find('_') == std::string::npos ) {
109 transientType = configuredType;
110 } else {
111 transientType = configuredType.substr( 0, configuredType.find('_') );
112 }
113 CLID clid{0};
114 if ( m_clidSvc->getIDOfTypeName(transientType, clid).isFailure() ) {
115 ATH_MSG_ERROR( "Can not find CLID for " << transientType << " that is needed for serialisation " << key );
116 return StatusCode::FAILURE;
117 }
118 ATH_MSG_VERBOSE("Decoded transient type: " << transientType << " with the CLID " << clid );
119 if ( transientType == configuredType ) {
120 std::string realTypeName;
121 if( m_clidSvc->getTypeInfoNameOfID( clid, realTypeName ).isFailure() ) {
122 ATH_MSG_ERROR( "Can not find real type name for " << transientType << " that is needed for serialisation " << key );
123 return StatusCode::FAILURE;
124 }
125 persistentType = transientType + version( realTypeName );
126 ATH_MSG_VERBOSE(transientType << " = "<< configuredType << " thus obtained real type name from clid svc " << realTypeName << " forming persistent type name "<< persistentType );
127 } else {
128 persistentType = configuredType;
129 }
130
131 ATH_MSG_DEBUG( "Persistent type: " << persistentType );
132
133 RootType classDesc = RootType::ByNameNoQuiet( persistentType );
134 if ( ! classDesc.IsComplete() ) {
135 ATH_MSG_ERROR( "The type " << persistentType << " is not known to ROOT serialiser" );
136 return StatusCode::FAILURE;
137 }
138
139 // Set truncation mode
140 if ( def.size() > 2 && def[2].find("allowTruncation") != std::string::npos ) {
141 ATH_MSG_DEBUG("Truncation allowed for " << configuredType << "#" << key);
142 truncationMode = Address::Truncation::Allowed;
143 }
144
145 std::vector<uint16_t> moduleIdVec = CxxUtils::tokenize<uint16_t, char>(def[1], ',');
146 std::sort(moduleIdVec.begin(), moduleIdVec.end());
147
148 if (moduleIdVec.empty()) {
149 ATH_MSG_ERROR( "No HLT result module IDs given for " << typeKeyAux );
150 return StatusCode::FAILURE;
151 }
152
153 ATH_MSG_DEBUG( "Transient type " << transientType << " persistent type " << persistentType << " will be written to " << moduleIdVec.size() << " result ROBFragments with IDs: "
154 << moduleIdVec << "" );
155
156 if ( persistentType.rfind("xAOD", 0) != std::string::npos ) { // xAOD - either interface of Aux
158 if ( typeKeyAux.find('.') != std::string::npos ) { // Aux, possibly with selection of variables
159 ATH_MSG_DEBUG( "with aux content: " );
160 const std::string allVars = std::string(typeKeyAux.substr( typeKeyAux.find('.')+1 ));
161 if (!allVars.empty()) {
162 std::set<std::string> variableNames;
163 boost::split( variableNames, allVars, [](const char c){ return c == '.'; } );
164 if (msgLvl(MSG::DEBUG)) {
165 for ( const auto& el: variableNames ) {
166 ATH_MSG_DEBUG( " \"" << el << "\"" );
167 }
168 }
169 sel.selectAux( variableNames );
170 }
171 addressVec.push_back( {transientType, persistentType, clid, std::string(key), moduleIdVec, Address::Category::xAODAux, truncationMode, sel} );
172 } else {
173 addressVec.push_back( {transientType, persistentType, clid, std::string(key), moduleIdVec, Address::Category::xAODInterface, truncationMode} );
174 }
175 } else { // an old T/P type
176 addressVec.push_back( {transientType, persistentType, clid, std::string(key), 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( "" );
210 ATH_MSG_DEBUG( "About to start streaming aux data of " << address.key );
211 DataBucketBase* dObjAux = dynamic_cast<DataBucketBase*>(dObj);
212 ATH_CHECK( dObjAux != nullptr );
213
214 const SG::IAuxStoreIO* auxStoreIO = dObjAux->template cast<SG::IAuxStoreIO> (nullptr, true);
215 if ( auxStoreIO == nullptr ) {
216 ATH_MSG_DEBUG( "Can't obtain AuxContainerBase of " << address.key << " no dynamic variables presumably" );
217 return StatusCode::SUCCESS;
218 }
219
220 const SG::auxid_set_t& selected = address.sel.getSelectedAuxIDs( auxStoreIO->getDynamicAuxIDs() );
221
222 if ( selected.empty() ) {
223 ATH_MSG_VERBOSE( "Empty set of dynamic variables to store, do nothing" );
224 return StatusCode::SUCCESS;
225 }
226 ATH_MSG_DEBUG("Ready for serialisation of " << selected.size() << " dynamic variables");
227
228 for (SG::auxid_t auxVarID : selected ) {
229
230 const std::string decorationName = SG::AuxTypeRegistry::instance().getName(auxVarID);
231 const std::type_info* tinfo = auxStoreIO->getIOType (auxVarID);
232 const std::string typeName = SG::AuxTypeRegistry::instance().getVecTypeName(auxVarID);
233 const std::string fullTypeName = System::typeinfoName( *tinfo );
234
235 ATH_CHECK( tinfo != nullptr );
236 TClass* cls = TClass::GetClass (*tinfo);
237 ATH_CHECK( cls != nullptr );
238 ATH_MSG_DEBUG( "" );
239 ATH_MSG_DEBUG( "Streaming '" << decorationName << "' of type '" << typeName
240 << "' fulltype '" << fullTypeName << "' aux ID '" << auxVarID << "' class '" << cls->GetName() );
241
242 CLID clid{0};
243 if ( m_clidSvc->getIDOfTypeName(typeName, clid).isFailure() ) { // First try
244 if ( m_clidSvc->getIDOfTypeInfoName(fullTypeName, clid).isFailure() ) { // Second try
245 ATH_MSG_ERROR("Unable to obtain CLID for either typeName:" << typeName << " or fullTypeName:" << fullTypeName);
246 ATH_MSG_ERROR("Please check if this is something which should obtain a CLID via TriggerEDMCLIDs.h");
247 return StatusCode::FAILURE;
248 }
249 }
250 ATH_MSG_DEBUG( "CLID " << clid );
251
252 RootType classDesc = RootType::ByNameNoQuiet( cls->GetName() );
253
254 const void* rawptr = auxStoreIO->getIOData( auxVarID );
255 ATH_CHECK( rawptr != nullptr );
256
257 size_t sz=0;
258 void* mem = m_serializerSvc->serialize( rawptr, classDesc, sz );
259
260 if ( mem == nullptr or sz == 0 ) {
261 ATH_MSG_ERROR( "Serialisation of " << address.persType <<"#" << address.key << "."<< decorationName << " unsuccessful" );
262 return StatusCode::FAILURE;
263 }
264 ATH_MSG_DEBUG( "Serialised " << address.persType <<"#" << address.key << "."<< decorationName << " memory size " << sz );
265
266 std::vector<uint32_t> fragment;
267
268 Address auxAddress { typeName, cls->GetName(), clid, decorationName, address.moduleIdVec, Address::Category::xAODDecoration };
269
270 ATH_CHECK( makeHeader( auxAddress, fragment ) );
271 ATH_CHECK( fillPayload( mem, sz, fragment ) );
272 fragment[0] = fragment.size();
273
274 delete [] static_cast<const char*>( mem );
275
276 buffer.insert( buffer.end(), fragment.begin(), fragment.end() );
277 ++nDynWritten;
278 }
279 return StatusCode::SUCCESS;
280}
281
282
283StatusCode TriggerEDMSerialiserTool::serialiseContainer( void* data, const Address& address, std::vector<uint32_t>& buffer ) const {
284
285 RootType classDesc = RootType::ByNameNoQuiet( address.persType );
286 size_t sz=0;
287 void* mem = m_serializerSvc->serialize( data, classDesc, sz );
288
289 ATH_MSG_DEBUG( "Streamed to buffer at address " << mem << " of " << sz << " bytes" );
290
291 if ( mem == nullptr or sz == 0 ) {
292 ATH_MSG_ERROR( "Serialisation of " << address.persType << " " << address.key << " unsuccessful" );
293 return StatusCode::FAILURE;
294 }
295
296 // prepare fragment
297 std::vector<uint32_t> fragment;
298 ATH_CHECK( makeHeader( address, fragment ) );
299 ATH_CHECK( fillPayload( mem, sz, fragment ) );
300 if ( mem != nullptr ) delete [] static_cast<const char*>( mem );
301
302
303 ATH_MSG_DEBUG( address.transType << "#" << address.key << " Fragment size: " << fragment.size()*sizeof(uint32_t) << " bytes");
304 fragment[0] = fragment.size();
305 buffer.insert( buffer.end(), fragment.begin(), fragment.end() );
306
307 return StatusCode::SUCCESS;
308}
309
311 void* data,
312 const Address& address,
313 std::vector<uint32_t>& buffer,
314 SGImplSvc* evtStore) const
315{
316 ATH_MSG_DEBUG("xAOD Aux Container");
317
318 void* copy = data;
319 RootType classDesc = RootType::ByNameNoQuiet( address.persType );
320 //Get the Base Info given clid.
321 const SG::BaseInfoBase* bib = SG::BaseInfoBase::find (address.clid);
322 //cast data to xAOD::AuxContainerBase
323 void* data_interface = bib->cast (data, ClassID_traits<xAOD::AuxContainerBase>::ID());
324 if (data_interface != nullptr) {
325 const xAOD::AuxContainerBase* store = reinterpret_cast<const xAOD::AuxContainerBase*> (data_interface);
326 copy = classDesc.Construct();
327 //cast copy to xAOD::AuxContainerBase
328 void* copy_interface = bib->cast (copy, ClassID_traits<xAOD::AuxContainerBase>::ID());
329 xAOD::AuxContainerBase* copy_store = reinterpret_cast<xAOD::AuxContainerBase*> (copy_interface);
331 *copy_store,
332 nullptr);
333 }
334
335 ATH_CHECK( serialiseContainer( copy, address, buffer ) );
336
337 if (copy != data) {
338 classDesc.Destruct (copy);
339 }
340
341 size_t baseSize = buffer.size();
342 if ( not m_saveDynamic )
343 return StatusCode::SUCCESS;
344
345 DataObject* dObj = evtStore->accessData( address.clid, address.key );
346 ATH_CHECK( dObj != nullptr );
347 size_t nDynWritten = 0;
348 ATH_CHECK( serialiseDynAux( dObj, address, buffer, nDynWritten ) );
349 if ( nDynWritten > 0 ) {
350 ATH_MSG_DEBUG( " Fragment size including " << (buffer.size() - baseSize)*sizeof(uint32_t) << " bytes from "
351 << nDynWritten << "x DynAux : " << buffer.size()*sizeof(uint32_t) );
352 }
353 return StatusCode::SUCCESS;
354}
355
356StatusCode TriggerEDMSerialiserTool::serialiseTPContainer( void* data, const Address& address, std::vector<uint32_t>& buffer ) const {
357
358 ATH_MSG_DEBUG("TP Container, converting from: " << address.transType << " to " << address.persType );
359 std::string converterPersistentType;
360 void * persistent = m_tpTool->convertTP( address.transType, data, converterPersistentType );
361 ATH_CHECK( persistent != nullptr );
362 ATH_CHECK ( converterPersistentType == address.persType );
363 ATH_CHECK( serialiseContainer( persistent, address, buffer ) );
364
365 RootType classDesc = RootType::ByNameNoQuiet( address.persType );
366 classDesc.Destruct( persistent );
367
368 return StatusCode::SUCCESS;
369}
370
371StatusCode TriggerEDMSerialiserTool::serialise( const Address& address, std::vector<uint32_t>& buffer, SGImplSvc* evtStore ) const {
372 DataObject* dObj = evtStore->accessData( address.clid, address.key );
373 if ( dObj == nullptr ) {
374 ATH_MSG_DEBUG("Data Object with the CLID " << address.clid << " and the key " << address.key << " is missing");
375 return StatusCode::SUCCESS;
376 }
377
378 void* rawptr = SG::fromStorable( dObj, address.clid, nullptr, msgLvl(MSG::DEBUG) );
379 if ( rawptr == nullptr ) {
380 ATH_MSG_DEBUG( "Data Object with key " << address.key << " can not be converted to void* for streaming" );
381 return StatusCode::SUCCESS;
382 }
383 ATH_MSG_DEBUG("Obtained raw pointer " << rawptr );
384
386 return serialiseContainer( rawptr, address, buffer );
387 }
388 if ( address.category == Address::Category::xAODAux ) {
389 return serialisexAODAuxContainer( rawptr, address, buffer, evtStore );
390 }
391 if ( address.category == Address::Category::OldTP ) {
392 return serialiseTPContainer( rawptr, address, buffer );
393 }
394 ATH_MSG_ERROR("Unknown Address category - neither of xAODInterface, xAODAux, OldTP");
395 return StatusCode::FAILURE;
396}
397
398StatusCode TriggerEDMSerialiserTool::fill( HLT::HLTResultMT& resultToFill, const EventContext& ctx ) const {
399
400 // Leave this check until there is a justified case for appending data to an existing result
401 if (not resultToFill.getSerialisedData().empty()) {
402 ATH_MSG_ERROR("Trying to fill a result which is not empty! Likely misconfiguration, returning a FAILURE");
403 return StatusCode::FAILURE;
404 }
405
406 SGImplSvc* evtStore = dynamic_cast<SGImplSvc*>(Atlas::getExtendedEventContext(ctx).proxy());
407 ATH_CHECK( evtStore != nullptr );
408
409 // Map storing information to be written out in case of truncation for each module
410 TruncationInfoMap truncationInfoMap;
411
412 // Record debug info container to be filled in case of truncation
413 auto debugInfo = SG::makeHandle(m_debugInfoWHKey, ctx);
414 auto debugInfoData = std::make_unique<xAOD::TrigCompositeContainer>();
415 auto debugInfoAux = std::make_unique<xAOD::TrigCompositeAuxContainer>();
416 debugInfoData->setStore(debugInfoAux.get());
417 ATH_CHECK(debugInfo.record(std::move(debugInfoData), std::move(debugInfoAux)));
418
419 // Find a list of active moduleIDs in this event to skip inactive ones
420 std::set<uint16_t> activeModules = activeModuleIDs(resultToFill);
421 if (activeModules.empty()) {
422 ATH_MSG_DEBUG("No active module IDs in this event. This is normal for events accepted "
423 << "only to calibration streams. Skip all EDM serialisation.");
424 return StatusCode::SUCCESS;
425 }
426
427 // Create buffer for serialised data
428 std::vector<uint32_t> buffer;
429 buffer.reserve(1000);
430
431 std::unordered_map<uint16_t, std::vector<uint32_t>> deferredInterfaceBuffer;
432 for ( const Address& address: m_toSerialise ) {
433 // Check if we need to serialise this object for this event
434 std::vector<uint16_t> addressActiveModuleIds;
435 std::set_intersection(address.moduleIdVec.begin(), address.moduleIdVec.end(),
436 activeModules.begin(), activeModules.end(),
437 std::back_inserter(addressActiveModuleIds));
438 if (addressActiveModuleIds.empty()) {
439 ATH_MSG_DEBUG("Streaming of " << address.persTypeName() << " is skipped "
440 << "because its module IDs are not active in this event");
441 continue;
442 }
443
444 buffer.clear();
445 ATH_MSG_DEBUG( "Streaming " << address.persTypeName() );
446 ATH_CHECK( serialise(address, buffer, evtStore) );
447 if (buffer.empty()) {
448 ATH_MSG_DEBUG("Streaming of " << address.persTypeName() << " is skipped");
449 continue;
450 }
451
452 const size_t thisFragmentSize = buffer.size()*sizeof(uint32_t);
453 ATH_MSG_DEBUG( "Serialised size of " << address.persTypeName() << " is " << thisFragmentSize << " bytes" );
454 for (const uint16_t id : addressActiveModuleIds) {
455 // If result not yet truncated, try adding the serialised data
456 if (resultToFill.getTruncatedModuleIds().count(id)==0) {
457 // for truncation allowed collections, save the interface for a deferred addition
458 if (address.truncationMode==Address::Truncation::Allowed &&
459 address.category == Address::Category::xAODInterface){
460 deferredInterfaceBuffer[id]=buffer;
461 continue;
462 }
463 else {
464 ATH_CHECK(tryAddData(resultToFill, id, buffer, address.truncationMode, deferredInterfaceBuffer));
465 // clean up the deferred interface buffer, if used
466 deferredInterfaceBuffer.erase(id);
467 }
468 }
469 // Check for truncation after adding data
470 if (resultToFill.getTruncatedModuleIds().count(id)==0) {
471 ATH_MSG_DEBUG("Module " << id << " payload after inserting " << address.persTypeName() << " has "
472 << resultToFill.getSerialisedData().at(id).size()*sizeof(uint32_t) << " bytes");
473 truncationInfoMap[id].push_back({&address, thisFragmentSize, true});
474 }
475 else {
476 ATH_MSG_WARNING("HLTResult with module ID " << id <<
477 " truncated - could not add " << address.persTypeName() <<
478 (address.truncationMode==Address::Truncation::Allowed ? " (truncation allowed)" : ""));
479 truncationInfoMap[id].push_back({&address, thisFragmentSize, false});
480 }
481 }
482 }
483
484 // Handle truncation
485 ATH_CHECK(fillDebugInfo(truncationInfoMap, *debugInfo, resultToFill, evtStore));
486
487 return StatusCode::SUCCESS;
488}
489
491 const uint16_t id,
492 const std::vector<uint32_t>& data,
493 Address::Truncation truncationMode,
494 const std::unordered_map<uint16_t, std::vector<uint32_t>> & deferredInterfaceBuffer) const {
495 if (m_truncationThresholds.value().count(id)==0) {
496 ATH_MSG_ERROR("Module ID " << id << " missing from TruncationThresholds map. Cannot determine if result needs truncation");
497 return StatusCode::FAILURE;
498 }
499
500 // Size in this module
501 const uint32_t currentSizeBytes = hltResult.getSerialisedData().count(id)==0
502 ? 0 : hltResult.getSerialisedData().at(id).size()*sizeof(uint32_t);
503 // Total size
504 size_t currentTotalSizeWords = 0;
505 for (const auto& [id, data] : hltResult.getSerialisedData()) currentTotalSizeWords += data.size();
506 const uint32_t currentTotalSizeBytes = currentTotalSizeWords*sizeof(uint32_t);
507 // Size to be added
508 const uint32_t extraSizeBytes = data.size()*sizeof(uint32_t);
509
510 bool severeTruncation = truncationMode==Address::Truncation::Error;
511 if (currentTotalSizeBytes+extraSizeBytes > m_truncationThresholds.value().at(fullResultTruncationID)) {
512 // The data doesn't fit, flag the full result as truncated
513 ATH_MSG_DEBUG("Skipping adding data to result with module ID " << id << " because of full-result truncation");
514 hltResult.addTruncatedModuleId(fullResultTruncationID, severeTruncation);
515 hltResult.addTruncatedModuleId(id, severeTruncation);
516 }
517 else if (currentSizeBytes+extraSizeBytes > m_truncationThresholds.value().at(id)) {
518 // The data doesn't fit, flag this module's result as truncated
519 ATH_MSG_DEBUG("Skipping adding data to truncated result with module ID " << id);
520 hltResult.addTruncatedModuleId(id, severeTruncation);
521 }
522 else {
523 // for truncation allowed collections, add first the interface, only if the Aux is can be stored
524 if (truncationMode==Address::Truncation::Allowed){
525 hltResult.addSerialisedData(id, deferredInterfaceBuffer.at(id));
526 }
527 // The data fits, so add it to the result
528 ATH_MSG_DEBUG("Adding data to result with module ID " << id);
529 hltResult.addSerialisedData(id, data);
530 }
531 return StatusCode::SUCCESS;
532}
533
535 xAOD::TrigCompositeContainer& debugInfoCont,
536 HLT::HLTResultMT& resultToFill,
537 SGImplSvc* evtStore) const {
538 // If full result truncation happened, flag all results as truncated to produce debug info for all
539 if (resultToFill.getTruncatedModuleIds().count(fullResultTruncationID)>0) {
540 ATH_MSG_ERROR("HLT result truncation on total size! Limit of "
541 << m_truncationThresholds.value().at(fullResultTruncationID)/1024./1024.
542 << " MB exceeded. Flagging all module IDs as truncated.");
543 for (const auto& [id, data] : resultToFill.getSerialisedData()) {
544 resultToFill.addTruncatedModuleId(id);
545 }
546 }
547 // Loop over truncation info and fill histograms and debug info objects
548 for (const auto& [id, truncationInfoVec] : truncationInfoMap) {
549 if (resultToFill.getTruncatedModuleIds().count(id)>0) {
550 // Create and fill a debug info object
551 xAOD::TrigComposite* debugInfoThisModule = new xAOD::TrigComposite;
552 debugInfoCont.push_back(debugInfoThisModule); // the container in event store takes ownership of debugInfoThisModule
553 xAOD::TrigComposite::Accessor<uint16_t> moduleId("moduleId");
554 xAOD::TrigComposite::Accessor<uint32_t> totalSize("totalSize");
555 xAOD::TrigComposite::Accessor<std::vector<std::string>> typeNameVec("typeName");
556 xAOD::TrigComposite::Accessor<std::vector<uint32_t>> sizeVec("size");
557 xAOD::TrigComposite::Accessor<std::vector<char>> isRecordedVec("isRecorded");
558 std::pair<std::string, size_t> largestRecorded{"None", 0};
559 std::pair<std::string, size_t> largestDropped{"None", 0};
560 std::pair<std::string, size_t> firstDropped{"None", 0};
561 moduleId(*debugInfoThisModule) = id;
562 uint32_t sizeSum = 0;
563 bool severeTruncation = false;
564 bool truncated = false;
565 for (const TruncationInfo& truncationInfo : truncationInfoVec) {
566 // Store typeName and size information
567 sizeSum += truncationInfo.size;
568 typeNameVec(*debugInfoThisModule).push_back(truncationInfo.addrPtr->persTypeName());
569 sizeVec(*debugInfoThisModule).push_back(truncationInfo.size);
570 isRecordedVec(*debugInfoThisModule).push_back(static_cast<char>(truncationInfo.recorded));
571 if (truncationInfo.recorded && truncationInfo.size > largestRecorded.second) {
572 largestRecorded = {truncationInfo.addrPtr->persTypeName(), truncationInfo.size};
573 }
574 if (!truncationInfo.recorded && truncationInfo.size > largestDropped.second) {
575 largestDropped = {truncationInfo.addrPtr->persTypeName(), truncationInfo.size};
576 }
577 if (!truncationInfo.recorded && !truncated) {
578 firstDropped = {truncationInfo.addrPtr->persTypeName(), truncationInfo.size};
579 truncated = true;
580 }
581 // Decide if this was a severe truncation (event goes to debug stream)
582 if (!truncationInfo.recorded) {
583 severeTruncation |= (truncationInfo.addrPtr->truncationMode==Address::Truncation::Error);
584 }
585 }
586 totalSize(*debugInfoThisModule) = sizeSum;
587 msg(severeTruncation ? MSG::ERROR : MSG::WARNING)
588 << "HLT result truncation" << (severeTruncation ? "." : " in low priority collections.")
589 << " Module ID: " << id << ", limit: "
590 << m_truncationThresholds.value().at(id)/1024. << " kB, total size: "
591 << sizeSum/1024. << " kB, largest recorded collection: " << largestRecorded.first
592 << " (" << largestRecorded.second/1024. << " kB), largest dropped collection: "
593 << largestDropped.first << " (" << largestDropped.second/1024. << " kB), "
594 << " first dropped collection: " <<firstDropped.first << " (" << firstDropped.second/1024. << " kB)"
595 << endmsg;
596 // Give more information on the chains which accepted this event
597 using namespace TrigCompositeUtils;
598 SG::ReadHandle<DecisionContainer> navigation(m_debugNavigationSummaryRHKey); // Implicit ctx lookup - OK, rare code path
599 const Decision* terminus = getTerminusNode(navigation);
600 if (terminus) {
601 std::stringstream ss;
602 ss << "Passing chains in this event: ";
603 for (const DecisionID chainID : decisionIDs(terminus)) {
604 ss << HLT::Identifier(chainID).name() << ", ";
605 addDecisionID(chainID, debugInfoThisModule); // Save this list also into the output, it is then accessible offline too
606 }
607 ATH_MSG_WARNING(ss.str());
608 }
609 // Monitoring
610 const std::string prefix = severeTruncation ? "" : "Allowed";
611 auto monModuleId = Monitored::Scalar<int>(prefix+"Truncation_ModuleId", id);
612 auto monTotalSize = Monitored::Scalar<float>(prefix+"Truncation_TotalSize", sizeSum/1024.);
613 auto monLargestName = Monitored::Scalar<std::string>(
614 prefix+"Truncation_LargestName",
615 largestRecorded.second > largestDropped.second ? largestRecorded.first : largestDropped.first);
616 auto monLargestSize = Monitored::Scalar<float>(
617 prefix+"Truncation_LargestSize",
618 largestRecorded.second > largestDropped.second ? largestRecorded.second/1024. : largestDropped.second/1024.);
619 auto mon = Monitored::Group(m_monTool, monModuleId, monTotalSize, monLargestName, monLargestSize);
620 }
621 }
622 // Serialise and write the debug info only in case of truncation
623 if (!debugInfoCont.empty()) {
624 std::vector<Address> debugInfoAddressVec;
625 const std::string debugInfoID = std::string("xAOD::TrigCompositeContainer#")+m_debugInfoWHKey.key()+";0";
626 const std::string debugInfoAuxID = std::string("xAOD::TrigCompositeAuxContainer#")+m_debugInfoWHKey.key()+"Aux.;0";
627 ATH_CHECK(addCollectionToSerialise(debugInfoID, debugInfoAddressVec));
628 ATH_CHECK(addCollectionToSerialise(debugInfoAuxID, debugInfoAddressVec));
629 std::vector<uint32_t> buffer;
630 for (const Address& address : debugInfoAddressVec) {
631 buffer.clear();
632 ATH_CHECK( serialise(address, buffer, evtStore) );
633 resultToFill.addSerialisedData(0, buffer); // 0 is the main result ID
634 // It would be better to avoid hard-coding main result ID but it should not be configurable either
635 }
636 }
637 return StatusCode::SUCCESS;
638}
639
640std::string TriggerEDMSerialiserTool::version( const std::string& name ) {
641 if ( name.find("DataVector") != std::string::npos ) {
642 size_t start = name.find('_');
643 return name.substr( start, name.find('>') - start );
644 }
645 if ( name.find('_') != std::string::npos ) {
646 return name.substr( name.find('_') );
647 }
648 return "";
649}
650
652 std::set<uint16_t> activeIDs;
653 for (const eformat::helper::StreamTag& st : result.getStreamTags()) {
654 if (st.robs.empty() && st.dets.empty()) { // Full Event Building stream
655 activeIDs.insert(0); // 0 is the main result ID
656 continue;
657 }
658 for (const uint32_t robid : st.robs) {
659 eformat::helper::SourceIdentifier sid(robid);
660 if (sid.subdetector_id() != eformat::SubDetector::TDAQ_HLT) {
661 continue;
662 }
663 activeIDs.insert(sid.module_id());
664 }
665 }
666 return activeIDs;
667}
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(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.
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
Interface providing I/O for a generic auxiliary store.
static Double_t sz
static Double_t ss
unsigned int DecisionID
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
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
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