00001
00002
00003 import os, sys
00004 try: import simplejson as json
00005 except ImportError: import json
00006
00007
00008 def get_min_error(list):
00009 min = 1e20
00010 for node in list:
00011 value = node['average'] - node['error']
00012 if value < min:
00013 min = value
00014 return min
00015
00016 def get_max_error(list):
00017 max = -1
00018 for node in list:
00019 value = node['average'] + node['error']
00020 if value > max:
00021 max = value
00022 return max
00023
00024 def operate(timelog, memlog, json_f, num):
00025
00026 import re
00027 import commands
00028 import ROOT
00029 from datetime import datetime
00030
00031 script_name=os.path.basename(__file__)
00032
00033
00034 timefile=open(timelog, 'r')
00035 timelog_lines=timefile.readlines()
00036 timefile.close()
00037
00038 memfile=open(memlog, 'r')
00039 memlog_lines=memfile.readlines()
00040 memfile.close()
00041
00042
00043 max_rss=average=error=' '
00044 i=0
00045 while i<len(timelog_lines):
00046 line=timelog_lines[i]
00047 if 'Uncertainty of Average Time' in line:
00048 line=line[:-1]
00049 line_list=line.split(' ')
00050 average=line_list[5]
00051 error=line_list[7]
00052 i+=1
00053 i=0
00054 while i<len(memlog_lines):
00055 line=memlog_lines[i]
00056 if 'Maximum rss' in line:
00057 line=line[:-1]
00058 line_list=line.split(' ')
00059 max_rss=line_list[3]
00060 break
00061 i+=1
00062
00063
00064 IB=os.path.basename(commands.getoutput("echo $CMSSW_BASE"))
00065
00066
00067
00068 try:
00069
00070 regex="^\d+\.?\d*$"
00071 if average == ' ' or re.match(regex, average) is None:
00072 raise RuntimeError('Could not parse \"' + timelog + '\" properly. ' +\
00073 'Check if Average Time is defined correctly.')
00074 if error == ' ' or re.match(regex, error) is None:
00075 raise RuntimeError('Could not parse \"' + timelog + '\" properly. ' +\
00076 'Check if Uncertainty of Average Time is defined correctly.')
00077 if max_rss == ' ' or re.match(regex, max_rss) is None:
00078 raise RuntimeError('Could not parse \"' + memlog + '\" properly. ' +\
00079 ' Check if Maximum rss is defined correct.')
00080
00081
00082 regex = '(19|20|21)\d\d-(0[1-9]|1[012])-(0[1-9]|[12]'+\
00083 '[0-9]|3[01])-([01][0-9]|2[0-4])([0-5][0-9])$'
00084 if re.search(regex, IB) is None:
00085 raise RuntimeError('Not a valid IB. Valid IB: ' +\
00086 '[CMSSW_X_X_X_YYYY-MM-DD-HHMM]')
00087 except Exception, err:
00088 sys.stderr.write(script_name + ': Error: ' + str(err) + '\n')
00089 return 2
00090
00091
00092 json_db=open(json_f, "r")
00093 dict=json.load(json_db)
00094 json_db.close()
00095
00096
00097 ib_list=IB.split('_')
00098 cmsrelease=ib_list[0] + '_' + ib_list[1] +\
00099 '_' + ib_list[2] + '_' + ib_list[3]
00100 data={"IB" : ib_list[4], "average" : float(average), "error" : float(error), "max_rss" : float(max_rss)}
00101
00102 if data in dict["strips"]:
00103 sys.stderr.write(script_name + ": Warning: Entry already exists " +\
00104 "in json file and will not be stored! " +\
00105 "Only the strip charts will be created.\n")
00106 else:
00107 dict["strips"].append(data)
00108 print 'Storing entry to \"' + json_f +\
00109 '\" file with attribute values:\n' +\
00110 'IB=' + IB + '\naverage=' + average +\
00111 '\nUncertainty of average=' + error +'\nmax_rss=' + max_rss
00112
00113 json_db = open(json_f, "w+")
00114 json.dump(dict, json_db, indent=2)
00115 json_db.close()
00116 print 'File \"%s\" was updated successfully!' % json_f
00117
00118
00119 for record in dict["strips"]:
00120 time_list = record['IB'].split('-')
00121 d = datetime(int(time_list[0]), int(time_list[1]),
00122 int(time_list[2]), int(time_list[3][0:2]),
00123 int(time_list[3][2:]))
00124 record['IB'] = d
00125
00126
00127 list = sorted(dict["strips"], key=lambda k : k['IB'], reverse=True)
00128
00129
00130 if num > len(list):
00131 new_num = len(list)
00132 sys.stderr.write(script_name + ': Warning: There are less than ' +\
00133 str(num) + ' entries in json file. Changed number to ' +\
00134 str(new_num) + '.\n')
00135 num = new_num
00136
00137
00138 ROOT.gROOT.SetStyle("Plain")
00139 outdir='.'
00140
00141
00142 rootfilename=outdir + '/histograms.root'
00143 myfile=ROOT.TFile(rootfilename, 'RECREATE')
00144
00145
00146 histo1=ROOT.TH1F("AveCPU per IB", "Ave CPU per IB", num, 0., num)
00147 histo1.SetTitle(cmsrelease + ": Showing last " + str(num) + " IB's")
00148 histo1.SetName('avecpu_histo')
00149
00150
00151 histo2=ROOT.TH1F("Max rrs per IB", "Max rss per IB", num, 0., num)
00152 histo2.SetTitle(cmsrelease + ": Showing last " + str(num) + " IB's")
00153 histo2.SetName('maxrss_histo')
00154
00155
00156
00157 for i in range(num):
00158 datime = list[i]['IB'].__format__('%Y-%b-%d %H:%M')
00159 average = list[i]['average']
00160 max_rss = list[i]['max_rss']
00161 error = list[i]['error']
00162
00163 histo1.GetXaxis().SetBinLabel(num-i, datime)
00164 histo1.SetBinContent(num-i, average)
00165 histo1.SetBinError(num-i, error)
00166 histo2.GetXaxis().SetBinLabel(num-i, datime)
00167 histo2.SetBinContent(num-i, max_rss)
00168
00169 histo1.SetStats(0)
00170 histo1.GetYaxis().SetTitle("Average CPU time")
00171 histo1.GetYaxis().SetTitleOffset(1.8)
00172 histo1.GetXaxis().SetTitle("Integration Build")
00173 histo1.GetXaxis().SetTitleOffset(4.)
00174 histo1.GetXaxis().CenterTitle()
00175 histo1.GetXaxis().LabelsOption('v')
00176
00177 min = get_min_error(list)
00178 max = get_max_error(list)
00179 interval = max - min
00180 min = min-interval*0.1
00181 max = max+interval*0.1
00182 histo1.GetYaxis().SetRangeUser(min, max)
00183
00184 histo2.SetStats(0)
00185 histo2.GetYaxis().SetTitle("Maximum rss")
00186 histo2.GetYaxis().SetTitleOffset(1.8)
00187 histo2.GetXaxis().SetTitle("Integration Build")
00188 histo2.GetXaxis().SetTitleOffset(4.)
00189 histo2.GetXaxis().CenterTitle()
00190 histo2.GetXaxis().LabelsOption('v')
00191
00192
00193
00194 ave_canvas = ROOT.TCanvas(cmsrelease + '_average_canvas')
00195 ave_canvas.SetGridy()
00196 ave_canvas.SetBottomMargin(0.28)
00197 ave_canvas.SetLeftMargin(0.18)
00198 ave_canvas.cd()
00199
00200 histo1.SetLineColor(2)
00201 histo1.SetLineWidth(2)
00202 histo1.DrawCopy("HISTO L")
00203
00204 histo1.SetLineColor(1)
00205 histo1.SetLineStyle(2)
00206 histo1.SetLineWidth(1)
00207 histo1.SetMarkerStyle(8)
00208 histo1.SetMarkerSize(.6)
00209 histo1.SetMarkerColor(1)
00210 histo1.Draw("E1P SAME")
00211 ave_canvas.Print(outdir + "/average_cpu_histo.png","png")
00212
00213 rss_canvas = ROOT.TCanvas(cmsrelease + '_maxrss_canvas')
00214 rss_canvas.SetGridy()
00215 rss_canvas.SetBottomMargin(0.28)
00216 rss_canvas.SetLeftMargin(0.18)
00217 rss_canvas.cd()
00218
00219 histo2.SetLineColor(2)
00220 histo2.SetLineWidth(2)
00221 histo2.DrawCopy("L")
00222
00223 histo2.SetMarkerStyle(8)
00224 histo2.SetMarkerSize(.6)
00225 histo2.SetMarkerColor(1)
00226 histo2.Draw("P SAME")
00227 rss_canvas.Print(outdir + "/maximum_rss_histo.png","png")
00228
00229
00230 histo1.Write()
00231 ave_canvas.Write()
00232 histo2.Write()
00233 rss_canvas.Write()
00234
00235
00236
00237
00238 if __name__ == '__main__':
00239
00240 import optparse, stat
00241
00242
00243
00244
00245 script_name= os.path.basename(__file__)
00246 usage = script_name + ' <options> -t TIMELOG -m MEMLOG'
00247 parser = optparse.OptionParser(usage)
00248 parser.add_option('-t', '--timelog',
00249 action='store',
00250 dest='timelog',
00251 default='',
00252 metavar='TIMELOG',
00253 help='input file TIMELOG, the output of cmsTiming_parser.py')
00254 parser.add_option('-m', '--memlog',
00255 action='store',
00256 dest='memlog',
00257 default='',
00258 metavar='MEMLOG',
00259 help='input file MEMLOG, the output of cmsSimplememchecker_parser.py')
00260 parser.add_option('-j', '--jsonfile',
00261 action='store',
00262 dest='json_f',
00263 default='strips.json',
00264 metavar='FILE.JSON',
00265 help='the .json file database')
00266 parser.add_option('-n', type='int',
00267 action='store',
00268 dest='num',
00269 default='30',
00270 metavar='NUM',
00271 help='last NUM entries to be printed in the strip charts. Default is 30.')
00272 (options, args) = parser.parse_args()
00273
00274
00275
00276
00277 if options.timelog == '' or\
00278 options.memlog == '':
00279 sys.exit('%s: Missing file operands!\n' % script_name+\
00280 'Type %s --help for more information!' % script_name)
00281 if not os.path.exists(options.timelog) or\
00282 not os.path.exists(options.memlog):
00283 sys.exit('%s: Error: Not present file(s)!' % script_name)
00284
00285
00286
00287
00288
00289
00290 format = "\n { \"strips\" :\n" +\
00291 " [\n {\"IB\" : \"XXX_XXX\", \"average\" : M, \"error\" : E \"max_rss\" : N},\n" +\
00292 " .........................................\n" +\
00293 " ]\n"+\
00294 " }\n"
00295
00296
00297
00298 json_db = open(options.json_f, "r+")
00299 try:
00300
00301 if os.stat(options.json_f)[stat.ST_SIZE] == 0:
00302 sys.stderr.write(script_name + ': Warning: File \"' + options.json_f +\
00303 '\" is empty. A new database will be created upon it.\n')
00304 json_db.write("{\n \"strips\" : [\n ]\n}\n")
00305 json_db.seek(0, 0)
00306
00307
00308 dict = json.load(json_db)
00309
00310
00311 dict["strips"]
00312
00313
00314 if not isinstance(dict["strips"], list):
00315 raise Exception
00316
00317
00318 if dict["strips"]:
00319 for item in dict["strips"]:
00320 if not set(['IB', 'average', 'error', 'max_rss']).issubset(item):
00321 raise KeyError
00322 except ValueError:
00323 sys.exit(script_name + ': Error: Not a valid json file! Please, check the format:\n' + format)
00324 except KeyError:
00325 sys.exit(script_name + ': Error: Invalid format in the json file! Check it here:\n' + format)
00326 finally:
00327 json_db.close()
00328
00329
00330
00331
00332
00333
00334 sys.exit(operate(options.timelog, options.memlog, options.json_f, options.num))
00335