mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Usage: ./analyzeDylibSize.py libswiftCore.dylib Sample output: Function Kind, Count, Size, Value Witness, 1837, 89850, Type Metadata, 46, 43326, Swift Function, 3214, 706372, Specialization, 554, 166471, Protocol Witness,1905, 335607, Partial Apply, 193, 20356, CPP, 939, 179991, Unknown, 206, 12061, Swift SVN r24975
104 lines
2.6 KiB
Python
Executable File
104 lines
2.6 KiB
Python
Executable File
#!/usr/bin/env python
|
|
import subprocess
|
|
import sys
|
|
|
|
if len(sys.argv) < 2:
|
|
print "Usage: %s file.dylib" % sys.argv[0]
|
|
sys.exit(0)
|
|
|
|
class BinaryFunction:
|
|
"""
|
|
This class represents a disassembled binary function.
|
|
"""
|
|
def __init__(self, symbolName):
|
|
self.name = symbolName
|
|
self.start = None
|
|
self.end = None
|
|
|
|
def addLine(self, opcodeLine):
|
|
"""
|
|
Parse a single disassembly line that is not the header.
|
|
Example input:
|
|
0000000000002b0a callq 0x1aef4c
|
|
"""
|
|
# Ignore the second part of the multi-line instruction.
|
|
if not opcodeLine.startswith("000"): return
|
|
# Normalize the spaces in the line.
|
|
opcodeLine = opcodeLine.replace("\t"," ")
|
|
# Find the address of the instruction.
|
|
addr = int(opcodeLine.split(" ")[0], 16)
|
|
# Initialize the start address if we haven't done this before.
|
|
if not self.start: self.start = addr
|
|
# notice that we don't have the size of the last instruction
|
|
# and assume it is zero.
|
|
self.end = addr
|
|
|
|
def getSize(self):
|
|
"""
|
|
Return the size of the function in the binary.
|
|
"""
|
|
if not self.end: return 0
|
|
return self.end - self.start
|
|
|
|
def __str__(self): return self.name + ", " + str(self.getSize())
|
|
|
|
#Disassemble the dylib.
|
|
content = subprocess.check_output(["otool", "-v", "-t", sys.argv[1]]).split("\n")
|
|
|
|
# parse the disassembled test:
|
|
Funcs = []
|
|
CurrF = None
|
|
for line in content:
|
|
# Parse the function header.
|
|
if line.endswith(":"):
|
|
CurrF = BinaryFunction(line[:-1])
|
|
Funcs.append(CurrF)
|
|
continue
|
|
# Parse the instructions.
|
|
CurrF.addLine(line)
|
|
|
|
Prefix = {
|
|
# Cpp
|
|
"__Z" : "CPP",
|
|
"_swift" : "CPP",
|
|
"__swift" : "CPP",
|
|
|
|
# Objective-C
|
|
"+[" : "CPP",
|
|
"-[" : "CPP",
|
|
|
|
# Swift
|
|
"__TP" : "Partial Apply",
|
|
"__TTW" : "Protocol Witness",
|
|
"__Tw" : "Value Witness",
|
|
"__TM" : "Type Metadata",
|
|
"__TF" : "Swift Function",
|
|
"__TTS" : "Specialization",
|
|
|
|
# Default
|
|
"" : "Unknown",
|
|
}
|
|
|
|
# initialize an empty score board for the prefixes.
|
|
ScoreBoard = {}
|
|
for key in Prefix:
|
|
ScoreBoard[Prefix[key]] = (0,0)
|
|
|
|
# Sort the functions by size (in case we want to print them)
|
|
SortedFunctions = sorted(Funcs, key = lambda x: x.getSize())
|
|
|
|
# Calculate the size of each kind of function.
|
|
for BinFunc in SortedFunctions:
|
|
for prefix in reversed(sorted(Prefix)):
|
|
if BinFunc.name.startswith(prefix):
|
|
count, size = ScoreBoard[Prefix[prefix]]
|
|
ScoreBoard[Prefix[prefix]] = (count + 1, size + BinFunc.getSize())
|
|
break
|
|
|
|
# Print the different prefixes.
|
|
print "Function Kind, Count, Size,"
|
|
for Entry in reversed(sorted(ScoreBoard)):
|
|
print Entry, ", ", ScoreBoard[Entry][0], ",", ScoreBoard[Entry][1],","
|
|
|
|
|