Skip to content

Commit 7932796

Browse files
committed
[cmpcodesize] Convert into Python package
Split up cmpcodesize script into a package, with a main.py file that acts as an entry point to the program. The functions that use otool to actually determine binary size have been moved into compare.py. Note that to execute cmpcodesize, you may now run either: 1. `utils/cmpcodesize/cmpcodesize.py` 2. `python utils/cmpcodesize/cmpcodesize/main.py`
1 parent 34c9c2c commit 7932796

File tree

4 files changed

+214
-186
lines changed

4 files changed

+214
-186
lines changed

utils/cmpcodesize/cmpcodesize.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env python
2+
3+
import cmpcodesize
4+
5+
if __name__ == '__main__':
6+
cmpcodesize.main()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from __future__ import absolute_import
2+
from .main import main
3+
4+
__author__ = 'Brian Gesiak'
5+
__email__ = '[email protected]'
6+
__versioninfo__ = (0, 1, 0)
7+
__version__ = '.'.join(str(v) for v in __versioninfo__)
8+
9+
__all__ = []

utils/cmpcodesize/cmpcodesize renamed to utils/cmpcodesize/cmpcodesize/compare.py

Lines changed: 7 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
1-
#!/usr/bin/env python
2-
3-
import argparse
41
import re
5-
import sys
62
import os
7-
import os.path
8-
import glob
93
import subprocess
104
import collections
115
from operator import itemgetter
@@ -39,18 +33,12 @@
3933
"q_" : "Generic Function"
4034
}
4135

42-
SHORTCUTS = {
43-
"O": "bin/PerfTests_O",
44-
"Ounchecked": "bin/PerfTests_Ounchecked",
45-
"Onone": "bin/PerfTests_Onone",
46-
"dylib": "lib/swift/macosx/x86_64/libswiftCore.dylib",
47-
}
48-
4936
GenericFunctionPrefix = "__TTSg"
5037

5138
SortedPrefixes = sorted(Prefixes)
5239
SortedInfixes = sorted(Infixes)
5340

41+
5442
def addFunction(sizes, function, startAddr, endAddr, groupByPrefix):
5543
if not function or startAddr == None or endAddr == None:
5644
return
@@ -75,6 +63,7 @@ def addFunction(sizes, function, startAddr, endAddr, groupByPrefix):
7563
else:
7664
sizes[function] += size
7765

66+
7867
def flatten(*args):
7968
for x in args:
8069
if hasattr(x, '__iter__'):
@@ -83,6 +72,7 @@ def flatten(*args):
8372
else:
8473
yield x
8574

75+
8676
def readSizes(sizes, fileName, functionDetails, groupByPrefix):
8777
# Check if multiple architectures are supported by the object file.
8878
# Prefer arm64 if available.
@@ -146,6 +136,7 @@ def readSizes(sizes, fileName, functionDetails, groupByPrefix):
146136

147137
addFunction(sizes, currFunc, startAddr, endAddr, groupByPrefix)
148138

139+
149140
def compareSizes(oldSizes, newSizes, nameKey, title):
150141
oldSize = oldSizes[nameKey]
151142
newSize = newSizes[nameKey]
@@ -156,6 +147,7 @@ def compareSizes(oldSizes, newSizes, nameKey, title):
156147
perc = "- "
157148
print "%-26s%16s: %8d %8d %6s" % (title, nameKey, oldSize, newSize, perc)
158149

150+
159151
def compareSizesOfFile(oldFiles, newFiles, allSections, listCategories):
160152
oldSizes = collections.defaultdict(int)
161153
newSizes = collections.defaultdict(int)
@@ -195,12 +187,14 @@ def compareSizesOfFile(oldFiles, newFiles, allSections, listCategories):
195187
compareSizes(oldSizes, newSizes, "__common", sectionTitle)
196188
compareSizes(oldSizes, newSizes, "__bss", sectionTitle)
197189

190+
198191
def listFunctionSizes(sizeArray):
199192
for pair in sorted(sizeArray, key=itemgetter(1)):
200193
name = pair[0]
201194
size = pair[1]
202195
print "%8d %s" % (size, name)
203196

197+
204198
def compareFunctionSizes(oldFiles, newFiles):
205199
oldSizes = collections.defaultdict(int)
206200
newSizes = collections.defaultdict(int)
@@ -263,176 +257,3 @@ def compareFunctionSizes(oldFiles, newFiles):
263257
print "Total size of functions that got smaller: {}".format(sizeDecrease)
264258
print "Total size of functions that got bigger: {}".format(sizeIncrease)
265259
print "Total size change of functions present in both files: {}".format(sizeIncrease - sizeDecrease)
266-
267-
def main():
268-
parser = argparse.ArgumentParser(
269-
formatter_class=argparse.RawDescriptionHelpFormatter,
270-
description="""
271-
Compares code sizes of "new" files, taking "old" files as a reference.
272-
273-
Environment variables:
274-
SWIFT_NEW_BUILDDIR The old build-dir
275-
E.g. $HOME/swift-work/build/Ninja-ReleaseAssert+stdlib-Release/swift-macosx-x86_64
276-
SWIFT_OLD_BUILDDIR The new build-dir
277-
E.g. $HOME/swift-reference/build/Ninja-ReleaseAssert+stdlib-Release/swift-macosx-x86_64
278-
279-
How to specify files:
280-
1) No files:
281-
Compares codesize of the PerfTests_* executables and the swiftCore dylib in the new and old build-dirs.
282-
Example:
283-
cmpcodesize
284-
285-
2) One or more paths relative to the build-dirs (can be a pattern):
286-
Compares the files in the new and old build-dirs.
287-
Aliases:
288-
O => bin/PerfTests_O
289-
Ounchecked => bin/PerfTests_Ounchecked
290-
Onone => bin/PerfTests_Onone
291-
dylib => lib/swift/macosx/x86_64/libswiftCore.dylib
292-
Examples:
293-
cmpcodesize Onone
294-
cmpcodesize benchmark/PerfTestSuite/O/*.o
295-
296-
3) Two files:
297-
Compares these two files (the first is the old file).
298-
Example:
299-
cmpcodesize test.o newversion.o
300-
301-
4) Two lists of files, separated by '--':
302-
Compares a set a files.
303-
Example:
304-
cmpcodesize olddir/*.o -- newdir/*.o
305-
306-
5) One file (only available with the -l option):
307-
Lists function sizes for that file
308-
Example:
309-
cmpcodesize -l test.o""")
310-
311-
# Optional arguments.
312-
parser.add_argument('-a', '--additional-sections',
313-
help='Show sizes of additional sections.',
314-
action='store_true',
315-
dest='all_sections',
316-
default=False)
317-
parser.add_argument('-c', '--category',
318-
help='Show functions by category.',
319-
action='store_true',
320-
dest='list_categories',
321-
default=False)
322-
parser.add_argument('-l', '--list',
323-
help='List all functions (can be a very long list). ' +
324-
'Cannot be used in conjunction with ' +
325-
'--additional-sections or --category. ' +
326-
'You must specify between one and two files ' +
327-
'when using this option.',
328-
action='store_true',
329-
dest='list_functions',
330-
default=False)
331-
parser.add_argument('-s', '--summarize',
332-
help='Summarize the sizes of multiple files instead ' +
333-
'of listing each file separately.',
334-
action='store_true',
335-
dest='sum_sizes',
336-
default=False)
337-
338-
# Positional arguments.
339-
# These can be specififed in means beyond what argparse supports,
340-
# so we gather them in a list and parse them manually.
341-
parser.add_argument('files', nargs='*',
342-
help='A list of old and new files.')
343-
344-
# argparse can't handle an '--' argument, so we replace it with
345-
# a custom identifier.
346-
separator_token = '*-*-*'
347-
parsed_arguments = parser.parse_args(
348-
[separator_token if arg == '--' else arg for arg in sys.argv[1:]])
349-
350-
if parsed_arguments.list_functions:
351-
# --list is mutually exclusive with both --additional-sections
352-
# and --category. argparse is only capable of expressing mutual
353-
# exclusivity among options, not among groups of options, so
354-
# we detect this case manually.
355-
assert (not parsed_arguments.all_sections and
356-
not parsed_arguments.list_categories), \
357-
'Incorrect usage: --list cannot be specified in conjunction ' + \
358-
'with --additional-sections or --category.'
359-
# A file must be specified when using --list.
360-
assert parsed_arguments.files, \
361-
'Incorrect usage: Must specify between one and two files when ' + \
362-
'using --list, but you specified no files.'
363-
364-
if separator_token in parsed_arguments.files:
365-
separator_index = parsed_arguments.files.index(separator_token)
366-
oldFiles = parsed_arguments.files[:separator_index]
367-
newFiles = parsed_arguments.files[separator_index + 1:]
368-
else:
369-
oldFileArgs = parsed_arguments.files
370-
371-
oldBuildDir = os.environ.get("SWIFT_OLD_BUILDDIR")
372-
newBuildDir = os.environ.get("SWIFT_NEW_BUILDDIR")
373-
374-
if not parsed_arguments.files:
375-
assert oldBuildDir and newBuildDir, \
376-
'Incorrect usage: You must specify either a list of ' + \
377-
'files, or have both $SWIFT_OLD_BUILDDIR and ' + \
378-
'$SWIFT_NEW_BUILDDIR environment variables set.\n' + \
379-
'$SWIFT_OLD_BUILDDIR = {0}\n$SWIFT_NEW_BUILDDIR = {1}'.format(
380-
oldBuildDir, newBuildDir)
381-
oldFileArgs = SHORTCUTS.keys()
382-
383-
oldFiles = []
384-
newFiles = []
385-
numExpanded = 0
386-
for file in oldFileArgs:
387-
if file in SHORTCUTS:
388-
file = SHORTCUTS[file]
389-
390-
if not file.startswith("./") and oldBuildDir and newBuildDir:
391-
oldExpanded = glob.glob(os.path.join(oldBuildDir, file))
392-
newExpanded = glob.glob(os.path.join(newBuildDir, file))
393-
if oldExpanded and newExpanded:
394-
oldFiles.extend(oldExpanded)
395-
newFiles.extend(newExpanded)
396-
numExpanded += 1
397-
398-
if numExpanded != 0 and numExpanded != len(oldFileArgs):
399-
sys.exit("mix of expanded/not-expanded arguments")
400-
if numExpanded == 0:
401-
if len(oldFileArgs) > 2:
402-
sys.exit("too many arguments")
403-
oldFiles = oldFileArgs[0:1]
404-
newFiles = oldFileArgs[1:2]
405-
406-
for file in (oldFiles + newFiles):
407-
if not os.path.isfile(file):
408-
sys.exit("file " + file + " not found")
409-
410-
if parsed_arguments.list_functions:
411-
if not newFiles:
412-
sizes = collections.defaultdict(int)
413-
for file in oldFiles:
414-
readSizes(sizes, file, True, False)
415-
listFunctionSizes(sizes.items())
416-
else:
417-
compareFunctionSizes(oldFiles, newFiles)
418-
else:
419-
print "%-26s%16s %8s %8s %s" % ("", "Section", "Old", "New", "Percent")
420-
if parsed_arguments.sum_sizes:
421-
compareSizesOfFile(oldFiles, newFiles,
422-
parsed_arguments.all_sections,
423-
parsed_arguments.list_categories)
424-
else:
425-
if len(oldFiles) != len(newFiles):
426-
sys.exit("number of new files must be the same of old files")
427-
428-
oldFiles.sort
429-
newFiles.sort
430-
431-
for idx, oldFile in enumerate(oldFiles):
432-
newFile = newFiles[idx]
433-
compareSizesOfFile([oldFile], [newFile],
434-
parsed_arguments.all_sections,
435-
parsed_arguments.list_categories)
436-
437-
if __name__ == '__main__':
438-
main()

0 commit comments

Comments
 (0)