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