ATLAS Offline Software
trigbs_dumpHLTContentInBS_run3.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 #
3 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
4 #
5 
6 '''
7 Dump content of the HLT result and HLT related details from the event header
8 '''
9 
10 import argparse
11 import eformat
12 from TrigByteStreamTools import hltResultMT
13 
14 from AthenaCommon.Logging import logging
15 log = logging.getLogger('dumpHLTContentInBS')
16 
17 
18 def get_parser():
19  parser = argparse.ArgumentParser(usage='%(prog)s [options] files',
20  description=__doc__)
21  parser.add_argument('files',
22  metavar='FILE', nargs='+',
23  help='RAW file to inspect')
24  parser.add_argument('-n', '--events',
25  metavar='N', action='store', type=int,
26  help='Process N events')
27  parser.add_argument('-s', '--skip',
28  metavar='N', action='store', type=int,
29  help='Skip N events')
30  parser.add_argument('--ctp', nargs="?", metavar="MODULE_ID", default=False, const=1,
31  help="CTP ROB details of ROB with MODULE_ID [default=%(const)s]")
32  parser.add_argument('--l1',
33  action='store_true', default=False,
34  help='L1 trigger bits (from event header)')
35  parser.add_argument('--ef', '--hlt',
36  action='store_true', default=False,
37  help='EF/HLT trigger bits (from event header)')
38  parser.add_argument('--stag',
39  action='store_true', default=False,
40  help='stream tag')
41  parser.add_argument('--efres', '--hltres',
42  action='store_true', default=False,
43  help='details of EF/HLT ROB payload')
44  parser.add_argument('--sizes',
45  action='store_true', default=False,
46  help='dump info about EDM sizes per result; implies --hltres')
47  parser.add_argument('--deserialize',
48  action='store_true', default=False,
49  help='deserialize EDM collections (slow!); implies --hltres')
50  parser.add_argument('--sizeSummary',
51  action='store_true', default=False,
52  help='dump summary info about EDM sizes at the end')
53  parser.add_argument('--confKeys',
54  action='store_true', default=False,
55  help='dump TrigConfKeys stored in the events; implies --hltres')
56  parser.add_argument('--runtimeMetadata',
57  action='store_true', default=False,
58  help='dump HLT_RuntimeMetadata stored in the events; implies --hltres')
59  return parser
60 
61 
62 def decodeTriggerBits(words, num_sets, base=32):
63  assert len(words) % num_sets == 0
64  n_words_per_set = len(words) // num_sets
65  result = []
66  for iset in range(num_sets):
67  words_in_set = words[iset*n_words_per_set:(iset+1)*n_words_per_set]
68  bit_indices = []
69  for iw in range(len(words_in_set)):
70  bit_indices.extend([base*iw+i for i in range(base) if words_in_set[iw] & (1 << i)])
71  result.append(bit_indices)
72  return result
73 
74 
75 def header_info(event):
76  '''Return a string with basic information about the event from the header'''
77 
78  info_str = 'RunNumber: {:6d}, '.format(event.run_no())
79  info_str += 'LB: {:4d}, '.format(event.lumi_block())
80  info_str += 'Global_ID: {:10d}, '.format(event.global_id())
81  info_str += 'LVL1_ID: {:10d}, '.format(event.lvl1_id())
82  info_str += 'BC_ID: {:4d}, '.format(event.bc_id())
83  info_str += 'TT: 0x{:2x}, '.format(event.lvl1_trigger_type())
84  info_str += 'Status: ' + decode_status(event)
85  return info_str
86 
87 
88 def decode_status(fragment):
89  '''Return event/ROB fragment status and string representation'''
90 
91  if not fragment.status():
92  return 'None'
93 
94  info_str = '[' + ', '.join('0x%x' % s for s in fragment.status()) + ']'
95 
96  # First word:
97  status = eformat.helper.Status(fragment.status()[0])
98  info_str += ''.join(f' {item.name}' for code, item in eformat.helper.GenericStatus.values.items()
99  if status.generic() & code)
100 
101  # The specific bits of the first word are only relevant for the full event:
102  if isinstance(fragment, eformat.FullEventFragment):
103  info_str += ''.join(f' {item.name}' for code, item in eformat.helper.FullEventStatus.values.items()
104  if status.specific() & code)
105 
106  # HLT-specific event status:
107  if len(fragment.status())>1:
108  import cppyy
109  cppyy.gbl.HLT.OnlineErrorCode # trigger auto-loading via enum
110  info_str += ' '+ cppyy.gbl.HLT.OnlineErrorCodeToString(fragment.status()[1]).data()
111 
112  return info_str
113 
114 
115 def ctp_rob(event, module_id=1):
116  '''Return a string with information from the CTP ROB'''
117 
118  ctp_robs = [rob for rob in event \
119  if rob.source_id().subdetector_id() == eformat.helper.SubDetector.TDAQ_CTP \
120  and rob.source_id().module_id()==module_id]
121 
122  if len(ctp_robs)==0:
123  log.warning('No CTP ROB found')
124  return ''
125 
126  assert len(ctp_robs)==1
127  rob = ctp_robs[0]
128 
129  from TrigByteStreamTools import CTPfragment
130  x = CTPfragment.getExtraPayloadObject(rob)
131  info_str = (f'ROB 0x{rob.source_id().code():x}, '
132  f'L1ID {event.lvl1_id():10d}, '
133  f'LB {event.lumi_block():4d}, '
134  f'Version {CTPfragment.ctpFormatVersion(rob)}, '
135  f'Bunch {CTPfragment.lvl1AcceptBunch(rob)}, '
136  f'HLT counter: {CTPfragment.hltCounter(rob):3d}, '
137  f'Payload #{CTPfragment.numberHltExtraPayloadWords(rob)} '
138  f'{CTPfragment.hltExtraPayloadWords(rob)} '
139  f'L1PSK {x.getL1PSK()} BGK {x.getBGK()}')
140  folderUpdates = CTPfragment.getFolderUpdates(x)
141  if len(folderUpdates)>0:
142  info_str += ' COOLUPD '+''.join([f'[{f.second.folderIndex}, {f.second.lumiBlock}]' for f in folderUpdates])
143  return info_str
144 
145 
146 def lvl1_bits(event):
147  '''Return a string with information about LVL1 bits (IDs of items passed at TBP, TAP, TAV)'''
148 
149  info = event.lvl1_trigger_info()
150  lvl1_bits = decodeTriggerBits(info, 3) # TBP, TAP, TAV
151  info_str = 'L1 CTP IDs - TBP: {:s}\n'.format(str(lvl1_bits[0]))
152  info_str += 'L1 CTP IDs - TAP: {:s}\n'.format(str(lvl1_bits[1]))
153  info_str += 'L1 CTP IDs - TAV: {:s}'.format(str(lvl1_bits[2]))
154  return info_str
155 
156 
157 def hlt_bits(event, version=(1,1)):
158  '''Return a string with information about passed chain IDs at HLT'''
159 
160  # Version 1.0 has {passed, prescaled, rerun}, 1.1 and later only {passed, prescaled}
161  num_sets = 3 if version[0] < 1 or version==(1,0) else 2
162 
163  info = event.event_filter_info()
164  hlt_bits = decodeTriggerBits(info, num_sets)
165  info_str = 'HLT passed chain IDs: {:s}'.format(str(hlt_bits[0]))
166  info_str += '\nHLT prescaled chain IDs: {:s}'.format(str(hlt_bits[1]))
167  if num_sets==3:
168  info_str += '\nHLT rerun chain IDs: {:s}'.format(str(hlt_bits[2]))
169  return info_str
170 
171 
172 def stream_tags(event):
173  def hex_list(nums):
174  return '[' + ', '.join([hex(num) for num in nums]) + ']'
175  info_str = 'Stream Tags:'
176  for st in event.stream_tag():
177  info_str += '\n-- {}_{}'.format(st.type, st.name)
178  robs = list(st.robs)
179  dets = list(st.dets)
180  if len(robs) == 0 and len(dets) == 0:
181  info_str += ' - Full Event Building'
182  else:
183  info_str += ' - Partial Event Building, robs={}, dets={}'.format(hex_list(robs), hex_list(dets))
184  return info_str
185 
186 
188  version = rob.rod_version()
189  minor_version = version.minor_version()
190  minor_version_M = (minor_version & 0xff00) >> 8
191  minor_version_L = minor_version & 0xff
192  return (minor_version_M, minor_version_L)
193 
194 
196  for rob in event.children():
197  if rob.source_id().subdetector_id() == eformat.helper.SubDetector.TDAQ_HLT:
198  return hlt_rod_minor_version(rob)
199 
200 
201 def hlt_result(event, print_sizes=False, deserialize=False, conf_keys=False, runtime_metadata=False):
202  num_hlt_robs = 0
203  info_str = ""
204  for rob in event.children():
205  if rob.source_id().subdetector_id() != eformat.helper.SubDetector.TDAQ_HLT:
206  continue
207  num_hlt_robs += 1
208  version = hlt_rod_minor_version(rob)
209  info_str += '\n-- {:s} SourceID: {:s}, Version: {:s}, Size: {:d} bytes, Status: {:s}'.format(
210  rob.__class__.__name__,
211  rob.source_id().human(),
212  f'{version[0]:d}.{version[1]:d}',
213  rob.fragment_size_word()*4,
214  decode_status(rob)
215  )
216  if print_sizes or deserialize or conf_keys or runtime_metadata:
217  if version[0] < 1:
218  raise RuntimeError('Cannot decode data from before Run 3, HLT ROD minor version needs to be >= 1.0')
219  skip_payload = not conf_keys and not runtime_metadata and not deserialize
220  collections = hltResultMT.get_collections(rob, skip_payload=skip_payload)
221  if conf_keys:
222  conf_list = [c for c in collections if 'xAOD::TrigConfKeys_v' in c.name_persistent]
223  conf_available = False
224  for conf in conf_list:
225  conf_obj = conf.deserialise()
226  if not conf_obj:
227  continue
228  conf_available = True
229  info_str += '\n---- {:s}#{:s} SMK: {:d}, L1PSK: {:d}, HLTPSK: {:d}'.format(
230  conf.name_persistent, conf.name_key,
231  conf_obj.smk(), conf_obj.l1psk(), conf_obj.hltpsk())
232  if not conf_available:
233  info_str += '\n---- TrigConfKeys unavailable in this ROB'
234  if runtime_metadata:
235  decorations = ['hostname']
236  meta_list = [c for c in collections if any([f'RuntimeMetadataAux.{decor}' in c.name() for decor in decorations])]
237  meta_available = False
238  for meta in meta_list:
239  meta_obj = meta.deserialise()
240  if not meta_obj:
241  continue
242  meta_available = True
243  info_str += '\n---- RuntimeMetadata {:s}: {:s}'.format(
244  meta.name_key, meta_obj.at(0))
245  if not meta_available:
246  info_str += '\n---- RuntimeMetadata unavailable in this ROB'
247  if print_sizes or deserialize:
248  for coll in collections:
249  indent = 4 if not coll.is_xAOD_decoration() else 6
250  info_str += '\n{:s} {:s}'.format('-'*indent, str(coll))
251  if deserialize and (coll_obj := coll.deserialise()) is not None:
252  try:
253  length = coll_obj.size() # all collections should have this method
254  except Exception:
255  length = None
256  if length is not None:
257  info_str += f' ({length} element' + ('s)' if length!=1 else ')')
258  info_str += '\n{:s} {:s}'.format(' '*indent, str(coll_obj))
259 
260 
261  info_str = 'Found {:d} HLT ROBs'.format(num_hlt_robs) + info_str
262  return info_str
263 
264 
265 def size_summary(events):
266  data = {}
267  # Format of the data dictionary:
268  # {
269  # 0: {
270  # 'total': 123,
271  # 'collections': {
272  # 'collA': 22,
273  # 'collB': 35
274  # }
275  # }
276  # }
277  for event in events:
278  for rob in event.children():
279  if rob.source_id().subdetector_id() != eformat.helper.SubDetector.TDAQ_HLT:
280  continue
281  version = hlt_rod_minor_version(rob)
282  if version[0] < 1:
283  raise RuntimeError('Cannot decode data from before Run 3, HLT ROD minor version needs to be >= 1.0')
284  module = rob.source_id().module_id()
285  if module not in data.keys():
286  data[module] = {'total': 0}
287  data[module]['total'] += rob.fragment_size_word()*4
288  if 'collections' not in data[module].keys():
289  data[module]['collections'] = {}
290  for coll in hltResultMT.get_collections(rob, skip_payload=True):
291  coll_name = coll.name()
292  if coll_name in data[module]['collections'].keys():
293  data[module]['collections'][coll_name] += coll.size_bytes
294  else:
295  data[module]['collections'][coll_name] = coll.size_bytes
296  info_str = '='*20 + '\nSize summary:\n' + '='*20
297  for module in data.keys():
298  module_size = data[module]['total']
299  module_size_per_evt = module_size / float(len(events))
300  info_str += '\n-- TDAQ_HLT module {:d} total size {:d} bytes, {:.3f} bytes/event'.format(
301  module, module_size, module_size_per_evt)
302  sorted_colls = sorted(data[module]['collections'].items(),
303  key=lambda kv: kv[1],
304  reverse=True)
305  max_name_len = len(max(data[module]['collections'].keys(), key=len))
306  max_name_len = min(120, max_name_len) # Make a reasonable limit to avoid line breaks
307  for coll_name, coll_size in sorted_colls:
308  coll_size_per_evt = coll_size / float(len(events))
309  info_str += '\n---- {:{width}} {:12d} B {:12.3f} B/ev'.format(
310  coll_name, coll_size, coll_size_per_evt, width=max_name_len)
311  return info_str
312 
313 def dump_info(bsfile, args):
314  log.info('Opening %s', bsfile)
315  input = eformat.istream(bsfile)
316  offset = args.skip if args.skip else 0
317  max_events = min(args.events, len(input)) if args.events else len(input)
318  event_count = 0
319  events = []
320  version = None
321 
322  # Loop over events
323  for event in input:
324  event_count += 1
325  if event_count <= offset:
326  continue
327  if event_count > offset+max_events:
328  break
329  events.append(event)
330 
331  if version is None:
332  version = hlt_rod_minor_version_from_event(event)
333 
334  # Print header info
335  print('{sep:s} Event: {:{width}d}, {:s} {sep:s}'.format(
336  event_count, header_info(event),
337  sep='='*20, width=len(str(max_events))))
338 
339  # Print CTP ROB
340  if args.ctp is not False:
341  print(ctp_rob(event, 1))
342 
343  # Print L1/L2/HLT bits
344  if args.l1:
345  print(lvl1_bits(event))
346  if args.ef:
347  print(hlt_bits(event, version))
348 
349  # Print Stream Tags
350  if args.stag:
351  print(stream_tags(event))
352 
353  # HLT Result
354  if args.efres or args.sizes or args.deserialize or args.confKeys or args.runtimeMetadata:
355  print(hlt_result(event, args.sizes, args.deserialize, args.confKeys, args.runtimeMetadata))
356 
357  # Size summary (after the loop over events)
358  if args.sizeSummary:
359  print(size_summary(events))
360 
361 
362 if '__main__' in __name__:
364  for f in args.files:
365  dump_info(f, args)
trigbs_dumpHLTContentInBS_run3.decodeTriggerBits
def decodeTriggerBits(words, num_sets, base=32)
Definition: trigbs_dumpHLTContentInBS_run3.py:62
data
char data[hepevt_bytes_allocation_ATLAS]
Definition: HepEvt.cxx:11
max
#define max(a, b)
Definition: cfImp.cxx:41
trigbs_dumpHLTContentInBS_run3.ctp_rob
def ctp_rob(event, module_id=1)
Definition: trigbs_dumpHLTContentInBS_run3.py:115
vtune_athena.format
format
Definition: vtune_athena.py:14
trigbs_dumpHLTContentInBS_run3.hlt_rod_minor_version
def hlt_rod_minor_version(rob)
Definition: trigbs_dumpHLTContentInBS_run3.py:187
trigbs_dumpHLTContentInBS_run3.stream_tags
def stream_tags(event)
Definition: trigbs_dumpHLTContentInBS_run3.py:172
trigbs_dumpHLTContentInBS_run3.header_info
def header_info(event)
Definition: trigbs_dumpHLTContentInBS_run3.py:75
trigbs_dumpHLTContentInBS_run3.decode_status
def decode_status(fragment)
Definition: trigbs_dumpHLTContentInBS_run3.py:88
trigbs_dumpHLTContentInBS_run3.size_summary
def size_summary(events)
Definition: trigbs_dumpHLTContentInBS_run3.py:265
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
trigbs_dumpHLTContentInBS_run3.dump_info
def dump_info(bsfile, args)
Definition: trigbs_dumpHLTContentInBS_run3.py:313
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
DerivationFramework::TriggerMatchingUtils::sorted
std::vector< typename T::value_type > sorted(T begin, T end)
Helper function to create a sorted vector from an unsorted one.
min
#define min(a, b)
Definition: cfImp.cxx:40
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
CTPfragment::getFolderUpdates
std::map< const FolderIndex, FolderEntry > getFolderUpdates(const CTPfragment::ExtraPayload &x)
Definition: TrigByteStreamToolsDict.h:26
trigbs_dumpHLTContentInBS_run3.lvl1_bits
def lvl1_bits(event)
Definition: trigbs_dumpHLTContentInBS_run3.py:146
trigbs_dumpHLTContentInBS_run3.hlt_bits
def hlt_bits(event, version=(1, 1))
Definition: trigbs_dumpHLTContentInBS_run3.py:157
TrigJetMonitorAlgorithm.items
items
Definition: TrigJetMonitorAlgorithm.py:79
trigbs_dumpHLTContentInBS_run3.get_parser
def get_parser()
Definition: trigbs_dumpHLTContentInBS_run3.py:18
Muon::print
std::string print(const MuPatSegment &)
Definition: MuonTrackSteering.cxx:28
confTool.parse_args
def parse_args()
Definition: confTool.py:35
str
Definition: BTagTrackIpAccessor.cxx:11
python.Bindings.keys
keys
Definition: Control/AthenaPython/python/Bindings.py:790
trigbs_dumpHLTContentInBS_run3.hlt_result
def hlt_result(event, print_sizes=False, deserialize=False, conf_keys=False, runtime_metadata=False)
Definition: trigbs_dumpHLTContentInBS_run3.py:201
trigbs_dumpHLTContentInBS_run3.hlt_rod_minor_version_from_event
def hlt_rod_minor_version_from_event(event)
Definition: trigbs_dumpHLTContentInBS_run3.py:195
readCCLHist.float
float
Definition: readCCLHist.py:83