Last active
May 14, 2022 17:11
-
-
Save Zren/b4d2c234b5f84228e2475e4c0f0d2592 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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