xref: /aosp_15_r20/external/grpc-grpc/tools/profiling/ios_bin/parse_link_map.py (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1#!/usr/bin/python
2# Copyright 2018 gRPC authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16# This script analyzes link map file generated by Xcode. It calculates and
17# prints out the sizes of each dependent library and the total sizes of the
18# symbols.
19# The script takes one parameter, which is the path to the link map file.
20
21import re
22import sys
23
24
25def parse_link_map(filename):
26    table_tag = {}
27    state = "start"
28
29    table_stats_symbol = {}
30    table_stats_dead = {}
31    section_total_size = 0
32    symbol_total_size = 0
33
34    boringssl_size = 0
35    core_size = 0
36    objc_size = 0
37    protobuf_size = 0
38
39    lines = open(filename, encoding="utf-8", errors="ignore").readlines()
40    for line in lines:
41        line_stripped = line[:-1]
42        if "# Object files:" == line_stripped:
43            state = "object"
44            continue
45        elif "# Sections:" == line_stripped:
46            state = "section"
47            continue
48        elif "# Symbols:" == line_stripped:
49            state = "symbol"
50            continue
51        elif "# Dead Stripped Symbols:" == line_stripped:
52            state = "dead"
53            continue
54
55        if state == "object":
56            segs = re.search("(\[ *[0-9]*\]) (.*)", line_stripped)
57            table_tag[segs.group(1)] = segs.group(2)
58
59        if state == "section":
60            if len(line_stripped) == 0 or line_stripped[0] == "#":
61                continue
62            segs = re.search("^(.+?)\s+(.+?)\s+.*", line_stripped)
63            section_total_size += int(segs.group(2), 16)
64
65        if state == "symbol":
66            if len(line_stripped) == 0 or line_stripped[0] == "#":
67                continue
68            segs = re.search("^.+?\s+(.+?)\s+(\[.+?\]).*", line_stripped)
69            if not segs:
70                continue
71            target = table_tag[segs.group(2)]
72            target_stripped = re.search("^(.*?)(\(.+?\))?$", target).group(1)
73            size = int(segs.group(1), 16)
74            if not target_stripped in table_stats_symbol:
75                table_stats_symbol[target_stripped] = 0
76            table_stats_symbol[target_stripped] += size
77            if "BoringSSL" in target_stripped:
78                boringssl_size += size
79            elif "libgRPC-Core" in target_stripped:
80                core_size += size
81            elif (
82                "libgRPC-RxLibrary" in target_stripped
83                or "libgRPC" in target_stripped
84                or "libgRPC-ProtoLibrary" in target_stripped
85            ):
86                objc_size += size
87            elif "libProtobuf" in target_stripped:
88                protobuf_size += size
89
90    for target in table_stats_symbol:
91        symbol_total_size += table_stats_symbol[target]
92
93    return (
94        core_size,
95        objc_size,
96        boringssl_size,
97        protobuf_size,
98        symbol_total_size,
99    )
100
101
102def main():
103    filename = sys.argv[1]
104    (
105        core_size,
106        objc_size,
107        boringssl_size,
108        protobuf_size,
109        total_size,
110    ) = parse_link_map(filename)
111    print("Core size:{:,}".format(core_size))
112    print("ObjC size:{:,}".format(objc_size))
113    print("BoringSSL size:{:,}".format(boringssl_size))
114    print("Protobuf size:{:,}\n".format(protobuf_size))
115    print("Total size:{:,}".format(total_size))
116
117
118if __name__ == "__main__":
119    main()
120