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 import json
8 from collections import defaultdict
9 #----------------------------------------------
10 def printHelp():
11  s = '''
12 To Use: Add the Tracer Service to the cmsRun job use something like this
13  in the configuration:
14 
15  process.add_(cms.Service("Tracer", fileName = cms.untracked.string("tracer.log")))
16 
17  After running the job, execute this script and pass the name of the
18  Tracer log file to the script.
19 
20  This script will output a more human readable form of the data in the Tracer log file.'''
21  return s
22 
23 #these values come from tracer_setupFile.cc
24 #enum class Step : char {
25 # preSourceTransition = 'S',
26 # postSourceTransition = 's',
27 # preModulePrefetching = 'P',
28 # postModulePrefetching = 'p',
29 # preModuleEventAcquire = 'A',
30 # postModuleEventAcquire = 'a',
31 # preModuleTransition = 'M',
32 # preEventReadFromSource = 'R',
33 # postEventReadFromSource = 'r',
34 # preModuleEventDelayedGet = 'D',
35 # postModuleEventDelayedGet = 'd',
36 # postModuleTransition = 'm',
37 # preESModulePrefetching = 'Q',
38 # postESModulePrefetching = 'q',
39 # preESModule = 'N',
40 # postESModule = 'n',
41 # preESModuleAcquire = 'B',
42 # postESModuleAcquire = 'b',
43 # preFrameworkTransition = 'F',
44 # postFrameworkTransition = 'f'
45 #};
46 
47 
48 kMicroToSec = 0.000001
49 #Special names
50 kSourceFindEvent = "sourceFindEvent"
51 kSourceDelayedRead ="sourceDelayedRead"
52 #this value is defined in the framework itself
53 kLargestLumiNumber = 4294967295
54 
55 #these values must match the enum class Phase in tracer_setupFile.cc
56 class Phase (object):
57  destruction = -16
58  endJob = -12
59  endStream = -11
60  writeProcessBlock = -10
61  endProcessBlock = -9
62  globalWriteRun = -7
63  globalEndRun = -6
64  streamEndRun = -5
65  globalWriteLumi = -4
66  globalEndLumi = -3
67  streamEndLumi = -2
68  clearEvent = -1
69  Event = 0
70  streamBeginLumi = 2
71  globalBeginLumi = 3
72  streamBeginRun = 5
73  globalBeginRun = 6
74  accessInputProcessBlock = 8
75  beginProcessBlock = 9
76  openFile = 10
77  beginStream = 11
78  beginJob = 12
79  esSync = 13
80  esSyncEnqueue = 14
81  getNextTransition = 15
82  construction = 16
83  startTracing = 17
84 
85 #used for json output
86 class Activity (object):
87  prefetch = 0
88  acquire = 1
89  process = 2
90  delayedGet = 3
91  externalWork = 4
92  temporary = 100
93 
94 transitionToNames_ = {
95  Phase.startTracing: 'start tracing',
96  Phase.construction: 'construction',
97  Phase.destruction: 'destruction',
98  Phase.beginJob: 'begin job',
99  Phase.endJob: 'end job',
100  Phase.beginStream: 'begin stream',
101  Phase.endStream: 'end stream',
102  Phase.beginProcessBlock: 'begin process block',
103  Phase.endProcessBlock: 'end process block',
104  Phase.accessInputProcessBlock: 'access input process block',
105  Phase.writeProcessBlock: 'write process block',
106  Phase.globalBeginRun: 'global begin run',
107  Phase.globalEndRun: 'global end run',
108  Phase.globalWriteRun: 'global write run',
109  Phase.streamBeginRun: 'stream begin run',
110  Phase.streamEndRun: 'stream end run',
111  Phase.globalBeginLumi: 'global begin lumi',
112  Phase.globalEndLumi: 'global end lumi',
113  Phase.globalWriteLumi: 'global write lumi',
114  Phase.streamBeginLumi: 'stream begin lumi',
115  Phase.streamEndLumi: 'stream end lumi',
116  Phase.esSyncEnqueue: 'EventSetup synchronization',
117  Phase.esSync: 'EventSetup synchronization',
118  Phase.Event: 'event',
119  Phase.clearEvent: 'clear event',
120  Phase.getNextTransition: 'get next transition'
121 }
122 
123 def transitionName(transition):
124  return transitionToNames_[transition]
125 
126 transitionToIndent_ = {
127  Phase.startTracing: 0,
128  Phase.construction: 0,
129  Phase.destruction: 0,
130  Phase.endJob: 0,
131  Phase.beginJob: 0,
132  Phase.beginStream: 0,
133  Phase.endStream: 0,
134  Phase.beginProcessBlock: 1,
135  Phase.endProcessBlock: 1,
136  Phase.accessInputProcessBlock: 1,
137  Phase.writeProcessBlock: 1,
138  Phase.globalBeginRun: 1,
139  Phase.globalEndRun: 1,
140  Phase.globalWriteRun: 1,
141  Phase.streamBeginRun: 1,
142  Phase.streamEndRun: 1,
143  Phase.globalBeginLumi: 2,
144  Phase.globalEndLumi: 2,
145  Phase.globalWriteLumi: 2,
146  Phase.streamBeginLumi: 2,
147  Phase.streamEndLumi: 2,
148  Phase.Event: 3,
149  Phase.clearEvent: 3,
150  Phase.esSyncEnqueue: 1,
151  Phase.esSync: 1,
152  Phase.getNextTransition: 1
153 }
154 def transitionIndentLevel(transition):
155  return transitionToIndent_[transition]
156 
157 globalTransitions_ = {
158  Phase.startTracing,
159  Phase.construction,
160  Phase.destruction,
161  Phase.endJob,
162  Phase.beginJob,
163  Phase.beginProcessBlock,
164  Phase.endProcessBlock,
165  Phase.accessInputProcessBlock,
166  Phase.writeProcessBlock,
167  Phase.globalBeginRun,
168  Phase.globalEndRun,
169  Phase.globalWriteRun,
170  Phase.globalBeginLumi,
171  Phase.globalEndLumi,
172  Phase.globalWriteLumi,
173  Phase.esSyncEnqueue,
174  Phase.esSync,
175  Phase.getNextTransition
176 }
177 def transitionIsGlobal(transition):
178  return transition in globalTransitions_;
179 
180 def textPrefix_(time, indentLevel):
181  #using 11 spaces for time should accomodate a job that runs 24 hrs
182  return f'{time:>11} '+"++"*indentLevel
183 
185  def __init__(self, payload):
186  self.transition = int(payload[0])
187  self.index = int(payload[1])
188  self.sync = (int(payload[2]), int(payload[3]), int(payload[4]))
189  self.time = int(payload[5])
190  def indentLevel(self):
191  return transitionIndentLevel(self.transition)
192  def textPrefix(self):
193  return textPrefix_(self.time, self.indentLevel())
194  def syncText(self):
195  if self.transition == Phase.globalBeginRun or Phase.globalEndRun == self.transition:
196  return f'run={self.sync[0]}'
197  if self.transition == Phase.globalWriteRun:
198  return f'run={self.sync[0]}'
199  if self.transition == Phase.streamBeginRun or Phase.streamEndRun == self.transition:
200  return f'run={self.sync[0]}'
201  if self.transition == Phase.globalBeginLumi or Phase.globalEndLumi == self.transition:
202  return f'run={self.sync[0]} lumi={self.sync[1]}'
203  if self.transition == Phase.globalWriteLumi:
204  return f'run={self.sync[0]} lumi={self.sync[1]}'
205  if self.transition == Phase.streamBeginLumi or Phase.streamEndLumi == self.transition:
206  return f'run={self.sync[0]} lumi={self.sync[1]}'
207  if self.transition == Phase.Event:
208  return f'run={self.sync[0]} lumi={self.sync[1]} event={self.sync[2]}'
209  if self.transition == Phase.esSyncEnqueue or self.transition == Phase.esSync:
210  return f'run={self.sync[0]} lumi={self.sync[1]}'
211  if self.transition == Phase.beginJob:
212  return ''
213  if self.transition == Phase.beginProcessBlock or self.transition == Phase.endProcessBlock or self.transition == Phase.writeProcessBlock or self.transition == Phase.accessInputProcessBlock:
214  return ''
215  if self.transition == Phase.startTracing:
216  return ''
217  if self.transition == Phase.construction or self.transition == Phase.destruction:
218  return ''
219  def textPostfix(self):
220  return f'{transitionName(self.transition)} : id={self.index} {self.syncText()}'
221  def text(self, context):
222  return f'{self.textPrefix()} {self.textSpecial()}: {self.textPostfix()}'
223 
224 def findMatchingTransition(sync, containers):
225  for i in range(len(containers)):
226  if containers[i][-1]["sync"] == sync:
227  return i
228  #need more exhausting search
229  for i in range(len(containers)):
230  for t in containers[i]:
231  if t["sync"] == sync:
232  return i
233 
234  print("find failed",sync, containers)
235  return None
236 
237 def popQueuedTransitions(sync, container):
238  results = []
239  for i in range(len(container)):
240  if sync == container[i]["sync"]:
241  results.append(container[i])
242  results.append(container[i+1])
243  del container[i]
244  del container[i]
245  break
246  return results
247 
248 transitionsToFindMatch_ = {
249  Phase.globalEndRun,
250  Phase.globalEndLumi,
251  Phase.globalWriteRun,
252  Phase.globalWriteLumi
253 }
254 
256  def __init__(self, payload):
257  super().__init__(payload)
258  def textSpecial(self):
259  return "starting"
260  def jsonInfo(self, counter, data):
262  index = 0
263  if self.transition == Phase.startTracing:
264  data.indexedGlobal(0).append(jsonTransition(type=self.transition, id=index, sync=list(self.sync),start=0, finish=self.time ))
265  return
266  elif self.transition == Phase.esSync:
267  if self.sync[1] == kLargestLumiNumber:
268  #at end run transition
269  index = findMatchingTransition(list(self.sync), data.allGlobals())
270  container = data.indexedGlobal(index)
271  container[-1]["finish"] = self.time*kMicroToSec
272  else:
273  data._queued[-1]["finish"] = self.time*kMicroToSec
274  data._queued.append( jsonTransition(type=self.transition, id = index, sync=list(self.sync), start=self.time , finish=0))
275  return
276  elif self.transition==Phase.globalBeginRun:
277  index = self.index
278  #find associated es queued items
279  queued = data._queued
280  q = popQueuedTransitions(list(self.sync), queued)
281  container = data.indexedGlobal(index)
282  #find source, should be previous
283  last = container[-1]
284  if last["type"]==Phase.globalBeginRun and last["isSrc"]:
285  last["sync"]=list(self.sync)
286  container.append(q[0])
287  container.append(q[1])
288  elif self.transition==Phase.globalBeginLumi:
289  index = self.index
290  #find associated es queued items
291  queued = data._queued
292  q = popQueuedTransitions(list(self.sync), queued)
293  container = data.indexedGlobal(index)
294  #find source, should be previous
295  last = container[-1]
296  if last["type"]==Phase.globalBeginLumi and last["isSrc"]:
297  last["sync"]=list(self.sync)
298  container.append(q[0])
299  container.append(q[1])
300  elif self.transition in transitionsToFindMatch_:
301  index = findMatchingTransition(list(self.sync), data.allGlobals())
302  container = data.indexedGlobal(index)
303  else:
304  container = data.indexedStream(self.index)
305  if self.transition == Phase.Event:
306  #find source, should be previous
307  last = container[-1]
308  if last["type"]==Phase.Event and last["isSrc"]:
309  last["sync"]=list(self.sync)
310  index = self.index
311  container.append( jsonTransition(type=self.transition, id = index, sync=list(self.sync), start=self.time , finish=0))
312 
313 
315  def __init__(self, payload):
316  super().__init__(payload)
317  def textSpecial(self):
318  return "finished"
319  def jsonInfo(self, counter, data):
321  if self.transition == Phase.esSync and self.sync[1] != kLargestLumiNumber:
322  data._queued[-1]['finish']=self.time*kMicroToSec
323  return
324  index = findMatchingTransition(list(self.sync), data.allGlobals())
325  container = data.indexedGlobal(index)
326  else:
327  container = data.indexedStream(self.index)
328  container[-1]["finish"]=self.time*kMicroToSec
329 
330 
332  def __init__(self, payload):
333  super().__init__(payload)
334  def textSpecial(self):
335  return "queuing"
336  def jsonInfo(self, counter, data):
337  index = -1
338  if self.sync[1] == kLargestLumiNumber:
339  #find the mtching open run
340  index = findMatchingTransition([self.sync[0],0,0], data.allGlobals())
341  data.indexedGlobal(index).append( jsonTransition(type=self.transition, id = index, sync=list(self.sync), start=self.time , finish=0))
342  else:
343  data._queued.append(jsonTransition(type=self.transition, id = index, sync=list(self.sync), start=self.time , finish=0))
344 
346  def __init__(self, payload):
347  self.transition = int(payload[0])
348  if self.transition == Phase.getNextTransition:
349  self.time = int(payload[1])
350  self.index = -1
351  return
352  self.index = int(payload[1])
353  self.time = int(payload[2])
354  def indentLevel(self):
355  if self.transition == Phase.globalBeginRun:
356  return 1
357  if self.transition == Phase.globalBeginLumi:
358  return 2
359  if self.transition == Phase.Event:
360  return 3
361  if self.transition == Phase.construction:
362  return 1
363  if self.transition == Phase.getNextTransition:
364  return 1
365  return None
366  def textPrefix(self):
367  return textPrefix_(self.time, self.indentLevel())
368  def textPostfix(self):
369  return f'source during {transitionName(self.transition)} : id={self.index}'
370  def text(self, context):
371  return f'{self.textPrefix()} {self.textSpecial()}: {self.textPostfix()}'
372 
374  def __init__(self, payload, moduleCentric):
375  self._moduleCentric = moduleCentric
376  super().__init__(payload)
377  def textSpecial(self):
378  return "starting"
379  def jsonInfo(self, counter, data):
380  if self.transition == Phase.getNextTransition:
381  data._nextTrans.append(jsonTransition(type=self.transition, id=self.index, sync=[0,0,0], start=self.time, finish=0, isSrc=True))
382  if self._moduleCentric:
383  #this all goes to a module ID sorted container so not knowing actual index is OK
384  data.findOpenSlotInModGlobals(0,0).append(data._nextTrans[-1])
385  return
386  elif self.transition == Phase.construction:
387  index = counter.start()
388  container = data.indexedGlobal(index)
389  elif self.transition == Phase.Event:
390  index = self.index
391  container = data.indexedStream(index)
392  else:
393  index = self.index
394  container = data.indexedGlobal(index)
395  nextTrans = data._nextTrans
396  if nextTrans:
397  data._nextTrans = []
398  for t in nextTrans:
399  t['id']=index
400  #find proper time order in the container
401  transStartTime = t['start']
402  inserted = False
403  for i in range(-1, -1*len(container), -1):
404  if transStartTime > container[i]['start']:
405  if i == -1:
406  container.append(t)
407  inserted = True
408  break
409  else:
410  container.insert(i+1,t)
411  inserted = True
412  break
413  if not inserted:
414  container.insert(0,t)
415  container.append(jsonTransition(type=self.transition, id=index, sync=[0,0,0], start=self.time, finish=0, isSrc=True))
416  if self._moduleCentric:
417  if self.transition == Phase.Event:
418  data.findOpenSlotInModStreams(index,0).append(container[-1])
419  else:
420  data.findOpenSlotInModGlobals(index,0).append(container[-1])
421 
423  def __init__(self, payload, moduleCentric):
424  super().__init__(payload)
425  self._moduleCentric = moduleCentric
426  def textSpecial(self):
427  return "finished"
428  def jsonInfo(self, counter, data):
429  index = self.index
430  if self.transition == Phase.Event:
431  container = data.indexedStream(index)
432  elif self.transition == Phase.getNextTransition:
433  data._nextTrans[-1]['finish'] = self.time*kMicroToSec
434  return
435  elif self.transition == Phase.construction:
436  pre = None
437  for i, g in enumerate(data.allGlobals()):
438  for t in reversed(g):
439  if t["type"] != Phase.construction:
440  break
441  if t["isSrc"]:
442  pre = t
443  break
444  if pre:
445  pre["finish"]=self.time*kMicroToSec
446  break
447  counter.finish(i)
448  return
449  else:
450  container = data.indexedGlobal(index)
451 
452  container[-1]["finish"]=self.time*kMicroToSec
453 
455  def __init__(self, payload, moduleNames):
456  self.transition = int(payload[0])
457  self.index = int(payload[1])
458  self.moduleID = int(payload[2])
459  self.moduleName = moduleNames[self.moduleID]
460  self.callID = int(payload[3])
461  self.requestingModuleID = int(payload[4])
462  self.requestingCallID = int(payload[5])
464  if self.requestingModuleID != 0:
465  self.requestingModuleName = moduleNames[self.requestingModuleID]
466  self.time = int(payload[6])
467  def baseIndentLevel(self):
468  return transitionIndentLevel(self.transition)
469  def textPrefix(self, context):
470  indent = 0
471  if self.requestingModuleID != 0:
472  indent = context[(self.transition, self.index, self.requestingModuleID, self.requestingCallID)]
473  context[(self.transition, self.index, self.moduleID, self.callID)] = indent+1
474  return textPrefix_(self.time, indent+1+self.baseIndentLevel())
475  def textPostfix(self):
476  return f'{self.moduleName} during {transitionName(self.transition)} : id={self.index}'
477  def textIfTransform(self):
478  if self.callID:
479  return f' transform {self.callID-1}'
480  return ''
481  def text(self, context):
482  return f'{self.textPrefix(context)} {self.textSpecial()}{self.textIfTransform()}: {self.textPostfix()}'
483  def _preJson(self, activity, counter, data, mayUseTemp = False):
484  index = self.index
485  found = False
486  if mayUseTemp:
487  compare = lambda x: x['type'] == self.transition and x['id'] == self.index and x['mod'] == self.moduleID and x['call'] == self.callID and (x['act'] == Activity.temporary or x['act'] == Activity.externalWork)
489  item,slot = data.findLastInModGlobals(index, self.moduleID, compare)
490  else:
491  item,slot = data.findLastInModStreams(index, self.moduleID, compare)
492  if slot:
493  if item['act'] == Activity.temporary:
494  slot.pop()
495  else:
496  item['finish']=self.time*kMicroToSec
497  found = True
498  if not found:
500  slot = data.findOpenSlotInModGlobals(index, self.moduleID)
501  else:
502  slot = data.findOpenSlotInModStreams(index, self.moduleID)
503  slot.append(jsonModuleTransition(type=self.transition, id=self.index, modID=self.moduleID, callID=self.callID, activity=activity, start=self.time))
504  return slot[-1]
505  def _postJson(self, counter, data, injectAfter = None):
506  compare = lambda x: x['id'] == self.index and x['mod'] == self.moduleID and x['call'] == self.callID and x['type'] == self.transition
507  index = self.index
509  item,slot = data.findLastInModGlobals(index, self.moduleID, compare)
510  else:
511  item,slot = data.findLastInModStreams(index, self.moduleID, compare)
512  if item is None:
513  print(f"failed to find {self.moduleID} for {self.transition} in {self.index}")
514  else:
515  item["finish"]=self.time*kMicroToSec
516  if injectAfter:
517  slot.append(injectAfter)
518 
520  def __init__(self, payload, names, moduleCentric):
521  super().__init__(payload, names)
522  self._moduleCentric = moduleCentric
523  def textSpecial(self):
524  return "starting action"
525  def jsonInfo(self, counter, data):
526  return self._preJson(Activity.process, counter,data, mayUseTemp=self._moduleCentric)
527 
529  def __init__(self, payload, names):
530  super().__init__(payload, names)
531  def textSpecial(self):
532  return "finished action"
533  def jsonInfo(self, counter, data):
534  return self._postJson(counter,data)
535 
537  def __init__(self, payload, names, moduleCentric):
538  super().__init__(payload, names)
539  self._moduleCentric = moduleCentric
540  def textSpecial(self):
541  return "starting prefetch"
542  def jsonInfo(self, counter, data):
543  #the total time in prefetching isn't useful, but seeing the start is
544  entry = self._preJson(Activity.prefetch, counter,data)
545  if self._moduleCentric:
546  return entry
547  kPrefetchLength = 2*kMicroToSec
548  entry["finish"]=entry["start"]+kPrefetchLength
549  return entry
550 
551 
553  def __init__(self, payload, names, moduleCentric):
554  super().__init__(payload, names)
555  self._moduleCentric = moduleCentric
556  def textSpecial(self):
557  return "finished prefetch"
558  def jsonInfo(self, counter, data):
559  if self._moduleCentric:
560  #inject a dummy at end of the same slot to guarantee module run is in that slot
561  return self._postJson(counter, data, jsonModuleTransition(type=self.transition, id=self.index, modID=self.moduleID, callID=self.callID, activity=Activity.temporary, start=self.time))
562  pass
563 
565  def __init__(self, payload, names, moduleCentric):
566  super().__init__(payload, names)
567  self._moduleCentric = moduleCentric
568  def textSpecial(self):
569  return "starting acquire"
570  def jsonInfo(self, counter, data):
571  return self._preJson(Activity.acquire, counter,data, mayUseTemp=self._moduleCentric)
572 
574  def __init__(self, payload, names, moduleCentric):
575  super().__init__(payload, names)
576  self._moduleCentric = moduleCentric
577  def textSpecial(self):
578  return "finished acquire"
579  def jsonInfo(self, counter, data):
580  if self._moduleCentric:
581  #inject an external work at end of the same slot to guarantee module run is in that slot
582  return self._postJson(counter, data, jsonModuleTransition(type=self.transition, id=self.index, modID=self.moduleID, callID=self.callID, activity=Activity.externalWork, start=self.time))
583  return self._postJson(counter,data)
584 
586  def __init__(self, payload, names):
587  super().__init__(payload, names)
588  def textSpecial(self):
589  return "starting delayed get"
590  def jsonInfo(self, counter, data):
591  return self._preJson(Activity.delayedGet, counter,data)
592 
594  def __init__(self, payload, names):
595  super().__init__(payload, names)
596  def textSpecial(self):
597  return "finished delayed get"
598  def jsonInfo(self, counter, data):
599  return self._postJson(counter,data)
600 
602  def __init__(self, payload, names):
603  super().__init__(payload, names)
604  def textSpecial(self):
605  return "starting read from source"
606  def jsonInfo(self, counter, data):
607  slot = self._preJson(Activity.process, counter,data)
608  slot['isSrc'] = True
609  return slot
610 
612  def __init__(self, payload, names):
613  super().__init__(payload, names)
614  def textSpecial(self):
615  return "finished read from source"
616  def jsonInfo(self, counter, data):
617  return self._postJson(counter,data)
618 
620  def __init__(self, payload, moduleNames, esModuleNames, recordNames):
621  self.transition = int(payload[0])
622  self.index = int(payload[1])
623  self.moduleID = int(payload[2])
624  self.moduleName = esModuleNames[self.moduleID]
625  self.recordID = int(payload[3])
626  self.recordName = recordNames[self.recordID]
627  self.callID = int(payload[4])
628  self.requestingModuleID = int(payload[5])
629  self.requestingCallID = int(payload[6])
631  if self.requestingModuleID < 0 :
632  self.requestingModuleName = esModuleNames[-1*self.requestingModuleID]
633  else:
634  self.requestingModuleName = moduleNames[self.requestingModuleID]
635  self.time = int(payload[7])
636  def baseIndentLevel(self):
637  return transitionIndentLevel(self.transition)
638  def textPrefix(self, context):
639  indent = 0
640  indent = context[(self.transition, self.index, self.requestingModuleID, self.requestingCallID)]
641  context[(self.transition, self.index, -1*self.moduleID, self.callID)] = indent+1
642  return textPrefix_(self.time, indent+1+self.baseIndentLevel())
643  def textPostfix(self):
644  return f'esmodule {self.moduleName} in record {self.recordName} during {transitionName(self.transition)} : id={self.index}'
645  def text(self, context):
646  return f'{self.textPrefix(context)} {self.textSpecial()}: {self.textPostfix()}'
647  def _preJson(self, activity, counter, data):
648  index = self.index
650  slot = data.findOpenSlotInModGlobals(index, -1*self.moduleID)
651  else:
652  slot = data.findOpenSlotInModStreams(index, -1*self.moduleID)
653  slot.append(jsonModuleTransition(type=self.transition, id=self.index, modID=-1*self.moduleID, callID=self.callID, activity=activity, start=self.time))
654  return slot[-1]
655  def _postJson(self, counter, data):
656  compare = lambda x: x['id'] == self.index and x['mod'] == -1*self.moduleID and x['call'] == self.callID
657  index = self.index
659  item,s = data.findLastInModGlobals(index, -1*self.moduleID, compare)
660  else:
661  item,s = data.findLastInModStreams(index, -1*self.moduleID, compare)
662  if item is None:
663  print(f"failed to find {-1*self.moduleID} for {self.transition} in {self.index}")
664  return
665  item["finish"]=self.time*kMicroToSec
666 
667 
669  def __init__(self, payload, names, esNames, recordNames):
670  super().__init__(payload, names, esNames, recordNames)
671  def textSpecial(self):
672  return "starting action"
673  def jsonInfo(self, counter, data):
674  return self._preJson(Activity.process, counter,data)
675 
677  def __init__(self, payload, names, esNames, recordNames):
678  super().__init__(payload, names, esNames, recordNames)
679  def textSpecial(self):
680  return "finished action"
681  def jsonInfo(self, counter, data):
682  return self._postJson(counter,data)
683 
685  def __init__(self, payload, names, esNames, recordNames, moduleCentric):
686  super().__init__(payload, names, esNames, recordNames)
687  self._moduleCentric = moduleCentric
688  def textSpecial(self):
689  return "starting prefetch"
690  def jsonInfo(self, counter, data):
691  entry = self._preJson(Activity.prefetch, counter,data)
692  if not self._moduleCentric:
693  entry["finish"] = entry["start"]+2*kMicroToSec;
694  return entry
695 
697  def __init__(self, payload, names, esNames, recordNames, moduleCentric):
698  super().__init__(payload, names, esNames, recordNames)
699  self._moduleCentric = moduleCentric
700  def textSpecial(self):
701  return "finished prefetch"
702  def jsonInfo(self, counter, data):
703  if self._moduleCentric:
704  return self._postJson(counter, data)
705  pass
706 
708  def __init__(self, payload, names, recordNames):
709  super().__init__(payload, names, recordNames)
710  def textSpecial(self):
711  return "starting acquire"
712  def jsonInfo(self, counter, data):
713  return self._preJson(Activity.acquire, counter,data)
714 
716  def __init__(self, payload, names, esNames, recordNames):
717  super().__init__(payload, names, esNames, recordNames)
718  def textSpecial(self):
719  return "finished acquire"
720  def jsonInfo(self, counter, data):
721  return self._postJson(counter,data)
722 
723 
724 def lineParserFactory (step, payload, moduleNames, esModuleNames, recordNames, frameworkOnly, moduleCentric):
725  if step == 'F':
726  parser = PreFrameworkTransitionParser(payload)
727  if parser.transition == Phase.esSyncEnqueue:
728  return QueuingFrameworkTransitionParser(payload)
729  return parser
730  if step == 'f':
731  return PostFrameworkTransitionParser(payload)
732  if step == 'S':
733  return PreSourceTransitionParser(payload, moduleCentric)
734  if step == 's':
735  return PostSourceTransitionParser(payload, moduleCentric)
736  if frameworkOnly:
737  return None
738  if step == 'M':
739  return PreEDModuleTransitionParser(payload, moduleNames, moduleCentric)
740  if step == 'm':
741  return PostEDModuleTransitionParser(payload, moduleNames)
742  if step == 'P':
743  return PreEDModulePrefetchingParser(payload, moduleNames, moduleCentric)
744  if step == 'p':
745  return PostEDModulePrefetchingParser(payload, moduleNames, moduleCentric)
746  if step == 'A':
747  return PreEDModuleAcquireParser(payload, moduleNames, moduleCentric)
748  if step == 'a':
749  return PostEDModuleAcquireParser(payload, moduleNames, moduleCentric)
750  if step == 'D':
751  return PreEDModuleEventDelayedGetParser(payload, moduleNames)
752  if step == 'd':
753  return PostEDModuleEventDelayedGetParser(payload, moduleNames)
754  if step == 'R':
755  return PreEventReadFromSourceParser(payload, moduleNames)
756  if step == 'r':
757  return PostEventReadFromSourceParser(payload, moduleNames)
758  if step == 'N':
759  return PreESModuleTransitionParser(payload, moduleNames, esModuleNames, recordNames)
760  if step == 'n':
761  return PostESModuleTransitionParser(payload, moduleNames, esModuleNames, recordNames)
762  if step == 'Q':
763  return PreESModulePrefetchingParser(payload, moduleNames, esModuleNames, recordNames, moduleCentric)
764  if step == 'q':
765  return PostESModulePrefetchingParser(payload, moduleNames, esModuleNames, recordNames, moduleCentric)
766  if step == 'B':
767  return PreESModuleAcquireParser(payload, moduleNames, esModuleNames, recordNames)
768  if step == 'b':
769  return PostESModuleAcquireParser(payload, moduleNames, esModuleNames, recordNames)
770 
771 
772 #----------------------------------------------
773 def processingStepsFromFile(f,moduleNames, esModuleNames, recordNames, frameworkOnly, moduleCentric):
774  for rawl in f:
775  l = rawl.strip()
776  if not l or l[0] == '#':
777  continue
778  (step,payload) = tuple(l.split(None,1))
779  payload=payload.split()
780 
781  parser = lineParserFactory(step, payload, moduleNames, esModuleNames, recordNames, frameworkOnly, moduleCentric)
782  if parser:
783  yield parser
784  return
785 
787  def __init__(self,f, frameworkOnly, moduleCentric):
788  streamBeginRun = str(Phase.streamBeginRun)
789  numStreams = 0
790  numStreamsFromSource = 0
791  moduleNames = {}
792  esModuleNames = {}
793  recordNames = {}
794  for rawl in f:
795  l = rawl.strip()
796  if l and l[0] == 'M':
797  i = l.split(' ')
798  if i[3] == streamBeginRun:
799  #found global begin run
800  numStreams = int(i[1])+1
801  break
802  if numStreams == 0 and l and l[0] == 'S':
803  s = int(l.split(' ')[1])
804  if s > numStreamsFromSource:
805  numStreamsFromSource = s
806  if len(l) > 5 and l[0:2] == "#M":
807  (id,name)=tuple(l[2:].split())
808  moduleNames[int(id)] = name
809  continue
810  if len(l) > 5 and l[0:2] == "#N":
811  (id,name)=tuple(l[2:].split())
812  esModuleNames[int(id)] = name
813  continue
814  if len(l) > 5 and l[0:2] == "#R":
815  (id,name)=tuple(l[2:].split())
816  recordNames[int(id)] = name
817  continue
818 
819  self._f = f
820  self._frameworkOnly = frameworkOnly
821  self._moduleCentric = moduleCentric
822  if numStreams == 0:
823  numStreams = numStreamsFromSource +2
824  self.numStreams =numStreams
825  self._moduleNames = moduleNames
826  self._esModuleNames = esModuleNames
827  self._recordNames = recordNames
828  self.maxNameSize =0
829  for n in moduleNames.items():
830  self.maxNameSize = max(self.maxNameSize,len(n))
831  for n in esModuleNames.items():
832  self.maxNameSize = max(self.maxNameSize,len(n))
833  self.maxNameSize = max(self.maxNameSize,len(kSourceDelayedRead))
834  self.maxNameSize = max(self.maxNameSize, len('streamBeginLumi'))
835 
836  def processingSteps(self):
837  """Create a generator which can step through the file and return each processing step.
838  Using a generator reduces the memory overhead when parsing a large file.
839  """
840  self._f.seek(0)
842 
843 def textOutput( parser ):
844  context = {}
845  for p in parser.processingSteps():
846  print(p.text(context))
847 
849  def __init__(self):
850  self.activeSlots = [False]
851  def start(self):
852  if 0 != self.activeSlots.count(False):
853  index = self.activeSlots.index(False)
854  self.activeSlots[index]=True
855  return index
856  index = len(self.activeSlots)
857  self.activeSlots.append(True)
858  return index
859  def finish(self, index):
860  self.activeSlots[index] = False
861 
863  def __init__(self):
864  self._modGlobals = [[]]
865  self._modStreams = [[]]
866  self._globals = [[]]
867  self._streams = [[]]
868  self._queued = []
869  self._nextTrans = []
870  def _extendIfNeeded(self, container, index):
871  while len(container) < index+1:
872  container.append([])
873  def allGlobals(self):
874  return self._globals
875  def indexedGlobal(self, index):
876  self._extendIfNeeded(self._globals, index)
877  return self._globals[index]
878  def allStreams(self):
879  return self._streams
880  def indexedStream(self, index):
881  self._extendIfNeeded(self._streams, index)
882  return self._streams[index]
883  def _findOpenSlot(self, index, fullContainer):
884  self._extendIfNeeded(fullContainer, index)
885  container = fullContainer[index]
886  #find open slot
887  foundOpenSlot = False
888  for slot in container:
889  if len(slot) == 0:
890  foundOpenSlot = True
891  break
892  if slot[-1]["finish"] != 0:
893  foundOpenSlot = True
894  break
895  if not foundOpenSlot:
896  container.append([])
897  slot = container[-1]
898  return slot
899  def findOpenSlotInModGlobals(self, index, modID):
900  return self._findOpenSlot(index, self._modGlobals)
901  def findOpenSlotInModStreams(self, index, modID):
902  return self._findOpenSlot(index, self._modStreams)
903  def _findLastIn(self, index, fullContainer, comparer):
904  container = fullContainer[index]
905  #find slot containing the pre
906  for slot in container:
907  if comparer(slot[-1]):
908  return (slot[-1],slot)
909  return (None,None)
910  def findLastInModGlobals(self, index, modID, comparer):
911  return self._findLastIn(index, self._modGlobals, comparer)
912  def findLastInModStreams(self, index, modID, comparer):
913  return self._findLastIn(index, self._modStreams, comparer)
914 
915 
917  def __init__(self):
918  self._modules= []
919  self._globals = [[]]
920  self._streams = [[]]
921  self._queued = []
922  self._nextTrans = []
924  def _moduleID2Index(self, modID):
925  return modID + self._moduleIDOffset
926  def _extendIfNeeded(self, container, index):
927  while len(container) < index+1:
928  container.append([])
929  def _extendModulesIfNeeded(self, container, index):
930  while index + self._moduleIDOffset < 0:
931  container.insert(0,[])
932  self._moduleIDOffset +=1
933  self._extendIfNeeded(container, self._moduleID2Index(index))
934  def allGlobals(self):
935  return self._globals
936  def indexedGlobal(self, index):
937  self._extendIfNeeded(self._globals, index)
938  return self._globals[index]
939  def allStreams(self):
940  return self._streams
941  def indexedStream(self, index):
942  self._extendIfNeeded(self._streams, index)
943  return self._streams[index]
944  def _findOpenSlot(self, index, fullContainer):
945  self._extendModulesIfNeeded(fullContainer, index)
946  container = fullContainer[self._moduleID2Index(index)]
947  #find open slot
948  foundOpenSlot = False
949  for slot in container:
950  if len(slot) == 0:
951  foundOpenSlot = True
952  break
953  if slot[-1]["finish"] != 0:
954  foundOpenSlot = True
955  break
956  if not foundOpenSlot:
957  container.append([])
958  slot = container[-1]
959  return slot
960  def findOpenSlotInModGlobals(self, index, modID):
961  return self._findOpenSlot(modID, self._modules)
962  def findOpenSlotInModStreams(self, index, modID):
963  return self._findOpenSlot(modID, self._modules)
964  def _findLastIn(self, index, fullContainer, comparer):
965  if not fullContainer:
966  return (None, None)
967  if len(fullContainer) > self._moduleID2Index(index):
968  container = fullContainer[self._moduleID2Index(index)]
969  else:
970  return (None, None)
971  #find slot containing the pre
972  for slot in container:
973  if slot is not None and comparer(slot[-1]):
974  return (slot[-1],slot)
975  return (None, None)
976  def findLastInModGlobals(self, index, modID, comparer):
977  return self._findLastIn(modID, self._modules, comparer)
978  def findLastInModStreams(self, index, modID, comparer):
979  return self._findLastIn(modID, self._modules, comparer)
980 
981 
982 
983 def jsonTransition(type, id, sync, start, finish, isSrc=False):
984  return {"type": type, "id": id, "sync": sync, "start": start*kMicroToSec, "finish": finish*kMicroToSec, "isSrc":isSrc}
985 
986 def jsonModuleTransition(type, id, modID, callID, activity, start, finish=0):
987  return {"type": type, "id": id, "mod": modID, "call": callID, "act": activity, "start": start*kMicroToSec, "finish": finish*kMicroToSec}
988 
989 def startTime(x):
990  return x["start"]
991 def jsonInfo(parser):
992  counter = Counter()
993  if parser._moduleCentric:
994  data = ModuleCentricContainers()
995  else:
996  data = Containers()
997  for p in parser.processingSteps():
998  p.jsonInfo(counter, data)
999  #make sure everything is sorted
1000  for g in data.allGlobals():
1001  g.sort(key=startTime)
1002  final = {"transitions" : [] , "modules": [], "esModules": []}
1003  final["transitions"].append({ "name":"Global", "slots": []})
1004  globals = final["transitions"][-1]["slots"]
1005  for i, g in enumerate(data.allGlobals()):
1006  globals.append(g)
1007  if not parser._moduleCentric and not parser._frameworkOnly:
1008  if len(data._modGlobals) < i+1:
1009  break
1010  for mod in data._modGlobals[i]:
1011  globals.append(mod)
1012  for i,s in enumerate(data.allStreams()):
1013  final["transitions"].append({"name": f"Stream {i}", "slots":[]})
1014  stream = final["transitions"][-1]["slots"]
1015  stream.append(s)
1016  if not parser._moduleCentric and not parser._frameworkOnly:
1017  for mod in data._modStreams[i]:
1018  stream.append(mod)
1019  if parser._moduleCentric:
1020  sourceSlot = data._modules[data._moduleID2Index(0)]
1021  modules = []
1022  for i,m in parser._moduleNames.items():
1023  modules.append({"name": f"{m}", "slots":[]})
1024  slots = modules[-1]["slots"]
1025  foundSlots = data._modules[data._moduleID2Index(i)]
1026  time = 0
1027  for s in foundSlots:
1028  slots.append(s)
1029  for t in s:
1030  if t["act"] !=Activity.prefetch:
1031  time += t["finish"]-t["start"]
1032  modules[-1]['time']=time
1033  for i,m in parser._esModuleNames.items():
1034  modules.append({"name": f"{m}", "slots":[]})
1035  slots = modules[-1]["slots"]
1036  foundSlots = data._modules[data._moduleID2Index(-1*i)]
1037  time = 0
1038  for s in foundSlots:
1039  slots.append(s)
1040  for t in s:
1041  if t["act"] !=Activity.prefetch:
1042  time += t["finish"]-t["start"]
1043  modules[-1]['time']=time
1044  modules.sort(key= lambda x : x['time'], reverse=True)
1045  final['transitions'].append({"name": "source", "slots":sourceSlot})
1046  for m in modules:
1047  final['transitions'].append(m)
1048 
1049  if not parser._frameworkOnly:
1050  max = 0
1051  for k in parser._moduleNames.keys():
1052  if k > max:
1053  max = k
1054 
1055  final["modules"] =['']*(max+1)
1056  final["modules"][0] = 'source'
1057  for k,v in parser._moduleNames.items():
1058  final["modules"][k]=v
1059 
1060  max = 0
1061  for k in parser._esModuleNames.keys():
1062  if k > max:
1063  max = k
1064  final["esModules"] = ['']*(max+1)
1065  for k,v in parser._esModuleNames.items():
1066  final["esModules"][k] = v
1067  return final
1068 
1069 #=======================================
1070 import unittest
1071 
1072 class DummyFile(list):
1073  def __init__(self):
1074  super()
1075  def seek(self, i):
1076  pass
1077 
1078 class TestModuleCommand(unittest.TestCase):
1079  def setUp(self):
1081  t = [0]
1082  def incr(t):
1083  t[0] += 1
1084  return t[0]
1085 
1086  self.tracerFile.extend([
1087  '#R 1 Record',
1088  '#M 1 Module',
1089  '#N 1 ESModule',
1090  f'F {Phase.startTracing} 0 0 0 0 {incr(t)}',
1091  f'S {Phase.construction} 0 {incr(t)}',
1092  f's {Phase.construction} 0 {incr(t)}3',
1093  f'M {Phase.construction} 0 1 0 0 0 {incr(t)}',
1094  f'm {Phase.construction} 0 1 0 0 0 {incr(t)}',
1095  f'F {Phase.beginJob} 0 0 0 0 {incr(t)}',
1096  f'M {Phase.beginJob} 0 1 0 0 0 {incr(t)}',
1097  f'm {Phase.beginJob} 0 1 0 0 0 {incr(t)}',
1098  f'f {Phase.beginJob} 0 0 0 0 {incr(t)}',
1099  f'F {Phase.beginProcessBlock} 0 0 0 0 {incr(t)}',
1100  f'f {Phase.beginProcessBlock} 0 0 0 0 {incr(t)}',
1101  f'S {Phase.getNextTransition} {incr(t)}',
1102  f's {Phase.getNextTransition} {incr(t)}',
1103  f'F {Phase.esSyncEnqueue} -1 1 0 0 {incr(t)}',
1104  f'F {Phase.esSync} -1 1 0 0 {incr(t)}',
1105  f'f {Phase.esSync} -1 1 0 0 {incr(t)}',
1106  f'S {Phase.globalBeginRun} 0 {incr(t)}',
1107  f's {Phase.globalBeginRun} 0 {incr(t)}',
1108  f'S {Phase.getNextTransition} {incr(t)}',
1109  f's {Phase.getNextTransition} {incr(t)}',
1110  f'F {Phase.globalBeginRun} 0 1 0 0 {incr(t)}',
1111  f'P {Phase.globalBeginRun} 0 1 0 0 0 {incr(t)}',
1112  f'p {Phase.globalBeginRun} 0 1 0 0 0 {incr(t)}',
1113  f'M {Phase.globalBeginRun} 0 1 0 0 0 {incr(t)}',
1114  f'm {Phase.globalBeginRun} 0 1 0 0 0 {incr(t)}',
1115  f'f {Phase.globalBeginRun} 0 1 0 0 {incr(t)}',
1116  f'F {Phase.esSyncEnqueue} -1 1 1 0 {incr(t)}',
1117  f'F {Phase.esSync} -1 1 1 0 {incr(t)}',
1118  f'f {Phase.esSync} -1 1 1 0 {incr(t)}',
1119  f'S {Phase.getNextTransition} {incr(t)}',
1120  f's {Phase.getNextTransition} {incr(t)}',
1121  f'F {Phase.streamBeginRun} 0 1 0 0 {incr(t)}',
1122  f'M {Phase.streamBeginRun} 0 1 0 0 0 {incr(t)}',
1123  f'm {Phase.streamBeginRun} 0 1 0 0 0 {incr(t)}',
1124  f'f {Phase.streamBeginRun} 0 1 0 0 {incr(t)}',
1125  f'F {Phase.streamBeginRun} 1 1 0 0 {incr(t)}',
1126  f'M {Phase.streamBeginRun} 1 1 0 0 0 {incr(t)}',
1127  f'm {Phase.streamBeginRun} 1 1 0 0 0 {incr(t)}',
1128  f'f {Phase.streamBeginRun} 1 1 0 0 {incr(t)}',
1129  f'S {Phase.globalBeginLumi} 0 {incr(t)}',
1130  f's {Phase.globalBeginLumi} 0 {incr(t)}',
1131  f'S {Phase.getNextTransition} {incr(t)}',
1132  f's {Phase.getNextTransition} {incr(t)}',
1133  f'F {Phase.globalBeginLumi} 0 1 1 0 {incr(t)}',
1134  f'P {Phase.globalBeginLumi} 0 1 0 0 0 {incr(t)}',
1135  f'p {Phase.globalBeginLumi} 0 1 0 0 0 {incr(t)}',
1136  f'M {Phase.globalBeginLumi} 0 1 0 0 0 {incr(t)}',
1137  f'm {Phase.globalBeginLumi} 0 1 0 0 0 {incr(t)}',
1138  f'f {Phase.globalBeginLumi} 0 1 1 0 {incr(t)}',
1139  f'F {Phase.streamBeginLumi} 0 1 1 0 {incr(t)}',
1140  f'f {Phase.streamBeginLumi} 0 1 1 0 {incr(t)}',
1141  f'F {Phase.streamBeginLumi} 1 1 1 0 {incr(t)}',
1142  f'f {Phase.streamBeginLumi} 1 1 1 0 {incr(t)}',
1143  f'S {Phase.Event} 0 {incr(t)}',
1144  f's {Phase.Event} 0 {incr(t)}',
1145  f'S {Phase.getNextTransition} {incr(t)}',
1146  f's {Phase.getNextTransition} {incr(t)}',
1147  f'F {Phase.Event} 0 1 1 1 {incr(t)}',
1148  f'S {Phase.Event} 1 {incr(t)}',
1149  f's {Phase.Event} 1 {incr(t)}',
1150  f'F {Phase.Event} 1 1 1 2 {incr(t)}',
1151  f'P {Phase.Event} 0 1 0 0 0 {incr(t)}',
1152  f'p {Phase.Event} 0 1 0 0 0 {incr(t)}',
1153  f'Q {Phase.Event} 0 1 1 0 1 0 {incr(t)}',
1154  f'q {Phase.Event} 0 1 1 0 1 0 {incr(t)}',
1155  f'N {Phase.Event} 0 1 1 0 1 0 {incr(t)}',
1156  f'n {Phase.Event} 0 1 1 0 1 0 {incr(t)}',
1157  f'P {Phase.Event} 1 1 0 0 0 {incr(t)}',
1158  f'p {Phase.Event} 1 1 0 0 0 {incr(t)}',
1159  f'M {Phase.Event} 0 1 0 0 0 {incr(t)}',
1160  f'M {Phase.Event} 1 1 0 0 0 {incr(t)}',
1161  f'm {Phase.Event} 1 1 0 0 0 {incr(t)}',
1162  f'm {Phase.Event} 0 1 0 0 0 {incr(t)}',
1163  f'f {Phase.Event} 0 1 1 1 {incr(t)}',
1164  f'f {Phase.Event} 1 1 1 2 {incr(t)}'])
1165 
1166  None
1167  def testContainers(self):
1168  c = Containers()
1169  c.indexedGlobal(2)
1170  self.assertEqual(len(c.allGlobals()), 3)
1171  c.indexedStream(2)
1172  self.assertEqual(len(c.allStreams()), 3)
1173  slot = c.findOpenSlotInModGlobals(2, 1)
1174  self.assertEqual(len(c._modGlobals),3)
1175  self.assertEqual(len(slot),0)
1176  slot.append({"start":1, "finish":0, "id":1})
1177  def testFind(item):
1178  return item["id"]==1
1179  item,s = c.findLastInModGlobals(2, 1, testFind)
1180  self.assertEqual(item["id"],1)
1181  self.assertEqual(slot,s)
1182  slot = c.findOpenSlotInModStreams(2, 1)
1183  self.assertEqual(len(c._modStreams),3)
1184  self.assertEqual(len(slot),0)
1185  slot.append({"start":1, "finish":0, "id":1})
1186  item,s = c.findLastInModStreams(2, 1, testFind)
1187  self.assertEqual(item["id"],1)
1188  self.assertEqual(slot,s)
1190  parser = TracerCompactFileParser(self.tracerFile, True, False)
1191  j = jsonInfo(parser)
1192  #print(j)
1193  self.assertEqual(len(j["modules"]), 0)
1194  self.assertEqual(len(j["esModules"]), 0)
1195  self.assertEqual(len(j['transitions']), 3)
1196  self.assertEqual(j['transitions'][0]['name'], "Global")
1197  self.assertEqual(j['transitions'][1]['name'], "Stream 0")
1198  self.assertEqual(j['transitions'][2]['name'], "Stream 1")
1199  self.assertEqual(len(j["transitions"][0]["slots"]), 1)
1200  self.assertEqual(len(j["transitions"][0]["slots"][0]), 15)
1201  self.assertEqual(len(j["transitions"][1]["slots"]), 1)
1202  self.assertEqual(len(j["transitions"][1]["slots"][0]), 5)
1203  self.assertEqual(len(j["transitions"][2]["slots"]), 1)
1204  self.assertEqual(len(j["transitions"][2]["slots"][0]), 5)
1205  def testFull(self):
1206  parser = TracerCompactFileParser(self.tracerFile, False, False)
1207  j = jsonInfo(parser)
1208  #print(j)
1209  self.assertEqual(len(j["modules"]), 2)
1210  self.assertEqual(len(j["esModules"]), 2)
1211  self.assertEqual(len(j['transitions']), 3)
1212  self.assertEqual(j['transitions'][0]['name'], "Global")
1213  self.assertEqual(j['transitions'][1]['name'], "Stream 0")
1214  self.assertEqual(j['transitions'][2]['name'], "Stream 1")
1215  self.assertEqual(len(j["transitions"][0]["slots"]), 2)
1216  self.assertEqual(len(j["transitions"][0]["slots"][0]), 15)
1217  self.assertEqual(len(j["transitions"][0]["slots"][1]), 6)
1218  self.assertEqual(len(j["transitions"][1]["slots"]), 2)
1219  self.assertEqual(len(j["transitions"][1]["slots"][0]), 5)
1220  self.assertEqual(len(j["transitions"][1]["slots"][1]), 5)
1221  self.assertEqual(len(j["transitions"][2]["slots"]), 2)
1222  self.assertEqual(len(j["transitions"][2]["slots"][0]), 5)
1223  self.assertEqual(len(j["transitions"][2]["slots"][1]), 3)
1225  parser = TracerCompactFileParser(self.tracerFile, False, True)
1226  j = jsonInfo(parser)
1227  #print(j)
1228  self.assertEqual(len(j["modules"]), 2)
1229  self.assertEqual(len(j["esModules"]), 2)
1230  self.assertEqual(len(j['transitions']), 6)
1231  self.assertEqual(j['transitions'][0]['name'], "Global")
1232  self.assertEqual(j['transitions'][1]['name'], "Stream 0")
1233  self.assertEqual(j['transitions'][2]['name'], "Stream 1")
1234  self.assertEqual(j['transitions'][3]['name'], "source")
1235  self.assertEqual(j['transitions'][4]['name'], "Module")
1236  self.assertEqual(j['transitions'][5]['name'], "ESModule")
1237  self.assertEqual(len(j["transitions"][0]["slots"]), 1)
1238  self.assertEqual(len(j["transitions"][0]["slots"][0]), 15)
1239  self.assertEqual(len(j["transitions"][1]["slots"]), 1)
1240  self.assertEqual(len(j["transitions"][1]["slots"][0]), 5)
1241  self.assertEqual(len(j["transitions"][2]["slots"]), 1)
1242  self.assertEqual(len(j["transitions"][2]["slots"][0]), 5)
1243  self.assertEqual(len(j["transitions"][4]["slots"]), 2)
1244  self.assertEqual(len(j["transitions"][4]["slots"][0]), 10)
1245  self.assertEqual(len(j["transitions"][4]["slots"][1]), 2)
1246  self.assertTrue(j["transitions"][4]["slots"][1][-1]['finish'] != 0.0)
1247  self.assertEqual(len(j["transitions"][5]["slots"]), 1)
1248  self.assertEqual(len(j["transitions"][5]["slots"][0]), 2)
1249 
1250 def runTests():
1251  return unittest.main(argv=sys.argv[:1])
1252 
1253 #=======================================
1254 if __name__=="__main__":
1255  import argparse
1256  import re
1257  import sys
1258 
1259  # Program options
1260  parser = argparse.ArgumentParser(description='Convert a compact tracer file into human readable output.',
1261  formatter_class=argparse.RawDescriptionHelpFormatter,
1262  epilog=printHelp())
1263  parser.add_argument('filename',
1264  type=argparse.FileType('r'), # open file
1265  help='file to process')
1266  parser.add_argument('-f', '--frameworkOnly',
1267  action='store_true',
1268  help='''Output only the framework transitions, excluding the individual module transitions.''')
1269  parser.add_argument('-j', '--json',
1270  action='store_true',
1271  help='''Write output in json format.''' )
1272  parser.add_argument('-w', '--web',
1273  action='store_true',
1274  help='''Writes data.js file that can be used with the web based inspector. To use, copy directory ${CMSSW_RELEASE_BASE}/src/FWCore/Services/template/web to a web accessible area and move data.js into that directory.''')
1275  parser.add_argument('-m', '--module_centric',
1276  action = 'store_true',
1277  help='''For --json or --web, organize data by module instead of by global/stream.''' )
1278  parser.add_argument('-t', '--test',
1279  action='store_true',
1280  help='''Run internal tests.''')
1281 
1282  args = parser.parse_args()
1283  if args.test:
1284  runTests()
1285  else :
1286  parser = TracerCompactFileParser(args.filename, args.frameworkOnly, args.module_centric)
1287  if args.json or args.web:
1288  j = json.dumps(jsonInfo(parser))
1289  if args.json:
1290  print(j)
1291  if args.web:
1292  f=open('data.json', 'w')
1293  f.write(j)
1294  f.close()
1295  else:
1296  textOutput(parser)
def _preJson(self, activity, counter, data, mayUseTemp=False)
def processingStepsFromFile(f, moduleNames, esModuleNames, recordNames, frameworkOnly, moduleCentric)
def __init__(self, payload, names, esNames, recordNames, moduleCentric)
def _postJson(self, counter, data, injectAfter=None)
def jsonTransition(type, id, sync, start, finish, isSrc=False)
def __init__(self, f, frameworkOnly, moduleCentric)
def _findOpenSlot(self, index, fullContainer)
def lineParserFactory(step, payload, moduleNames, esModuleNames, recordNames, frameworkOnly, moduleCentric)
def __init__(self, payload, names, esNames, recordNames)
def __init__(self, payload, names, esNames, recordNames, moduleCentric)
def findLastInModGlobals(self, index, modID, comparer)
def jsonModuleTransition(type, id, modID, callID, activity, start, finish=0)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:47
def _findLastIn(self, index, fullContainer, comparer)
def findMatchingTransition(sync, containers)
def textPrefix_(time, indentLevel)
def __init__(self, payload, moduleNames, esModuleNames, recordNames)
def __init__(self, payload, names, moduleCentric)
def findLastInModStreams(self, index, modID, comparer)
def __init__(self, payload, names, esNames, recordNames)
#define str(s)
def _findLastIn(self, index, fullContainer, comparer)
def popQueuedTransitions(sync, container)
def __init__(self, payload, names, esNames, recordNames)