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