test
CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
cmsPerfRegress.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 import time, os, sys, math, re, gzip
4 import tempfile as tmp
5 import optparse as opt
6 from cmsPerfCommons import CandFname
7 #from ROOT import gROOT, TCanvas, TF1
8 import ROOT
9 from array import array
10 #Substitute popen with subprocess.Popen! popen obsolete...
11 import subprocess
12 from functools import reduce
13 
14 _cmsver = os.environ['CMSSW_VERSION']
15 values_set=('vsize','delta_vsize','rss','delta_rss')
16 
18  """Base class for exceptions in this module."""
19  pass
20 
22  """Exception raised when Could not parse TimingReport Log.
23 
24  Attributes:
25  expression -- input expression in which the error occurred
26  message -- explanation of the error
27  """
28 
29  def __init__(self, message):
30  self.message = message
31 
33  """Exception raised when Could not parse TimingReport Log.
34 
35  Attributes:
36  expression -- input expression in which the error occurred
37  message -- explanation of the error
38  """
39 
40  def __init__(self, message):
41  self.message = message
42 
44  """Exception raised when Could not parse TimingReport Log.
45 
46  Attributes:
47  expression -- input expression in which the error occurred
48  message -- explanation of the error
49  """
50 
51  def __init__(self, message):
52  self.message = message
53 
55  """Exception raised when Could not parse TimingReport Log.
56 
57  Attributes:
58  expression -- input expression in which the error occurred
59  message -- explanation of the error
60  """
61 
62  def __init__(self, message):
63  self.message = message
64 
65 #############
66 # Option parser
67 #
69  parser = opt.OptionParser()
70  #
71  # Options
72  #
73  parser.add_option('-n',
74  type="int",
75  help='Number of secs per bin. Default is 1.' ,
76  default=1,
77  dest='startevt')
78  parser.add_option('-t',
79  '--report-type',
80  type="choice",
81  choices= ("timing", "simplememory","edmsize","igprof","callgrind",""),
82  help='Type of report to perform regrssion on. Default is TimingReport.' ,
83  default="timing",
84  dest='reporttype')
85  parser.add_option('-i',
86  '--IgProfMemOption',
87  type="choice",
88  choices= ("-y MEM_TOTAL", "-y MEM_LIVE",""),
89  help='Eventual IgProfMem counter to use for the regression. Default is no argument (IgProfPerf).' ,
90  default="",
91  dest='igprofmem')
92  (options,args) = parser.parse_args()
93  if len(args) < 2:
94  parser.error("ERROR: Not enough arguments")
95  sys.exit()
96 
97 
98  path1 = os.path.abspath(args[0])
99  path2 = os.path.abspath(args[1])
100  if os.path.exists(path1) and os.path.exists(path2):
101  return (path1, path2, options.startevt, options.reporttype, options.igprofmem)
102  else:
103  print "Error: one of the paths does not exist"
104  sys.exit()
105 
106 ###########
107 # Get max value in data set
108 #
109 def get_max(data,index=1):
110  max_time=-1
111  for el in data:
112  sec=el[index]
113  if max_time<sec:
114  max_time=sec
115  return max_time
116 
117 ###########
118 # Get min value in data set
119 #
120 def get_min(data,index=1):
121  min_time=1e20
122  for el in data:
123  sec=el[index]
124  if min_time>sec:
125  min_time=sec
126  return min_time
127 
128 ###########
129 # Setup PyRoot as a batch run
130 #
131 def setBatch():
132  __argv=sys.argv # trick for a strange behaviour of the TApp..
133  sys.argv=sys.argv[:1]
134  ROOT.gROOT.SetStyle("Plain") # style paranoia
135  sys.argv=__argv
136  #Cannot use this option when the logfile includes
137  #a large number of events... PyRoot seg-faults.
138  #Set ROOT in batch mode to avoid canvases popping up!
139  ROOT.gROOT.SetBatch(1)
140 
141 ##########
142 # Create the root file to save the graphs in
143 #
144 def createROOT(outdir,filename):
145 
146  # Save in file
147  rootfilename = os.path.join(outdir,filename)
148  myfile = None
149  exists = os.path.exists(rootfilename)
150  if exists:
151  myfile=ROOT.TFile(rootfilename,'UPDATE')
152  else:
153  myfile=ROOT.TFile(rootfilename,'RECREATE')
154  return myfile
155 
156 ##########
157 # Parse timing data from log file
158 #
159 def getTimingLogData(logfile_name):
160  data=[]
161 
162  # open file and read it and fill the structure!
163  logfile=open(logfile_name,'r')
164  logfile_lines=logfile.readlines()
165  logfile.close()
166 
167  # we get the info we need!
168  i=0
169  while i < len(logfile_lines):
170  line=logfile_lines[i]
171  if 'TimeEvent>' in line:
172  line=line.strip()
173  line_content_list = line.split(' ')[0:]
174  event_number = int(line_content_list[1])
175  seconds = float(line_content_list[3])
176  data.append((event_number,seconds))
177  i+=1
178 
179  return data
180 
181 ###########
182 # Parse memory check data from log file
183 #
184 def getSimpleMemLogData(logfile_name,startevt, candle):
185  data=[]
186  values_set=('vsize','delta_vsize','rss','delta_rss')
187 
188  # open file and read it and fill the structure!
189  logfile=open(logfile_name,'r')
190  logfile_lines=logfile.readlines()
191  logfile.close()
192 
193  step = ""
194  steps = []
195  #print candle
196  #print CandFname[candle]
197  #Get the step from log filename:
198 
199  #Catching the case of command line use in which the candle is unknown (and the log name does not match the perfsuite naming convention
200  if candle:
201  stepreg = re.compile("%s_([^_]*(_PILEUP)?)_%s((.log)|(.gz))?" % (CandFname[candle],"TimingReport"))
202  else:
203  stepreg = re.compile("([^_]*(_PILEUP)?)_%s((.log)|(.gz))?"%"TimingReport")
204 
205  #print logfile_name
206  found=stepreg.search(logfile_name)
207  if found:
208  step=found.groups()[0]
209  print "Determined step from log filename to be %s"%step
210  else:
211  print "Could not determine step from log filename"
212 
213  #steps.append((step,data))
214 
215  #Rewriting the following code... what a mess!
216  # we get the info we need!
217  #i=0
218  #while i < len(logfile_lines):
219  #line=logfile_lines[i]
220  #Format has changed... we use the output of individual steps, so no need to read into the logfile to find which step we are
221  #referring too (by the way it would not work now!)... the step info comes from the logfilename done above...
222  #if "RelValreport" in line and "cmsDriver" in line and "step" in line:
223  # stepreg = re.compile("--step=([^ ]*)")
224  # found = stepreg.search(line)
225  # if found:
226  # if step == "":
227  # step = found.groups()[0]
228  # else:
229  # steps.append((step,data))
230  # step = found.groups()[0]
231  # data = []
232  #if '%MSG-w MemoryCheck:' in line:
233  # line=line[:-1] #no \n!
234  # line_content_list=line.split(' ')
235  # event_number=int(line_content_list[-1])
236  # if event_number<startevt:
237  # i+=1
238  # continue
239  # i+=1 # we inspect the following line
240  # try:
241  # line=logfile_lines[i]
242  # except IndexError:
243  # continue
244  # line=line[:-1] #no \n!
245  # line_content_list=line.split(' ')
246  # vsize=float(line_content_list[4])
247  # delta_vsize=float(line_content_list[5])
248  # rss=float(line_content_list[7])
249  # delta_rss=float(line_content_list[8])
250  #
251  # data.append((event_number,{'vsize':vsize,
252  # 'delta_vsize':delta_vsize,
253  # 'rss':rss,
254  # 'delta_rss':delta_rss}))
255  #i += 1
256  event_number= startevt
257  for line in logfile_lines:
258  #Match SimpleMemoryCheck output to get the event number
259  if '%MSG-w MemoryCheck:' in line: #Harcoded based on format: %MSG-w MemoryCheck: PostModule 12-Jan-2009 16:00:29 CET Run: 1 Event: 1
260  tokens=line.split()
261  if int(tokens[-1])>= startevt:
262  event_number=int(tokens[-1])
263  if 'VSIZE' in line: #Harcoded based on format: MemoryCheck: event : VSIZE 648.426 0 RSS 426.332 0
264  tokens=line.split()
265  vsize=float(tokens[4])
266  delta_vsize=float(tokens[5])
267  rss=float(tokens[7])
268  delta_rss=float(tokens[8])
269  data.append((event_number,{'vsize':vsize,
270  'delta_vsize':delta_vsize,
271  'rss':rss,
272  'delta_rss':delta_rss
273  }
274  )
275  )
276 
277  if not len(data) == 0:
278  #print "!!!!!!!!!!!!!Adding step %s and data!"%step
279  steps.append((step,data))
280 
281  #print "PRINTOUT@@@@@@"
282  #print steps
283  return steps
284 
285 ###############
286 #
287 # Create a new timing graph and histogram
288 #
289 def newGraphAndHisto(histoleg,leg,npoints,nbins,min_val,max_val,data,graph_num,prevrev=""):
290 
291  colors = [2,4]
292  prevRevName = "???"
293  if not prevrev == "":
294  (head, tail) = os.path.split(prevrev)
295  prevRevName = os.path.basename(tail)
296  releaseNames = ["Previous (%s)" % prevRevName,_cmsver]
297 
298  histo=ROOT.TH1F("Seconds per event (histo: %s)" % graph_num,'Seconds per event',nbins,min_val,max_val)
299 
300  graph=ROOT.TGraph(npoints)
301 
302  evt_counter=0
303  peak = data[0][1]
304  for evt_num,secs in data:
305  if secs > peak:
306  peak = secs
307  graph.SetPoint(evt_counter,evt_num,secs)
308  histo.Fill(secs)
309  evt_counter+=1
310 
311  allsecs = []
312  map(lambda x: allsecs.append(x[1]),data)
313  total = reduce(lambda x,y: x + y,allsecs)
314  mean = total / evt_counter
315  rms = math.sqrt(reduce(lambda x,y: x + y,map(lambda x: x * x,allsecs)) / evt_counter)
316 
317 
318  graph.SetMarkerStyle(8)
319  graph.SetMarkerSize(.7)
320  graph.SetMarkerColor(1)
321  graph.SetLineWidth(3)
322  graph.SetLineColor(colors[graph_num]) # for each iterate through colors
323  histo.SetLineColor(colors[graph_num])
324  histo.SetStats(1)
325  histoleg.AddEntry(histo, "%s release" % releaseNames[graph_num], "l")
326  leg.AddEntry(graph , "%s release" % releaseNames[graph_num], "l")
327  leg.AddEntry(graph , "Mean: %s" % str(mean) , "l")
328  leg.AddEntry(graph , "RMS : %s" % str(rms) , "l")
329  leg.AddEntry(graph , "Peak: %s" % str(peak) , "l")
330  leg.AddEntry(graph , "Total time: %s" % str(total) , "l")
331  if graph_num == 0 :
332  histo.SetFillColor(colors[graph_num])
333 
334  return (graph,histo,mean)
335 
336 ###########
337 # Get limits to plot the graph
338 #
339 def getLimits(data,secsperbin):
340  min_val=get_min(data,1)
341  max_val=get_max(data,1)
342  interval=int(max_val-min_val)
343 
344  min_val=min_val-interval*0.2
345  max_val=max_val+interval*0.2
346  interval=int(max_val-min_val)
347 
348  nbins=int(interval/secsperbin)
349 
350  npoints=len(data)
351 
352  last_event=data[-1][0]
353 
354  return (min_val,max_val,interval,npoints,last_event)
355 
356 ##############
357 # Setup graph information for one graph (no need to it on both if they are superimposed)
358 #
359 def setupSuperimpose(graph1,graph2,last_event,max_val,reporttype=0, title = ""):
360  name = ""
361  xtitle = ""
362  ytitle = ""
363  if reporttype == 0:
364  title = 'Seconds per event'
365  name = 'SecondsPerEvent'
366  xtitle = "Event"
367  ytitle = "Processing time for each event (s)"
368  graph1.GetYaxis().SetRangeUser(0,max_val)
369  graph2.GetYaxis().SetRangeUser(0,max_val)
370  elif reporttype == 1:
371  name = "%s_graph" % title
372  xtitle = "Event"
373  ytitle = "MB"
374 
375  graph1.SetTitle(title)
376  graph1.SetName(name)
377  graph1.GetXaxis().SetTitle(xtitle)
378  graph1.GetYaxis().SetTitleOffset(1.3)
379  graph1.GetYaxis().SetTitle(ytitle)
380  graph1.GetXaxis().SetLimits(0,last_event)
381  # Do I need to set limits on graph 2? I don't know
382  # I'm doing it anyway, can't hurt.
383  graph2.GetXaxis().SetLimits(0,last_event)
384 
385 #############
386 # Plot the mean line on a graph
387 #
388 def getMeanLines(avg,last_event,graph_num):
389  colors = [2,4]
390  avg_line=ROOT.TLine(1,avg,last_event,avg)
391  avg_line.SetLineColor(colors[graph_num])
392  avg_line.SetLineWidth(2)
393 
394  return avg_line
395 
396 ############
397 # Get the difference in timing data (for comparison of two releases)
398 #
399 def getTimingDiff(data1,data2,npoints,last_event,orig_max_val):
400  data3 = []
401  for x in range(len(data2)):
402  try:
403  if data2[x][0] == data1[x][0]:
404  avgEventNum = data2[x][0]
405  diffSecs = data2[x][1] - data1[x][1]
406  data3.append((avgEventNum,diffSecs))
407  except IndexError:
408  pass
409  except ValueError:
410  pass
411 
412  graph=ROOT.TGraph(npoints)
413 
414  evt_counter=0
415  peak = data3[0][1]
416  for evt_num,secs in data3:
417  if secs > peak:
418  peak = secs
419  graph.SetPoint(evt_counter,evt_num,secs)
420  evt_counter+=1
421 
422  allsecs = []
423  map(lambda x: allsecs.append(x[1]),data3)
424  total = reduce(lambda x,y: x + y,allsecs)
425  mean = total / evt_counter
426  rms = math.sqrt(reduce(lambda x,y: x + y,map(lambda x: x * x,allsecs)) / evt_counter)
427 
428  min_val=get_min(data3,1)
429  max_val=get_max(data3,1)
430  interval=int(max_val-min_val)
431 
432  min_val=min_val-interval*0.2
433  max_val=max_val+interval*0.2
434  interval=int(max_val-min_val)
435 
436  # Determine the max value to be something that makes the scale similar to what
437  # the original graph had. Unless we can't seem the maximum value.
438 
439  new_max = min_val + orig_max_val
440  if new_max < max_val:
441  pass
442  else :
443  max_val = new_max
444 
445  graph.SetTitle('Change in processing time for each event between revs')
446  graph.SetName('SecondsPerEvent')
447  graph.GetXaxis().SetTitle("Event Number")
448  graph.GetYaxis().SetTitle("Change in processing time between revs (s)")
449  graph.GetYaxis().SetTitleOffset(1.3)
450  graph.SetLineColor(2)
451  graph.SetMarkerStyle(8)
452  graph.SetMarkerSize(.7)
453  graph.SetMarkerColor(1)
454  graph.SetLineWidth(3)
455  graph.GetXaxis().SetLimits(0,last_event)
456  graph.GetYaxis().SetRangeUser(min_val,max_val)
457  leg = ROOT.TLegend(0.5,0.7,0.89,0.89)
458  leg.AddEntry(graph, "Mean: %s" % str(mean), "l")
459  leg.AddEntry(graph, "RMS : %s" % str(rms) , "l")
460  leg.AddEntry(graph, "Peak: %s" % str(peak), "l")
461  leg.AddEntry(graph, "Total time change: %s" % str(total) , "l")
462 
463  return (graph,leg)
464 
465 ##########
466 # Draw superimposed graphs on a separate canvas
467 #
468 def drawGraphs(graph1,graph2,avg1,avg2,leg):
469  graph_canvas = ROOT.TCanvas("graph_canvas")
470  graph_canvas.cd()
471  graph1.Draw("ALP")
472  graph2.Draw("LP")
473  avg1.Draw("Same")
474  avg2.Draw("Same")
475  leg.Draw()
476  return graph_canvas
477 
478 ##########
479 # Draw superimposed histograms on a separate canvas
480 #
481 def drawHistos(histo_stack,hstleg):
482  histo_canvas = ROOT.TCanvas("histo_canvas")
483  histo_canvas.cd()
484  histo_stack.Draw("nostack")
485  hstleg.Draw()
486  return histo_canvas
487 
488 ##########
489 # Draw data differences (comparison between two data sets or releases) on a separate canvas
490 #
491 def drawChanges(graph,chgleg):
492  graph_canvas = ROOT.TCanvas("change_canvas")
493  graph_canvas.cd()
494  graph.Draw("ALP")
495  chgleg.Draw()
496  return graph_canvas
497 
498 ###########
499 # Get limits for two graphs that will be superimposed upon one another
500 #
501 def getTwoGraphLimits(last_event1,max_val1,last_event2,max_val2,min_val1=-1,min_val2=-1):
502  biggestLastEvt = last_event1
503  biggestMaxval = max_val1
504  lowest_val = min_val1
505 
506  if min_val2 < lowest_val:
507  lowest_val = min_val2
508  if last_event2 > biggestLastEvt:
509  biggestLastEvt = last_event2
510  if max_val2 > biggestMaxval:
511  biggestMaxval = max_val2
512  return (biggestLastEvt,biggestMaxval,lowest_val)
513 
514 def getNpoints(data):
515  new_data=[]
516  try:
517  #This was necessary due to a bug in the getSimpleMemLogData parsing!!! no more necessary!
518  if data[0][0]==data[1][0]:
519  print 'Two modules seem to have some output.\nCollapsing ...'
520  i=0
521  while True:
522  dataline1=data[i]
523  i+=1
524  dataline2=data[i]
525  new_eventnumber=dataline1[0]
526  new_vsize=dataline2[1]['vsize']
527  new_delta_vsize=dataline1[1]['delta_vsize']+dataline2[1]['delta_vsize']
528  new_rss=dataline2[1]['rss']
529  new_delta_rss=dataline1[1]['delta_rss']+dataline2[1]['delta_rss']
530 
531  new_data.append((new_eventnumber,{'vsize':new_vsize,
532  'delta_vsize':new_delta_vsize,
533  'rss':new_rss,
534  'delta_rss':new_delta_rss}))
535  i+=1
536  if i==len(data): break
537 
538  data=new_data
539  print 'Collapsing: Done!'
540  except IndexError:
541  pass
542 
543  return (data,len(data))
544 
545 ###########
546 # Create simple memory check graphs
547 #
548 def createSimplMemGraphs(data,npoints,graph_num,legs,prevrev=""):
549  colors = [2,4]
550  values = ["vsize", "rss"]
551 
552  prevRevName = "???"
553  if not prevrev == "":
554  (head, tail) = os.path.split(prevrev)
555  prevRevName = os.path.basename(tail)
556 
557  releaseNames = ["Previous (%s)" % prevRevName,_cmsver]
558 
559  #fill the graphs
560  graphs = []
561  minim = -1
562  peak = -1
563  peaks = []
564  minims = []
565  idx = 0
566  for value in values:
567  leg = legs[idx]
568 
569  graph = ROOT.TGraph(npoints)
570  graph.SetTitle(value)
571  graph.SetLineColor(colors[graph_num])
572  graph.SetMarkerStyle(8)
573  graph.SetMarkerSize(.7)
574  graph.SetMarkerColor(1)
575  graph.SetLineWidth(3)
576  graph.GetXaxis().SetTitle("Event")
577  graph.GetYaxis().SetTitleOffset(1.3)
578  graph.GetYaxis().SetTitle("MB")
579 
580  total = 0
581  point_counter=0
582  rms = 0
583  first = True
584  for event_number,vals_dict in data:
585  if first:
586  minim = vals_dict[value]
587  peak = vals_dict[value]
588  first = False
589  if vals_dict[value] > peak:
590  peak = vals_dict[value]
591  if vals_dict[value] < minim:
592  minim = vals_dict[value]
593  graph.SetPoint(point_counter, event_number, vals_dict[value])
594  total += vals_dict[value]
595  rms += vals_dict[value] * vals_dict[value]
596  point_counter+=1
597 
598  rms = math.sqrt(rms / float(point_counter))
599  mean = total / float(point_counter)
600  last_event=data[-1][0]
601  peaks.append(peak)
602  minims.append(minim)
603  graph.GetXaxis().SetRangeUser(0,last_event+1)
604  leg.AddEntry(graph , "%s release" % releaseNames[graph_num], "l")
605  leg.AddEntry(graph , "Mean: %s" % str(mean) , "l")
606  leg.AddEntry(graph , "RMS : %s" % str(rms) , "l")
607  leg.AddEntry(graph , "Peak: %s" % str(peak) , "l")
608  graphs.append(graph)
609  idx += 1
610 
611  return (graphs[0] , last_event, peaks[0], minims[0], graphs[1], last_event, peaks[1], minims[1])
612 
613 #############
614 # Produce the difference of two memory data sets
615 #
616 def getMemDiff(data1,data2,npoints,last_event,orig_max_val,stepname,rss=False):
617  data3 = []
618  memtype = "vsize"
619  if rss:
620  memtype = "rss"
621 
622  graph=ROOT.TGraph(npoints)
623  total = 0
624  rms = 0
625  evt_counter=0
626  peak = -1
627  minum = -1
628  first = True
629  for x in range(len(data2)):
630  try:
631  (evtnum2,valdict2) = data2[x]
632  (evtnum1,valdict1) = data1[x]
633  if evtnum2 == evtnum1:
634  diffMBytes = valdict2[memtype] - valdict1[memtype]
635 
636  if first:
637  peak = diffMBytes
638  minum = diffMBytes
639  first = False
640  if diffMBytes > peak:
641  peak = diffMBytes
642  if diffMBytes < minum:
643  minum = diffMBytes
644  graph.SetPoint(evt_counter,evtnum2,diffMBytes)
645  evt_counter+=1
646  total += diffMBytes
647  rms += (diffMBytes * diffMBytes)
648  except IndexError:
649  pass
650  except ValueError:
651  pass
652 
653  mean = total / evt_counter
654  rms = math.sqrt(rms / float(evt_counter))
655 
656  min_val = minum
657  max_val = peak
658  interval = int(max_val-min_val)
659 
660  min_val=min_val-interval*0.2
661  max_val=max_val+interval*0.2
662  interval=int(max_val-min_val)
663  # Determine the max value to be something that makes the scale similar to what
664  # the original graph had. Unless we can't seem the maximum value.
665 
666  new_max = min_val + orig_max_val
667  if new_max < max_val:
668  pass
669  else :
670  max_val = new_max
671 
672  graph.SetTitle("Change in %s memory usage for each event between revs for step %s" % (memtype,stepname))
673  graph.SetName('MemoryUsagePerEvent')
674  graph.GetXaxis().SetTitle("Event Number")
675  graph.GetYaxis().SetTitle("Change in memory usage between revs (MBs)")
676  graph.GetYaxis().SetTitleOffset(1.3)
677  graph.SetLineColor(2)
678  graph.SetMarkerStyle(8)
679  graph.SetMarkerSize(.7)
680  graph.SetMarkerColor(1)
681  graph.SetLineWidth(3)
682  graph.GetXaxis().SetLimits(0,last_event)
683  graph.GetYaxis().SetRangeUser(min_val,max_val)
684  leg = ROOT.TLegend(0.5,0.7,0.89,0.89)
685  leg.AddEntry(graph, "Mean: %s" % str(mean), "l")
686  leg.AddEntry(graph, "RMS : %s" % str(rms) , "l")
687  leg.AddEntry(graph, "Peak: %s" % str(peak), "l")
688  leg.AddEntry(graph, "Trough: %s" % str(minum) , "l")
689 
690  return (graph,leg)
691 
692 ############
693 # Draw two memory graphs superimposed on one another
694 #
695 def drawMemGraphs(graph1,graph2,min_val,max_val,last_event,leg,memtype,stepname):
696  graph_canvas=ROOT.TCanvas("%s_%s_canvas" % (memtype,stepname))
697  graph_canvas.cd()
698  graph1.GetYaxis().SetRangeUser(min_val,max_val)
699  graph1.GetXaxis().SetRangeUser(0,last_event)
700  graph1.Draw("ALP")
701  graph2.Draw("LP" )
702  leg.Draw()
703  graph_canvas.ForceUpdate()
704  graph_canvas.Flush()
705  return graph_canvas
706 
707 ###########
708 # Draw the comparison graphs of two memory graphs
709 #
710 def drawMemChangeGraphs(graph,leg,memtype,stepname):
711  graph_canvas=ROOT.TCanvas("%s_%s_change_canvas" % (memtype,stepname))
712  graph_canvas.cd()
713  graph.Draw("ALP" )
714  leg.Draw()
715  graph_canvas.ForceUpdate()
716  graph_canvas.Flush()
717  return graph_canvas
718 
719 def getMemOrigScale(fst_min,snd_min,fst_max,snd_max):
720  minim = fst_min
721  if snd_min < minim:
722  minim = snd_min
723  maxim = fst_max
724  if snd_max > maxim:
725  maxim = snd_max
726  return (minim,maxim)
727 
728 def cmpSimpMemReport(rootfilename,outdir,oldLogfile,newLogfile,startevt,batch=True,candle="",prevrev=""):
729  if batch:
730  setBatch()
731  # the fundamental structure: the key is the evt number the value is a list containing
732  # VSIZE deltaVSIZE RSS deltaRSS
733  print "#####LOGFILES in cmsPErfRegress:"
734  print oldLogfile
735  print newLogfile
736  try:
737  info1 = getSimpleMemLogData(oldLogfile,startevt, candle)
738  if len(info1) == 0:
739  raise IndexError
740  except IndexError:
741  raise SimpMemParseErr(oldLogfile)
742  except IOError:
743  raise SimpMemParseErr(oldLogfile)
744 
745  try:
746  info2 = getSimpleMemLogData(newLogfile,startevt, candle)
747  if len(info2) == 0:
748  raise IndexError
749  except IndexError:
750  raise SimpMemParseErr(newLogfile)
751  except IOError:
752  raise SimpMemParseErr(newLogfile)
753  #print "DDDDD info1 %s"%info1 #Format is of the type:[('GEN,SIM', [(1, {'delta_vsize': 0.0, 'delta_rss': 0.0, 'vsize': 648.42600000000004, 'rss': 426.33199999999999}), (2,{...
754  #print "DDDDD info2 %s"%info2
755  canvases = []
756  # skim the second entry when the event number is the same BUG!!!!!!!
757  # i take elements in couples!
758 
759  candreg = re.compile("(.*)(?:\.log)")
760  vsize_canvas = None
761  rss_canvas = None
762  i = 0
763  firstRoot = True
764  newrootfile = None
765  #The following whileis confusing and not necessary info1 and info2 are supposed to only contain one set of simplememorycheck numbers
766  #in a tuple as seen above ('GEN,SIM',[(event_number,{'delta_vsize': 0.0, etc
767  #The data structure is questionable... but it is a remnant of past format of the log files I guess.
768  #while ( i < len(info1) and i < len(info2)):
769  #curinfo1 = info1[i]
770  #curinfo2 = info2[i]
771  (stepname1, data1) = info1[0]
772  (stepname2, data2) = info2[0]
773 
774  #Again this is not necessary anymore...
775  #if not stepname1 == stepname2:
776  #print "WARNING: Could not compare %s step and %s step because they are not the same step" % (stepname1, stepname2)
777  # print " Searching for next occurence"
778  # x = 1
779  # if not (i + 1) > len(info1):
780  # found = False
781  # for info in info1[i + 1:]:
782  # (stepname,trash) = info
783  # if stepname == stepname2:
784  # i += x
785  #print " Next occurence found, skipping in-between steps"
786  # assert i < len(info1)
787  # found = True
788  # break
789  # x += 1
790  # if found:
791  # continue
792  # print " No more occurences of this step, continuing"
793  # i += 1
794  # continue
795 
796  #Not sure what this is for!
797  #OK it was due to the bug of duplicated info in getSimpleMemLogData parsing!
798  #No need!
799  #(data1,npoints1) = getNpoints(data1)
800  #(data2,npoints2) = getNpoints(data2)
801  npoints1=len(data1)
802  npoints2=len(data2)
803 
804  legs = []
805  leg = ROOT.TLegend(0.6,0.99,0.89,0.8)
806  legs.append(leg)
807  leg = ROOT.TLegend(0.6,0.99,0.89,0.8)
808  legs.append(leg)
809 
810  try:
811  if len(data1) == 0:
812  raise IndexError
813  (vsize_graph1,
814  vsize_lstevt1,
815  vsize_peak1,
816  vsize_minim1,
817  rss_graph1,
818  rss_lstevt1,
819  rss_peak1,
820  rss_minim1) = createSimplMemGraphs(data1,npoints1,0,legs,prevrev=prevrev)
821  #candFilename = CandFname[candle]
822  #outputdir = "%s_%s_SimpleMemReport" % (candFilename,stepname1)
823  #outputdir = os.path.join(outdir,outputdir)
824  #print "Graph1"
825  #vsize_graph1.Print()
826  except IndexError:
827  raise SimpMemParseErr(oldLogfile)
828 
829  try:
830  if len(data2) == 0:
831  raise IndexError
832  (vsize_graph2,
833  vsize_lstevt2,
834  vsize_peak2,
835  vsize_minim2,
836  rss_graph2,
837  rss_lstevt2,
838  rss_peak2,
839  rss_minim2) = createSimplMemGraphs(data2,npoints2,1,legs,prevrev=prevrev)
840  #candFilename = CandFname[candle]
841  #outputdir = "%s_%s_SimpleMemReport" % (candFilename,stepname1)
842  #outputdir = os.path.join(outdir,outputdir)
843  #print "Graph2"
844  #vsize_graph2.Print()# os.path.join(outputdir,"vsize_graph2.png"))
845  except IndexError:
846  raise SimpMemParseErr(newLogfile)
847 
848 
849  (vsize_lstevt, vsize_max_val, vsize_min_val) = getTwoGraphLimits(vsize_lstevt1, vsize_peak1, vsize_lstevt2, vsize_peak2, vsize_minim1, vsize_minim2)
850  (rss_lstevt , rss_max_val , rss_min_val) = getTwoGraphLimits(rss_lstevt1 , rss_peak1, rss_lstevt2 , rss_peak2, rss_minim1, rss_minim2)
851 
852  (vsize_min,vsize_max) = getMemOrigScale(vsize_minim1,vsize_minim2,vsize_peak1,vsize_peak2)
853  (rss_min ,rss_max ) = getMemOrigScale(rss_minim1,rss_minim2,rss_peak1,rss_peak2)
854 
855  setupSuperimpose(vsize_graph1,
856  vsize_graph2,
857  vsize_lstevt,
858  0,
859  reporttype = 1,
860  title = "%s_vsize" % stepname1)
861  setupSuperimpose(rss_graph1 ,
862  rss_graph2 ,
863  rss_lstevt ,
864  0,
865  reporttype = 1,
866  title = "%s_rss" % stepname2)
867 
868  (vsizePerfDiffgraph, vsizeleg) = getMemDiff(data1,data2,npoints2,vsize_lstevt, (vsize_max - vsize_min), stepname1, rss=False)
869  (rssPerfDiffgraph, rssleg) = getMemDiff(data1,data2,npoints2,rss_lstevt , (rss_max - rss_min) , stepname1, rss=True )
870 
871  vsize_canvas = drawMemGraphs(vsize_graph1, vsize_graph2, vsize_min_val, vsize_max_val, vsize_lstevt, legs[0], "vsize", stepname1)
872  rss_canvas = drawMemGraphs(rss_graph1 , rss_graph2 , rss_min_val, rss_max_val, rss_lstevt, legs[1], "rss" , stepname1)
873  vsize_change_canvas = drawMemChangeGraphs(vsizePerfDiffgraph, vsizeleg, "vsize", stepname1)
874  rss_change_canvas = drawMemChangeGraphs(rssPerfDiffgraph , rssleg , "rss" , stepname1)
875 
876  if batch:
877 
878 
879  logcandle = ""
880  candname = ""
881  found = candreg.search(os.path.basename(newLogfile))
882 
883  if found:
884  logcandle = found.groups()[0]
885 
886  if candle in CandFname:
887  candFilename = CandFname[candle]
888  elif logcandle in CandFname:
889  candFilename = CandFname[logcandle]
890  else:
891  print "%s is an unknown candle!"%candle
892  candFilename = "Unknown-candle"
893 
894  outputdir = "%s_%s_SimpleMemReport" % (candFilename,stepname1)
895  outputdir = os.path.join(outdir,outputdir)
896 
897  if not os.path.exists(outputdir):
898  os.mkdir(outputdir)
899 
900  #print the graphs as files :)
901 
902  newrootfile = createROOT(outputdir,rootfilename)
903 
904  vsize_canvas.Print( os.path.join(outputdir,"vsize_graphs.png"), "png")
905  rss_canvas.Print( os.path.join(outputdir,"rss_graphs.png" ), "png")
906  vsize_change_canvas.Print(os.path.join(outputdir,"vsize_change.png"), "png")
907  rss_change_canvas.Print( os.path.join(outputdir,"rss_change.png" ), "png")
908  # write it on file
909  map(lambda x: x.Write(), [vsize_graph1,vsize_graph2, rss_graph1, rss_graph2, vsizePerfDiffgraph, rssPerfDiffgraph])
910  map(lambda x: x.Write(), [vsize_canvas,rss_canvas,vsize_change_canvas,rss_change_canvas])
911  newrootfile.Close()
912  else:
913  # we have to do this if we are running the application standalone
914  # For some reason it will not draw some graphs at all if there is more than
915  # one step.
916  # If we wait between iterations of this loop the graphs will be drawn correctly.
917  # Perhaps a graphics buffer problem with ROOT?
918  # Perhaps a garbage collection problem in python? (Doubt it)
919  canvases.append(rss_canvas)
920  canvases.append(vsize_canvas)
921  canvases.append(vsize_change_canvas)
922  canvases.append(rss_change_canvas)
923  time.sleep(5.0)
924 
925  #Eliminated the while loop!
926  #i += 1
927 
928  #
929  # Create a one dimensional function and draw it
930  #
931 
932  if batch:
933  pass
934  else:
935  if len(canvases) > 0:
936  while reduce(lambda x,y: x or y ,canvases):
937  time.sleep(2.5)
938  return 0
939 
940 
941 def cmpTimingReport(rootfilename,outdir,oldLogfile,newLogfile,secsperbin,batch=True,prevrev=""):
942  if batch:
943  setBatch()
944 
945  data1 = getTimingLogData(oldLogfile)
946  data2 = getTimingLogData(newLogfile)
947 
948  try:
949  (min_val1,max_val1,nbins1,npoints1,last_event1) = getLimits(data1,secsperbin)
950  except IndexError as detail:
951  raise TimingParseErr(oldLogfile)
952 
953  try:
954  (min_val2,max_val2,nbins2,npoints2,last_event2) = getLimits(data2,secsperbin)
955  except IndexError as detail:
956  raise TimingParseErr(newLogfile)
957 
958  hsStack = ROOT.THStack("hsStack","Histogram Comparison")
959  leg = ROOT.TLegend(0.6,0.99,0.89,0.8)
960  histoleg = ROOT.TLegend(0.5,0.8,0.89,0.89)
961 
962  #
963 
964  (graph1,histo1,mean1) = newGraphAndHisto(histoleg,leg,npoints1,nbins1,min_val1,max_val1,data1,0,prevrev)
965  hsStack.Add(histo1)
966  (graph2,histo2,mean2) = newGraphAndHisto(histoleg,leg,npoints2,nbins2,min_val2,max_val2,data2,1,prevrev)
967  hsStack.Add(histo2)
968 
969  (biggestLastEvt,biggestMaxval, trashthis) = getTwoGraphLimits(last_event1,max_val1,last_event2,max_val2,min_val1,min_val2)
970 
971  (changegraph,chgleg) = getTimingDiff(data1,data2,npoints2,biggestLastEvt,biggestMaxval)
972  setupSuperimpose(graph1,graph2,biggestLastEvt,biggestMaxval)
973  avg_line1 = getMeanLines(mean1,last_event1,0)
974  avg_line2 = getMeanLines(mean2,last_event2,1)
975 
976  #
977  # Create a one dimensional function and draw it
978  #
979  histo1.GetXaxis().SetTitle("s")
980  graph_canvas = drawGraphs(graph1,graph2,avg_line1,avg_line2,leg)
981  changes_canvas = drawChanges(changegraph,chgleg)
982  histo_canvas = drawHistos(hsStack,histoleg)
983 
984  newrootfile = None
985  if batch:
986 
987  newrootfile = createROOT(outdir,rootfilename)
988 
989  cput = ROOT.TTree()
990  # array(typecode, initializer)
991  # typecode is i for int, f for float etc.
992  tot_a1 = array( "f", [ 0 ] )
993  tot_a2 = array( "f", [ 0 ] )
994 
995  tot_a1[0] = mean1
996  tot_a2[0] = mean2
997 
998  cput.Branch("total1",tot_a1,"total1/F")
999  cput.Branch("total2",tot_a2,"total2/F")
1000  cput.Fill()
1001  cput.Write("cpu_time_tuple",ROOT.TObject.kOverwrite)
1002 
1003  names = ["graphs.png","changes.png","histos.png"]
1004 
1005  graph_canvas.Print( os.path.join(outdir,names[0]),"png")
1006  changes_canvas.Print(os.path.join(outdir,names[1]),"png")
1007  histo_canvas.Print( os.path.join(outdir,names[2]),"png")
1008 
1009  map(lambda x:x.Write(),[graph1,graph2,changegraph,hsStack,histo1,histo2])
1010 
1011  graph_canvas.Write() # to file
1012  changes_canvas.Write()
1013  histo_canvas.Write()
1014  newrootfile.Close()
1015 
1016  return names
1017  else:
1018 
1019  while graph_canvas or histo_canvas or changes_canvas:
1020  time.sleep(2.5)
1021  return 0
1022 
1023 def rmtree(path):
1024  try:
1025  #os.remove(path)
1026  #Brute force solution:
1027  RemoveCmd="rm -Rf %s"%path
1028  os.system(RemoveCmd)
1029  except OSError as detail:
1030  if detail.errno == 39:
1031  try:
1032  gen = os.walk(path)
1033  nodes = next(gen)
1034  nodes[0] = par
1035  nodes[1] = dirs
1036  nodes[2] = files
1037  for f in files:
1038  os.remove(os.path.join(path,f))
1039  for d in dirs:
1040  rmtree(os.path.join(path,d))
1041  except OSError as detail:
1042  print detail
1043  except IOError as detail:
1044  print detail
1045  os.remove(path)
1046 
1047 def perfreport(perftype,file1,file2,outdir,IgProfMemopt=""):
1048  src = ""
1049  try:
1050  src = os.environ["CMSSW_SEARCH_PATH"]
1051  except KeyError as detail:
1052  print "ERROR: scramv1 environment could not be located", detail
1053 
1054  vars = src.split(":")
1055  loc = vars[0]
1056 
1057  proftype = ""
1058  if perftype == 0: # EdmSize
1059  proftype = "-fe"
1060  elif perftype == 1: # IgProf
1061  proftype = "-fi"
1062  else: # Callgrind
1063  proftype = "-ff"
1064 
1065  cmssw_release_base = ""
1066  cmssw_data = ""
1067  try:
1068  cmssw_release_base = os.environ['CMSSW_RELEASE_BASE']
1069  cmssw_data = os.environ['CMSSW_DATA_PATH']
1070  except KeyError as detail:
1071  raise PerfReportErr
1072 
1073  xmlfile = os.path.join(cmssw_release_base,"src","Validation","Performance","doc","regress.xml")
1074 
1075  prRoot = "/afs/cern.ch/user/g/gbenelli/public/PerfReport2/2.0.1"
1076 
1077  # this might be useful at some point
1078  #cd %s ; eval `scramv1 runtime -csh` ; source $CMSSW_DATA_PATH/perfreport/2.0.0/etc/profile.d/init.csh; cd - ; %s\"" % (loc,perfcmd)
1079 
1080  # Before adding Danilo's 2.1 we did this
1081  #perfcmd = "perfreport -tmp %s -i %s -r %s -o %s" % (proftype,file2,file1,outdir)
1082  #cmd = "tcsh -c \"source %s/perfreport/2.0.0/etc/profile.d/init.csh; cd - ; %s\"" % (cmssw_data,perfcmd)
1083 
1084  # now we do
1085 
1086  tmpdir = tmp.mkdtemp(prefix=os.path.join(outdir,"tmp"))
1087 
1088  perfcmd = "%s %s %s -c %s -t%s -i %s -r %s -o %s" % (os.path.join(prRoot,"bin","perfreport"),proftype,IgProfMemopt,xmlfile,tmpdir,file2,file1,outdir)
1089  cmd = "tcsh -c \"cd %s ; eval `scramv1 runtime -csh` ; cd - ;source %s/etc/profile.d/init.csh ; %s\"" % (loc,prRoot,perfcmd)
1090  #Obsolete popen4-> subprocess.Popen
1091  #process = os.popen(cmd)
1092  process = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
1093  exitstat = process.wait()
1094  cmdout = process.stdout.read()
1095  exitstat = process.returncode
1096 
1097  try:
1098  rmtree(tmpdir) #Brute force solution rm -RF tmpdir done in rmtree()
1099  #os.rmdir(tmpdir)
1100  except IOError as detail:
1101  print "WARNING: Could not remove dir because IO%s" % detail
1102  except OSError as detail:
1103  print "WARNING: Could not remove dir because %s" % detail
1104 
1105  if True:
1106  print cmd
1107  print cmdout
1108 
1109  if not exitstat == None:
1110  sig = exitstat >> 16 # Get the top 16 bits
1111  xstatus = exitstat & 0xffff # Mask out all bits except the bottom 16
1112  raise PerfReportErr("ERROR: PerfReport returned a non-zero exit status (%s, SIG_INT = %s) run %s. Dump follows: \n%s" % (perfcmd,xstatus,sig,cmdout))
1113 
1114 
1115 def cmpEdmSizeReport(outdir,file1,file2):
1116  perfreport(0,file1,file2,outdir)
1117 
1118 def ungzip(inf,outh):
1119  gzf = gzip.open(inf,"r")
1120  print "ungzipping"
1121  for char in gzf:
1122  os.write(outh,char)
1123  os.close(outh)
1124  print "finish ungzipping"
1125  gzf.close()
1126 
1127 def ungzip2(inf,out):
1128  os.system("gzip -c -d %s > %s" % (inf,out))
1129 
1130 def cmpIgProfReport(outdir,file1,file2,IgProfMemOpt=""):
1131  (tfile1, tfile2) = ("", "")
1132  try:
1133  # don't make temp files in /tmp because it's never bloody big enough
1134  (th1, tfile1) = tmp.mkstemp(prefix=os.path.join(outdir,"igprofRegressRep."))
1135  (th2, tfile2) = tmp.mkstemp(prefix=os.path.join(outdir,"igprofRegressRep."))
1136  os.close(th1)
1137  os.close(th2)
1138  os.remove(tfile1)
1139  os.remove(tfile2)
1140  ungzip2(file1,tfile1)
1141  ungzip2(file2,tfile2)
1142 
1143  perfreport(1,tfile1,tfile2,outdir,IgProfMemOpt)
1144 
1145  os.remove(tfile1)
1146  os.remove(tfile2)
1147  except OSError as detail:
1148  raise PerfReportErr("WARNING: The OS returned the following error when comparing %s and %s\n%s" % (file1,file2,str(detail)))
1149  if os.path.exists(tfile1):
1150  os.remove(tfile1)
1151  if os.path.exists(tfile2):
1152  os.remove(tfile2)
1153  except IOError as detail:
1154  raise PerfReportErr("IOError: When comparing %s and %s using temporary files %s and %s. Error message:\n%s" % (file1,file2,tfile1,tfile2,str(detail)))
1155  if os.path.exists(tfile1):
1156  os.remove(tfile1)
1157  if os.path.exists(tfile2):
1158  os.remove(tfile2)
1159 
1160 
1161 def cmpCallgrindReport(outdir,file1,file2):
1162  perfreport(2,file1,file2,outdir)
1163 
1164 def _main():
1165  outdir = os.getcwd()
1166 
1167  (file1,file2,secsperbin,reporttype,IgProfMemOptions) = getParameters()
1168 
1169  try:
1170  if reporttype == "timing":
1171  rootfilename = "timingrep-regression.root"
1172  cmpTimingReport(rootfilename ,outdir,file1,file2,secsperbin,True)
1173  elif reporttype == "simplememory":
1174  rootfilename = "simpmem-regression.root"
1175  cmpSimpMemReport(rootfilename,outdir,file1,file2,secsperbin,True)
1176  elif reporttype == "edmsize":
1177  cmpEdmSizeReport(outdir,file1,file2)
1178  elif reporttype == "callgrind":
1179  cmpCallgrindReport(outdir,file1,file2)
1180  elif reporttype == "igprof":
1181  cmpIgProfReport(outdir,file1,file2,IgProfMemOptions)
1182  except TimingParseErr as detail:
1183  print "WARNING: Could not parse data from Timing report file %s; not performing regression" % detail.message
1184  except SimpMemParseErr as detail:
1185  print "WARNING: Could not parse data from Memory report file %s; not performing regression" % detail.message
1186  except PerfReportErr as detail:
1187  print "WARNING: Could not parse data from Edm file %s; not performing regression" % detail.message
1188  except IOError as detail:
1189  print detail
1190  except OSError as detail:
1191  print detail
1192 
1193 if __name__ == "__main__":
1194  _main()
1195 
def getMeanLines
Plot the mean line on a graph.
def getTwoGraphLimits
Get limits for two graphs that will be superimposed upon one another.
tuple array
Definition: mps_check.py:181
def getMemDiff
Produce the difference of two memory data sets.
def setBatch
Setup PyRoot as a batch run.
def getLimits
Get limits to plot the graph.
def createSimplMemGraphs
Create simple memory check graphs.
def newGraphAndHisto
Create a new timing graph and histogram.
def drawMemGraphs
Draw two memory graphs superimposed on one another.
def drawMemChangeGraphs
Draw the comparison graphs of two memory graphs.
def get_max
Get max value in data set.
def setupSuperimpose
Setup graph information for one graph (no need to it on both if they are superimposed) ...
def drawChanges
Draw data differences (comparison between two data sets or releases) on a separate canvas...
def drawGraphs
Draw superimposed graphs on a separate canvas.
def getTimingDiff
Get the difference in timing data (for comparison of two releases)
def getSimpleMemLogData
Parse memory check data from log file.
def getTimingLogData
Parse timing data from log file.
def get_min
Get min value in data set.
def drawHistos
Draw superimposed histograms on a separate canvas.
def createROOT
Create the root file to save the graphs in.