Belle II Software  release-08-01-10
benchmark.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 
16 
17 import basf2 as b2
18 from generators import add_kkmc_generator
19 from simulation import add_simulation
20 from validation_gt import get_validation_globaltags
21 from rawdata import add_unpackers
22 from reconstruction import add_reconstruction
23 from argparse import ArgumentParser
24 import os
25 import glob
26 import sys
27 
28 # parse command line options
29 parser = ArgumentParser(description='Measure the execution time.')
30 parser.add_argument('-m', '--multiplicity', default='high', choices=['high', 'low', 'data'], help='Multiplicity or type of events')
31 parser.add_argument('-l', '--limits', help='Name of file containing limits')
32 parser.add_argument('-f', '--file', help='Name of benchmark output file')
33 args = parser.parse_args()
34 
35 # create path and reduce log level
36 main = b2.create_path()
37 b2.set_log_level(b2.LogLevel.ERROR)
38 
39 if args.multiplicity == 'data':
40  # Global Tag needed as these are Raw data
41  b2.conditions.override_globaltags(get_validation_globaltags())
42 
43  input_files = glob.glob(os.environ.get('BELLE2_VALIDATION_DATA_DIR', '') + '/rawdata/physics.0010.05095*.root')
44  main.add_module("RootInput", inputFileNames=input_files)
45 
46  main.add_module('EventInfoPrinter').set_log_level(b2.LogLevel.INFO)
47 
48  # gearbox and geometry
49  main.add_module('Gearbox')
50  main.add_module('Geometry', useDB=True)
51 
52  # unpacking
53  add_unpackers(main)
54 
55 else:
56  # specify number of events to be generated
57  main.add_module('EventInfoSetter', evtNumList=[1000])
58  main.add_module('EventInfoPrinter').set_log_level(b2.LogLevel.INFO)
59 
60  if args.multiplicity == 'high':
61  # generate BBbar events if high multiplicity is selected
62  main.add_module('EvtGenInput')
63 
64  elif args.multiplicity == 'low':
65  # generate mu pair events if low multiplicity is selected
66  add_kkmc_generator(main, 'mu+mu-')
67 
68  # detector and L1 trigger simulation
69  add_simulation(main, bkgfiles=glob.glob(os.environ.get('BELLE2_BACKGROUND_DIR', '/sw/belle2/bkg') + '/*.root'))
70 
71 # reconstruction
72 add_reconstruction(main)
73 
74 # process events and print call statistics
75 b2.process(main)
76 print(b2.statistics)
77 
78 # read limits
79 limits = {}
80 limits_file = args.limits
81 default_limits_file = args.multiplicity + '.limits'
82 if limits_file is None and os.path.isfile(default_limits_file):
83  limits_file = default_limits_file
84 if limits_file is not None:
85  for line in open(limits_file).readlines():
86  entries = line.split()
87  limits[entries[0]] = float(entries[1])
88  if len(entries) > 2:
89  limits[entries[0]] /= float(entries[2])
90 
91 # get execution times
92 categories = [
93  'Simulation',
94  'TriggerSimulation',
95  'Clustering',
96  'Prefilter_Tracking',
97  'Posttracking_Reconstruction',
98  'Postfilter_Reconstruction']
99 times = {}
100 for module in b2.statistics.modules:
101  if module.name not in ['Sum_' + category for category in categories]:
102  continue
103  category = module.name[4:]
104  if category not in times.keys():
105  times[category] = 0
106  times[category] += module.time_mean(b2.statistics.EVENT) * 1e-6
107 
108 # open output file
109 output = None
110 if args.file is not None:
111  output = open(args.file, 'wt')
112 
113 # print benchmark results and write them to the output file
114 b2.set_log_level(b2.LogLevel.INFO)
115 max_fraction = -1
116 for category in categories:
117  if category not in times.keys():
118  continue
119  time = times[category]
120  message = 'Execution time per event for %s is %.f ms' % (category, time)
121  fraction = -1
122  if category in limits.keys():
123  fraction = time / limits[category]
124  if fraction > max_fraction:
125  max_fraction = fraction
126  message += ' = %.f%% of the limit.' % (100 * fraction)
127  if fraction <= 0.9:
128  b2.B2INFO(message)
129  elif fraction <= 1:
130  b2.B2WARNING(message)
131  else:
132  b2.B2ERROR(message)
133  else:
134  b2.B2INFO(message)
135 
136  if output is not None:
137  output.write('%s %.2f' % (category, time))
138  if fraction >= 0:
139  output.write(' %.4f' % fraction)
140  output.write('\n')
141 
142 # fail if above limit
143 sys.exit(0 if max_fraction <= 1 else 1)