forked from cms-sw/cmssw
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcmsTiming_parser.py
executable file
·200 lines (178 loc) · 7.01 KB
/
cmsTiming_parser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#! /usr/bin/env python3
from builtins import range
import sys, os
import time
import optparse
from math import sqrt, log10, floor
import ROOT
def manipulate_log(outdir, logfile_name, secsperbin):
""" Parses logfile_name and create an html report
with information and plots, at the outdir path.
Graphs' production is also done here.
"""
################################
#### Parse of the log file. ####
################################
logfile = open(logfile_name,'r')
logfile_lines = iter(logfile.readlines())
logfile.close()
data = {}
report = ''
for line in logfile_lines:
# Retrieve cpu time of every event.
if 'TimeEvent>' in line:
line = line[:-1] #no \n!
content = line.split(' ')
event = int(content[1])
seconds = float(content[3])
data[event] = seconds
# Fill the time report.
elif 'TimeReport' in line:
if '[sec]' in line:
report += line.replace('TimeReport', '\n')
elif 'headings' in line:
continue
elif 'complete' in line:
report += line.replace('TimeReport', '\n')
for count in range(12):
line = next(logfile_lines)
report += line
break
else:
report += line.replace('TimeReport', '')
##############################
#### Graph and Histogram ####
##############################
__argv = sys.argv # trick for a strange behaviour of the TApp..
sys.argv = sys.argv[:1]
ROOT.gROOT.SetStyle("Plain") # style paranoia
sys.argv = __argv
#Cannot use this option when the logfile includes
#a large number of events... PyRoot seg-faults.
#Set ROOT in batch mode to avoid canvases popping up!
ROOT.gROOT.SetBatch(1)
# Save in file
rootfilename = '%s/graphs.root' %outdir
myfile = ROOT.TFile(rootfilename,'RECREATE')
# Set limits
min_val = data[min(data, key=data.get)]
max_val = data[max(data, key=data.get)]
interval = max_val-min_val
min_val = min_val - (interval*0.2)
max_val = max_val + (interval*0.2)
interval = max_val - min_val
nbins = int(interval/secsperbin)
# Initialize Histogram
histo = ROOT.TH1F('Seconds per event','Seconds per event', nbins, min_val, max_val)
histo.GetXaxis().SetTitle("s")
# Initialize Graph
npoints = len(data)
graph = ROOT.TGraph(npoints)
graph.SetMarkerStyle(8)
graph.SetMarkerSize(.7)
graph.SetMarkerColor(1)
graph.SetLineWidth(3)
graph.SetLineColor(2)
graph.SetTitle('Seconds per event')
graph.SetName('SecondsPerEvent')
graph.GetXaxis().SetTitle("Event")
last_event = max(data)
graph.GetXaxis().SetLimits(0, last_event)
graph.GetYaxis().SetTitleOffset(1.3)
graph.GetYaxis().SetTitle("s")
graph.GetYaxis().SetRangeUser(0, max_val)
# Fill them
total_time = 0
for event_num in data.keys():
seconds = data[event_num]
graph.SetPoint(event_num-1, event_num, seconds)
histo.Fill(seconds)
total_time += seconds
# A line which represents the average is drawn in the TGraph
avg = histo.GetMean()
avg_line = ROOT.TLine(1,avg,last_event, avg)
avg_line.SetLineColor(4)
avg_line.SetLineWidth(2)
# Draw and save!
graph_canvas = ROOT.TCanvas('graph_canvas')
graph_canvas.cd()
graph.Draw("ALP")
avg_line.Draw("Same")
# Write graph to file
graph_canvas.Print("%s/graph.png" %outdir,"png")
graph.Write()
graph_canvas.Write()
histo_canvas = ROOT.TCanvas('histo_canvas')
histo_canvas.cd()
histo.Draw('')
# Write histogram to file
histo_canvas.Print("%s/histo.png" %outdir,"png")
histo.Write()
histo_canvas.Write()
myfile.Close()
########################
#### The html page! ####
########################
titlestring = '<b>Report executed with release %s on %s.</b>\n<br>\n<hr>\n'\
%(os.environ['CMSSW_VERSION'], time.asctime())
html_file_name = '%s/%s_TimingReport.html' %(outdir, logfile_name[:-4])
html_file = open(html_file_name,'w')
html_file.write('<html>\n<body>\n'+\
titlestring)
html_file.write('<table>\n'+\
'<tr>\n<td><img src=graph.png></img></td>\n'+\
'<td><img src=histo.png></img></td>\n</tr>\n'+\
'</table>\n')
html_file.write('<hr>\n<h2>Time Report</h2>\n<pre>\n' + report + '</pre>\n')
html_file.write('</body>\n</html>')
html_file.close()
##########################
#### Print statistics ####
##########################
total_events = max(data)
average_time = total_time / total_events
sum = 0.
for i in range(1, max(data)+1):
sum += (data[i]-average_time)**2
denominator = total_events**2 - total_events
uncertainty = sqrt(sum/denominator)
# Comment out next 2 line to round uncertainty to the most significant digit
#rounded_uncertainty=round(uncertainty, -int(floor(log10(uncertainty))))
#print 'Rounded uncertainty=' , rounded_uncertainty
print('------ Statistics ------')
print('last event = {}'.format(last_event))
print('Minval = {} maxval = {} interval = {}'.format(min_val, max_val, interval))
print('Total Time = {}'.format(total_time))
print('Average Time = {}'.format(average_time))
print('Uncertainty of Average Time = {} +/- {}'.format(average_time, uncertainty))
#################################################################################################
if __name__ == '__main__':
# Here we define an option parser to handle commandline options..
usage = 'timing_parser.py <options>'
parser = optparse.OptionParser(usage)
parser.add_option('-i', '--in_ profile',
help='The profile to manipulate' ,
default='',
dest='profile')
parser.add_option('-o', '--outdir',
help='The directory of the output' ,
default='',
dest='outdir')
parser.add_option('-n',
help='Number of secs per bin. Default is 1.' ,
default='1',
dest='startevt')
(options,args) = parser.parse_args()
# Now some fault control..If an error is found we raise an exception
if options.profile == '' or\
options.outdir == '':
raise Exception('Please select a profile and an output dir!')
if not os.path.exists(options.profile) or\
not os.path.exists(options.outdir):
raise Exception('Outdir or input profile not present!')
try:
startevt = float(options.startevt)
except ValueError:
print('Problems in convertng starting event value!')
# launch the function!
manipulate_log(options.outdir,options.profile,startevt)