File indexing completed on 2025-05-15 02:27:59
0001
0002 from builtins import range
0003 from itertools import groupby
0004 from operator import attrgetter,itemgetter
0005 import sys
0006 import json
0007 from collections import defaultdict
0008
0009 def printHelp():
0010 s = '''
0011 To Use: Add the Tracer Service to the cmsRun job use something like this
0012 in the configuration:
0013
0014 process.add_(cms.Service("Tracer", fileName = cms.untracked.string("tracer.log")))
0015
0016 After running the job, execute this script and pass the name of the
0017 Tracer log file to the script.
0018
0019 This script will output a more human readable form of the data in the Tracer log file.'''
0020 return s
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 kMicroToSec = 0.000001
0048
0049 kSourceFindEvent = "sourceFindEvent"
0050 kSourceDelayedRead ="sourceDelayedRead"
0051
0052 kLargestLumiNumber = 4294967295
0053
0054
0055 class Phase (object):
0056 destruction = -16
0057 endJob = -12
0058 endStream = -11
0059 writeProcessBlock = -10
0060 endProcessBlock = -9
0061 globalWriteRun = -7
0062 globalEndRun = -6
0063 streamEndRun = -5
0064 globalWriteLumi = -4
0065 globalEndLumi = -3
0066 streamEndLumi = -2
0067 clearEvent = -1
0068 Event = 0
0069 streamBeginLumi = 2
0070 globalBeginLumi = 3
0071 streamBeginRun = 5
0072 globalBeginRun = 6
0073 accessInputProcessBlock = 8
0074 beginProcessBlock = 9
0075 openFile = 10
0076 beginStream = 11
0077 beginJob = 12
0078 esSync = 13
0079 esSyncEnqueue = 14
0080 getNextTransition = 15
0081 construction = 16
0082 startTracing = 17
0083
0084
0085 class Activity (object):
0086 prefetch = 0
0087 acquire = 1
0088 process = 2
0089 delayedGet = 3
0090 externalWork = 4
0091 temporary = 100
0092
0093 transitionToNames_ = {
0094 Phase.startTracing: 'start tracing',
0095 Phase.construction: 'construction',
0096 Phase.destruction: 'destruction',
0097 Phase.beginJob: 'begin job',
0098 Phase.endJob: 'end job',
0099 Phase.beginStream: 'begin stream',
0100 Phase.endStream: 'end stream',
0101 Phase.beginProcessBlock: 'begin process block',
0102 Phase.endProcessBlock: 'end process block',
0103 Phase.accessInputProcessBlock: 'access input process block',
0104 Phase.writeProcessBlock: 'write process block',
0105 Phase.globalBeginRun: 'global begin run',
0106 Phase.globalEndRun: 'global end run',
0107 Phase.globalWriteRun: 'global write run',
0108 Phase.streamBeginRun: 'stream begin run',
0109 Phase.streamEndRun: 'stream end run',
0110 Phase.globalBeginLumi: 'global begin lumi',
0111 Phase.globalEndLumi: 'global end lumi',
0112 Phase.globalWriteLumi: 'global write lumi',
0113 Phase.streamBeginLumi: 'stream begin lumi',
0114 Phase.streamEndLumi: 'stream end lumi',
0115 Phase.esSyncEnqueue: 'EventSetup synchronization',
0116 Phase.esSync: 'EventSetup synchronization',
0117 Phase.Event: 'event',
0118 Phase.clearEvent: 'clear event',
0119 Phase.getNextTransition: 'get next transition'
0120 }
0121
0122 def transitionName(transition):
0123 return transitionToNames_[transition]
0124
0125 transitionToIndent_ = {
0126 Phase.startTracing: 0,
0127 Phase.construction: 0,
0128 Phase.destruction: 0,
0129 Phase.endJob: 0,
0130 Phase.beginJob: 0,
0131 Phase.beginStream: 0,
0132 Phase.endStream: 0,
0133 Phase.beginProcessBlock: 1,
0134 Phase.endProcessBlock: 1,
0135 Phase.accessInputProcessBlock: 1,
0136 Phase.writeProcessBlock: 1,
0137 Phase.globalBeginRun: 1,
0138 Phase.globalEndRun: 1,
0139 Phase.globalWriteRun: 1,
0140 Phase.streamBeginRun: 1,
0141 Phase.streamEndRun: 1,
0142 Phase.globalBeginLumi: 2,
0143 Phase.globalEndLumi: 2,
0144 Phase.globalWriteLumi: 2,
0145 Phase.streamBeginLumi: 2,
0146 Phase.streamEndLumi: 2,
0147 Phase.Event: 3,
0148 Phase.clearEvent: 3,
0149 Phase.esSyncEnqueue: 1,
0150 Phase.esSync: 1,
0151 Phase.getNextTransition: 1
0152 }
0153 def transitionIndentLevel(transition):
0154 return transitionToIndent_[transition]
0155
0156 globalTransitions_ = {
0157 Phase.startTracing,
0158 Phase.construction,
0159 Phase.destruction,
0160 Phase.endJob,
0161 Phase.beginJob,
0162 Phase.beginProcessBlock,
0163 Phase.endProcessBlock,
0164 Phase.accessInputProcessBlock,
0165 Phase.writeProcessBlock,
0166 Phase.globalBeginRun,
0167 Phase.globalEndRun,
0168 Phase.globalWriteRun,
0169 Phase.globalBeginLumi,
0170 Phase.globalEndLumi,
0171 Phase.globalWriteLumi,
0172 Phase.esSyncEnqueue,
0173 Phase.esSync,
0174 Phase.getNextTransition
0175 }
0176 def transitionIsGlobal(transition):
0177 return transition in globalTransitions_;
0178
0179 def textPrefix_(time, indentLevel):
0180
0181 return f'{time:>11} '+"++"*indentLevel
0182
0183 class FrameworkTransitionParser (object):
0184 def __init__(self, payload):
0185 self.transition = int(payload[0])
0186 self.index = int(payload[1])
0187 self.sync = (int(payload[2]), int(payload[3]), int(payload[4]))
0188 self.time = int(payload[5])
0189 def indentLevel(self):
0190 return transitionIndentLevel(self.transition)
0191 def textPrefix(self):
0192 return textPrefix_(self.time, self.indentLevel())
0193 def syncText(self):
0194 if self.transition == Phase.globalBeginRun or Phase.globalEndRun == self.transition:
0195 return f'run={self.sync[0]}'
0196 if self.transition == Phase.globalWriteRun:
0197 return f'run={self.sync[0]}'
0198 if self.transition == Phase.streamBeginRun or Phase.streamEndRun == self.transition:
0199 return f'run={self.sync[0]}'
0200 if self.transition == Phase.globalBeginLumi or Phase.globalEndLumi == self.transition:
0201 return f'run={self.sync[0]} lumi={self.sync[1]}'
0202 if self.transition == Phase.globalWriteLumi:
0203 return f'run={self.sync[0]} lumi={self.sync[1]}'
0204 if self.transition == Phase.streamBeginLumi or Phase.streamEndLumi == self.transition:
0205 return f'run={self.sync[0]} lumi={self.sync[1]}'
0206 if self.transition == Phase.Event:
0207 return f'run={self.sync[0]} lumi={self.sync[1]} event={self.sync[2]}'
0208 if self.transition == Phase.esSyncEnqueue or self.transition == Phase.esSync:
0209 return f'run={self.sync[0]} lumi={self.sync[1]}'
0210 if self.transition == Phase.beginJob:
0211 return ''
0212 if self.transition == Phase.beginProcessBlock or self.transition == Phase.endProcessBlock or self.transition == Phase.writeProcessBlock or self.transition == Phase.accessInputProcessBlock:
0213 return ''
0214 if self.transition == Phase.startTracing:
0215 return ''
0216 if self.transition == Phase.construction or self.transition == Phase.destruction:
0217 return ''
0218 def textPostfix(self):
0219 return f'{transitionName(self.transition)} : id={self.index} {self.syncText()}'
0220 def text(self, context):
0221 return f'{self.textPrefix()} {self.textSpecial()}: {self.textPostfix()}'
0222
0223 def findMatchingTransition(sync, containers):
0224 for i in range(len(containers)):
0225 if containers[i][-1]["sync"] == sync:
0226 return i
0227
0228 for i in range(len(containers)):
0229 for t in containers[i]:
0230 if t["sync"] == sync:
0231 return i
0232
0233 print("find failed",sync, containers)
0234 return None
0235
0236 def popQueuedTransitions(sync, container):
0237 results = []
0238 for i in range(len(container)):
0239 if sync == container[i]["sync"]:
0240 results.append(container[i])
0241 results.append(container[i+1])
0242 del container[i]
0243 del container[i]
0244 break
0245 return results
0246
0247 transitionsToFindMatch_ = {
0248 Phase.globalEndRun,
0249 Phase.globalEndLumi,
0250 Phase.globalWriteRun,
0251 Phase.globalWriteLumi
0252 }
0253
0254 class PreFrameworkTransitionParser (FrameworkTransitionParser):
0255 def __init__(self, payload):
0256 super().__init__(payload)
0257 def textSpecial(self):
0258 return "starting"
0259 def jsonInfo(self, counter, data):
0260 if transitionIsGlobal(self.transition):
0261 index = 0
0262 if self.transition == Phase.startTracing:
0263 data.indexedGlobal(0).append(jsonTransition(type=self.transition, id=index, sync=list(self.sync),start=0, finish=self.time ))
0264 return
0265 elif self.transition == Phase.esSync:
0266 if self.sync[1] == kLargestLumiNumber:
0267
0268 index = findMatchingTransition(list(self.sync), data.allGlobals())
0269 container = data.indexedGlobal(index)
0270 container[-1]["finish"] = self.time*kMicroToSec
0271 else:
0272 data._queued[-1]["finish"] = self.time*kMicroToSec
0273 data._queued.append( jsonTransition(type=self.transition, id = index, sync=list(self.sync), start=self.time , finish=0))
0274 return
0275 elif self.transition==Phase.globalBeginRun:
0276 index = self.index
0277
0278 queued = data._queued
0279 q = popQueuedTransitions(list(self.sync), queued)
0280 container = data.indexedGlobal(index)
0281
0282 last = container[-1]
0283 if last["type"]==Phase.globalBeginRun and last["isSrc"]:
0284 last["sync"]=list(self.sync)
0285 container.append(q[0])
0286 container.append(q[1])
0287 elif self.transition==Phase.globalBeginLumi:
0288 index = self.index
0289
0290 queued = data._queued
0291 q = popQueuedTransitions(list(self.sync), queued)
0292 container = data.indexedGlobal(index)
0293
0294 last = container[-1]
0295 if last["type"]==Phase.globalBeginLumi and last["isSrc"]:
0296 last["sync"]=list(self.sync)
0297 container.append(q[0])
0298 container.append(q[1])
0299 elif self.transition in transitionsToFindMatch_:
0300 index = findMatchingTransition(list(self.sync), data.allGlobals())
0301 container = data.indexedGlobal(index)
0302 else:
0303 container = data.indexedStream(self.index)
0304 if self.transition == Phase.Event:
0305
0306 last = container[-1]
0307 if last["type"]==Phase.Event and last["isSrc"]:
0308 last["sync"]=list(self.sync)
0309 index = self.index
0310 container.append( jsonTransition(type=self.transition, id = index, sync=list(self.sync), start=self.time , finish=0))
0311
0312
0313 class PostFrameworkTransitionParser (FrameworkTransitionParser):
0314 def __init__(self, payload):
0315 super().__init__(payload)
0316 def textSpecial(self):
0317 return "finished"
0318 def jsonInfo(self, counter, data):
0319 if transitionIsGlobal(self.transition):
0320 if self.transition == Phase.esSync and self.sync[1] != kLargestLumiNumber:
0321 data._queued[-1]['finish']=self.time*kMicroToSec
0322 return
0323 index = findMatchingTransition(list(self.sync), data.allGlobals())
0324 container = data.indexedGlobal(index)
0325 else:
0326 container = data.indexedStream(self.index)
0327 container[-1]["finish"]=self.time*kMicroToSec
0328
0329
0330 class QueuingFrameworkTransitionParser (FrameworkTransitionParser):
0331 def __init__(self, payload):
0332 super().__init__(payload)
0333 def textSpecial(self):
0334 return "queuing"
0335 def jsonInfo(self, counter, data):
0336 index = -1
0337 if self.sync[1] == kLargestLumiNumber:
0338
0339 index = findMatchingTransition([self.sync[0],0,0], data.allGlobals())
0340 data.indexedGlobal(index).append( jsonTransition(type=self.transition, id = index, sync=list(self.sync), start=self.time , finish=0))
0341 else:
0342 data._queued.append(jsonTransition(type=self.transition, id = index, sync=list(self.sync), start=self.time , finish=0))
0343
0344 class SourceTransitionParser(object):
0345 def __init__(self, payload):
0346 self.transition = int(payload[0])
0347 if self.transition == Phase.getNextTransition:
0348 self.time = int(payload[1])
0349 self.index = -1
0350 return
0351 self.index = int(payload[1])
0352 self.time = int(payload[2])
0353 def indentLevel(self):
0354 if self.transition == Phase.globalBeginRun:
0355 return 1
0356 if self.transition == Phase.globalBeginLumi:
0357 return 2
0358 if self.transition == Phase.Event:
0359 return 3
0360 if self.transition == Phase.construction:
0361 return 1
0362 if self.transition == Phase.getNextTransition:
0363 return 1
0364 return None
0365 def textPrefix(self):
0366 return textPrefix_(self.time, self.indentLevel())
0367 def textPostfix(self):
0368 return f'source during {transitionName(self.transition)} : id={self.index}'
0369 def text(self, context):
0370 return f'{self.textPrefix()} {self.textSpecial()}: {self.textPostfix()}'
0371
0372 class PreSourceTransitionParser(SourceTransitionParser):
0373 def __init__(self, payload, moduleCentric):
0374 self._moduleCentric = moduleCentric
0375 super().__init__(payload)
0376 def textSpecial(self):
0377 return "starting"
0378 def jsonInfo(self, counter, data):
0379 if self.transition == Phase.getNextTransition:
0380 data._nextTrans.append(jsonTransition(type=self.transition, id=self.index, sync=[0,0,0], start=self.time, finish=0, isSrc=True))
0381 if self._moduleCentric:
0382
0383 data.findOpenSlotInModGlobals(0,0).append(data._nextTrans[-1])
0384 return
0385 elif self.transition == Phase.construction:
0386 index = counter.start()
0387 container = data.indexedGlobal(index)
0388 elif self.transition == Phase.Event:
0389 index = self.index
0390 container = data.indexedStream(index)
0391 else:
0392 index = self.index
0393 container = data.indexedGlobal(index)
0394 nextTrans = data._nextTrans
0395 if nextTrans:
0396 data._nextTrans = []
0397 for t in nextTrans:
0398 t['id']=index
0399
0400 transStartTime = t['start']
0401 inserted = False
0402 for i in range(-1, -1*len(container), -1):
0403 if transStartTime > container[i]['start']:
0404 if i == -1:
0405 container.append(t)
0406 inserted = True
0407 break
0408 else:
0409 container.insert(i+1,t)
0410 inserted = True
0411 break
0412 if not inserted:
0413 container.insert(0,t)
0414 container.append(jsonTransition(type=self.transition, id=index, sync=[0,0,0], start=self.time, finish=0, isSrc=True))
0415 if self._moduleCentric:
0416 if self.transition == Phase.Event:
0417 data.findOpenSlotInModStreams(index,0).append(container[-1])
0418 else:
0419 data.findOpenSlotInModGlobals(index,0).append(container[-1])
0420
0421 class PostSourceTransitionParser(SourceTransitionParser):
0422 def __init__(self, payload, moduleCentric):
0423 super().__init__(payload)
0424 self._moduleCentric = moduleCentric
0425 def textSpecial(self):
0426 return "finished"
0427 def jsonInfo(self, counter, data):
0428 index = self.index
0429 if self.transition == Phase.Event:
0430 container = data.indexedStream(index)
0431 elif self.transition == Phase.getNextTransition:
0432 data._nextTrans[-1]['finish'] = self.time*kMicroToSec
0433 return
0434 elif self.transition == Phase.construction:
0435 pre = None
0436 for i, g in enumerate(data.allGlobals()):
0437 for t in reversed(g):
0438 if t["type"] != Phase.construction:
0439 break
0440 if t["isSrc"]:
0441 pre = t
0442 break
0443 if pre:
0444 pre["finish"]=self.time*kMicroToSec
0445 break
0446 counter.finish(i)
0447 return
0448 else:
0449 container = data.indexedGlobal(index)
0450
0451 container[-1]["finish"]=self.time*kMicroToSec
0452
0453 class EDModuleTransitionParser(object):
0454 def __init__(self, payload, moduleNames):
0455 self.transition = int(payload[0])
0456 self.index = int(payload[1])
0457 self.moduleID = int(payload[2])
0458 self.moduleName = moduleNames[self.moduleID]
0459 self.callID = int(payload[3])
0460 self.requestingModuleID = int(payload[4])
0461 self.requestingCallID = int(payload[5])
0462 self.requestingModuleName = None
0463 if self.requestingModuleID != 0:
0464 self.requestingModuleName = moduleNames[self.requestingModuleID]
0465 self.time = int(payload[6])
0466 def baseIndentLevel(self):
0467 return transitionIndentLevel(self.transition)
0468 def textPrefix(self, context):
0469 indent = 0
0470 if self.requestingModuleID != 0:
0471 indent = context[(self.transition, self.index, self.requestingModuleID, self.requestingCallID)]
0472 context[(self.transition, self.index, self.moduleID, self.callID)] = indent+1
0473 return textPrefix_(self.time, indent+1+self.baseIndentLevel())
0474 def textPostfix(self):
0475 return f'{self.moduleName} during {transitionName(self.transition)} : id={self.index}'
0476 def textIfTransform(self):
0477 if self.callID:
0478 return f' transform {self.callID-1}'
0479 return ''
0480 def text(self, context):
0481 return f'{self.textPrefix(context)} {self.textSpecial()}{self.textIfTransform()}: {self.textPostfix()}'
0482 def _preJson(self, activity, counter, data, mayUseTemp = False, isSrc = False):
0483 index = self.index
0484 found = False
0485 if mayUseTemp:
0486 compare = lambda x: x['type'] == self.transition and x['id'] == self.index and x['mod'] == self.moduleID and x['call'] == self.callID and ((x.get('isSrc') != None) == isSrc ) and (x['act'] == Activity.temporary or x['act'] == Activity.externalWork)
0487 if transitionIsGlobal(self.transition):
0488 item,slot = data.findLastInModGlobals(index, self.moduleID, compare)
0489 else:
0490 item,slot = data.findLastInModStreams(index, self.moduleID, compare)
0491 if slot:
0492 if item['act'] == Activity.temporary:
0493 slot.pop()
0494 else:
0495 item['finish']=self.time*kMicroToSec
0496 found = True
0497 if not found:
0498 if transitionIsGlobal(self.transition):
0499 slot = data.findOpenSlotInModGlobals(index, self.moduleID)
0500 else:
0501 slot = data.findOpenSlotInModStreams(index, self.moduleID)
0502 slot.append(jsonModuleTransition(type=self.transition, id=self.index, modID=self.moduleID, callID=self.callID, activity=activity, start=self.time))
0503 return slot[-1]
0504 def _postJson(self, counter, data, injectAfter = None, isSrc = False):
0505 compare = lambda x: x['id'] == self.index and x['mod'] == self.moduleID and x['call'] == self.callID and x['type'] == self.transition and ((x.get('isSrc') != None) == isSrc )
0506 index = self.index
0507 if transitionIsGlobal(self.transition):
0508 item,slot = data.findLastInModGlobals(index, self.moduleID, compare)
0509 else:
0510 item,slot = data.findLastInModStreams(index, self.moduleID, compare)
0511 if item is None:
0512 print(f"failed to find {self.moduleID} for {self.transition} in {self.index}")
0513 else:
0514 item["finish"]=self.time*kMicroToSec
0515 if injectAfter:
0516 slot.append(injectAfter)
0517
0518 class PreEDModuleTransitionParser(EDModuleTransitionParser):
0519 def __init__(self, payload, names, moduleCentric):
0520 super().__init__(payload, names)
0521 self._moduleCentric = moduleCentric
0522 def textSpecial(self):
0523 return "starting action"
0524 def jsonInfo(self, counter, data):
0525 return self._preJson(Activity.process, counter,data, mayUseTemp=self._moduleCentric)
0526
0527 class PostEDModuleTransitionParser(EDModuleTransitionParser):
0528 def __init__(self, payload, names):
0529 super().__init__(payload, names)
0530 def textSpecial(self):
0531 return "finished action"
0532 def jsonInfo(self, counter, data):
0533 return self._postJson(counter,data)
0534
0535 class PreEDModulePrefetchingParser(EDModuleTransitionParser):
0536 def __init__(self, payload, names, moduleCentric):
0537 super().__init__(payload, names)
0538 self._moduleCentric = moduleCentric
0539 def textSpecial(self):
0540 return "starting prefetch"
0541 def jsonInfo(self, counter, data):
0542
0543 entry = self._preJson(Activity.prefetch, counter,data)
0544 if self._moduleCentric:
0545 return entry
0546 kPrefetchLength = 2*kMicroToSec
0547 entry["finish"]=entry["start"]+kPrefetchLength
0548 return entry
0549
0550
0551 class PostEDModulePrefetchingParser(EDModuleTransitionParser):
0552 def __init__(self, payload, names, moduleCentric):
0553 super().__init__(payload, names)
0554 self._moduleCentric = moduleCentric
0555 def textSpecial(self):
0556 return "finished prefetch"
0557 def jsonInfo(self, counter, data):
0558 if self._moduleCentric:
0559
0560 return self._postJson(counter, data, jsonModuleTransition(type=self.transition, id=self.index, modID=self.moduleID, callID=self.callID, activity=Activity.temporary, start=self.time))
0561 pass
0562
0563 class PreEDModuleAcquireParser(EDModuleTransitionParser):
0564 def __init__(self, payload, names, moduleCentric):
0565 super().__init__(payload, names)
0566 self._moduleCentric = moduleCentric
0567 def textSpecial(self):
0568 return "starting acquire"
0569 def jsonInfo(self, counter, data):
0570 return self._preJson(Activity.acquire, counter,data, mayUseTemp=self._moduleCentric)
0571
0572 class PostEDModuleAcquireParser(EDModuleTransitionParser):
0573 def __init__(self, payload, names, moduleCentric):
0574 super().__init__(payload, names)
0575 self._moduleCentric = moduleCentric
0576 def textSpecial(self):
0577 return "finished acquire"
0578 def jsonInfo(self, counter, data):
0579 if self._moduleCentric:
0580
0581 return self._postJson(counter, data, jsonModuleTransition(type=self.transition, id=self.index, modID=self.moduleID, callID=self.callID, activity=Activity.externalWork, start=self.time))
0582 return self._postJson(counter,data)
0583
0584 class PreEDModuleEventDelayedGetParser(EDModuleTransitionParser):
0585 def __init__(self, payload, names, moduleCentric):
0586 super().__init__(payload, names)
0587 self._moduleCentric = moduleCentric
0588 def textSpecial(self):
0589 return "starting delayed get"
0590 def jsonInfo(self, counter, data):
0591
0592 if self._moduleCentric:
0593
0594 return self._postJson(counter, data, jsonModuleTransition(type=self.transition, id=self.index, modID=self.moduleID, callID=self.callID, activity=Activity.temporary, start=self.time))
0595 return self._postJson(counter,data)
0596
0597
0598 class PostEDModuleEventDelayedGetParser(EDModuleTransitionParser):
0599 def __init__(self, payload, names, moduleCentric):
0600 super().__init__(payload, names)
0601 self._moduleCentric = moduleCentric
0602 def textSpecial(self):
0603 return "finished delayed get"
0604 def jsonInfo(self, counter, data):
0605 return self._preJson(Activity.process, counter,data, mayUseTemp=self._moduleCentric)
0606
0607
0608 class PreEventReadFromSourceParser(EDModuleTransitionParser):
0609 def __init__(self, payload, names, moduleCentric):
0610 super().__init__(payload, names)
0611 self._moduleCentric = moduleCentric
0612 def textSpecial(self):
0613 return "starting read from source"
0614 def jsonInfo(self, counter, data):
0615 slot = self._preJson(Activity.process, counter,data, mayUseTemp=self._moduleCentric, isSrc=True)
0616 slot['isSrc'] = True
0617 return slot
0618
0619 class PostEventReadFromSourceParser(EDModuleTransitionParser):
0620 def __init__(self, payload, names):
0621 super().__init__(payload, names)
0622 def textSpecial(self):
0623 return "finished read from source"
0624 def jsonInfo(self, counter, data):
0625 return self._postJson(counter,data, isSrc=True)
0626
0627 class ESModuleTransitionParser(object):
0628 def __init__(self, payload, moduleNames, esModuleNames, recordNames):
0629 self.transition = int(payload[0])
0630 self.index = int(payload[1])
0631 self.moduleID = int(payload[2])
0632 self.moduleName = esModuleNames[self.moduleID]
0633 self.recordID = int(payload[3])
0634 self.recordName = recordNames[self.recordID]
0635 self.callID = int(payload[4])
0636 self.requestingModuleID = int(payload[5])
0637 self.requestingCallID = int(payload[6])
0638 self.requestingModuleName = None
0639 if self.requestingModuleID < 0 :
0640 self.requestingModuleName = esModuleNames[-1*self.requestingModuleID]
0641 else:
0642 self.requestingModuleName = moduleNames[self.requestingModuleID]
0643 self.time = int(payload[7])
0644 def baseIndentLevel(self):
0645 return transitionIndentLevel(self.transition)
0646 def textPrefix(self, context):
0647 indent = 0
0648 indent = context[(self.transition, self.index, self.requestingModuleID, self.requestingCallID)]
0649 context[(self.transition, self.index, -1*self.moduleID, self.callID)] = indent+1
0650 return textPrefix_(self.time, indent+1+self.baseIndentLevel())
0651 def textPostfix(self):
0652 return f'esmodule {self.moduleName} in record {self.recordName} during {transitionName(self.transition)} : id={self.index}'
0653 def text(self, context):
0654 return f'{self.textPrefix(context)} {self.textSpecial()}: {self.textPostfix()}'
0655 def _preJson(self, activity, counter, data):
0656 index = self.index
0657 if transitionIsGlobal(self.transition):
0658 slot = data.findOpenSlotInModGlobals(index, -1*self.moduleID)
0659 else:
0660 slot = data.findOpenSlotInModStreams(index, -1*self.moduleID)
0661 slot.append(jsonModuleTransition(type=self.transition, id=self.index, modID=-1*self.moduleID, callID=self.callID, activity=activity, start=self.time))
0662 return slot[-1]
0663 def _postJson(self, counter, data):
0664 compare = lambda x: x['id'] == self.index and x['mod'] == -1*self.moduleID and x['call'] == self.callID
0665 index = self.index
0666 if transitionIsGlobal(self.transition):
0667 item,s = data.findLastInModGlobals(index, -1*self.moduleID, compare)
0668 else:
0669 item,s = data.findLastInModStreams(index, -1*self.moduleID, compare)
0670 if item is None:
0671 print(f"failed to find {-1*self.moduleID} for {self.transition} in {self.index}")
0672 return
0673 item["finish"]=self.time*kMicroToSec
0674
0675
0676 class PreESModuleTransitionParser(ESModuleTransitionParser):
0677 def __init__(self, payload, names, esNames, recordNames):
0678 super().__init__(payload, names, esNames, recordNames)
0679 def textSpecial(self):
0680 return "starting action"
0681 def jsonInfo(self, counter, data):
0682 return self._preJson(Activity.process, counter,data)
0683
0684 class PostESModuleTransitionParser(ESModuleTransitionParser):
0685 def __init__(self, payload, names, esNames, recordNames):
0686 super().__init__(payload, names, esNames, recordNames)
0687 def textSpecial(self):
0688 return "finished action"
0689 def jsonInfo(self, counter, data):
0690 return self._postJson(counter,data)
0691
0692 class PreESModulePrefetchingParser(ESModuleTransitionParser):
0693 def __init__(self, payload, names, esNames, recordNames, moduleCentric):
0694 super().__init__(payload, names, esNames, recordNames)
0695 self._moduleCentric = moduleCentric
0696 def textSpecial(self):
0697 return "starting prefetch"
0698 def jsonInfo(self, counter, data):
0699 entry = self._preJson(Activity.prefetch, counter,data)
0700 if not self._moduleCentric:
0701 entry["finish"] = entry["start"]+2*kMicroToSec;
0702 return entry
0703
0704 class PostESModulePrefetchingParser(ESModuleTransitionParser):
0705 def __init__(self, payload, names, esNames, recordNames, moduleCentric):
0706 super().__init__(payload, names, esNames, recordNames)
0707 self._moduleCentric = moduleCentric
0708 def textSpecial(self):
0709 return "finished prefetch"
0710 def jsonInfo(self, counter, data):
0711 if self._moduleCentric:
0712 return self._postJson(counter, data)
0713 pass
0714
0715 class PreESModuleAcquireParser(ESModuleTransitionParser):
0716 def __init__(self, payload, names, recordNames):
0717 super().__init__(payload, names, recordNames)
0718 def textSpecial(self):
0719 return "starting acquire"
0720 def jsonInfo(self, counter, data):
0721 return self._preJson(Activity.acquire, counter,data)
0722
0723 class PostESModuleAcquireParser(ESModuleTransitionParser):
0724 def __init__(self, payload, names, esNames, recordNames):
0725 super().__init__(payload, names, esNames, recordNames)
0726 def textSpecial(self):
0727 return "finished acquire"
0728 def jsonInfo(self, counter, data):
0729 return self._postJson(counter,data)
0730
0731
0732 def lineParserFactory (step, payload, moduleNames, esModuleNames, recordNames, frameworkOnly, moduleCentric):
0733 if step == 'F':
0734 parser = PreFrameworkTransitionParser(payload)
0735 if parser.transition == Phase.esSyncEnqueue:
0736 return QueuingFrameworkTransitionParser(payload)
0737 return parser
0738 if step == 'f':
0739 return PostFrameworkTransitionParser(payload)
0740 if step == 'S':
0741 return PreSourceTransitionParser(payload, moduleCentric)
0742 if step == 's':
0743 return PostSourceTransitionParser(payload, moduleCentric)
0744 if frameworkOnly:
0745 return None
0746 if step == 'M':
0747 return PreEDModuleTransitionParser(payload, moduleNames, moduleCentric)
0748 if step == 'm':
0749 return PostEDModuleTransitionParser(payload, moduleNames)
0750 if step == 'P':
0751 return PreEDModulePrefetchingParser(payload, moduleNames, moduleCentric)
0752 if step == 'p':
0753 return PostEDModulePrefetchingParser(payload, moduleNames, moduleCentric)
0754 if step == 'A':
0755 return PreEDModuleAcquireParser(payload, moduleNames, moduleCentric)
0756 if step == 'a':
0757 return PostEDModuleAcquireParser(payload, moduleNames, moduleCentric)
0758 if step == 'D':
0759 return PreEDModuleEventDelayedGetParser(payload, moduleNames, moduleCentric)
0760 if step == 'd':
0761 return PostEDModuleEventDelayedGetParser(payload, moduleNames, moduleCentric)
0762 if step == 'R':
0763 return PreEventReadFromSourceParser(payload, moduleNames, moduleCentric)
0764 if step == 'r':
0765 return PostEventReadFromSourceParser(payload, moduleNames)
0766 if step == 'N':
0767 return PreESModuleTransitionParser(payload, moduleNames, esModuleNames, recordNames)
0768 if step == 'n':
0769 return PostESModuleTransitionParser(payload, moduleNames, esModuleNames, recordNames)
0770 if step == 'Q':
0771 return PreESModulePrefetchingParser(payload, moduleNames, esModuleNames, recordNames, moduleCentric)
0772 if step == 'q':
0773 return PostESModulePrefetchingParser(payload, moduleNames, esModuleNames, recordNames, moduleCentric)
0774 if step == 'B':
0775 return PreESModuleAcquireParser(payload, moduleNames, esModuleNames, recordNames)
0776 if step == 'b':
0777 return PostESModuleAcquireParser(payload, moduleNames, esModuleNames, recordNames)
0778
0779
0780
0781 def processingStepsFromFile(f,moduleNames, esModuleNames, recordNames, frameworkOnly, moduleCentric):
0782 for rawl in f:
0783 l = rawl.strip()
0784 if not l or l[0] == '#':
0785 continue
0786 (step,payload) = tuple(l.split(None,1))
0787 payload=payload.split()
0788
0789 parser = lineParserFactory(step, payload, moduleNames, esModuleNames, recordNames, frameworkOnly, moduleCentric)
0790 if parser:
0791 yield parser
0792 return
0793
0794 class TracerCompactFileParser(object):
0795 def __init__(self,f, frameworkOnly, moduleCentric):
0796 streamBeginRun = str(Phase.streamBeginRun)
0797 numStreams = 0
0798 numStreamsFromSource = 0
0799 moduleNames = {}
0800 esModuleNames = {}
0801 recordNames = {}
0802 for rawl in f:
0803 l = rawl.strip()
0804 if l and l[0] == 'M':
0805 i = l.split(' ')
0806 if i[3] == streamBeginRun:
0807
0808 numStreams = int(i[1])+1
0809 break
0810 if numStreams == 0 and l and l[0] == 'S':
0811 s = int(l.split(' ')[1])
0812 if s > numStreamsFromSource:
0813 numStreamsFromSource = s
0814 if len(l) > 5 and l[0:2] == "#M":
0815 (id,name)=tuple(l[2:].split())
0816 moduleNames[int(id)] = name
0817 continue
0818 if len(l) > 5 and l[0:2] == "#N":
0819 (id,name)=tuple(l[2:].split())
0820 esModuleNames[int(id)] = name
0821 continue
0822 if len(l) > 5 and l[0:2] == "#R":
0823 (id,name)=tuple(l[2:].split())
0824 recordNames[int(id)] = name
0825 continue
0826
0827 self._f = f
0828 self._frameworkOnly = frameworkOnly
0829 self._moduleCentric = moduleCentric
0830 if numStreams == 0:
0831 numStreams = numStreamsFromSource +2
0832 self.numStreams =numStreams
0833 self._moduleNames = moduleNames
0834 self._esModuleNames = esModuleNames
0835 self._recordNames = recordNames
0836 self.maxNameSize =0
0837 for n in moduleNames.items():
0838 self.maxNameSize = max(self.maxNameSize,len(n))
0839 for n in esModuleNames.items():
0840 self.maxNameSize = max(self.maxNameSize,len(n))
0841 self.maxNameSize = max(self.maxNameSize,len(kSourceDelayedRead))
0842 self.maxNameSize = max(self.maxNameSize, len('streamBeginLumi'))
0843
0844 def processingSteps(self):
0845 """Create a generator which can step through the file and return each processing step.
0846 Using a generator reduces the memory overhead when parsing a large file.
0847 """
0848 self._f.seek(0)
0849 return processingStepsFromFile(self._f,self._moduleNames, self._esModuleNames, self._recordNames, self._frameworkOnly, self._moduleCentric)
0850
0851 def textOutput( parser ):
0852 context = {}
0853 for p in parser.processingSteps():
0854 print(p.text(context))
0855
0856 class Counter(object):
0857 def __init__(self):
0858 self.activeSlots = [False]
0859 def start(self):
0860 if 0 != self.activeSlots.count(False):
0861 index = self.activeSlots.index(False)
0862 self.activeSlots[index]=True
0863 return index
0864 index = len(self.activeSlots)
0865 self.activeSlots.append(True)
0866 return index
0867 def finish(self, index):
0868 self.activeSlots[index] = False
0869
0870 class Containers(object):
0871 def __init__(self):
0872 self._modGlobals = [[]]
0873 self._modStreams = [[]]
0874 self._globals = [[]]
0875 self._streams = [[]]
0876 self._queued = []
0877 self._nextTrans = []
0878 def _extendIfNeeded(self, container, index):
0879 while len(container) < index+1:
0880 container.append([])
0881 def allGlobals(self):
0882 return self._globals
0883 def indexedGlobal(self, index):
0884 self._extendIfNeeded(self._globals, index)
0885 return self._globals[index]
0886 def allStreams(self):
0887 return self._streams
0888 def indexedStream(self, index):
0889 self._extendIfNeeded(self._streams, index)
0890 return self._streams[index]
0891 def _findOpenSlot(self, index, fullContainer):
0892 self._extendIfNeeded(fullContainer, index)
0893 container = fullContainer[index]
0894
0895 foundOpenSlot = False
0896 for slot in container:
0897 if len(slot) == 0:
0898 foundOpenSlot = True
0899 break
0900 if slot[-1]["finish"] != 0:
0901 foundOpenSlot = True
0902 break
0903 if not foundOpenSlot:
0904 container.append([])
0905 slot = container[-1]
0906 return slot
0907 def findOpenSlotInModGlobals(self, index, modID):
0908 return self._findOpenSlot(index, self._modGlobals)
0909 def findOpenSlotInModStreams(self, index, modID):
0910 return self._findOpenSlot(index, self._modStreams)
0911 def _findLastIn(self, index, fullContainer, comparer):
0912 container = fullContainer[index]
0913
0914 for slot in container:
0915 if comparer(slot[-1]):
0916 return (slot[-1],slot)
0917 return (None,None)
0918 def findLastInModGlobals(self, index, modID, comparer):
0919 return self._findLastIn(index, self._modGlobals, comparer)
0920 def findLastInModStreams(self, index, modID, comparer):
0921 return self._findLastIn(index, self._modStreams, comparer)
0922
0923
0924 class ModuleCentricContainers(object):
0925 def __init__(self):
0926 self._modules= []
0927 self._globals = [[]]
0928 self._streams = [[]]
0929 self._queued = []
0930 self._nextTrans = []
0931 self._moduleIDOffset = 0
0932 def _moduleID2Index(self, modID):
0933 return modID + self._moduleIDOffset
0934 def _extendIfNeeded(self, container, index):
0935 while len(container) < index+1:
0936 container.append([])
0937 def _extendModulesIfNeeded(self, container, index):
0938 while index + self._moduleIDOffset < 0:
0939 container.insert(0,[])
0940 self._moduleIDOffset +=1
0941 self._extendIfNeeded(container, self._moduleID2Index(index))
0942 def allGlobals(self):
0943 return self._globals
0944 def indexedGlobal(self, index):
0945 self._extendIfNeeded(self._globals, index)
0946 return self._globals[index]
0947 def allStreams(self):
0948 return self._streams
0949 def indexedStream(self, index):
0950 self._extendIfNeeded(self._streams, index)
0951 return self._streams[index]
0952 def _findOpenSlot(self, index, fullContainer):
0953 self._extendModulesIfNeeded(fullContainer, index)
0954 container = fullContainer[self._moduleID2Index(index)]
0955
0956 foundOpenSlot = False
0957 for slot in container:
0958 if len(slot) == 0:
0959 foundOpenSlot = True
0960 break
0961 if slot[-1]["finish"] != 0:
0962 foundOpenSlot = True
0963 break
0964 if not foundOpenSlot:
0965 container.append([])
0966 slot = container[-1]
0967 return slot
0968 def findOpenSlotInModGlobals(self, index, modID):
0969 return self._findOpenSlot(modID, self._modules)
0970 def findOpenSlotInModStreams(self, index, modID):
0971 return self._findOpenSlot(modID, self._modules)
0972 def _findLastIn(self, index, fullContainer, comparer):
0973 if not fullContainer:
0974 return (None, None)
0975 if len(fullContainer) > self._moduleID2Index(index):
0976 container = fullContainer[self._moduleID2Index(index)]
0977 else:
0978 return (None, None)
0979
0980 for slot in container:
0981 if slot is not None and comparer(slot[-1]):
0982 return (slot[-1],slot)
0983 return (None, None)
0984 def findLastInModGlobals(self, index, modID, comparer):
0985 return self._findLastIn(modID, self._modules, comparer)
0986 def findLastInModStreams(self, index, modID, comparer):
0987 return self._findLastIn(modID, self._modules, comparer)
0988
0989
0990
0991 def jsonTransition(type, id, sync, start, finish, isSrc=False):
0992 return {"type": type, "id": id, "sync": sync, "start": start*kMicroToSec, "finish": finish*kMicroToSec, "isSrc":isSrc}
0993
0994 def jsonModuleTransition(type, id, modID, callID, activity, start, finish=0):
0995 return {"type": type, "id": id, "mod": modID, "call": callID, "act": activity, "start": start*kMicroToSec, "finish": finish*kMicroToSec}
0996
0997 def startTime(x):
0998 return x["start"]
0999 def jsonInfo(parser):
1000 counter = Counter()
1001 if parser._moduleCentric:
1002 data = ModuleCentricContainers()
1003 else:
1004 data = Containers()
1005 for p in parser.processingSteps():
1006 p.jsonInfo(counter, data)
1007
1008 for g in data.allGlobals():
1009 g.sort(key=startTime)
1010 final = {"transitions" : [] , "modules": [], "esModules": []}
1011 final["transitions"].append({ "name":"Global", "slots": []})
1012 globals = final["transitions"][-1]["slots"]
1013 for i, g in enumerate(data.allGlobals()):
1014 globals.append(g)
1015 if not parser._moduleCentric and not parser._frameworkOnly:
1016 if len(data._modGlobals) < i+1:
1017 break
1018 for mod in data._modGlobals[i]:
1019 globals.append(mod)
1020 for i,s in enumerate(data.allStreams()):
1021 final["transitions"].append({"name": f"Stream {i}", "slots":[]})
1022 stream = final["transitions"][-1]["slots"]
1023 stream.append(s)
1024 if not parser._moduleCentric and not parser._frameworkOnly:
1025 for mod in data._modStreams[i]:
1026 stream.append(mod)
1027 if parser._moduleCentric:
1028 sourceSlot = data._modules[data._moduleID2Index(0)]
1029 modules = []
1030 for i,m in parser._moduleNames.items():
1031 modules.append({"name": f"{m}", "slots":[]})
1032 slots = modules[-1]["slots"]
1033 foundSlots = data._modules[data._moduleID2Index(i)]
1034 time = 0
1035 for s in foundSlots:
1036 slots.append(s)
1037 for t in s:
1038 if t["act"] !=Activity.prefetch:
1039 time += t["finish"]-t["start"]
1040 modules[-1]['time']=time
1041 for i,m in parser._esModuleNames.items():
1042 modules.append({"name": f"{m}", "slots":[]})
1043 slots = modules[-1]["slots"]
1044 foundSlots = data._modules[data._moduleID2Index(-1*i)]
1045 time = 0
1046 for s in foundSlots:
1047 slots.append(s)
1048 for t in s:
1049 if t["act"] !=Activity.prefetch:
1050 time += t["finish"]-t["start"]
1051 modules[-1]['time']=time
1052 modules.sort(key= lambda x : x['time'], reverse=True)
1053 final['transitions'].append({"name": "source", "slots":sourceSlot})
1054 for m in modules:
1055 final['transitions'].append(m)
1056
1057 if not parser._frameworkOnly:
1058 max = 0
1059 for k in parser._moduleNames.keys():
1060 if k > max:
1061 max = k
1062
1063 final["modules"] =['']*(max+1)
1064 final["modules"][0] = 'source'
1065 for k,v in parser._moduleNames.items():
1066 final["modules"][k]=v
1067
1068 max = 0
1069 for k in parser._esModuleNames.keys():
1070 if k > max:
1071 max = k
1072 final["esModules"] = ['']*(max+1)
1073 for k,v in parser._esModuleNames.items():
1074 final["esModules"][k] = v
1075 return final
1076
1077
1078 import unittest
1079
1080 class DummyFile(list):
1081 def __init__(self):
1082 super()
1083 def seek(self, i):
1084 pass
1085
1086 class TestModuleCommand(unittest.TestCase):
1087 def setUp(self):
1088 self.tracerFile = DummyFile()
1089 t = [0]
1090 def incr(t):
1091 t[0] += 1
1092 return t[0]
1093
1094 self.tracerFile.extend([
1095 '#R 1 Record',
1096 '#M 1 Module',
1097 '#N 1 ESModule',
1098 f'F {Phase.startTracing} 0 0 0 0 {incr(t)}',
1099 f'S {Phase.construction} 0 {incr(t)}',
1100 f's {Phase.construction} 0 {incr(t)}3',
1101 f'M {Phase.construction} 0 1 0 0 0 {incr(t)}',
1102 f'm {Phase.construction} 0 1 0 0 0 {incr(t)}',
1103 f'F {Phase.beginJob} 0 0 0 0 {incr(t)}',
1104 f'M {Phase.beginJob} 0 1 0 0 0 {incr(t)}',
1105 f'm {Phase.beginJob} 0 1 0 0 0 {incr(t)}',
1106 f'f {Phase.beginJob} 0 0 0 0 {incr(t)}',
1107 f'F {Phase.beginProcessBlock} 0 0 0 0 {incr(t)}',
1108 f'f {Phase.beginProcessBlock} 0 0 0 0 {incr(t)}',
1109 f'S {Phase.getNextTransition} {incr(t)}',
1110 f's {Phase.getNextTransition} {incr(t)}',
1111 f'F {Phase.esSyncEnqueue} -1 1 0 0 {incr(t)}',
1112 f'F {Phase.esSync} -1 1 0 0 {incr(t)}',
1113 f'f {Phase.esSync} -1 1 0 0 {incr(t)}',
1114 f'S {Phase.globalBeginRun} 0 {incr(t)}',
1115 f's {Phase.globalBeginRun} 0 {incr(t)}',
1116 f'S {Phase.getNextTransition} {incr(t)}',
1117 f's {Phase.getNextTransition} {incr(t)}',
1118 f'F {Phase.globalBeginRun} 0 1 0 0 {incr(t)}',
1119 f'P {Phase.globalBeginRun} 0 1 0 0 0 {incr(t)}',
1120 f'p {Phase.globalBeginRun} 0 1 0 0 0 {incr(t)}',
1121 f'M {Phase.globalBeginRun} 0 1 0 0 0 {incr(t)}',
1122 f'm {Phase.globalBeginRun} 0 1 0 0 0 {incr(t)}',
1123 f'f {Phase.globalBeginRun} 0 1 0 0 {incr(t)}',
1124 f'F {Phase.esSyncEnqueue} -1 1 1 0 {incr(t)}',
1125 f'F {Phase.esSync} -1 1 1 0 {incr(t)}',
1126 f'f {Phase.esSync} -1 1 1 0 {incr(t)}',
1127 f'S {Phase.getNextTransition} {incr(t)}',
1128 f's {Phase.getNextTransition} {incr(t)}',
1129 f'F {Phase.streamBeginRun} 0 1 0 0 {incr(t)}',
1130 f'M {Phase.streamBeginRun} 0 1 0 0 0 {incr(t)}',
1131 f'm {Phase.streamBeginRun} 0 1 0 0 0 {incr(t)}',
1132 f'f {Phase.streamBeginRun} 0 1 0 0 {incr(t)}',
1133 f'F {Phase.streamBeginRun} 1 1 0 0 {incr(t)}',
1134 f'M {Phase.streamBeginRun} 1 1 0 0 0 {incr(t)}',
1135 f'm {Phase.streamBeginRun} 1 1 0 0 0 {incr(t)}',
1136 f'f {Phase.streamBeginRun} 1 1 0 0 {incr(t)}',
1137 f'S {Phase.globalBeginLumi} 0 {incr(t)}',
1138 f's {Phase.globalBeginLumi} 0 {incr(t)}',
1139 f'S {Phase.getNextTransition} {incr(t)}',
1140 f's {Phase.getNextTransition} {incr(t)}',
1141 f'F {Phase.globalBeginLumi} 0 1 1 0 {incr(t)}',
1142 f'P {Phase.globalBeginLumi} 0 1 0 0 0 {incr(t)}',
1143 f'p {Phase.globalBeginLumi} 0 1 0 0 0 {incr(t)}',
1144 f'M {Phase.globalBeginLumi} 0 1 0 0 0 {incr(t)}',
1145 f'm {Phase.globalBeginLumi} 0 1 0 0 0 {incr(t)}',
1146 f'f {Phase.globalBeginLumi} 0 1 1 0 {incr(t)}',
1147 f'F {Phase.streamBeginLumi} 0 1 1 0 {incr(t)}',
1148 f'f {Phase.streamBeginLumi} 0 1 1 0 {incr(t)}',
1149 f'F {Phase.streamBeginLumi} 1 1 1 0 {incr(t)}',
1150 f'f {Phase.streamBeginLumi} 1 1 1 0 {incr(t)}',
1151 f'S {Phase.Event} 0 {incr(t)}',
1152 f's {Phase.Event} 0 {incr(t)}',
1153 f'S {Phase.getNextTransition} {incr(t)}',
1154 f's {Phase.getNextTransition} {incr(t)}',
1155 f'F {Phase.Event} 0 1 1 1 {incr(t)}',
1156 f'S {Phase.Event} 1 {incr(t)}',
1157 f's {Phase.Event} 1 {incr(t)}',
1158 f'F {Phase.Event} 1 1 1 2 {incr(t)}',
1159 f'P {Phase.Event} 0 1 0 0 0 {incr(t)}',
1160 f'p {Phase.Event} 0 1 0 0 0 {incr(t)}',
1161 f'Q {Phase.Event} 0 1 1 0 1 0 {incr(t)}',
1162 f'q {Phase.Event} 0 1 1 0 1 0 {incr(t)}',
1163 f'N {Phase.Event} 0 1 1 0 1 0 {incr(t)}',
1164 f'n {Phase.Event} 0 1 1 0 1 0 {incr(t)}',
1165 f'P {Phase.Event} 1 1 0 0 0 {incr(t)}',
1166 f'p {Phase.Event} 1 1 0 0 0 {incr(t)}',
1167 f'M {Phase.Event} 0 1 0 0 0 {incr(t)}',
1168 f'M {Phase.Event} 1 1 0 0 0 {incr(t)}',
1169 f'm {Phase.Event} 1 1 0 0 0 {incr(t)}',
1170 f'm {Phase.Event} 0 1 0 0 0 {incr(t)}',
1171 f'f {Phase.Event} 0 1 1 1 {incr(t)}',
1172 f'f {Phase.Event} 1 1 1 2 {incr(t)}'])
1173
1174 None
1175 def testContainers(self):
1176 c = Containers()
1177 c.indexedGlobal(2)
1178 self.assertEqual(len(c.allGlobals()), 3)
1179 c.indexedStream(2)
1180 self.assertEqual(len(c.allStreams()), 3)
1181 slot = c.findOpenSlotInModGlobals(2, 1)
1182 self.assertEqual(len(c._modGlobals),3)
1183 self.assertEqual(len(slot),0)
1184 slot.append({"start":1, "finish":0, "id":1})
1185 def testFind(item):
1186 return item["id"]==1
1187 item,s = c.findLastInModGlobals(2, 1, testFind)
1188 self.assertEqual(item["id"],1)
1189 self.assertEqual(slot,s)
1190 slot = c.findOpenSlotInModStreams(2, 1)
1191 self.assertEqual(len(c._modStreams),3)
1192 self.assertEqual(len(slot),0)
1193 slot.append({"start":1, "finish":0, "id":1})
1194 item,s = c.findLastInModStreams(2, 1, testFind)
1195 self.assertEqual(item["id"],1)
1196 self.assertEqual(slot,s)
1197 def testFrameworkOnly(self):
1198 parser = TracerCompactFileParser(self.tracerFile, True, False)
1199 j = jsonInfo(parser)
1200
1201 self.assertEqual(len(j["modules"]), 0)
1202 self.assertEqual(len(j["esModules"]), 0)
1203 self.assertEqual(len(j['transitions']), 3)
1204 self.assertEqual(j['transitions'][0]['name'], "Global")
1205 self.assertEqual(j['transitions'][1]['name'], "Stream 0")
1206 self.assertEqual(j['transitions'][2]['name'], "Stream 1")
1207 self.assertEqual(len(j["transitions"][0]["slots"]), 1)
1208 self.assertEqual(len(j["transitions"][0]["slots"][0]), 15)
1209 self.assertEqual(len(j["transitions"][1]["slots"]), 1)
1210 self.assertEqual(len(j["transitions"][1]["slots"][0]), 5)
1211 self.assertEqual(len(j["transitions"][2]["slots"]), 1)
1212 self.assertEqual(len(j["transitions"][2]["slots"][0]), 5)
1213 def testFull(self):
1214 parser = TracerCompactFileParser(self.tracerFile, False, False)
1215 j = jsonInfo(parser)
1216
1217 self.assertEqual(len(j["modules"]), 2)
1218 self.assertEqual(len(j["esModules"]), 2)
1219 self.assertEqual(len(j['transitions']), 3)
1220 self.assertEqual(j['transitions'][0]['name'], "Global")
1221 self.assertEqual(j['transitions'][1]['name'], "Stream 0")
1222 self.assertEqual(j['transitions'][2]['name'], "Stream 1")
1223 self.assertEqual(len(j["transitions"][0]["slots"]), 2)
1224 self.assertEqual(len(j["transitions"][0]["slots"][0]), 15)
1225 self.assertEqual(len(j["transitions"][0]["slots"][1]), 6)
1226 self.assertEqual(len(j["transitions"][1]["slots"]), 2)
1227 self.assertEqual(len(j["transitions"][1]["slots"][0]), 5)
1228 self.assertEqual(len(j["transitions"][1]["slots"][1]), 5)
1229 self.assertEqual(len(j["transitions"][2]["slots"]), 2)
1230 self.assertEqual(len(j["transitions"][2]["slots"][0]), 5)
1231 self.assertEqual(len(j["transitions"][2]["slots"][1]), 3)
1232 def testModuleCentric(self):
1233 parser = TracerCompactFileParser(self.tracerFile, False, True)
1234 j = jsonInfo(parser)
1235
1236 self.assertEqual(len(j["modules"]), 2)
1237 self.assertEqual(len(j["esModules"]), 2)
1238 self.assertEqual(len(j['transitions']), 6)
1239 self.assertEqual(j['transitions'][0]['name'], "Global")
1240 self.assertEqual(j['transitions'][1]['name'], "Stream 0")
1241 self.assertEqual(j['transitions'][2]['name'], "Stream 1")
1242 self.assertEqual(j['transitions'][3]['name'], "source")
1243 self.assertEqual(j['transitions'][4]['name'], "Module")
1244 self.assertEqual(j['transitions'][5]['name'], "ESModule")
1245 self.assertEqual(len(j["transitions"][0]["slots"]), 1)
1246 self.assertEqual(len(j["transitions"][0]["slots"][0]), 15)
1247 self.assertEqual(len(j["transitions"][1]["slots"]), 1)
1248 self.assertEqual(len(j["transitions"][1]["slots"][0]), 5)
1249 self.assertEqual(len(j["transitions"][2]["slots"]), 1)
1250 self.assertEqual(len(j["transitions"][2]["slots"][0]), 5)
1251 self.assertEqual(len(j["transitions"][4]["slots"]), 2)
1252 self.assertEqual(len(j["transitions"][4]["slots"][0]), 10)
1253 self.assertEqual(len(j["transitions"][4]["slots"][1]), 2)
1254 self.assertTrue(j["transitions"][4]["slots"][1][-1]['finish'] != 0.0)
1255 self.assertEqual(len(j["transitions"][5]["slots"]), 1)
1256 self.assertEqual(len(j["transitions"][5]["slots"][0]), 2)
1257
1258 def runTests():
1259 return unittest.main(argv=sys.argv[:1])
1260
1261
1262 if __name__=="__main__":
1263 import argparse
1264 import re
1265 import sys
1266
1267
1268 parser = argparse.ArgumentParser(description='Convert a compact tracer file into human readable output.',
1269 formatter_class=argparse.RawDescriptionHelpFormatter,
1270 epilog=printHelp())
1271 parser.add_argument('filename',
1272 type=argparse.FileType('r'),
1273 help='file to process')
1274 parser.add_argument('-f', '--frameworkOnly',
1275 action='store_true',
1276 help='''Output only the framework transitions, excluding the individual module transitions.''')
1277 parser.add_argument('-j', '--json',
1278 action='store_true',
1279 help='''Write output in json format.''' )
1280 parser.add_argument('-w', '--web',
1281 action='store_true',
1282 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.''')
1283 parser.add_argument('-m', '--module_centric',
1284 action = 'store_true',
1285 help='''For --json or --web, organize data by module instead of by global/stream.''' )
1286 parser.add_argument('-t', '--test',
1287 action='store_true',
1288 help='''Run internal tests.''')
1289
1290 args = parser.parse_args()
1291 if args.test:
1292 runTests()
1293 else :
1294 parser = TracerCompactFileParser(args.filename, args.frameworkOnly, args.module_centric)
1295 if args.json or args.web:
1296 j = json.dumps(jsonInfo(parser))
1297 if args.json:
1298 print(j)
1299 if args.web:
1300 f=open('data.json', 'w')
1301 f.write(j)
1302 f.close()
1303 else:
1304 textOutput(parser)