Back to home page

Project CMSSW displayed by LXR

 
 

    


Warning, /HLTrigger/Configuration/scripts/hltDumpStream is written in an unsupported language. File is not indexed.

0001 #!/usr/bin/env python3
0002 # -*- coding: utf-8 -*-
0003 """hltDumpStream: print information on streams, primary datasets, triggers and (HLT) prescales of a HLT menu
0004 
0005 examples:
0006   # run hltDumpStream on HLT menu used in run 123456 (output in CSV format)
0007   hltConfigFromDB --runNumber 123456 | hltDumpStream --mode csv
0008   # run hltDumpStream on local cfg file hlt.py (output in text format)
0009   hltDumpStream hlt.py --mode text
0010 """
0011 import os
0012 import sys
0013 import argparse
0014 import re
0015 import fnmatch
0016 import operator
0017 from importlib.machinery import SourceFileLoader
0018 import types
0019 import tempfile
0020 import FWCore.ParameterSet.Config as cms
0021 
0022 def getPathSeeds(path):
0023   '''list of strings, each corresponding to one of the seeds of the trigger
0024   '''
0025   seeds = []
0026   pathModList = path.expandAndClone()._seq._collection
0027   for pathMod in pathModList:
0028     # skip ignored EDFilters
0029     if pathMod.isOperation() and pathMod.decoration() == '-':
0030       continue
0031 
0032     if pathMod.type_() == 'HLTPrescaler':
0033       break
0034 
0035     elif pathMod.type_() == 'HLTL1TSeed':
0036       seeds.append(pathMod.L1SeedsLogicalExpression.value())
0037 
0038     elif pathMod.type_() == 'TriggerResultsFilter':
0039       trigConds = pathMod.triggerConditions
0040       if len(trigConds) == 1:
0041         seeds.append(trigConds[0])
0042       else:
0043         seeds.append('(' + ') OR ('.join(trigConds) + ')')
0044   return seeds
0045 
0046 def getPathSeedsDescription(path):
0047   '''string representing the logical expression of the trigger's seeding
0048   '''
0049   seeds = getPathSeeds(path)
0050   if len(seeds) == 0:
0051     seedDesc = '(none)'
0052   elif len(seeds) == 1:
0053     seedDesc = seeds[0]
0054   else:
0055     seedDesc = '(' + ') AND ('.join(seeds) + ')'
0056   return seedDesc
0057 
0058 def getBPTXMatching(path):
0059   '''integer representing the BPTX coincidence information for the given path
0060   '''
0061   bptxDict = {
0062     'hltL1sL1BPTX': False,
0063     'hltL1sL1BPTXPlusOnly': False,
0064     'hltL1sL1BPTXMinusOnly': False,
0065     'hltL1sZeroBias': False,
0066     'hltBPTXCoincidence': False,
0067   }
0068   for bptxMod in bptxDict:
0069     if hasattr(process, bptxMod):
0070       bptxDict[bptxMod] = path.contains(getattr(process, bptxMod))
0071 
0072   if bptxDict['hltL1sL1BPTX'] or bptxDict['hltL1sL1BPTXPlusOnly'] or \
0073      bptxDict['hltL1sL1BPTXMinusOnly'] or bptxDict['hltL1sZeroBias']:
0074     bptx = 2
0075   elif bptxDict['hltBPTXCoincidence']:
0076     bptx = 1
0077   else:
0078     bptx = 0
0079   return bptx
0080 
0081 def getBPTXMatchingDescription(path):
0082   '''string representing the BPTX coincidence information for the given path
0083   '''
0084   return ' ~='[getBPTXMatching(path)]
0085 
0086 def getStreamsInfoFromProcess(process, prescaleValues, numberOfPrescaleColumns):
0087   '''extract the info on streams, datasets and triggers:
0088   the return type is a list of dictionaries, one per stream
0089 
0090   each stream dict contains the following entries (key: value)
0091    - name: name of the stream
0092    - path: cms.EndPath associated to the stream
0093    - prescales: list of prescale values (1 per PS column) applied to the EndPath associated to the stream
0094    - smartPrescales: dictionary (path:ps) of smart-prescales applied at stream level
0095    - datasets: list of dataset dictionaries (see below)
0096 
0097   every dataset dictionary contains the following entries (key: value)
0098    - name: name of the dataset
0099    - path: cms.Path associated to the dataset, i.e. the "DatasetPath" (path=None if there is no DatasetPath)
0100    - prescales: list of prescale values (1 per PS column) applied to the DatasetPath (a list of 1s if there is no DatasetPath)
0101    - smartPrescales: dictionary (path:ps) of smart-prescales applied at dataset level (a list of 1s if there is no DatasetPath)
0102    - triggers: list of trigger dictionaries (see below)
0103 
0104   every trigger dictionary contains the following entries (key: value)
0105    - name: name of the high-level trigger
0106    - path: cms.Path associated to the trigger
0107    - prescales: list of prescale values (1 per PS column) applied to the Path
0108    - bptx: string expressing the BPTX condition used by the trigger (if any)
0109    - seed: string expressing the logical expression seeding the trigger
0110            (this is tipically based on L1-Trigger algorithms,
0111            but in general it can also include selections on other HLT Paths, incl. DatasetPaths);
0112            seed modules are required to precede the HLTPrescaler module of the trigger (if any)
0113   '''
0114 
0115   # get hold of Schedule if present
0116   procSchedule = process.schedule_()
0117   if procSchedule == None:
0118     # older HLT configs used "HLTSchedule", which appears under '_Process__partialschedules'
0119     partialScheduleNames = list(process._Process__partialschedules.keys())
0120     if len(partialScheduleNames) == 1:
0121       procSchedule = getattr(process, partialScheduleNames[0])
0122     elif len(partialScheduleNames) > 1:
0123       raise RuntimeError('ERROR -- the process holds multiple partial schedules: '+str(process._Process__partialschedules))
0124 
0125   # find list of streams:
0126   #  - stream XYZ exists if the configuration contains a EndPath that contains an OutputModule named hltOutputXYZ
0127   #  - if more than one such EndPath exists, it is an error (unsupported configuration)
0128   #  - if the configuration contains a cms.Schedule, the EndPath is required to be part of the cms.Schedule
0129   #  - reliance on the PSet "streams" is minimised:
0130   #    - the latter PSet, if present, should be a superset of the streams found in the configuration
0131   #      (this is the case for HLT configs containing only a subset of the triggers of a menu, e.g. "hltGetConfiguration --paths [..]")
0132   streams = []
0133 
0134   # regex to find smart-prescale value
0135   smartPS_recomp = re.compile(r'(.*)\s*/\s*(\d+)')
0136 
0137   # find valid streams based on OutputModules
0138   for outModName in process.outputModules_():
0139     # find stream OutputModules by name: "hltOutput*"
0140     if not outModName.startswith('hltOutput'):
0141       continue
0142     streamName = outModName[len('hltOutput'):]
0143 
0144     # find EndPath containing stream OutputModule
0145     streamPath = None
0146     outputModule = process.outputModules_()[outModName]
0147     for efPath in process.endpaths_().values():
0148       if procSchedule != None:
0149         # skip EndPath if not included in the schedule
0150         # (schedule.contains does not seem to be enough, so the index of the EndPath in the schedule is searched;
0151         #  if the EndPath is not in the schedule, this search leads to a runtime-error)
0152         try: procSchedule.index(efPath)
0153         except: continue
0154       if efPath.contains(outputModule):
0155         # if streamPath is already set, throw a runtime error:
0156         # no more than one EndPath can hold a given OutputModule in valid HLT configurations
0157         if streamPath != None:
0158           errMsg = 'ERROR -- output module "'+outModName+'" is associated to'
0159           errMsg += ' more than one EndPath: '+str([streamPath.label(), efPath.label()])
0160           raise RuntimeError(errMsg)
0161         streamPath = efPath
0162 
0163     # OutputModule not included in any active EndPath
0164     if streamPath == None:
0165       continue
0166 
0167     # fill info of all datasets assigned to this stream
0168     datasetsOfStream = []
0169 
0170     datasetNames = []
0171     usesDatasetPaths = False
0172 
0173     pathsOfStream = sorted(list(set(fooPathName for fooPathName in outputModule.SelectEvents.SelectEvents)))
0174     datasetPathsOfStream = [foo for foo in pathsOfStream if foo.startswith('Dataset_')]
0175 
0176     if len(datasetPathsOfStream) == 0:
0177       # no DatasetPaths found (older HLT menus, before Run 3), fall back on the "streams" PSet
0178       datasetNames = sorted(list(set(getattr(process.streams, streamName))))
0179 
0180     elif len(datasetPathsOfStream) == len(pathsOfStream):
0181       # HLT menus with OutputModules selecting on DatasetPaths (HLT menus of 2022 and later)
0182       datasetNames = [foo[len('Dataset_'):] for foo in datasetPathsOfStream]
0183       usesDatasetPaths = True
0184 
0185     else:
0186       # only a subset of the Paths in the OutputModule's SelectEvents are DatasetPaths:
0187       # this is not expected to happen in valid HLT configurations
0188       errMsg = 'ERROR -- output module "'+outModName+'" has a mixture of DatasetPaths and non-DatasetPaths'
0189       errMsg += ' in its SelectEvents.SelectEvents PSet: '+str(outputModule.SelectEvents.SelectEvents)
0190       raise RuntimeError(errMsg)
0191 
0192     for datasetName in datasetNames:
0193 
0194       datasetPath = None
0195       datasetPrescales = [1]*numberOfPrescaleColumns
0196       datasetSmartPrescales = {}
0197 
0198       if not usesDatasetPaths:
0199         # for non-DatasetPaths, fall back on "datasets" PSet
0200         pathNames = sorted(list(set(getattr(process.datasets, datasetName))))
0201         for foo in pathNames:
0202           datasetSmartPrescales[foo] = 1
0203 
0204       else:
0205         datasetPathName = 'Dataset_'+datasetName
0206         if datasetPathName in psValues:
0207           datasetPrescales = psValues[datasetPathName]
0208 
0209         if not hasattr(process, datasetPathName):
0210           msgErr = 'ERROR -- process does not have DatasetPath "'+datasetPathName+'" required by stream "'+streamName+'"'
0211           raise RuntimeError(msgErr)
0212 
0213         datasetPath = getattr(process, datasetPathName)
0214 
0215         datasetSmartPrescales = {}
0216 
0217         # find smart-PS module of DatasetPath
0218         # (used to extract both trigger name and smart-PS values)
0219         datasetPathSmartPSModule = None
0220         for pathMod in datasetPath.expandAndClone()._seq._collection:
0221           # check only EDFilters
0222           if not isinstance(pathMod, cms.EDFilter):
0223             continue
0224           if pathMod.type_() == 'TriggerResultsFilter':
0225             if datasetPathSmartPSModule == None:
0226               datasetPathSmartPSModule = pathMod
0227             else:
0228               msgErr = 'ERROR -- found more than one smart-PS module associated to DatasetPath "'+datasetPathName+'":'
0229               msgErr = ' '+str([datasetPathSmartPSModule.label(), pathMod.label()])
0230               raise RuntimeError(msgErr)
0231 
0232         if datasetPathSmartPSModule == None:
0233           raise RuntimeError('ERROR -- DatasetPath "'+datasetPathName+'" does not contain any smart-PS module (type: TriggerResultsFilter)')
0234 
0235         # get list of Paths, and their smartPSs, from TriggerResultsFilter module of the Dataset Path
0236         # (by construction, the smart-PS module inside a DatasetPath does not use wildcards, but only the exact names of the Paths)
0237         for triggerCond in datasetPathSmartPSModule.triggerConditions:
0238           smartPS_match = smartPS_recomp.match(triggerCond)
0239           if smartPS_match:
0240             smartPS_key = smartPS_match.group(1).strip()
0241             smartPS_val = int(smartPS_match.group(2))
0242           else:
0243             smartPS_key = triggerCond
0244             smartPS_val = 1
0245 
0246           if smartPS_key in datasetSmartPrescales:
0247             msgErr = 'ERROR -- multiple smart-PS for trigger expression "'+smartPS_key+'" in module "'+datasetPathSmartPSModule.label()+'"'
0248             raise RuntimeError(msgErr)
0249 
0250           datasetSmartPrescales[smartPS_key] = smartPS_val
0251 
0252         pathNames = sorted(datasetSmartPrescales.keys())
0253 
0254       # info on triggers assigned to a dataset
0255       triggersOfDataset = []
0256       for pathName in pathNames:
0257         if not hasattr(process, pathName):
0258           msgErr = 'ERROR -- process does not have Path "'+pathName+'" required by dataset "'+datasetName+'"'
0259           raise RuntimeError(msgErr)
0260         path = getattr(process, pathName)
0261         # seed of HLT path (tipically, a selection on L1-Trigger algos)
0262         seedStr = getPathSeedsDescription(path)
0263         # look for BPTX coincidence in the given path
0264         bptxStr = getBPTXMatchingDescription(path)
0265         # global prescales of the trigger
0266         pathPrescales = prescaleValues[pathName] if pathName in prescaleValues else [1]*numberOfPrescaleColumns
0267         # trigger information
0268         triggersOfDataset += [{
0269           'name': pathName,
0270           'path': path,
0271           'seed': seedStr,
0272           'BPTX': bptxStr,
0273           'prescales': pathPrescales,
0274         }]
0275 
0276       # order triggers alphabetically by name
0277       triggersOfDataset.sort(key = lambda x: x['name'])
0278 
0279       datasetsOfStream += [{
0280         'name': datasetName,
0281         'path': datasetPath,
0282         'prescales': datasetPrescales,
0283         'smartPrescales': datasetSmartPrescales,
0284         'triggers': triggersOfDataset,
0285       }]
0286 
0287     # order datasets alphabetically by name
0288     datasetsOfStream.sort(key = lambda x: x['name'])
0289 
0290     # fill smart-PS applied at stream level
0291     # (in Run-2 HLT menus, smart-PSs are applied to standard Paths in the stream EndPath)
0292     streamSmartPrescales = {} # dictionary of smart-PSs applied at stream level
0293     smartPSModuleName = None  # smart-PS module in the stream EndPath
0294 
0295     # build list of Paths that can have a smart-PS at stream level:
0296     # this includes the Paths of all datasets in the stream, and the DatasetPaths (if present)
0297     pathNamesForStreamSmartPS = []
0298     for dset in datasetsOfStream:
0299       pathNamesForStreamSmartPS += [foo['name'] for foo in dset['triggers']]
0300       if dset['path'] != None:
0301         pathNamesForStreamSmartPS += [dset['path'].label()]
0302     pathNamesForStreamSmartPS = sorted(list(set(pathNamesForStreamSmartPS)))
0303 
0304     # default to 1 (correct value if smart-PS module is absent)
0305     for foo in pathNamesForStreamSmartPS:
0306       streamSmartPrescales[foo] = 1
0307 
0308     # loop on modules preceding the OutputModule in the EndPath
0309     # to extract smart prescales at stream level, requiring no more than one smart-PS module
0310     streamPathExpanded = streamPath.expandAndClone()
0311     for modIdx in range(streamPathExpanded.index(outputModule)):
0312       mod = streamPathExpanded._seq._collection[modIdx]
0313 
0314       # find smart-PS modules by type
0315       if mod.type_() not in ['TriggerResultsFilter', 'HLTHighLevelDev']:
0316         continue
0317 
0318       if smartPSModuleName != None:
0319         msgErr = 'ERROR -- found more than one smart-PS module associated to stream "'+streamName+'":'
0320         msgErr = ' '+str([smartPSModuleName, mod.label()])
0321         raise RuntimeError(msgErr)
0322       else:
0323         smartPSModuleName = mod.label()
0324 
0325       # smart-PS module is present: start by setting to None, and extract smart-PSs
0326       for foo in pathNamesForStreamSmartPS:
0327         streamSmartPrescales[foo] = None
0328 
0329       # "TriggerResultsFilter": latest type of smart-prescale module
0330       if mod.type_() == 'TriggerResultsFilter':
0331 
0332         for triggerCond in mod.triggerConditions:
0333           smartPS_match = smartPS_recomp.match(triggerCond)
0334           if smartPS_match:
0335             smartPS_key = smartPS_match.group(1).strip()
0336             smartPS_val = int(smartPS_match.group(2))
0337           else:
0338             smartPS_key = triggerCond
0339             smartPS_val = 1
0340 
0341           for pathName in streamSmartPrescales:
0342             if fnmatch.fnmatch(pathName, smartPS_key):
0343               if streamSmartPrescales[pathName] == None:
0344                 streamSmartPrescales[pathName] = smartPS_val
0345               else:
0346                 msgWarn = 'WARNING -- multiple matches for smart-PS of Path "'+pathName+'" in stream "'+streamName+'"'
0347                 msgWarn += ', the lowest smart-PS value will be used (ignoring zero).'
0348                 print(msgWarn, file=sys.stderr)
0349                 streamSmartPrescales[pathName] = min(streamSmartPrescales[pathName], max(1, smartPS_val))
0350 
0351       # "HLTHighLevelDev": old type of smart-prescale module
0352       else:
0353         for idx,triggerExpr in enumerate(mod.HLTPaths.value()):
0354           smartPS_key = triggerExpr
0355           smartPS_val = mod.HLTPathsPrescales.value()[idx] * mod.HLTOverallPrescale.value()
0356 
0357           for pathName in streamSmartPrescales:
0358             if fnmatch.fnmatch(pathName, smartPS_key):
0359               if streamSmartPrescales[pathName] == None:
0360                 streamSmartPrescales[pathName] = smartPS_val
0361               else:
0362                 msgWarn = 'WARNING -- multiple matches for smart-PS of Path "'+pathName+'" in stream "'+streamName+'"'
0363                 msgWarn += ', the lowest smart-PS value will be used (ignoring zero).'
0364                 print(msgWarn, file=sys.stderr)
0365                 streamSmartPrescales[pathName] = min(streamSmartPrescales[pathName], max(1, smartPS_val))
0366 
0367       # if a smart-PS is still None, there is a smart-PS module,
0368       # but no match for a given Path, so set its smart-PS to zero
0369       for foo in pathNamesForStreamSmartPS:
0370         if streamSmartPrescales[foo] == None:
0371           msgWarn = 'WARNING -- smart-PS of Path "'+foo+'" in stream "'+streamName+'" not found, will be set to zero.'
0372           print(msgWarn, file=sys.stderr)
0373           streamSmartPrescales[foo] = 0
0374 
0375     streams += [{
0376       'name': streamName,
0377       'path': streamPath,
0378       'prescales': prescaleValues[streamPath.label()] if streamPath.label() in prescaleValues else [1]*numberOfPrescaleColumns,
0379       'datasets': datasetsOfStream,
0380       'smartPrescales': streamSmartPrescales,
0381     }]
0382 
0383   # order streams alphabetically by name
0384   streams.sort(key = lambda x: x['name'])
0385 
0386   return streams
0387 
0388 def printHeader(mode, selectedPrescaleColumns):
0389   '''print to stdout the header of the hltDumpStream output
0390   '''
0391   if mode == 'text':
0392     if len(selectedPrescaleColumns) > 0:
0393       print('-----------------')
0394       print('Prescale Columns:')
0395       print('-----------------')
0396       for psColIdx,psColName in selectedPrescaleColumns:
0397         print(f'{psColIdx: >4d} : {psColName}')
0398       print('-----------------\n')
0399   elif mode == 'csv':
0400     psColNamesStr = ', '.join(foo[1] for foo in selectedPrescaleColumns)
0401     if psColNamesStr: psColNamesStr += ', '
0402     print('stream, dataset, path, ' + psColNamesStr + 'seed')
0403 
0404 def printStreamInfo(mode, stream, selectedPrescaleColumns, pathStrSize=100, showPrescaleValues=True, showSeedNames=True):
0405   '''print to stdout the information on triggers and datasets of a given stream
0406   '''
0407   streamName = stream['name']
0408   if mode == 'text':
0409     print('stream', streamName)
0410 
0411   for dataset in stream['datasets']:
0412     datasetName = dataset['name']
0413     if mode == 'text':
0414       print('    dataset', datasetName)
0415 
0416     datasetPathName = None
0417     if dataset['path'] != None:
0418       datasetPathName = dataset['path'].label()
0419 
0420     datasetSmartPrescaleInStream = 1
0421     if datasetPathName != None:
0422       datasetSmartPrescaleInStream = stream['smartPrescales'][datasetPathName]
0423 
0424     for trigger in dataset['triggers']:
0425 
0426       triggerName = trigger['name']
0427       triggerSeedDesc = trigger['seed']
0428       triggerBPTXDesc = trigger['BPTX']
0429 
0430       triggerSmartPrescaleInDataset = dataset['smartPrescales'][triggerName]
0431       triggerSmartPrescaleInStream = stream['smartPrescales'][triggerName]
0432 
0433       triggerSmartPrescale = triggerSmartPrescaleInDataset * triggerSmartPrescaleInStream * datasetSmartPrescaleInStream
0434 
0435       prescales = []
0436 
0437       for psColIdx,_ in selectedPrescaleColumns:
0438         triggerPrescale = trigger['prescales'][psColIdx]
0439         datasetPrescale = dataset['prescales'][psColIdx]
0440         streamPrescale = stream['prescales'][psColIdx]
0441         prescales.append(triggerSmartPrescale * triggerPrescale * datasetPrescale * streamPrescale)
0442 
0443       triggerStr = ''
0444 
0445       if mode == 'text':
0446         triggerStr += '      %s %-*s' % (triggerBPTXDesc, pathStrSize, triggerName)
0447         if showPrescaleValues:
0448           triggerStr += '%s' % (''.join('  %6d' % p for p in prescales))
0449         if showSeedNames:
0450           triggerStr += '    %s' % (triggerSeedDesc)
0451 
0452       elif mode == 'csv':
0453         triggerStr += '%s, %s, %s' % (streamName, datasetName, triggerName)
0454         if showPrescaleValues:
0455           prescaleStr = '%s' % (', '.join('%s' % p for p in prescales))
0456           if prescaleStr: prescaleStr = ', '+prescaleStr
0457           triggerStr += prescaleStr
0458         if showSeedNames:
0459           triggerStr += ', %s' % (triggerSeedDesc)
0460 
0461       print(triggerStr)
0462 
0463   if mode == 'text':
0464     print('---')
0465 
0466 ##
0467 ## main
0468 ##
0469 if __name__ == '__main__':
0470 
0471   ### args
0472   parser = argparse.ArgumentParser(
0473     prog = './'+os.path.basename(__file__),
0474     formatter_class = argparse.RawDescriptionHelpFormatter,
0475     description = __doc__,
0476     argument_default = argparse.SUPPRESS,
0477   )
0478 
0479   # menu: name of ConfDB config, or local cmsRun cfg file, or stdin
0480   parser.add_argument('menu',
0481                       nargs = '?',
0482                       metavar = 'MENU',
0483                       default = None,
0484                       help = 'path to local cmsRun cfg file (if not specified, stdin is used)' )
0485 
0486   # mode: format of output file
0487   parser.add_argument('-m', '--mode',
0488                       dest = 'mode',
0489                       action = 'store',
0490                       metavar = 'MODE',
0491                       default = 'text',
0492                       choices = ['text', 'csv'],
0493                       help = 'format of output file (must be "text", or "csv") [default: "text"]' )
0494 
0495   # prescale-columns: select prescale columns via regular expressions
0496   group = parser.add_mutually_exclusive_group()
0497   group.add_argument('-p', '--prescale-columns',
0498                      dest = 'ps_columns',
0499                      metavar = 'COLUMN',
0500                      nargs = '+',
0501                      default = ['*'],
0502                      help = 'list of patterns, passed to fnmatch, to select prescale columns [default: ["*"]]')
0503   group.add_argument('--no-prescales',
0504                      dest = 'ps_columns',
0505                      action = 'store_const',
0506                      const = [],
0507                      help = 'do not show information on prescales')
0508 
0509   # no-seeds: do not show information on trigger seeds
0510   parser.add_argument('--no-seeds',
0511                       dest = 'no_seeds',
0512                       action = 'store_true',
0513                       default = False,
0514                       help = 'do not show the seed of a HLT path [default: False]' )
0515 
0516   # parse command line arguments and options
0517   opts = parser.parse_args()
0518 
0519   # parse the HLT configuration from a local cfg file, or from standard input
0520   if opts.menu != None:
0521     loader = SourceFileLoader("pycfg", opts.menu)
0522     hlt = types.ModuleType(loader.name)
0523     loader.exec_module(hlt)
0524   else:
0525     with tempfile.NamedTemporaryFile(dir = "./", delete = False, suffix = ".py") as temp_file:
0526       temp_file.write(bytes(sys.stdin.read(), 'utf-8'))
0527       configname = temp_file.name
0528       # VarParsing expects python/cmsRun python.py
0529       sys.argv.append(configname)
0530     loader = SourceFileLoader("pycfg", configname)
0531     hlt = types.ModuleType(loader.name)
0532     loader.exec_module(hlt)
0533     os.remove(configname)
0534 
0535   # get hold of cms.Process object
0536   if 'process' in hlt.__dict__:
0537     process = hlt.process
0538   elif 'fragment' in hlt.__dict__:
0539     process = hlt.fragment
0540   else:
0541     sys.stderr.write("Error: the input is not a valid HLT configuration")
0542     sys.exit(1)
0543 
0544   # Info from PrescaleService:
0545   # values of all (global, i.e. non-smart) HLT prescales, and names of selected prescale columns
0546   #  - prescaleValues: dictionary of (key) name of Path to (value) list of Path's prescales
0547   #  - selectedPSColumns: list of tuples, each holding (index, name) of selected prescale column
0548   psValues = dict()
0549   numPSColumns = 0
0550   selectedPSColumns = []
0551   showPSValues = True
0552   if opts.ps_columns:
0553     if hasattr(process, 'PrescaleService') and process.PrescaleService.type_() == 'PrescaleService':
0554       # number of prescale columns in the configuration
0555       numPSColumns = len(process.PrescaleService.lvl1Labels)
0556       # keep PS values for all columns
0557       for entry in process.PrescaleService.prescaleTable:
0558         psValues[entry.pathName.value()] = entry.prescales.value()
0559       # find index and name of selected PS columns
0560       for psColIdx,psColName in enumerate(process.PrescaleService.lvl1Labels):
0561         for psColPattern in opts.ps_columns:
0562           if fnmatch.fnmatch(psColName, psColPattern):
0563             selectedPSColumns.append((psColIdx, psColName))
0564             break
0565       if not selectedPSColumns:
0566         print('WARNING -- selected zero prescale columns: information on prescales will not be shown.', file=sys.stderr)
0567         showPSValues = False
0568     else:
0569       print('WARNING -- PrescaleService module not found: information on prescales will not be shown.', file=sys.stderr)
0570       showPSValues = False
0571 
0572   # show seed expression of every HLT Path
0573   showSeeds = not opts.no_seeds
0574 
0575   # extract streams' information from cms.Process
0576   streams = getStreamsInfoFromProcess(process, psValues, numPSColumns)
0577 
0578   # print header information
0579   printHeader(opts.mode, selectedPSColumns)
0580 
0581   maxPathNameLength = max([16] + [len(foo) for foo in process.paths_() if not foo.startswith('Dataset_')])
0582 
0583   # print information of every stream
0584   for stream_i in streams:
0585     printStreamInfo(opts.mode, stream_i, selectedPSColumns, maxPathNameLength, showPSValues, showSeeds)