CMS 3D CMS Logo

edmTracerCompactLogViewer.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 from __future__ import print_function
3 from builtins import range
4 from itertools import groupby
5 from operator import attrgetter,itemgetter
6 import sys
7 from collections import defaultdict
8 #----------------------------------------------
9 def printHelp():
10  s = '''
11 To Use: Add the Tracer Service to the cmsRun job use something like this
12  in the configuration:
13 
14  process.add_(cms.Service("Tracer", fileName = cms.untracked.string("tracer.log")))
15 
16  After running the job, execute this script and pass the name of the
17  Tracer log file to the script.
18 
19  This script will output a more human readable form of the data in the Tracer log file.'''
20  return s
21 
22 #these values come from tracer_setupFile.cc
23 #enum class Step : char {
24 # preSourceTransition = 'S',
25 # postSourceTransition = 's',
26 # preModulePrefetching = 'P',
27 # postModulePrefetching = 'p',
28 # preModuleEventAcquire = 'A',
29 # postModuleEventAcquire = 'a',
30 # preModuleTransition = 'M',
31 # preEventReadFromSource = 'R',
32 # postEventReadFromSource = 'r',
33 # preModuleEventDelayedGet = 'D',
34 # postModuleEventDelayedGet = 'd',
35 # postModuleTransition = 'm',
36 # preESModulePrefetching = 'Q',
37 # postESModulePrefetching = 'q',
38 # preESModule = 'N',
39 # postESModule = 'n',
40 # preESModuleAcquire = 'B',
41 # postESModuleAcquire = 'b',
42 # preFrameworkTransition = 'F',
43 # postFrameworkTransition = 'f'
44 #};
45 
46 
47 #Special names
48 kSourceFindEvent = "sourceFindEvent"
49 kSourceDelayedRead ="sourceDelayedRead"
50 
51 #these values must match the enum class Phase in tracer_setupFile.cc
52 class Phase (object):
53  destruction = -14
54  endJob = -11
55  endStream = -10
56  writeProcessBlock = -9
57  endProcessBlock = -8
58  globalWriteRun = -6
59  globalEndRun = -5
60  streamEndRun = -4
61  globalWriteLumi = -3
62  globalEndLumi = -2
63  streamEndLumi = -1
64  Event = 0
65  streamBeginLumi = 1
66  globalBeginLumi = 2
67  streamBeginRun = 4
68  globalBeginRun = 5
69  accessInputProcessBlock = 7
70  beginProcessBlock = 8
71  beginStream = 10
72  beginJob = 11
73  esSync = 12
74  esSyncEnqueue = 13
75  construction = 14
76  startTracing = 15
77 
78 
79 def transitionName(transition):
80  if transition == Phase.startTracing:
81  return 'start tracing'
82  if transition == Phase.construction:
83  return 'construction'
84  if transition == Phase.destruction:
85  return 'destruction'
86  if transition == Phase.beginJob:
87  return 'begin job'
88  if transition == Phase.endJob:
89  return 'end job'
90  if transition == Phase.beginStream:
91  return 'begin stream'
92  if transition == Phase.endStream:
93  return 'end stream'
94  if transition == Phase.beginProcessBlock:
95  return 'begin process block'
96  if transition == Phase.endProcessBlock:
97  return 'end process block'
98  if transition == Phase.accessInputProcessBlock:
99  return 'access input process block'
100  if transition == Phase.writeProcessBlock:
101  return 'write process block'
102  if transition == Phase.globalBeginRun:
103  return 'global begin run'
104  if transition == Phase.globalEndRun:
105  return 'global end run'
106  if transition == Phase.globalWriteRun:
107  return 'global write run'
108  if transition == Phase.streamBeginRun:
109  return 'stream begin run'
110  if transition == Phase.streamEndRun:
111  return 'stream end run'
112  if transition == Phase.globalBeginLumi:
113  return 'global begin lumi'
114  if transition == Phase.globalEndLumi:
115  return 'global end lumi'
116  if transition == Phase.globalWriteLumi:
117  return 'global write lumi'
118  if transition == Phase.streamBeginLumi:
119  return 'stream begin lumi'
120  if transition == Phase.streamEndLumi:
121  return 'stream end lumi'
122  if transition == Phase.esSyncEnqueue:
123  return 'EventSetup synchronization'
124  if transition == Phase.esSync:
125  return 'EventSetup synchronization'
126  if transition == Phase.Event:
127  return 'event'
128 
129 def transitionIndentLevel(transition):
130  if transition == Phase.startTracing:
131  return 0
132  if transition == Phase.construction or transition == Phase.destruction:
133  return 0
134  if transition == Phase.endJob or transition == Phase.beginJob:
135  return 0
136  if transition == Phase.beginStream or transition == Phase.endStream:
137  return 0
138  if transition == Phase.beginProcessBlock or transition == Phase.endProcessBlock:
139  return 1
140  if transition == Phase.accessInputProcessBlock:
141  return 1
142  if transition == Phase.writeProcessBlock:
143  return 1
144  if transition == Phase.globalBeginRun or Phase.globalEndRun == transition:
145  return 1
146  if transition == Phase.globalWriteRun:
147  return 1
148  if transition == Phase.streamBeginRun or Phase.streamEndRun == transition:
149  return 1
150  if transition == Phase.globalBeginLumi or Phase.globalEndLumi == transition:
151  return 2
152  if transition == Phase.globalWriteLumi:
153  return 2
154  if transition == Phase.streamBeginLumi or Phase.streamEndLumi == transition:
155  return 2
156  if transition == Phase.Event:
157  return 3
158  if transition == Phase.esSyncEnqueue or transition == Phase.esSync:
159  return 1
160  return None
161 
162 def textPrefix_(time, indentLevel):
163  #using 11 spaces for time should accomodate a job that runs 24 hrs
164  return f'{time:>11} '+"++"*indentLevel
165 
167  def __init__(self, payload):
168  self.transition = int(payload[0])
169  self.index = int(payload[1])
170  self.sync = (int(payload[2]), int(payload[3]), int(payload[4]))
171  self.time = int(payload[5])
172  def indentLevel(self):
173  return transitionIndentLevel(self.transition)
174  def textPrefix(self):
175  return textPrefix_(self.time, self.indentLevel())
176  def syncText(self):
177  if self.transition == Phase.globalBeginRun or Phase.globalEndRun == self.transition:
178  return f'run={self.sync[0]}'
179  if self.transition == Phase.globalWriteRun:
180  return f'run={self.sync[0]}'
181  if self.transition == Phase.streamBeginRun or Phase.streamEndRun == self.transition:
182  return f'run={self.sync[0]}'
183  if self.transition == Phase.globalBeginLumi or Phase.globalEndLumi == self.transition:
184  return f'run={self.sync[0]} lumi={self.sync[1]}'
185  if self.transition == Phase.globalWriteLumi:
186  return f'run={self.sync[0]} lumi={self.sync[1]}'
187  if self.transition == Phase.streamBeginLumi or Phase.streamEndLumi == self.transition:
188  return f'run={self.sync[0]} lumi={self.sync[1]}'
189  if self.transition == Phase.Event:
190  return f'run={self.sync[0]} lumi={self.sync[1]} event={self.sync[2]}'
191  if self.transition == Phase.esSyncEnqueue or self.transition == Phase.esSync:
192  return f'run={self.sync[0]} lumi={self.sync[1]}'
193  if self.transition == Phase.beginJob:
194  return ''
195  if self.transition == Phase.beginProcessBlock or self.transition == Phase.endProcessBlock or self.transition == Phase.writeProcessBlock or self.transition == Phase.accessInputProcessBlock:
196  return ''
197  if self.transition == Phase.startTracing:
198  return ''
199  if self.transition == Phase.construction or self.transition == Phase.destruction:
200  return ''
201  def textPostfix(self):
202  return f'{transitionName(self.transition)} : id={self.index} {self.syncText()}'
203  def text(self, context):
204  return f'{self.textPrefix()} {self.textSpecial()}: {self.textPostfix()}'
205 
207  def __init__(self, payload):
208  super().__init__(payload)
209  def textSpecial(self):
210  return "starting"
211 
212 
214  def __init__(self, payload):
215  super().__init__(payload)
216  def textSpecial(self):
217  return "finished"
218 
220  def __init__(self, payload):
221  super().__init__(payload)
222  def textSpecial(self):
223  return "queuing"
224 
226  def __init__(self, payload):
227  self.transition = int(payload[0])
228  self.index = int(payload[1])
229  self.time = int(payload[2])
230  def indentLevel(self):
231  if self.transition == Phase.globalBeginRun:
232  return 1
233  if self.transition == Phase.globalBeginLumi:
234  return 2
235  if self.transition == Phase.Event:
236  return 3
237  if self.transition == Phase.construction:
238  return 1
239  return None
240  def textPrefix(self):
241  return textPrefix_(self.time, self.indentLevel())
242  def textPostfix(self):
243  return f'source during {transitionName(self.transition)} : id={self.index}'
244  def text(self, context):
245  return f'{self.textPrefix()} {self.textSpecial()}: {self.textPostfix()}'
246 
248  def __init__(self, payload):
249  super().__init__(payload)
250  def textSpecial(self):
251  return "starting"
252 
254  def __init__(self, payload):
255  super().__init__(payload)
256  def textSpecial(self):
257  return "finished"
258 
260  def __init__(self, payload, moduleNames):
261  self.transition = int(payload[0])
262  self.index = int(payload[1])
263  self.moduleID = int(payload[2])
264  self.moduleName = moduleNames[self.moduleID]
265  self.requestingModuleID = int(payload[3])
267  if self.requestingModuleID != 0:
268  self.requestingModuleName = moduleNames[self.requestingModuleID]
269  self.time = int(payload[4])
270  def baseIndentLevel(self):
271  return transitionIndentLevel(self.transition)
272  def textPrefix(self, context):
273  indent = 0
274  if self.requestingModuleID != 0:
275  indent = context[(self.transition, self.index, self.requestingModuleID)]
276  context[(self.transition, self.index, self.moduleID)] = indent+1
277  return textPrefix_(self.time, indent+1+self.baseIndentLevel())
278  def textPostfix(self):
279  return f'{self.moduleName} during {transitionName(self.transition)} : id={self.index}'
280  def text(self, context):
281  return f'{self.textPrefix(context)} {self.textSpecial()}: {self.textPostfix()}'
282 
284  def __init__(self, payload, names):
285  super().__init__(payload, names)
286  def textSpecial(self):
287  return "starting action"
288 
290  def __init__(self, payload, names):
291  super().__init__(payload, names)
292  def textSpecial(self):
293  return "finished action"
294 
296  def __init__(self, payload, names):
297  super().__init__(payload, names)
298  def textSpecial(self):
299  return "starting prefetch"
300 
302  def __init__(self, payload, names):
303  super().__init__(payload, names)
304  def textSpecial(self):
305  return "finished prefetch"
306 
308  def __init__(self, payload, names):
309  super().__init__(payload, names)
310  def textSpecial(self):
311  return "starting acquire"
312 
314  def __init__(self, payload, names):
315  super().__init__(payload, names)
316  def textSpecial(self):
317  return "finished acquire"
318 
320  def __init__(self, payload, names):
321  super().__init__(payload, names)
322  def textSpecial(self):
323  return "starting delayed get"
324 
326  def __init__(self, payload, names):
327  super().__init__(payload, names)
328  def textSpecial(self):
329  return "finished delayed get"
330 
332  def __init__(self, payload, names):
333  super().__init__(payload, names)
334  def textSpecial(self):
335  return "starting read from source"
336 
338  def __init__(self, payload, names):
339  super().__init__(payload, names)
340  def textSpecial(self):
341  return "finished read from source"
342 
344  def __init__(self, payload, moduleNames, esModuleNames, recordNames):
345  self.transition = int(payload[0])
346  self.index = int(payload[1])
347  self.moduleID = int(payload[2])
348  self.moduleName = esModuleNames[self.moduleID]
349  self.recordID = int(payload[3])
350  self.recordName = recordNames[self.recordID]
351  self.requestingModuleID = int(payload[4])
353  if self.requestingModuleID < 0 :
354  self.requestingModuleName = esModuleNames[-1*self.requestingModuleID]
355  else:
356  self.requestingModuleName = moduleNames[self.requestingModuleID]
357  self.time = int(payload[5])
358  def baseIndentLevel(self):
359  return transitionIndentLevel(self.transition)
360  def textPrefix(self, context):
361  indent = 0
362  indent = context[(self.transition, self.index, self.requestingModuleID)]
363  context[(self.transition, self.index, -1*self.moduleID)] = indent+1
364  return textPrefix_(self.time, indent+1+self.baseIndentLevel())
365  def textPostfix(self):
366  return f'esmodule {self.moduleName} in record {self.recordName} during {transitionName(self.transition)} : id={self.index}'
367  def text(self, context):
368  return f'{self.textPrefix(context)} {self.textSpecial()}: {self.textPostfix()}'
369 
371  def __init__(self, payload, names, esNames, recordNames):
372  super().__init__(payload, names, esNames, recordNames)
373  def textSpecial(self):
374  return "starting action"
375 
377  def __init__(self, payload, names, esNames, recordNames):
378  super().__init__(payload, names, esNames, recordNames)
379  def textSpecial(self):
380  return "finished action"
381 
383  def __init__(self, payload, names, esNames, recordNames):
384  super().__init__(payload, names, esNames, recordNames)
385  def textSpecial(self):
386  return "starting prefetch"
387 
389  def __init__(self, payload, names, esNames, recordNames):
390  super().__init__(payload, names, esNames, recordNames)
391  def textSpecial(self):
392  return "finished prefetch"
393 
395  def __init__(self, payload, names, recordNames):
396  super().__init__(payload, names, recordNames)
397  def textSpecial(self):
398  return "starting acquire"
399 
401  def __init__(self, payload, names, esNames, recordNames):
402  super().__init__(payload, names, esNames, recordNames)
403  def textSpecial(self):
404  return "finished acquire"
405 
406 
407 def lineParserFactory (step, payload, moduleNames, esModuleNames, recordNames, frameworkOnly):
408  if step == 'F':
409  parser = PreFrameworkTransitionParser(payload)
410  if parser.transition == Phase.esSyncEnqueue:
411  return QueuingFrameworkTransitionParser(payload)
412  return parser
413  if step == 'f':
414  return PostFrameworkTransitionParser(payload)
415  if step == 'S':
416  return PreSourceTransitionParser(payload)
417  if step == 's':
418  return PostSourceTransitionParser(payload)
419  if frameworkOnly:
420  return None
421  if step == 'M':
422  return PreEDModuleTransitionParser(payload, moduleNames)
423  if step == 'm':
424  return PostEDModuleTransitionParser(payload, moduleNames)
425  if step == 'P':
426  return PreEDModulePrefetchingParser(payload, moduleNames)
427  if step == 'p':
428  return PostEDModulePrefetchingParser(payload, moduleNames)
429  if step == 'A':
430  return PreEDModuleAcquireParser(payload, moduleNames)
431  if step == 'a':
432  return PostEDModuleAcquireParser(payload, moduleNames)
433  if step == 'D':
434  return PreEDModuleEventDelayedGetParser(payload, moduleNames)
435  if step == 'd':
436  return PostEDModuleEventDelayedGetParser(payload, moduleNames)
437  if step == 'R':
438  return PreEventReadFromSourceParser(payload, moduleNames)
439  if step == 'r':
440  return PostEventReadFromSourceParser(payload, moduleNames)
441  if step == 'N':
442  return PreESModuleTransitionParser(payload, moduleNames, esModuleNames, recordNames)
443  if step == 'n':
444  return PostESModuleTransitionParser(payload, moduleNames, esModuleNames, recordNames)
445  if step == 'Q':
446  return PreESModulePrefetchingParser(payload, moduleNames, esModuleNames, recordNames)
447  if step == 'q':
448  return PostESModulePrefetchingParser(payload, moduleNames, esModuleNames, recordNames)
449  if step == 'B':
450  return PreESModuleAcquireParser(payload, moduleNames, esModuleNames, recordNames)
451  if step == 'b':
452  return PostESModuleAcquireParser(payload, moduleNames, esModuleNames, recordNames)
453 
454 
455 #----------------------------------------------
456 def processingStepsFromFile(f,moduleNames, esModuleNames, recordNames, frameworkOnly):
457  for rawl in f:
458  l = rawl.strip()
459  if not l or l[0] == '#':
460  continue
461  (step,payload) = tuple(l.split(None,1))
462  payload=payload.split()
463 
464  parser = lineParserFactory(step, payload, moduleNames, esModuleNames, recordNames, frameworkOnly)
465  if parser:
466  yield parser
467  return
468 
470  def __init__(self,f, frameworkOnly):
471  streamBeginRun = str(Phase.streamBeginRun)
472  numStreams = 0
473  numStreamsFromSource = 0
474  moduleNames = {}
475  esModuleNames = {}
476  recordNames = {}
477  for rawl in f:
478  l = rawl.strip()
479  if l and l[0] == 'M':
480  i = l.split(' ')
481  if i[3] == streamBeginRun:
482  #found global begin run
483  numStreams = int(i[1])+1
484  break
485  if numStreams == 0 and l and l[0] == 'S':
486  s = int(l.split(' ')[1])
487  if s > numStreamsFromSource:
488  numStreamsFromSource = s
489  if len(l) > 5 and l[0:2] == "#M":
490  (id,name)=tuple(l[2:].split())
491  moduleNames[int(id)] = name
492  continue
493  if len(l) > 5 and l[0:2] == "#N":
494  (id,name)=tuple(l[2:].split())
495  esModuleNames[int(id)] = name
496  continue
497  if len(l) > 5 and l[0:2] == "#R":
498  (id,name)=tuple(l[2:].split())
499  recordNames[int(id)] = name
500  continue
501 
502  self._f = f
503  self._frameworkOnly = frameworkOnly
504  if numStreams == 0:
505  numStreams = numStreamsFromSource +2
506  self.numStreams =numStreams
507  self._moduleNames = moduleNames
508  self._esModuleNames = esModuleNames
509  self._recordNames = recordNames
510  self.maxNameSize =0
511  for n in moduleNames.items():
512  self.maxNameSize = max(self.maxNameSize,len(n))
513  for n in esModuleNames.items():
514  self.maxNameSize = max(self.maxNameSize,len(n))
515  self.maxNameSize = max(self.maxNameSize,len(kSourceDelayedRead))
516  self.maxNameSize = max(self.maxNameSize, len('streamBeginLumi'))
517 
518  def processingSteps(self):
519  """Create a generator which can step through the file and return each processing step.
520  Using a generator reduces the memory overhead when parsing a large file.
521  """
522  self._f.seek(0)
524 
525 def textOutput( parser ):
526  context = {}
527  for p in parser.processingSteps():
528  print(p.text(context))
529 
530 #=======================================
531 if __name__=="__main__":
532  import argparse
533  import re
534  import sys
535 
536  # Program options
537  parser = argparse.ArgumentParser(description='Convert a compact tracer file into human readable output.',
538  formatter_class=argparse.RawDescriptionHelpFormatter,
539  epilog=printHelp())
540  parser.add_argument('filename',
541  type=argparse.FileType('r'), # open file
542  help='file to process')
543  parser.add_argument('-f', '--frameworkOnly',
544  action='store_true',
545  help='''Output only the framework transitions, excluding the individual module transitions.''')
546  args = parser.parse_args()
547 
548  parser = TracerCompactFileParser(args.filename, args.frameworkOnly)
549  textOutput(parser)
def __init__(self, payload, names, esNames, recordNames)
def lineParserFactory(step, payload, moduleNames, esModuleNames, recordNames, frameworkOnly)
def processingStepsFromFile(f, moduleNames, esModuleNames, recordNames, frameworkOnly)
def __init__(self, payload, names, esNames, recordNames)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:47
def textPrefix_(time, indentLevel)
def __init__(self, payload, names, esNames, recordNames)
def __init__(self, payload, moduleNames, esModuleNames, recordNames)
def __init__(self, payload, names, esNames, recordNames)
#define str(s)
def __init__(self, payload, names, esNames, recordNames)