Belle II Software  release-05-01-25
benchmark.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
8 
9 from basf2 import *
10 from generators import add_kkmc_generator
11 from simulation import add_simulation
12 from L1trigger import add_tsim
13 from reconstruction import add_reconstruction
14 from ROOT import TFile
15 from argparse import ArgumentParser
16 import os
17 import glob
18 import sys
19 
20 # parse command line options
21 parser = ArgumentParser(description='Measure the execution time.')
22 parser.add_argument('-m', '--multiplicity', default='high', choices=['high', 'low'], help='Multiplicity of events')
23 parser.add_argument('-l', '--limits', help='Name of file containing limits')
24 parser.add_argument('-f', '--file', help='Name of benchmark output file')
25 args = parser.parse_args()
26 
27 # create path and reduce log level
28 main = create_path()
29 set_log_level(LogLevel.ERROR)
30 
31 # specify number of events to be generated
32 main.add_module('EventInfoSetter', evtNumList=[1000])
33 main.add_module('EventInfoPrinter').set_log_level(LogLevel.INFO)
34 
35 if args.multiplicity == 'high':
36  # generate BBbar events if high multiplicity is selected
37  main.add_module('EvtGenInput')
38 elif args.multiplicity == 'low':
39  # generate mu pair events if low multiplicity is selected
40  add_kkmc_generator(main, 'mu+mu-')
41 
42 # detector simulation
43 add_simulation(main, bkgfiles=glob.glob(os.environ.get('BELLE2_BACKGROUND_DIR', '/sw/belle2/bkg') + '/*.root'))
44 
45 # trigger simulation
46 add_tsim(main)
47 
48 # reconstruction
49 add_reconstruction(main)
50 
51 # process events and print call statistics
52 process(main)
53 print(statistics)
54 
55 # read limits
56 limits = {}
57 limits_file = args.limits
58 default_limits_file = args.multiplicity + '.limits'
59 if limits_file is None and os.path.isfile(default_limits_file):
60  limits_file = default_limits_file
61 if limits_file is not None:
62  for line in open(limits_file).readlines():
63  entries = line.split()
64  limits[entries[0]] = float(entries[1])
65  if len(entries) > 2:
66  limits[entries[0]] /= float(entries[2])
67 
68 # get execution times
69 categories = ['Simulation', 'TriggerSimulation', 'Tracking', 'PID', 'Clustering']
70 times = {}
71 for module in statistics.modules:
72  if module.name not in ['Sum_' + category for category in categories]:
73  continue
74  category = module.name[4:]
75  if category not in times.keys():
76  times[category] = 0
77  times[category] += module.time_mean(statistics.EVENT) * 1e-6
78 
79 # open output file
80 output = None
81 if args.file is not None:
82  output = open(args.file, 'wt')
83 
84 # print benchmark results and write them to the output file
85 set_log_level(LogLevel.INFO)
86 max_fraction = -1
87 for category in categories:
88  if category not in times.keys():
89  continue
90  time = times[category]
91  message = 'Execution time per event for %s is %.f ms' % (category, time)
92  fraction = -1
93  if category in limits.keys():
94  fraction = time / limits[category]
95  if fraction > max_fraction:
96  max_fraction = fraction
97  message += ' = %.f%% of the limit.' % (100 * fraction)
98  if fraction <= 0.9:
99  B2INFO(message)
100  elif fraction <= 1:
101  B2WARNING(message)
102  else:
103  B2ERROR(message)
104  else:
105  B2INFO(message)
106 
107  if output is not None:
108  output.write('%s %.2f' % (category, time))
109  if fraction >= 0:
110  output.write(' %.4f' % fraction)
111  output.write('\n')
112 
113 # fail if above limit
114 sys.exit(0 if max_fraction <= 1 else 1)