CMS 3D CMS Logo

edmModuleAllocMonitorAnalyze.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 from builtins import range
3 from itertools import groupby
4 from operator import attrgetter,itemgetter
5 import sys
6 import json
7 from collections import defaultdict
8 #----------------------------------------------
9 def printHelp():
10  s = '''
11 To Use: Add the ModuleAllocMonitor Service to the cmsRun job use something like this
12  in the configuration:
13 
14  process.add_(cms.Service("ModuleAllocMonitor", fileName = cms.untracked.string("moduleAlloc.log")))
15 
16  After running the job, execute this script and pass the name of the
17  ModuleAllocMonitor log file to the script.
18 
19  This script will output a more human readable form of the data in the log file.'''
20  return s
21 
22 #these values come from moduleALloc_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 kMicroToSec = 0.000001
48 #Special names
49 kSourceFindEvent = "sourceFindEvent"
50 kSourceDelayedRead ="sourceDelayedRead"
51 #this value is defined in the framework itself
52 kLargestLumiNumber = 4294967295
53 
54 #these values must match the enum class Phase in tracer_setupFile.cc
55 class Phase (object):
56  destruction = -16
57  endJob = -12
58  endStream = -11
59  writeProcessBlock = -10
60  endProcessBlock = -9
61  globalWriteRun = -7
62  globalEndRun = -6
63  streamEndRun = -5
64  globalWriteLumi = -4
65  globalEndLumi = -3
66  streamEndLumi = -2
67  clearEvent = -1
68  Event = 0
69  streamBeginLumi = 2
70  globalBeginLumi = 3
71  streamBeginRun = 5
72  globalBeginRun = 6
73  accessInputProcessBlock = 8
74  beginProcessBlock = 9
75  openFile = 10
76  beginStream = 11
77  beginJob = 12
78  esSync = 13
79  esSyncEnqueue = 14
80  getNextTransition = 15
81  construction = 16
82  startTracing = 17
83 
84 #used for json output
85 class Activity (object):
86  prefetch = 0
87  acquire = 1
88  process = 2
89  delayedGet = 3
90  externalWork = 4
91  temporary = 100
92 
93 activityNames_ = { Activity.prefetch : 'prefetch',
94  Activity.acquire : 'acquire',
95  Activity.process : 'process',
96  Activity.delayedGet : 'delayedGet',
97  Activity.externalWork : 'externalWork' }
98 
99 def activityName(activity):
100  return activityNames_[activity]
101 
102 transitionToNames_ = {
103  Phase.startTracing: 'start tracing',
104  Phase.construction: 'construction',
105  Phase.destruction: 'destruction',
106  Phase.beginJob: 'begin job',
107  Phase.endJob: 'end job',
108  Phase.beginStream: 'begin stream',
109  Phase.endStream: 'end stream',
110  Phase.beginProcessBlock: 'begin process block',
111  Phase.endProcessBlock: 'end process block',
112  Phase.accessInputProcessBlock: 'access input process block',
113  Phase.writeProcessBlock: 'write process block',
114  Phase.globalBeginRun: 'global begin run',
115  Phase.globalEndRun: 'global end run',
116  Phase.globalWriteRun: 'global write run',
117  Phase.streamBeginRun: 'stream begin run',
118  Phase.streamEndRun: 'stream end run',
119  Phase.globalBeginLumi: 'global begin lumi',
120  Phase.globalEndLumi: 'global end lumi',
121  Phase.globalWriteLumi: 'global write lumi',
122  Phase.streamBeginLumi: 'stream begin lumi',
123  Phase.streamEndLumi: 'stream end lumi',
124  Phase.esSyncEnqueue: 'EventSetup synchronization',
125  Phase.esSync: 'EventSetup synchronization',
126  Phase.Event: 'event',
127  Phase.clearEvent: 'clear event',
128  Phase.getNextTransition: 'get next transition',
129  Phase.openFile : "open file"
130 }
131 
132 def transitionName(transition):
133  return transitionToNames_[transition]
134 
135 transitionToIndent_ = {
136  Phase.startTracing: 0,
137  Phase.construction: 0,
138  Phase.destruction: 0,
139  Phase.endJob: 0,
140  Phase.beginJob: 0,
141  Phase.beginStream: 0,
142  Phase.endStream: 0,
143  Phase.beginProcessBlock: 1,
144  Phase.endProcessBlock: 1,
145  Phase.accessInputProcessBlock: 1,
146  Phase.writeProcessBlock: 1,
147  Phase.globalBeginRun: 1,
148  Phase.globalEndRun: 1,
149  Phase.globalWriteRun: 1,
150  Phase.streamBeginRun: 1,
151  Phase.streamEndRun: 1,
152  Phase.globalBeginLumi: 2,
153  Phase.globalEndLumi: 2,
154  Phase.globalWriteLumi: 2,
155  Phase.streamBeginLumi: 2,
156  Phase.streamEndLumi: 2,
157  Phase.Event: 3,
158  Phase.clearEvent: 3,
159  Phase.esSyncEnqueue: 1,
160  Phase.esSync: 1,
161  Phase.getNextTransition: 1
162 }
163 def transitionIndentLevel(transition):
164  return transitionToIndent_[transition]
165 
166 globalTransitions_ = {
167  Phase.startTracing,
168  Phase.construction,
169  Phase.destruction,
170  Phase.endJob,
171  Phase.beginJob,
172  Phase.beginProcessBlock,
173  Phase.endProcessBlock,
174  Phase.accessInputProcessBlock,
175  Phase.writeProcessBlock,
176  Phase.globalBeginRun,
177  Phase.globalEndRun,
178  Phase.globalWriteRun,
179  Phase.globalBeginLumi,
180  Phase.globalEndLumi,
181  Phase.globalWriteLumi,
182  Phase.esSyncEnqueue,
183  Phase.esSync,
184  Phase.getNextTransition,
185  Phase.openFile
186 }
187 def transitionIsGlobal(transition):
188  return transition in globalTransitions_;
189 
190 def textPrefix_(time, indentLevel):
191  #using 11 spaces for time should accomodate a job that runs 24 hrs
192  return f'{time:>11} '+"++"*indentLevel
193 
195  def __init__(self,payload):
196  self.nAllocs = int(payload[0])
197  self.nDeallocs = int(payload[1])
198  self.added = int(payload[2])
199  self.minTemp = int(payload[3])
200  self.maxTemp = int(payload[4])
201  self.max1Alloc = int(payload[5])
202  def inject(self, transition):
203  transition["nAllocs"]=self.nAllocs
204  transition["nDeallocs"]=self.nDeallocs
205  transition["added"]=self.added
206  transition["minTemp"]=self.minTemp
207  transition["maxTemp"]=self.maxTemp
208  transition["max1Alloc"]=self.max1Alloc
209  def __repr__(self):
210  return "{{'nAlloc': {}, 'nDealloc': {}, 'added': {}, 'minTemp': {}, 'maxTemp': {}, 'max1Alloc': {} }}".format(self.nAllocs, self.nDeallocs, self.added, self.minTemp, self.maxTemp, self.max1Alloc)
211  def toSimpleDict(self):
212  return {'nAlloc' : self.nAllocs, 'nDealloc' :self.nDeallocs, 'added' : self.added, 'minTemp' : self.minTemp, 'maxTemp' : self.maxTemp, 'max1Alloc' : self.max1Alloc }
213 
215  def __init__(self):
216  self._runs = []
217  self._lumis = []
218  self._streams = []
219  def setRun(self, index, runNumber):
220  while len(self._runs) <= index:
221  self._runs.append(0)
222  self._runs[index] = runNumber
223  def runFor(self,index):
224  return self._runs[index]
225  def setLumi(self, index, runNumber, lumiNumber):
226  while len(self._lumis) <= index:
227  self._lumis.append((0,0))
228  self._lumis[index] = (runNumber, lumiNumber)
229  def lumiFor(self, index):
230  return self._lumis[index]
231  def setStream(self, index, runNumber, lumiNumber, eventNumber):
232  while len(self._streams) <= index:
233  self._streams.append((0,0,0))
234  self._streams[index] = (runNumber, lumiNumber, eventNumber)
235  def streamFor(self, index):
236  return self._streams[index]
237  def get(self, transition, index):
238  if transition == Phase.construction or transition == Phase.destruction:
239  return ()
240  if transition == Phase.beginJob or transition == Phase.endJob or transition == Phase.openFile:
241  return ()
242  if transition == Phase.globalBeginRun or transition == Phase.globalEndRun or transition == Phase.globalWriteRun:
243  return (self.runFor(index),)
244  if transition == Phase.globalBeginLumi or transition == Phase.globalEndLumi or transition == Phase.globalWriteLumi:
245  return self.lumiFor(index)
246  if transition == Phase.getNextTransition:
247  return ()
248  if transition == Phase.writeProcessBlock:
249  return ()
250  if transition == Phase.beginStream:
251  self.setStream(index, 0,0,0)
252  return ()
253  if not transitionIsGlobal(transition):
254  return self.streamFor(index)
255  raise RuntimeError("Unknown transition {}".format(transition))
256 
258  def __init__(self):
259  self._times = {}
260  self._esTimes = {}
261  def insertTime(self, label, transition, index, time):
262  self._times[(label, transition, index)] = time
263  def findTime(self, label, transition, index):
264  time = self._times[(label, transition, index)]
265  del self._times[(label, transition, index)]
266  return time
267  def insertTimeES(self, label, transition, index, record, call, time):
268  self._esTimes[(label, transition, index, record, call)] = time
269  def findTimeES(self, label, transition, index, record, call):
270  time = self._esTimes[(label, transition, index, record, call)]
271  del self._esTimes[(label, transition, index, record, call)]
272  return time
273 
275  def __init__(self, start, stop, transition, sync, activity, allocInfo, recordName=None, callID=None):
276  self.timeRange = (start, stop)
277  self.transition = transition
278  self.sync = sync
279  self.activity = activity
280  self.allocInfo = allocInfo
281  self.record = (recordName, callID)
282  def __repr__(self):
283  if self.record[0]:
284  return "{{ 'timeRange': {}, 'transition': {}, 'sync' :{}, 'activity':{}, 'record': {{'name' : {}, 'callID' :{} }}, 'alloc':{} }}".format(self.timeRange, self.transition, self.sync, self.activity, self.record[0], self.record[1], self.allocInfo)
285 
286  return "{{ 'timeRange': {}, 'transition': {}, 'sync' :{}, 'activity':{}, 'alloc':{} }}".format(self.timeRange, self.transition, self.sync, self.activity, self.allocInfo)
287  def syncToSimpleDict(self):
288  if len(self.sync) == 0:
289  return self.sync
290  if len(self.sync) == 1:
291  return {'run' : self.sync[0]}
292  if len(self.sync) == 2:
293  return {'run' : self.sync[0], 'lumi' : self.sync[1] }
294  return {'run' : self.sync[0], 'lumi' : self.sync[1], 'event' : self.sync[2] }
295  def toSimpleDict(self) :
296  if self.record[0]:
297  return {'timeRange': self.timeRange, 'transition': transitionName(self.transition), 'sync' : self.syncToSimpleDict(), 'activity' : activityName(self.activity), 'record' :{'name': self.record[0], 'callID' : self.record[1] }, 'alloc' : self.allocInfo.toSimpleDict() }
298  return {'timeRange': self.timeRange, 'transition': transitionName(self.transition), 'sync' : self.syncToSimpleDict(), 'activity': activityName(self.activity), 'alloc' : self.allocInfo.toSimpleDict() }
299 
300 
302  def __init__(self):
303  self._data = {}
304  self._last = {}
305  self._startTime = None
306  def setStartTime(self, time):
307  self._startTime = time
308  def insert(self, label, start, stop, transition, index, sync, activity, allocInfo, recordName=None, callID=None):
309  if label not in self._data:
310  self._data[label] = []
311  self._data[label].append(ModuleData(start, stop, transition, sync, activity, allocInfo, recordName, callID))
312  self._last[(label, transition, index, activity)] = self._data[label][-1]
313  def findLast(self, label, transition, index, activity):
314  return self._last[(label, transition, index, activity)]
315  def __repr__(self):
316  return str(self._data)
317  def data(self):
318  return self._data
319  def toSimpleDict(self):
320  dct = {'startedMonitoring': self._startTime, 'source' :[], 'clearEvent': [], 'modules' :{}}
321  modules = dct['modules']
322  for m,lst in self._data.items():
323  l = None
324  if m == 'source':
325  l = dct['source']
326  elif m == 'clearEvent':
327  l = dct['clearEvent']
328  else:
329  modules[m]=[]
330  l = modules[m]
331  for d in lst:
332  l.append( d.toSimpleDict() )
333  return dct
334  def sortModulesBy(self, attribute):
335  data = []
336  for m, lst in self._data.items():
337  data.append((m, max(lst, key = lambda x: getattr(x.allocInfo,attribute))) )
338  data.sort( key = lambda x: getattr(x[1].allocInfo,attribute), reverse=True)
339  return list(map(lambda x: (x[0], x[1].toSimpleDict()), data))
340 
342  def __init__(self):
343  self._data = []
344  self._last = {}
345  self._startTime = None
346  def setStartTime(self, time):
347  self._startTime = time
348  def insert(self, label, start, stop, transition, index, sync, activity, allocInfo, recordName=None, callID=None):
349  self._data.append((label, ModuleData(start, stop, transition, sync, activity, allocInfo, recordName, callID)))
350  self._last[(label,transition, index, activity)] = self._data[-1]
351  def findLast(self, label, transition,index, activity):
352  v = self._last.get((label, transition, index, activity), None)
353  if v:
354  return v[1]
355  return None
356  def __repr__(self):
357  return str(self._data)
358  def data(self):
359  return self._data
360  def toSimpleDict(self):
361  dct = {'startedMonitoring': self._startTime, 'measurements' :[]}
362  measurements = dct['measurements']
363  for d in self._data:
364  entry = d[1].toSimpleDict()
365  entry['label'] = d[0]
366  measurements.append(entry)
367  return dct
368 
369 
370 
371 
373  def __init__(self, payload):
374  self.transition = int(payload[0])
375  self.index = int(payload[1])
376  self.sync = (int(payload[2]), int(payload[3]), int(payload[4]))
377  self.time = int(payload[5])
378  def indentLevel(self):
379  return transitionIndentLevel(self.transition)
380  def textPrefix(self):
381  return textPrefix_(self.time, self.indentLevel())
382  def syncText(self):
383  if self.transition == Phase.globalBeginRun or Phase.globalEndRun == self.transition:
384  return f'run={self.sync[0]}'
385  if self.transition == Phase.globalWriteRun:
386  return f'run={self.sync[0]}'
387  if self.transition == Phase.streamBeginRun or Phase.streamEndRun == self.transition:
388  return f'run={self.sync[0]}'
389  if self.transition == Phase.globalBeginLumi or Phase.globalEndLumi == self.transition:
390  return f'run={self.sync[0]} lumi={self.sync[1]}'
391  if self.transition == Phase.globalWriteLumi:
392  return f'run={self.sync[0]} lumi={self.sync[1]}'
393  if self.transition == Phase.streamBeginLumi or Phase.streamEndLumi == self.transition:
394  return f'run={self.sync[0]} lumi={self.sync[1]}'
395  if self.transition == Phase.Event:
396  return f'run={self.sync[0]} lumi={self.sync[1]} event={self.sync[2]}'
397  if self.transition == Phase.esSyncEnqueue or self.transition == Phase.esSync:
398  return f'run={self.sync[0]} lumi={self.sync[1]}'
399  if self.transition == Phase.beginJob:
400  return ''
401  if self.transition == Phase.beginProcessBlock or self.transition == Phase.endProcessBlock or self.transition == Phase.writeProcessBlock or self.transition == Phase.accessInputProcessBlock:
402  return ''
403  if self.transition == Phase.startTracing:
404  return ''
405  if self.transition == Phase.construction or self.transition == Phase.destruction:
406  return ''
407  def textPostfix(self):
408  return f'{transitionName(self.transition)} : id={self.index} {self.syncText()}'
409  def text(self, context):
410  return f'{self.textPrefix()} {self.textSpecial()}: {self.textPostfix()}'
411 
412 def findMatchingTransition(sync, containers):
413  for i in range(len(containers)):
414  if containers[i][-1]["sync"] == sync:
415  return i
416  #need more exhausting search
417  for i in range(len(containers)):
418  for t in containers[i]:
419  if t["sync"] == sync:
420  return i
421 
422  print("find failed",sync, containers)
423  return None
424 
425 transitionsToFindMatch_ = {
426  Phase.globalEndRun,
427  Phase.globalEndLumi,
428  Phase.globalWriteRun,
429  Phase.globalWriteLumi
430 }
431 
433  def __init__(self, payload):
434  super().__init__(payload)
435  def textSpecial(self):
436  return "starting"
437  def jsonInfo(self, syncs, temp, data):
438  isSourceTrans = False
439  if self.transition == Phase.startTracing:
440  data.setStartTime(self.time)
441  elif self.transition == Phase.globalBeginRun:
442  syncs.setRun(self.index, self.sync[0])
443  isSourceTrans = True
444  elif self.transition == Phase.globalBeginLumi:
445  syncs.setLumi(self.index, self.sync[0], self.sync[1])
446  isSourceTrans = True
447  elif self.transition == Phase.Event:
448  syncs.setStream(self.index, self.sync[0], self.sync[1], self.sync[2])
449  isSourceTrans = True
450  elif self.transition == Phase.clearEvent:
451  temp.insertTime("clearEvent", self.transition, self.index, self.time)
452  elif not transitionIsGlobal(self.index):
453  syncs.setStream(self.index, self.sync[0], self.sync[1], self.sync[2])
454  if isSourceTrans:
455  src = data.findLast("source", self.transition, self.index, Activity.process)
456  if src.sync != self.index:
457  raise RuntimeError("Framework and Source transitions do not have matching index: source {} framework {} for transition type {} at framework time {} and source time {}".format(src.sync, self.index, self.transition, self.time, src.timeRange))
458  src.sync = syncs.get(self.transition, self.index)
459  def jsonVisInfo(self, data):
461  index = 0
462  if self.transition == Phase.startTracing:
463  data.indexedGlobal(0).append(jsonTransition(type=self.transition, id=index, sync=list(self.sync),start=0, finish=self.time ))
464  return
465  elif self.transition==Phase.globalBeginRun:
466  index = self.index
467  container = data.indexedGlobal(index)
468  #find source, should be previous
469  last = container[-1]
470  if last["type"]==Phase.globalBeginRun and last["isSrc"]:
471  last["sync"]=list(self.sync)
472  elif self.transition==Phase.globalBeginLumi:
473  index = self.index
474  container = data.indexedGlobal(index)
475  #find source, should be previous
476  last = container[-1]
477  if last["type"]==Phase.globalBeginLumi and last["isSrc"]:
478  last["sync"]=list(self.sync)
479  elif self.transition in transitionsToFindMatch_:
480  index = findMatchingTransition(list(self.sync), data.allGlobals())
481  container = data.indexedGlobal(index)
482  else:
483  container = data.indexedStream(self.index)
484  if self.transition == Phase.Event:
485  #find source, should be previous
486  last = container[-1]
487  if last["type"]==Phase.Event and last["isSrc"]:
488  last["sync"]=list(self.sync)
489  index = self.index
490  container.append( jsonTransition(type=self.transition, id = index, sync=list(self.sync), start=self.time , finish=0))
491 
492 
493 
495  def __init__(self, payload):
496  super().__init__(payload)
497  if self.transition == Phase.clearEvent:
498  self.alloc = AllocInfo(payload[6:])
499  def textSpecial(self):
500  return "finished"
501  def jsonInfo(self, syncs, temp, data):
502  if self.transition == Phase.clearEvent:
503  start = temp.findTime("clearEvent", self.transition, self.index)
504  data.insert( "clearEvent" , start, self.time, self.transition, self.index, syncs.get(Phase.Event, self.index) , Activity.process, self.alloc)
505  def jsonVisInfo(self, data):
507  index = findMatchingTransition(list(self.sync), data.allGlobals())
508  container = data.indexedGlobal(index)
509  else:
510  container = data.indexedStream(self.index)
511  container[-1]["finish"]=self.time*kMicroToSec
512  if self.transition == Phase.clearEvent:
513  self.alloc.inject(container[-1])
514 
515 
516 
518  def __init__(self, payload):
519  self.transition = int(payload[0])
520  if self.transition == Phase.getNextTransition:
521  self.time = int(payload[1])
522  self.index = -1
523  return
524  self.index = int(payload[1])
525  self.time = int(payload[2])
526  def indentLevel(self):
527  if self.transition == Phase.globalBeginRun:
528  return 1
529  if self.transition == Phase.globalBeginLumi:
530  return 2
531  if self.transition == Phase.Event:
532  return 3
533  if self.transition == Phase.construction:
534  return 1
535  if self.transition == Phase.getNextTransition:
536  return 1
537  if self.transition == Phase.openFile:
538  return 1
539  return None
540  def textPrefix(self):
541  return textPrefix_(self.time, self.indentLevel())
542  def textPostfix(self):
543  return f'source during {transitionName(self.transition)} : id={self.index}'
544  def text(self, context):
545  return f'{self.textPrefix()} {self.textSpecial()}: {self.textPostfix()}'
546 
548  def __init__(self, payload, moduleCentric):
549  self._moduleCentric = moduleCentric
550  super().__init__(payload)
551  def textSpecial(self):
552  return "starting"
553  def jsonInfo(self, syncs, temp, data):
554  temp.insertTime("source", self.transition, self.index, self.time)
555  def jsonVisInfo(self, data):
556  if self.transition == Phase.getNextTransition:
557  data._nextTrans.append(jsonTransition(type=self.transition, id=self.index, sync=[0,0,0], start=self.time, finish=0, isSrc=True))
558  if self._moduleCentric:
559  #this all goes to a module ID sorted container so not knowing actual index is OK
560  data.findOpenSlotInModGlobals(0,0).append(data._nextTrans[-1])
561  return
562  elif self.transition == Phase.construction:
563  index = 0
564  container = data.indexedGlobal(index)
565  elif self.transition == Phase.Event:
566  index = self.index
567  container = data.indexedStream(index)
568  else:
569  index = self.index
570  container = data.indexedGlobal(index)
571  nextTrans = data._nextTrans
572  if nextTrans:
573  data._nextTrans = []
574  for t in nextTrans:
575  t['id']=index
576  #find proper time order in the container
577  transStartTime = t['start']
578  inserted = False
579  for i in range(-1, -1*len(container), -1):
580  if transStartTime > container[i]['start']:
581  if i == -1:
582  container.append(t)
583  inserted = True
584  break
585  else:
586  container.insert(i+1,t)
587  inserted = True
588  break
589  if not inserted:
590  container.insert(0,t)
591  container.append(jsonTransition(type=self.transition, id=index, sync=[0,0,0], start=self.time, finish=0, isSrc=True))
592  if self._moduleCentric:
593  if self.transition == Phase.Event:
594  data.findOpenSlotInModStreams(index,0).append(container[-1])
595  else:
596  data.findOpenSlotInModGlobals(index,0).append(container[-1])
597 
599  def __init__(self, payload, moduleCentric):
600  super().__init__(payload)
601  #print(payload)
602  if self.index == -1:
603  self.allocInfo = AllocInfo(payload[2:])
604  else:
605  self.allocInfo = AllocInfo(payload[3:])
606  self._moduleCentric = moduleCentric
607  def textSpecial(self):
608  return "finished"
609  def jsonInfo(self, syncs, temp, data):
610  start = temp.findTime("source", self.transition, self.index)
611  #we do not know the sync yet so have to wait until the framework transition
612  if self.transition in [ Phase.construction, Phase.getNextTransition, Phase.destruction, Phase.openFile]:
613  data.insert( "source" , start, self.time, self.transition, self.index, (0,) , Activity.process, self.allocInfo)
614  else:
615  data.insert( "source" , start, self.time, self.transition, self.index, self.index , Activity.process, self.allocInfo)
616  def jsonVisInfo(self, data):
617  index = self.index
618  if self.transition == Phase.Event:
619  container = data.indexedStream(index)
620  elif self.transition == Phase.getNextTransition:
621  data._nextTrans[-1]['finish'] = self.time*kMicroToSec
622  self.allocInfo.inject(data._nextTrans[-1])
623  return
624  elif self.transition == Phase.construction:
625  pre = None
626  for i, g in enumerate(data.allGlobals()):
627  for t in reversed(g):
628  if t["type"] != Phase.construction:
629  break
630  if t["isSrc"]:
631  pre = t
632  break
633  if pre:
634  pre["finish"]=self.time*kMicroToSec
635  self.allocInfo.inject(pre)
636  break
637  return
638  else:
639  container = data.indexedGlobal(index)
640 
641  container[-1]["finish"]=self.time*kMicroToSec
642  self.allocInfo.inject(container[-1])
643 
645  def __init__(self, payload, moduleNames):
646  self.transition = int(payload[0])
647  self.index = int(payload[1])
648  self.moduleID = int(payload[2])
649  self.moduleName = moduleNames[self.moduleID]
650  self.callID = int(payload[3])
651  self.time = int(payload[4])
652  def baseIndentLevel(self):
653  return transitionIndentLevel(self.transition)
654  def textPrefix(self, context):
655  indent = 0
656  context[(self.transition, self.index, self.moduleID, self.callID)] = indent+1
657  return textPrefix_(self.time, indent+1+self.baseIndentLevel())
658  def textPostfix(self):
659  return f'{self.moduleName} during {transitionName(self.transition)} : id={self.index}'
660  def textIfTransform(self):
661  if self.callID:
662  return f' transform {self.callID-1}'
663  return ''
664  def text(self, context):
665  return f'{self.textPrefix(context)} {self.textSpecial()}{self.textIfTransform()}: {self.textPostfix()}'
666  def _preJsonVis(self, activity, data, mayUseTemp = False):
667  index = self.index
668  found = False
669  if mayUseTemp:
670  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)
672  item,slot = data.findLastInModGlobals(index, self.moduleID, compare)
673  else:
674  item,slot = data.findLastInModStreams(index, self.moduleID, compare)
675  if slot:
676  if item['act'] == Activity.temporary:
677  slot.pop()
678  else:
679  item['finish']=self.time*kMicroToSec
680  found = True
681  if not found:
683  slot = data.findOpenSlotInModGlobals(index, self.moduleID)
684  else:
685  slot = data.findOpenSlotInModStreams(index, self.moduleID)
686  slot.append(jsonModuleTransition(type=self.transition, id=self.index, modID=self.moduleID, callID=self.callID, activity=activity, start=self.time))
687  return slot[-1]
688  def _postJsonVis(self, data, alloc, injectAfter = None):
689  compare = lambda x: x['id'] == self.index and x['mod'] == self.moduleID and x['call'] == self.callID and x['type'] == self.transition
690  index = self.index
692  item,slot = data.findLastInModGlobals(index, self.moduleID, compare)
693  else:
694  item,slot = data.findLastInModStreams(index, self.moduleID, compare)
695  if item is None:
696  print(f"failed to find {self.moduleID} for {self.transition} in {self.index}")
697  else:
698  item["finish"]=self.time*kMicroToSec
699  alloc.inject(item)
700  if injectAfter:
701  slot.append(injectAfter)
702  def _preJsonInfo(self, temp):
703  temp.insertTime(self.moduleName, self.transition, self.index, self.time)
704  def _postJsonInfo(self, syncs, temp, data, activity):
705  start = temp.findTime(self.moduleName, self.transition, self.index)
706  data.insert( self.moduleName , start, self.time, self.transition, self.index, syncs.get(self.transition, self.index) , activity, self.allocInfo)
707 
708 
710  def __init__(self, payload, names, moduleCentric):
711  super().__init__(payload, names)
712  self._moduleCentric = moduleCentric
713  def textSpecial(self):
714  return "starting action"
715  def jsonVisInfo(self, data):
716  return self._preJsonVis(Activity.process, data, mayUseTemp=self._moduleCentric)
717  def jsonInfo(self, syncs, temp, data):
718  self._preJsonInfo(temp)
719 
720 
722  def __init__(self, payload, names):
723  super().__init__(payload, names)
724  self.allocInfo = AllocInfo(payload[5:])
725  def textSpecial(self):
726  return "finished action"
727  def jsonInfo(self, syncs, temp, data):
728  self._postJsonInfo(syncs, temp, data, Activity.process)
729  def jsonVisInfo(self, data):
730  return self._postJsonVis(data, self.allocInfo)
731 
732 
734  def __init__(self, payload, names, moduleCentric):
735  super().__init__(payload, names)
736  self._moduleCentric = moduleCentric
737  def textSpecial(self):
738  return "starting acquire"
739  def jsonVisInfo(self, data):
740  return self._preJsonVis(Activity.acquire, data, mayUseTemp=self._moduleCentric)
741  def jsonInfo(self, syncs, temp, data):
742  self._preJsonInfo(temp)
743 
744 
746  def __init__(self, payload, names, moduleCentric):
747  super().__init__(payload, names)
748  self.allocInfo = AllocInfo(payload[5:])
749  self._moduleCentric = moduleCentric
750  def textSpecial(self):
751  return "finished acquire"
752  def jsonVisInfo(self, data):
753  if self._moduleCentric:
754  #inject an external work at end of the same slot to guarantee module run is in that slot
755  return self._postJsonVis( data, jsonModuleTransition(type=self.transition, id=self.index, modID=self.moduleID, callID=self.callID, activity=Activity.externalWork, start=self.time))
756  return self._postJsonVis(data, self.allocInfo)
757  def jsonInfo(self, syncs, temp, data):
758  self._postJsonInfo(syncs, temp, data, Activity.acquire)
759 
761  def __init__(self, payload, names):
762  super().__init__(payload, names)
763  def textSpecial(self):
764  return "starting delayed get"
765  def jsonVisInfo(self, data):
766  return self._preJsonVis(Activity.delayedGet, data)
767  def jsonInfo(self, syncs, temp, data):
768  pass
769  #self._preJsonInfo(temp)
770 
771 class PostEDModuleEventDelayedGetParser(EDModuleTransitionParser):
772  def __init__(self, payload, names):
773  super().__init__(payload, names)
774  self.allocInfo = AllocInfo(payload[5:])
775  def textSpecial(self):
776  return "finished delayed get"
777  def jsonVisInfo(self, data):
778  return self._postJsonVis(data, self.allocInfo)
779  def jsonInfo(self, syncs, temp, data):
780  pass
781  #self._postJsonInfo(syncs, temp, data, Activity.delayedGet)
782 
783 class PreEventReadFromSourceParser(EDModuleTransitionParser):
784  def __init__(self, payload, names):
785  super().__init__(payload, names)
786  def textSpecial(self):
787  return "starting read from source"
788  def jsonVisInfo(self, data):
789  slot = self._preJsonVis(Activity.process, data)
790  slot['isSrc'] = True
791  return slot
792  def jsonInfo(self, syncs, temp, data):
793  temp.insertTime(self.moduleName+'source', self.transition, self.index, self.time)
794 
796  def __init__(self, payload, names):
797  super().__init__(payload, names)
798  self.allocInfo = AllocInfo(payload[5:])
799  def textSpecial(self):
800  return "finished read from source"
801  def jsonVisInfo(self, data):
802  return self._postJsonVis(data, self.allocInfo)
803  def jsonInfo(self, syncs, temp, data):
804  start = temp.findTime(self.moduleName+'source', self.transition, self.index)
805  data.insert( "source" , start, self.time, self.transition, self.index, syncs.get(self.transition, self.index) , Activity.delayedGet, self.allocInfo)
806 
808  def __init__(self, payload, moduleNames, esModuleNames, recordNames):
809  self.transition = int(payload[0])
810  self.index = int(payload[1])
811  self.moduleID = int(payload[2])
812  self.moduleName = esModuleNames[self.moduleID]
813  self.recordID = int(payload[3])
814  self.recordName = recordNames[self.recordID]
815  self.callID = int(payload[4])
816  self.time = int(payload[5])
817  def baseIndentLevel(self):
818  return transitionIndentLevel(self.transition)
819  def textPrefix(self, context):
820  indent = 0
821  context[(self.transition, self.index, -1*self.moduleID, self.callID)] = indent+1
822  return textPrefix_(self.time, indent+1+self.baseIndentLevel())
823  def textPostfix(self):
824  return f'esmodule {self.moduleName} in record {self.recordName} during {transitionName(self.transition)} : id={self.index}'
825  def text(self, context):
826  return f'{self.textPrefix(context)} {self.textSpecial()}: {self.textPostfix()}'
827  def _preJsonVis(self, activity, data):
828  index = self.index
830  slot = data.findOpenSlotInModGlobals(index, -1*self.moduleID)
831  else:
832  slot = data.findOpenSlotInModStreams(index, -1*self.moduleID)
833  slot.append(jsonModuleTransition(type=self.transition, id=self.index, modID=-1*self.moduleID, callID=self.callID, activity=activity, start=self.time))
834  return slot[-1]
835  def _postJsonVis(self, data, alloc):
836  compare = lambda x: x['id'] == self.index and x['mod'] == -1*self.moduleID and x['call'] == self.callID
837  index = self.index
839  item,s = data.findLastInModGlobals(index, -1*self.moduleID, compare)
840  else:
841  item,s = data.findLastInModStreams(index, -1*self.moduleID, compare)
842  if item is None:
843  print(f"failed to find {-1*self.moduleID} for {self.transition} in {self.index}")
844  return
845  item["finish"]=self.time*kMicroToSec
846  alloc.inject(item)
847  def _preJsonInfo(self, temp):
848  temp.insertTimeES(self.moduleName, self.transition, self.index, self.recordID, self.callID, self.time)
849  def _postJsonInfo(self, syncs, temp, data, activity):
850  start = temp.findTimeES(self.moduleName, self.transition, self.index, self.recordID, self.callID)
851  data.insert( self.moduleName , start, self.time, self.transition, self.index, syncs.get(self.transition, self.index) , activity, self.allocInfo, self.recordName, self.callID)
852 
853 
855  def __init__(self, payload, names, esNames, recordNames):
856  super().__init__(payload, names, esNames, recordNames)
857  def textSpecial(self):
858  return "starting action"
859  def jsonVisInfo(self, data):
860  return self._preJsonVis(Activity.process, data)
861  def jsonInfo(self, syncs, temp, data):
862  self._preJsonInfo(temp)
863 
865  def __init__(self, payload, names, esNames, recordNames):
866  super().__init__(payload, names, esNames, recordNames)
867  self.allocInfo = AllocInfo(payload[6:])
868  def textSpecial(self):
869  return "finished action"
870  def jsonVisInfo(self, data):
871  return self._postJsonVis(data,self.allocInfo)
872  def jsonInfo(self, syncs, temp, data):
873  self._postJsonInfo(syncs, temp, data, Activity.process)
874 
876  def __init__(self, payload, names, recordNames):
877  super().__init__(payload, names, recordNames)
878  def textSpecial(self):
879  return "starting acquire"
880  def jsonVisInfo(self, data):
881  return self._preJsonVis(Activity.acquire, data)
882 
884  def __init__(self, payload, names, esNames, recordNames):
885  super().__init__(payload, names, esNames, recordNames)
886  self.allocInfo = AllocInfo(payload[6:])
887  def textSpecial(self):
888  return "finished acquire"
889  def jsonVisInfo(self, data):
890  return self._postJsonVis(data, self.allocInfo)
891 
892 
893 def lineParserFactory (step, payload, moduleNames, esModuleNames, recordNames, moduleCentric):
894  if step == 'F':
895  parser = PreFrameworkTransitionParser(payload)
896  return parser
897  if step == 'f':
898  return PostFrameworkTransitionParser(payload)
899  if step == 'S':
900  return PreSourceTransitionParser(payload, moduleCentric)
901  if step == 's':
902  return PostSourceTransitionParser(payload, moduleCentric)
903  if step == 'M':
904  return PreEDModuleTransitionParser(payload, moduleNames, moduleCentric)
905  if step == 'm':
906  return PostEDModuleTransitionParser(payload, moduleNames)
907  if step == 'A':
908  return PreEDModuleAcquireParser(payload, moduleNames, moduleCentric)
909  if step == 'a':
910  return PostEDModuleAcquireParser(payload, moduleNames, moduleCentric)
911  if step == 'D':
912  return PreEDModuleEventDelayedGetParser(payload, moduleNames)
913  if step == 'd':
914  return PostEDModuleEventDelayedGetParser(payload, moduleNames)
915  if step == 'R':
916  return PreEventReadFromSourceParser(payload, moduleNames)
917  if step == 'r':
918  return PostEventReadFromSourceParser(payload, moduleNames)
919  if step == 'N':
920  return PreESModuleTransitionParser(payload, moduleNames, esModuleNames, recordNames)
921  if step == 'n':
922  return PostESModuleTransitionParser(payload, moduleNames, esModuleNames, recordNames)
923  if step == 'B':
924  return PreESModuleAcquireParser(payload, moduleNames, esModuleNames, recordNames)
925  if step == 'b':
926  return PostESModuleAcquireParser(payload, moduleNames, esModuleNames, recordNames)
927  raise LogicError("Unknown step '{}'".format(step))
928 
929 #----------------------------------------------
930 def processingStepsFromFile(f,moduleNames, esModuleNames, recordNames, moduleCentric):
931  for rawl in f:
932  l = rawl.strip()
933  if not l or l[0] == '#':
934  continue
935  (step,payload) = tuple(l.split(None,1))
936  payload=payload.split()
937 
938  parser = lineParserFactory(step, payload, moduleNames, esModuleNames, recordNames, moduleCentric)
939  if parser:
940  yield parser
941  return
942 
944  def __init__(self,f, moduleCentric):
945  streamBeginRun = str(Phase.streamBeginRun)
946  numStreams = 0
947  numStreamsFromSource = 0
948  moduleNames = {}
949  esModuleNames = {}
950  recordNames = {}
951  for rawl in f:
952  l = rawl.strip()
953  if l and l[0] == 'M':
954  i = l.split(' ')
955  if i[3] == streamBeginRun:
956  #found global begin run
957  numStreams = int(i[1])+1
958  break
959  if numStreams == 0 and l and l[0] == 'S':
960  s = int(l.split(' ')[1])
961  if s > numStreamsFromSource:
962  numStreamsFromSource = s
963  if len(l) > 5 and l[0:2] == "#M":
964  (id,name)=tuple(l[2:].split())
965  moduleNames[int(id)] = name
966  continue
967  if len(l) > 5 and l[0:2] == "#N":
968  (id,name)=tuple(l[2:].split())
969  esModuleNames[int(id)] = name
970  continue
971  if len(l) > 5 and l[0:2] == "#R":
972  (id,name)=tuple(l[2:].split())
973  recordNames[int(id)] = name
974  continue
975 
976  self._f = f
977  self._moduleCentric = moduleCentric
978  if numStreams == 0:
979  numStreams = numStreamsFromSource +2
980  self.numStreams =numStreams
981  self._moduleNames = moduleNames
982  self._esModuleNames = esModuleNames
983  self._recordNames = recordNames
984  self.maxNameSize =0
985  for n in moduleNames.items():
986  self.maxNameSize = max(self.maxNameSize,len(n))
987  for n in esModuleNames.items():
988  self.maxNameSize = max(self.maxNameSize,len(n))
989  self.maxNameSize = max(self.maxNameSize,len(kSourceDelayedRead))
990  self.maxNameSize = max(self.maxNameSize, len('streamBeginLumi'))
991 
992  def processingSteps(self):
993  """Create a generator which can step through the file and return each processing step.
994  Using a generator reduces the memory overhead when parsing a large file.
995  """
996  self._f.seek(0)
998 
999 def textOutput( parser ):
1000  context = {}
1001  for p in parser.processingSteps():
1002  print(p.text(context))
1003 
1005  def __init__(self):
1006  self._modGlobals = [[]]
1007  self._modStreams = [[]]
1008  self._globals = [[]]
1009  self._streams = [[]]
1010  self._nextTrans = []
1011  def _extendIfNeeded(self, container, index):
1012  while len(container) < index+1:
1013  container.append([])
1014  def allGlobals(self):
1015  return self._globals
1016  def indexedGlobal(self, index):
1017  self._extendIfNeeded(self._globals, index)
1018  return self._globals[index]
1019  def allStreams(self):
1020  return self._streams
1021  def indexedStream(self, index):
1022  self._extendIfNeeded(self._streams, index)
1023  return self._streams[index]
1024  def _findOpenSlot(self, index, fullContainer):
1025  self._extendIfNeeded(fullContainer, index)
1026  container = fullContainer[index]
1027  #find open slot
1028  foundOpenSlot = False
1029  for slot in container:
1030  if len(slot) == 0:
1031  foundOpenSlot = True
1032  break
1033  if slot[-1]["finish"] != 0:
1034  foundOpenSlot = True
1035  break
1036  if not foundOpenSlot:
1037  container.append([])
1038  slot = container[-1]
1039  return slot
1040  def findOpenSlotInModGlobals(self, index, modID):
1041  return self._findOpenSlot(index, self._modGlobals)
1042  def findOpenSlotInModStreams(self, index, modID):
1043  return self._findOpenSlot(index, self._modStreams)
1044  def _findLastIn(self, index, fullContainer, comparer):
1045  container = fullContainer[index]
1046  #find slot containing the pre
1047  for slot in container:
1048  if comparer(slot[-1]):
1049  return (slot[-1],slot)
1050  return (None,None)
1051  def findLastInModGlobals(self, index, modID, comparer):
1052  return self._findLastIn(index, self._modGlobals, comparer)
1053  def findLastInModStreams(self, index, modID, comparer):
1054  return self._findLastIn(index, self._modStreams, comparer)
1055 
1056 
1058  def __init__(self):
1059  self._modules= []
1060  self._globals = [[]]
1061  self._streams = [[]]
1062  self._nextTrans = []
1064  def _moduleID2Index(self, modID):
1065  return modID + self._moduleIDOffset
1066  def _extendIfNeeded(self, container, index):
1067  while len(container) < index+1:
1068  container.append([])
1069  def _extendModulesIfNeeded(self, container, index):
1070  while index + self._moduleIDOffset < 0:
1071  container.insert(0,[])
1072  self._moduleIDOffset +=1
1073  self._extendIfNeeded(container, self._moduleID2Index(index))
1074  def allGlobals(self):
1075  return self._globals
1076  def indexedGlobal(self, index):
1077  self._extendIfNeeded(self._globals, index)
1078  return self._globals[index]
1079  def allStreams(self):
1080  return self._streams
1081  def indexedStream(self, index):
1082  self._extendIfNeeded(self._streams, index)
1083  return self._streams[index]
1084  def _findOpenSlot(self, index, fullContainer):
1085  self._extendModulesIfNeeded(fullContainer, index)
1086  container = fullContainer[self._moduleID2Index(index)]
1087  #find open slot
1088  foundOpenSlot = False
1089  for slot in container:
1090  if len(slot) == 0:
1091  foundOpenSlot = True
1092  break
1093  if slot[-1]["finish"] != 0:
1094  foundOpenSlot = True
1095  break
1096  if not foundOpenSlot:
1097  container.append([])
1098  slot = container[-1]
1099  return slot
1100  def findOpenSlotInModGlobals(self, index, modID):
1101  return self._findOpenSlot(modID, self._modules)
1102  def findOpenSlotInModStreams(self, index, modID):
1103  return self._findOpenSlot(modID, self._modules)
1104  def _findLastIn(self, index, fullContainer, comparer):
1105  if not fullContainer:
1106  return (None, None)
1107  if len(fullContainer) > self._moduleID2Index(index):
1108  container = fullContainer[self._moduleID2Index(index)]
1109  else:
1110  return (None, None)
1111  #find slot containing the pre
1112  for slot in container:
1113  if slot is not None and comparer(slot[-1]):
1114  return (slot[-1],slot)
1115  return (None, None)
1116  def findLastInModGlobals(self, index, modID, comparer):
1117  return self._findLastIn(modID, self._modules, comparer)
1118  def findLastInModStreams(self, index, modID, comparer):
1119  return self._findLastIn(modID, self._modules, comparer)
1120 
1121 
1123  def __init__(self):
1124  self._modules= []
1125  self._globals = [[]]
1126  self._streams = [[]]
1127  self._nextTrans = []
1129  def _moduleID2Index(self, modID):
1130  return modID + self._moduleIDOffset
1131  def _extendIfNeeded(self, container, index):
1132  while len(container) < index+1:
1133  container.append([])
1134  def _extendModulesIfNeeded(self, container, index):
1135  while index + self._moduleIDOffset < 0:
1136  container.insert(0,[])
1137  self._moduleIDOffset +=1
1138  self._extendIfNeeded(container, self._moduleID2Index(index))
1139  def allGlobals(self):
1140  return self._globals
1141  def indexedGlobal(self, index):
1142  self._extendIfNeeded(self._globals, index)
1143  return self._globals[index]
1144  def allStreams(self):
1145  return self._streams
1146  def indexedStream(self, index):
1147  self._extendIfNeeded(self._streams, index)
1148  return self._streams[index]
1149  def _findOpenSlot(self, index, fullContainer):
1150  self._extendModulesIfNeeded(fullContainer, index)
1151  container = fullContainer[self._moduleID2Index(index)]
1152  #find open slot
1153  foundOpenSlot = False
1154  for slot in container:
1155  if len(slot) == 0:
1156  foundOpenSlot = True
1157  break
1158  if slot[-1]["finish"] != 0:
1159  foundOpenSlot = True
1160  break
1161  if not foundOpenSlot:
1162  container.append([])
1163  slot = container[-1]
1164  return slot
1165  def findOpenSlotInModGlobals(self, index, modID):
1166  return self._findOpenSlot(modID, self._modules)
1167  def findOpenSlotInModStreams(self, index, modID):
1168  return self._findOpenSlot(modID, self._modules)
1169  def _findLastIn(self, index, fullContainer, comparer):
1170  if not fullContainer:
1171  return (None, None)
1172  if len(fullContainer) > self._moduleID2Index(index):
1173  container = fullContainer[self._moduleID2Index(index)]
1174  else:
1175  return (None, None)
1176  #find slot containing the pre
1177  for slot in container:
1178  if slot is not None and comparer(slot[-1]):
1179  return (slot[-1],slot)
1180  return (None, None)
1181  def findLastInModGlobals(self, index, modID, comparer):
1182  return self._findLastIn(modID, self._modules, comparer)
1183  def findLastInModStreams(self, index, modID, comparer):
1184  return self._findLastIn(modID, self._modules, comparer)
1185 
1186 
1187 
1188 def jsonTransition(type, id, sync, start, finish, isSrc=False):
1189  return {"type": type, "id": id, "sync": sync, "start": start*kMicroToSec, "finish": finish*kMicroToSec, "isSrc":isSrc}
1190 
1191 def jsonModuleTransition(type, id, modID, callID, activity, start, finish=0):
1192  return {"type": type, "id": id, "mod": modID, "call": callID, "act": activity, "start": start*kMicroToSec, "finish": finish*kMicroToSec}
1193 
1194 
1195 def startTime(x):
1196  return x["start"]
1197 
1198 def jsonInfo(parser, temporal):
1199  sync = SyncValues()
1200  #used to keep track of outstanding module transitions
1201  temp = TempModuleTransitionInfos()
1202  if temporal:
1203  data = TemporalModuleData()
1204  else:
1205  data = ModuleCentricModuleData()
1206  for p in parser.processingSteps():
1207  if hasattr(p, "jsonInfo"):
1208  p.jsonInfo(sync,temp, data)
1209  return data
1210 
1211 def sortByAttribute(parser, attribute):
1212  sync = SyncValues()
1213  #used to keep track of outstanding module transitions
1214  temp = TempModuleTransitionInfos()
1215  data = ModuleCentricModuleData()
1216  for p in parser.processingSteps():
1217  if hasattr(p, "jsonInfo"):
1218  p.jsonInfo(sync,temp, data)
1219  return data.sortModulesBy(attribute)
1220 
1222  if parser._moduleCentric:
1223  data = ModuleCentricContainers()
1224  else:
1225  data = VisualizationContainers()
1226  for p in parser.processingSteps():
1227  p.jsonVisInfo( data)
1228  #make sure everything is sorted
1229  for g in data.allGlobals():
1230  g.sort(key=startTime)
1231  final = {"transitions" : [] , "modules": [], "esModules": []}
1232  final["transitions"].append({ "name":"Global", "slots": []})
1233  globals = final["transitions"][-1]["slots"]
1234  for i, g in enumerate(data.allGlobals()):
1235  globals.append(g)
1236  if not parser._moduleCentric:
1237  if len(data._modGlobals) < i+1:
1238  break
1239  for mod in data._modGlobals[i]:
1240  globals.append(mod)
1241  for i,s in enumerate(data.allStreams()):
1242  final["transitions"].append({"name": f"Stream {i}", "slots":[]})
1243  stream = final["transitions"][-1]["slots"]
1244  stream.append(s)
1245  if not parser._moduleCentric:
1246  for mod in data._modStreams[i]:
1247  stream.append(mod)
1248  if parser._moduleCentric:
1249  sourceSlot = data._modules[data._moduleID2Index(0)]
1250  modules = []
1251  for i,m in parser._moduleNames.items():
1252  modules.append({"name": f"{m}", "slots":[]})
1253  slots = modules[-1]["slots"]
1254  foundSlots = data._modules[data._moduleID2Index(i)]
1255  time = 0
1256  for s in foundSlots:
1257  slots.append(s)
1258  for t in s:
1259  if t["act"] !=Activity.prefetch:
1260  time += t["finish"]-t["start"]
1261  modules[-1]['time']=time
1262  for i,m in parser._esModuleNames.items():
1263  modules.append({"name": f"{m}", "slots":[]})
1264  slots = modules[-1]["slots"]
1265  foundSlots = data._modules[data._moduleID2Index(-1*i)]
1266  time = 0
1267  for s in foundSlots:
1268  slots.append(s)
1269  for t in s:
1270  if t["act"] !=Activity.prefetch:
1271  time += t["finish"]-t["start"]
1272  modules[-1]['time']=time
1273  modules.sort(key= lambda x : x['time'], reverse=True)
1274  final['transitions'].append({"name": "source", "slots":sourceSlot})
1275  for m in modules:
1276  final['transitions'].append(m)
1277 
1278  max = 0
1279  for k in parser._moduleNames.keys():
1280  if k > max:
1281  max = k
1282 
1283  final["modules"] =['']*(max+1)
1284  final["modules"][0] = 'source'
1285  for k,v in parser._moduleNames.items():
1286  final["modules"][k]=v
1287 
1288  max = 0
1289  for k in parser._esModuleNames.keys():
1290  if k > max:
1291  max = k
1292  final["esModules"] = ['']*(max+1)
1293  for k,v in parser._esModuleNames.items():
1294  final["esModules"][k] = v
1295  return final
1296 
1297 
1298 
1299 #=======================================
1300 import unittest
1301 
1302 class DummyFile(list):
1303  def __init__(self):
1304  super()
1305  def seek(self, i):
1306  pass
1307 
1308 class TestModuleCommand(unittest.TestCase):
1309  def setUp(self):
1311  t = [0]
1312  def incr(t):
1313  t[0] += 1
1314  return t[0]
1315 
1316  self.tracerFile.extend([
1317  '#R 1 Record',
1318  '#M 1 Module',
1319  '#N 1 ESModule',
1320  f'F {Phase.startTracing} 0 0 0 0 {incr(t)}',
1321  f'S {Phase.construction} 0 {incr(t)}',
1322  f's {Phase.construction} 0 {incr(t)} 1 1 10 0 10 10',
1323  f'M {Phase.construction} 0 1 0 {incr(t)}',
1324  f'm {Phase.construction} 0 1 0 {incr(t)} 3 2 20 0 50 25',
1325  f'F {Phase.beginJob} 0 0 0 0 {incr(t)}',
1326  f'M {Phase.beginJob} 0 1 0 {incr(t)}',
1327  f'm {Phase.beginJob} 0 1 0 {incr(t)} 3 2 20 0 50 25',
1328  f'f {Phase.beginJob} 0 0 0 0 {incr(t)}',
1329  f'F {Phase.beginProcessBlock} 0 0 0 0 {incr(t)}',
1330  f'f {Phase.beginProcessBlock} 0 0 0 0 {incr(t)}',
1331  f'S {Phase.getNextTransition} {incr(t)}',
1332  f's {Phase.getNextTransition} {incr(t)} 1 1 10 0 10 10',
1333  f'S {Phase.globalBeginRun} 0 {incr(t)}',
1334  f's {Phase.globalBeginRun} 0 {incr(t)} 1 1 10 0 10 10',
1335  f'S {Phase.getNextTransition} {incr(t)}',
1336  f's {Phase.getNextTransition} {incr(t)} 1 1 10 0 10 10',
1337  f'F {Phase.globalBeginRun} 0 1 0 0 {incr(t)}',
1338  f'M {Phase.globalBeginRun} 0 1 0 {incr(t)}',
1339  f'm {Phase.globalBeginRun} 0 1 0 {incr(t)} 3 2 20 0 50 25',
1340  f'f {Phase.globalBeginRun} 0 1 0 0 {incr(t)}',
1341  f'S {Phase.getNextTransition} {incr(t)}',
1342  f's {Phase.getNextTransition} {incr(t)} 1 1 10 0 10 10',
1343  f'F {Phase.streamBeginRun} 0 1 0 0 {incr(t)}',
1344  f'M {Phase.streamBeginRun} 0 1 0 {incr(t)}',
1345  f'm {Phase.streamBeginRun} 0 1 0 {incr(t)} 3 2 20 0 50 25',
1346  f'f {Phase.streamBeginRun} 0 1 0 0 {incr(t)}',
1347  f'F {Phase.streamBeginRun} 1 1 0 0 {incr(t)}',
1348  f'M {Phase.streamBeginRun} 1 1 0 {incr(t)}',
1349  f'm {Phase.streamBeginRun} 1 1 0 {incr(t)} 3 2 20 0 50 25',
1350  f'f {Phase.streamBeginRun} 1 1 0 0 {incr(t)}',
1351  f'S {Phase.globalBeginLumi} 0 {incr(t)}',
1352  f's {Phase.globalBeginLumi} 0 {incr(t)} 1 1 10 0 10 10',
1353  f'S {Phase.getNextTransition} {incr(t)}',
1354  f's {Phase.getNextTransition} {incr(t)} 1 1 10 0 10 10',
1355  f'F {Phase.globalBeginLumi} 0 1 1 0 {incr(t)}',
1356  f'M {Phase.globalBeginLumi} 0 1 0 {incr(t)}',
1357  f'm {Phase.globalBeginLumi} 0 1 0 {incr(t)} 3 2 20 0 50 25',
1358  f'f {Phase.globalBeginLumi} 0 1 1 0 {incr(t)}',
1359  f'F {Phase.streamBeginLumi} 0 1 1 0 {incr(t)}',
1360  f'f {Phase.streamBeginLumi} 0 1 1 0 {incr(t)}',
1361  f'F {Phase.streamBeginLumi} 1 1 1 0 {incr(t)}',
1362  f'f {Phase.streamBeginLumi} 1 1 1 0 {incr(t)}',
1363  f'S {Phase.Event} 0 {incr(t)}',
1364  f's {Phase.Event} 0 {incr(t)} 1 1 10 0 10 10',
1365  f'S {Phase.getNextTransition} {incr(t)}',
1366  f's {Phase.getNextTransition} {incr(t)} 1 1 10 0 10 10',
1367  f'F {Phase.Event} 0 1 1 1 {incr(t)}',
1368  f'S {Phase.Event} 1 {incr(t)}',
1369  f's {Phase.Event} 1 {incr(t)} 1 1 10 0 10 10',
1370  f'F {Phase.Event} 1 1 1 2 {incr(t)}',
1371  f'N {Phase.Event} 0 1 1 0 {incr(t)}',
1372  f'n {Phase.Event} 0 1 1 0 {incr(t)} 6 5 30 0 100 80',
1373  f'M {Phase.Event} 0 1 0 {incr(t)}',
1374  f'M {Phase.Event} 1 1 0 {incr(t)}',
1375  f'm {Phase.Event} 1 1 0 {incr(t)} 3 2 20 0 50 25',
1376  f'm {Phase.Event} 0 1 0 {incr(t)} 3 2 20 0 50 25',
1377  f'f {Phase.Event} 0 1 1 1 {incr(t)}',
1378  f'f {Phase.Event} 1 1 1 2 {incr(t)}'])
1379 
1380  None
1381  def testSyncValues(self):
1382  s = SyncValues()
1383  s.setRun(0,1)
1384  self.assertEqual(s.runFor(0), 1)
1385  s.setLumi(0,1, 1)
1386  self.assertEqual(s.lumiFor(0), (1,1))
1387  s.setStream(1, 1,1,3)
1388  self.assertEqual(s.streamFor(1), (1,1,3))
1389  def testContainers(self):
1391  c.indexedGlobal(2)
1392  self.assertEqual(len(c.allGlobals()), 3)
1393  c.indexedStream(2)
1394  self.assertEqual(len(c.allStreams()), 3)
1395  slot = c.findOpenSlotInModGlobals(2, 1)
1396  self.assertEqual(len(c._modGlobals),3)
1397  self.assertEqual(len(slot),0)
1398  slot.append({"start":1, "finish":0, "id":1})
1399  def testFind(item):
1400  return item["id"]==1
1401  item,s = c.findLastInModGlobals(2, 1, testFind)
1402  self.assertEqual(item["id"],1)
1403  self.assertEqual(slot,s)
1404  slot = c.findOpenSlotInModStreams(2, 1)
1405  self.assertEqual(len(c._modStreams),3)
1406  self.assertEqual(len(slot),0)
1407  slot.append({"start":1, "finish":0, "id":1})
1408  item,s = c.findLastInModStreams(2, 1, testFind)
1409  self.assertEqual(item["id"],1)
1410  self.assertEqual(slot,s)
1411  def testJson(self):
1412  parser = ModuleAllocCompactFileParser(self.tracerFile, False)
1413  j = jsonInfo(parser, False)
1414  self.assertEqual(len(j.data()),3)
1415  self.assertEqual(len(j.data()["source"]), 10)
1416  self.assertEqual(len(j.data()["Module"]), 8)
1417  self.assertEqual(len(j.data()["ESModule"]), 1)
1418  def testJsonTemporal(self):
1419  parser = ModuleAllocCompactFileParser(self.tracerFile, True)
1420  j = jsonInfo(parser, True)
1421  self.assertEqual(len(j.data()),19)
1422  def testSortBy(self):
1423  parser = ModuleAllocCompactFileParser(self.tracerFile, True)
1424  d = sortByAttribute(parser, 'maxTemp')
1425  #print(d)
1426  self.assertEqual(len(d), 3)
1427  self.assertEqual(d[0][0], 'ESModule')
1428  self.assertEqual(d[1][0], 'Module')
1429  self.assertEqual(d[2][0], 'source')
1431  parser = ModuleAllocCompactFileParser(self.tracerFile, False)
1432  j = jsonVisualizationInfo(parser)
1433  #print(j)
1434  self.assertEqual(len(j["modules"]), 2)
1435  self.assertEqual(len(j["esModules"]), 2)
1436  self.assertEqual(len(j['transitions']), 3)
1437  self.assertEqual(j['transitions'][0]['name'], "Global")
1438  self.assertEqual(j['transitions'][1]['name'], "Stream 0")
1439  self.assertEqual(j['transitions'][2]['name'], "Stream 1")
1440  self.assertEqual(len(j["transitions"][0]["slots"]), 2)
1441  self.assertEqual(len(j["transitions"][0]["slots"][0]), 11)
1442  self.assertEqual(len(j["transitions"][0]["slots"][1]), 4)
1443  self.assertEqual(len(j["transitions"][1]["slots"]), 2)
1444  self.assertEqual(len(j["transitions"][1]["slots"][0]), 5)
1445  self.assertEqual(len(j["transitions"][1]["slots"][1]), 3)
1446  self.assertEqual(len(j["transitions"][2]["slots"]), 2)
1447  self.assertEqual(len(j["transitions"][2]["slots"][0]), 5)
1448  self.assertEqual(len(j["transitions"][2]["slots"][1]), 2)
1450  parser = ModuleAllocCompactFileParser(self.tracerFile, True)
1451  j = jsonVisualizationInfo(parser)
1452  #print(j)
1453  self.assertEqual(len(j["modules"]), 2)
1454  self.assertEqual(len(j["esModules"]), 2)
1455  self.assertEqual(len(j['transitions']), 6)
1456  self.assertEqual(j['transitions'][0]['name'], "Global")
1457  self.assertEqual(j['transitions'][1]['name'], "Stream 0")
1458  self.assertEqual(j['transitions'][2]['name'], "Stream 1")
1459  self.assertEqual(j['transitions'][3]['name'], "source")
1460  self.assertEqual(j['transitions'][4]['name'], "Module")
1461  self.assertEqual(j['transitions'][5]['name'], "ESModule")
1462  self.assertEqual(len(j["transitions"][0]["slots"]), 1)
1463  self.assertEqual(len(j["transitions"][0]["slots"][0]), 11)
1464  self.assertEqual(len(j["transitions"][1]["slots"]), 1)
1465  self.assertEqual(len(j["transitions"][1]["slots"][0]), 5)
1466  self.assertEqual(len(j["transitions"][2]["slots"]), 1)
1467  self.assertEqual(len(j["transitions"][2]["slots"][0]), 5)
1468  self.assertEqual(len(j["transitions"][4]["slots"]), 2)
1469  self.assertEqual(len(j["transitions"][4]["slots"][0]), 7)
1470  self.assertEqual(len(j["transitions"][4]["slots"][1]), 1)
1471  self.assertTrue(j["transitions"][4]["slots"][1][-1]['finish'] != 0.0)
1472  self.assertEqual(len(j["transitions"][5]["slots"]), 1)
1473  self.assertEqual(len(j["transitions"][5]["slots"][0]), 1)
1474 
1475 def runTests():
1476  return unittest.main(argv=sys.argv[:1])
1477 
1478 #=======================================
1479 if __name__=="__main__":
1480  import argparse
1481  import re
1482  import sys
1483 
1484  # Program options
1485  parser = argparse.ArgumentParser(description='Convert a compact tracer file into human readable output.',
1486  formatter_class=argparse.RawDescriptionHelpFormatter,
1487  epilog=printHelp())
1488  parser.add_argument('filename',
1489  type=argparse.FileType('r'), # open file
1490  help='file to process')
1491  parser.add_argument('-j', '--json',
1492  action='store_true',
1493  help='''Write output in json format.''' )
1494  parser.add_argument('-s', '--sortBy',
1495  default = '',
1496  type = str,
1497  help="sort modules by attribute. Alloed values 'nAllocs', 'nDeallocs', 'added', 'minTemp', maxTemp', and 'max1Alloc'")
1498 # parser.add_argument('-w', '--web',
1499 # action='store_true',
1500 # 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.''')
1501  parser.add_argument('-t', '--timeOrdered',
1502  action = 'store_true',
1503  help='''For --json, organize data by time instead of by module.''' )
1504  parser.add_argument('-T', '--test',
1505  action='store_true',
1506  help='''Run internal tests.''')
1507 
1508  args = parser.parse_args()
1509  if args.test:
1510  runTests()
1511  else :
1512  parser = ModuleAllocCompactFileParser(args.filename, not args.timeOrdered)
1513 # if args.json or args.web:
1514  if args.json:
1515  json.dump(jsonInfo(parser, args.timeOrdered).toSimpleDict(), sys.stdout, indent=2)
1516 # if args.web:
1517 # j ='export const data = ' + j
1518 # f=open('data.js', 'w')
1519 # f.write(j)
1520 # f.close()
1521  elif args.sortBy:
1522  print(json.dumps(sortByAttribute(parser, args.sortBy), indent=2))
1523  else:
1524  textOutput(parser)
def insertTimeES(self, label, transition, index, record, call, time)
def setLumi(self, index, runNumber, lumiNumber)
def lineParserFactory(step, payload, moduleNames, esModuleNames, recordNames, moduleCentric)
def __init__(self, payload, moduleNames, esModuleNames, recordNames)
def insert(self, label, start, stop, transition, index, sync, activity, allocInfo, recordName=None, callID=None)
def findTimeES(self, label, transition, index, record, call)
def __init__(self, payload, names, esNames, recordNames)
def processingStepsFromFile(f, moduleNames, esModuleNames, recordNames, moduleCentric)
def setStream(self, index, runNumber, lumiNumber, eventNumber)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:47
def insert(self, label, start, stop, transition, index, sync, activity, allocInfo, recordName=None, callID=None)
def jsonModuleTransition(type, id, modID, callID, activity, start, finish=0)
def findLast(self, label, transition, index, activity)
def __init__(self, start, stop, transition, sync, activity, allocInfo, recordName=None, callID=None)
def findLast(self, label, transition, index, activity)
def jsonTransition(type, id, sync, start, finish, isSrc=False)
def __init__(self, payload, names, esNames, recordNames)
#define str(s)
def _preJsonVis(self, activity, data, mayUseTemp=False)
def __init__(self, payload, names, esNames, recordNames)