Skip to content

Instantly share code, notes, and snippets.

@Zren
Last active May 14, 2022 17:11
Show Gist options
  • Save Zren/b4d2c234b5f84228e2475e4c0f0d2592 to your computer and use it in GitHub Desktop.
Save Zren/b4d2c234b5f84228e2475e4c0f0d2592 to your computer and use it in GitHub Desktop.
#!/bin/python3
import os
import os.path
import re
import argparse
def formatSplitFilepath(filepath, splitIndex):
splitQtdFormat = filepath.replace('.qtd', '-{}{}.qtd')
assert splitIndex <= 26*26
a1 = chr(ord('a') + (splitIndex // 26))
a2 = chr(ord('a') + (splitIndex % 26))
return splitQtdFormat.format(a1, a2)
# Using tabs shaves off 2-3 Mb per file
def useTabs(line):
return re.sub(' ', '\t', line)
def splitFile(filepath, splitIndex, eventData, events, ranges, heapSize, heapUsed):
# Set <trace> traceStart and traceEnd
firstRange = ranges[0]
m = re.search(r'startTime="(\d+)"', firstRange)
traceStart = m.group(1)
lastRange = firstRange = ranges[-1]
m = re.search(r'startTime="(\d+)"', lastRange)
traceEnd = m.group(1)
trace = '<trace version="1.02" traceStart="{}" traceEnd="{}">\n'
trace = trace.format(traceStart, traceEnd)
xmlSchema = '<?xml version="1.0" encoding="UTF-8"?>\n'
split = '\t</eventData>\n\t<profilerDataModel>\n'
foot = '\t</profilerDataModel>\n</trace>\n'
if splitIndex != 0: # First split should already have starting heap size+used events.
# We need to add starting heap size/usage or it'll break Qt Creator if more memory
# is freed than allocated and the graph value goes negative.
heapRanges = [
' <range startTime="{}" eventIndex="0" amount="{}"/>\n'.format(traceStart, heapSize),
' <range startTime="{}" eventIndex="1" amount="{}"/>\n'.format(traceStart, heapUsed),
' <range startTime="{}" eventIndex="2" amount="0"/>\n'.format(traceStart),
]
ranges = heapRanges + ranges
splitFilepath = formatSplitFilepath(filepath, splitIndex)
print(splitFilepath)
with open(splitFilepath, 'w') as fout:
fout.write(xmlSchema)
fout.write(trace)
fout.write(eventData)
fout.write(events)
fout.write(split)
for r in ranges:
fout.write(r)
fout.write(foot)
def splitQtd(filepath, rangesPerFile):
eventData=''
events=''
ranges=[]
with open(filepath, 'r') as fin:
captureEvents = False
captureRanges = False
rangeCount = 0
splitIndex = 0
heapSize = 0
heapUsed = 0
for line in fin.readlines():
if captureEvents:
if '</eventData>' in line:
print(line.rstrip())
captureEvents = False
else:
events += useTabs(line)
elif captureRanges:
if '</profilerDataModel>' in line:
print(line.rstrip())
captureRanges = False
else:
# https://github.com/qt/qtdeclarative/blob/src/qml/jsruntime/qv4profiling_p.h
# eventIndex="0" is MemoryAllocation(type=0) aka MemoryType::HeapPage (shown as Memory/Heap Allocation in Qt Creator)
# eventIndex="1" is MemoryAllocation(type=2) aka MemoryType::LargeItem (shown as Memory/Heap Usage in Qt Creator)
# eventIndex="2" is MemoryAllocation(type=1) aka MemoryType::SmallItem (never used?)
if 'eventIndex="0"' in line: # Heap Allocation
m = re.search(r'amount="((-)?\d+)"', line)
amount = int(m.group(1))
heapSize += amount
elif 'eventIndex="1"' in line: # Heap Used
m = re.search(r'amount="((-)?\d+)"', line)
amount = int(m.group(1))
heapUsed += amount
ranges.append(useTabs(line))
rangeCount += 1
if rangeCount >= rangesPerFile:
splitFile(filepath, splitIndex, eventData, events, ranges, heapSize, heapUsed)
splitIndex += 1
rangeCount = 0
ranges = []
else:
if '<?xml ' in line:
print(line.rstrip())
elif '<trace ' in line:
print(line.rstrip())
elif '<eventData ' in line:
print(line.rstrip())
eventData = useTabs(line)
captureEvents = True
elif '<profilerDataModel>' in line:
print(line.rstrip())
captureRanges = True
if rangeCount > 0:
splitFile(filepath, splitIndex, eventData, events, ranges, heapSize, heapUsed)
def main():
eventsPerFileDefault = 200000
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('filepath', help='The .qtd filepath')
parser.add_argument('-n', '--eventsperfile', type=int, default=eventsPerFileDefault, dest='eventsPerFile', help='Number of events per split file.')
args = parser.parse_args()
splitQtd(args.filepath, args.eventsPerFile)
# filepath = 'plasmashell1649564180-1.qtd'
# filepath = 'plasmashell1649368701-1.qtd'
# splitQtd(filepath, eventsPerFileDefault)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment