Skip to content

Commit 0b6d7d4

Browse files
Merge pull request #32439 from aschwaighofer/analyze_code_size_categorize_specialized
analyze_code_size.py: provide option to further categorize specialized functions
2 parents 0b7fea6 + 674c689 commit 0b6d7d4

File tree

1 file changed

+204
-3
lines changed

1 file changed

+204
-3
lines changed

utils/analyze_code_size.py

Lines changed: 204 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88

99
useCSV = False
10+
groupSpecializations = False
11+
listGroupSpecializations = False
1012

1113

1214
def main(arguments):
@@ -19,6 +21,10 @@ def main(arguments):
1921
default=False)
2022
parser.add_argument('-list-category', type=str,
2123
help='list symbols in category')
24+
parser.add_argument('-group-specializations', action='store_true',
25+
help='group specializations')
26+
parser.add_argument('-list-group-specializations', action='store_true',
27+
help='list group specializations')
2228
parser.add_argument('-csv', dest='use_csv', action='store_true',
2329
help='print results as csv')
2430
parser.add_argument('-uncategorized', action='store_true',
@@ -34,6 +40,14 @@ def main(arguments):
3440
useCSV = True
3541
print("Using csv")
3642

43+
if args.group_specializations:
44+
global groupSpecializations
45+
groupSpecializations = True
46+
47+
if args.list_group_specializations:
48+
global listGroupSpecializations
49+
listGroupSpecializations = True
50+
3751
segments = parse_segments(args.bin, args.arch)
3852

3953
if args.build_categories:
@@ -82,14 +96,49 @@ def add(self, symbol):
8296
self.size += symbol.size
8397

8498

99+
class GenericSpecializationGroupKey(object):
100+
def __init__(self, module_name, type_name, specialization):
101+
self.module_name = module_name
102+
self.type_name = type_name
103+
self.specialization = specialization
104+
105+
def __hash__(self):
106+
return hash((self.module_name, self.type_name, self.specialization))
107+
108+
def __eq__(self, other):
109+
return (self.module_name == other.module_name
110+
and self.type_name == other.type_name
111+
and self.specialization == other.specialization)
112+
113+
114+
class GenericSpecialization(object):
115+
def __init__(self, module_name, type_name, specialization):
116+
self.module_name = module_name
117+
self.type_name = type_name
118+
self.specialization = specialization
119+
self.size = 0
120+
self.symbols = []
121+
122+
def add(self, symbol):
123+
self.symbols.append(symbol)
124+
self.size += symbol.size
125+
126+
def list_symbols(self):
127+
for symbol in self.symbols:
128+
print(" " + symbol.name + " " + str(symbol.size))
129+
130+
85131
class Categories(object):
86132
def __init__(self):
87133
self.category_matching = [
88134
['Objective-C function', re.compile(r'.*[+-]\[')],
89135
['C++', re.compile(r'_+swift')],
90-
['Generic specialization of stdlib',
91-
re.compile(r'.*generic specialization.* of Swift\.')],
92-
['Generic specialization',
136+
['Generic specialization of stdlib',
137+
re.compile(
138+
r'.*generic specialization.* of ' +
139+
r'(static )?(\(extension in Swift\):)?Swift\.'
140+
)],
141+
['Generic specialization',
93142
re.compile(r'.*generic specialization')],
94143
['Merged function', re.compile(r'merged ')],
95144
['Key path', re.compile(r'key path')],
@@ -178,6 +227,44 @@ def __init__(self):
178227
['Swift unknown', re.compile(r'^_\$s.*')],
179228
]
180229
self.categories = {}
230+
self.specializations = {}
231+
self.specialization_matcher = re.compile(
232+
r'.*generic specialization <(?P<spec_list>[^>]*)>.* of' +
233+
r' (static )?(\(extension in Swift\):)?(?P<module_name>[^.]*)\.' +
234+
r'(?:(?P<first_type>[^.^(^<]*)\.){0,1}' +
235+
r'(?:(?P<last_type>[^.^(^<]*)\.)*(?P<function_name>[^(^<]*)'
236+
)
237+
self.single_stdlib_specialized_type_matcher = re.compile(
238+
r'(Swift\.)?[^,^.]*$'
239+
)
240+
self.two_specialized_stdlib_types_matcher = re.compile(
241+
r'(Swift\.)?[^,^.]*, (Swift\.)?[^,^.]*$'
242+
)
243+
self.single_specialized_foundation_type_matcher = re.compile(
244+
r'(Foundation\.)?[^,^.]*$'
245+
)
246+
self.two_specialized_foundation_types_matcher = re.compile(
247+
r'(Swift\.)?[^,^.]*, (Foundation\.)?[^,^.]*$'
248+
)
249+
self.two_specialized_foundation_types_matcher2 = re.compile(
250+
r'(Foundation\.)?[^,^.]*, (Foundation\.)?[^,^.]*$'
251+
)
252+
self.two_specialized_foundation_types_matcher3 = re.compile(
253+
r'(Foundation\.)?[^,^.]*, (Swift\.)?[^,^.]*$'
254+
)
255+
self.array_type_matcher = re.compile(r'Array')
256+
self.dictionary = re.compile(r'Array')
257+
self.single_specialized_types_matcher = re.compile(
258+
r'(?P<module_name>[^,^.]*)\.(?P<type_name>[^,^.]*)$'
259+
)
260+
self.is_class_type_dict = {}
261+
self.stdlib_and_other_type_matcher = re.compile(
262+
r'(Swift\.)?[^,^.]*, (?P<module_name>[^,^.]*)\.(?P<type_name>[^,^.]*)$'
263+
)
264+
self.foundation_and_other_type_matcher = re.compile(
265+
r'(Foundation\.)?[^,^.]*, (?P<module_name>[^,^.]*)\.' +
266+
r'(?P<type_name>[^,^.]*)$'
267+
)
181268

182269
def categorize_by_name(self, symbol):
183270
for c in self.category_matching:
@@ -204,12 +291,121 @@ def add(self, symbol):
204291
category_name = self.categorize_by_name(symbol)
205292
if category_name:
206293
self.add_symbol(category_name, symbol)
294+
if (groupSpecializations and
295+
category_name == 'Generic specialization of stdlib'):
296+
self.add_specialization(symbol)
207297
return
208298
category_name = self.categorize_by_mangled_name(symbol)
209299
if category_name:
210300
self.add_symbol(category_name, symbol)
211301
else:
212302
self.add_symbol('Unknown', symbol)
303+
if (groupSpecializations and
304+
category_name == 'Generic specialization of stdlib'):
305+
self.add_specialization(symbol)
306+
307+
def is_class_type_(self, type_name, mangled_name):
308+
match_class_name = str(len(type_name)) + type_name + 'C'
309+
if match_class_name in mangled_name:
310+
return True
311+
return False
312+
313+
def is_class_type(self, type_name, mangled_name):
314+
existing_categorization = self.is_class_type_dict.get(type_name, 3)
315+
if existing_categorization == 3:
316+
is_class = self.is_class_type_(type_name, mangled_name)
317+
self.is_class_type_dict[type_name] = is_class
318+
return is_class
319+
else:
320+
return existing_categorization
321+
322+
def is_dictionary_like_type(self, type_name):
323+
if 'Dictionary' in type_name:
324+
return True
325+
if 'Set' in type_name:
326+
return True
327+
return False
328+
329+
def group_library_types(self, module, type_name, specialization, mangled_name):
330+
if module != 'Swift':
331+
return module, type_name, specialization
332+
if self.single_stdlib_specialized_type_matcher.match(specialization):
333+
return module, 'stdlib', 'stdlib'
334+
if self.two_specialized_stdlib_types_matcher.match(specialization):
335+
return module, 'stdlib', 'stdlib'
336+
if self.single_specialized_foundation_type_matcher.match(specialization):
337+
return module, 'stdlib', 'foundation'
338+
if self.two_specialized_foundation_types_matcher.match(specialization):
339+
return module, 'stdlib', 'foundation'
340+
if self.two_specialized_foundation_types_matcher2.match(specialization):
341+
return module, 'stdlib', 'foundation'
342+
if self.two_specialized_foundation_types_matcher3.match(specialization):
343+
return module, 'stdlib', 'foundation'
344+
single_spec = self.single_specialized_types_matcher.match(specialization)
345+
if single_spec:
346+
is_class = self.is_class_type(single_spec.group('type_name'), mangled_name)
347+
is_dict = type_name is not None and self.is_dictionary_like_type(type_name)
348+
if not is_dict and is_class:
349+
return module, 'stdlib', 'class'
350+
if is_dict and is_class:
351+
return module, 'stdlib', 'class(dict)'
352+
stdlib_other_spec = self.stdlib_and_other_type_matcher.match(specialization)
353+
if stdlib_other_spec:
354+
is_class = self.is_class_type(stdlib_other_spec.group('type_name'),
355+
mangled_name)
356+
if is_class:
357+
return module, 'stdlib', 'stdlib, class'
358+
foundation_other_spec = self.foundation_and_other_type_matcher.match(
359+
specialization)
360+
if foundation_other_spec:
361+
is_class = self.is_class_type(foundation_other_spec.group('type_name'),
362+
mangled_name)
363+
if is_class:
364+
return module, 'stdlib', 'foundation, class'
365+
return module, 'stdlib', 'other'
366+
367+
def add_specialization(self, symbol):
368+
specialization_match = self.specialization_matcher.match(symbol.name)
369+
if specialization_match:
370+
module = specialization_match.group('module_name')
371+
type_name = specialization_match.group('first_type')
372+
specialization = specialization_match.group('spec_list')
373+
module, type_name, specialization = self.group_library_types(
374+
module, type_name, specialization, symbol.mangled_name)
375+
key = GenericSpecializationGroupKey(module, type_name, specialization)
376+
existing_specialization = self.specializations.get(key)
377+
if existing_specialization:
378+
existing_specialization.add(symbol)
379+
else:
380+
new_specialization = GenericSpecialization(module, type_name,
381+
specialization)
382+
new_specialization.add(symbol)
383+
self.specializations[key] = new_specialization
384+
else:
385+
print(symbol.name)
386+
print('not matched')
387+
return
388+
389+
def print_specializations(self):
390+
values = self.specializations.values()
391+
sorted_specializations = []
392+
for v in values:
393+
sorted_specializations.append(v)
394+
395+
if not sorted_specializations:
396+
return None
397+
else:
398+
sorted_specializations.sort(key=lambda entry: entry.specialization)
399+
sorted_specializations.sort(key=lambda entry: entry.type_name)
400+
sorted_specializations.sort(key=lambda entry: entry.module_name)
401+
print("Specialization info")
402+
for spec in sorted_specializations:
403+
print("%20s.%s %20s %8d" % (spec.module_name, spec.type_name,
404+
spec.specialization, spec.size))
405+
if listGroupSpecializations:
406+
spec.list_symbols()
407+
print("")
408+
return None
213409

214410
def categorize(self, symbols):
215411
for sym in symbols:
@@ -361,6 +557,8 @@ def categorize(segments):
361557
categories.categorize(symbols)
362558
categories.print_summary(section.size)
363559
print('')
560+
if groupSpecializations:
561+
categories.print_specializations()
364562

365563

366564
def uncategorized(segments):
@@ -382,6 +580,9 @@ def list_category(segments, category):
382580
print('Section %22s: %8d' %
383581
(segment.name + ';' + section.name, section.size))
384582
categories.print_category(category)
583+
print('')
584+
if groupSpecializations:
585+
categories.print_specializations()
385586

386587

387588
if __name__ == '__main__':

0 commit comments

Comments
 (0)