1#!/usr/bin/env python3 2# 3# Copyright (c) 2011, Intel Corporation. 4# All rights reserved. 5# 6# This program is free software; you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 2 of the License, or 9# (at your option) any later version. 10# 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License 17# along with this program; if not, write to the Free Software 18# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19# 20# 21# Display details of the kernel build size, broken up by built-in.o. Sort 22# the objects by size. Run from the top level kernel build directory. 23# 24# Author: Darren Hart <dvhart@linux.intel.com> 25# 26 27import sys 28import getopt 29import os 30from subprocess import * 31 32def usage(): 33 prog = os.path.basename(sys.argv[0]) 34 print('Usage: %s [OPTION]...' % prog) 35 print(' -d, display an additional level of drivers detail') 36 print(' -h, --help display this help and exit') 37 print('') 38 print('Run %s from the top-level Linux kernel build directory.' % prog) 39 40 41class Sizes: 42 def __init__(self, glob): 43 self.title = glob 44 p = Popen("size -t " + str(glob), shell=True, stdout=PIPE, stderr=PIPE) 45 output = p.communicate()[0].splitlines() 46 if len(output) > 2: 47 sizes = output[-1].split()[0:4] 48 self.text = int(sizes[0]) 49 self.data = int(sizes[1]) 50 self.bss = int(sizes[2]) 51 self.total = int(sizes[3]) 52 else: 53 self.text = self.data = self.bss = self.total = 0 54 55 def show(self, indent=""): 56 print("%-32s %10d | %10d %10d %10d" % \ 57 (indent+self.title, self.total, self.text, self.data, self.bss)) 58 59 60class Report: 61 def create(filename, title, subglob=None): 62 r = Report(filename, title) 63 path = os.path.dirname(filename) 64 65 p = Popen("ls " + str(path) + "/*.o | grep -v built-in.o", 66 shell=True, stdout=PIPE, stderr=PIPE) 67 glob = ' '.join(p.communicate()[0].splitlines()) 68 oreport = Report(glob, str(path) + "/*.o") 69 oreport.sizes.title = str(path) + "/*.o" 70 r.parts.append(oreport) 71 72 if subglob: 73 p = Popen("ls " + subglob, shell=True, stdout=PIPE, stderr=PIPE) 74 for f in p.communicate()[0].splitlines(): 75 path = os.path.dirname(f) 76 r.parts.append(Report.create(f, path, str(path) + "/*/built-in.o")) 77 r.parts.sort(reverse=True) 78 79 for b in r.parts: 80 r.totals["total"] += b.sizes.total 81 r.totals["text"] += b.sizes.text 82 r.totals["data"] += b.sizes.data 83 r.totals["bss"] += b.sizes.bss 84 85 r.deltas["total"] = r.sizes.total - r.totals["total"] 86 r.deltas["text"] = r.sizes.text - r.totals["text"] 87 r.deltas["data"] = r.sizes.data - r.totals["data"] 88 r.deltas["bss"] = r.sizes.bss - r.totals["bss"] 89 return r 90 create = staticmethod(create) 91 92 def __init__(self, glob, title): 93 self.glob = glob 94 self.title = title 95 self.sizes = Sizes(glob) 96 self.parts = [] 97 self.totals = {"total":0, "text":0, "data":0, "bss":0} 98 self.deltas = {"total":0, "text":0, "data":0, "bss":0} 99 100 def show(self, indent=""): 101 rule = str.ljust(indent, 80, '-') 102 print("%-32s %10s | %10s %10s %10s" % \ 103 (indent+self.title, "total", "text", "data", "bss")) 104 print(rule) 105 self.sizes.show(indent) 106 print(rule) 107 for p in self.parts: 108 if p.sizes.total > 0: 109 p.sizes.show(indent) 110 print(rule) 111 print("%-32s %10d | %10d %10d %10d" % \ 112 (indent+"sum", self.totals["total"], self.totals["text"], 113 self.totals["data"], self.totals["bss"])) 114 print("%-32s %10d | %10d %10d %10d" % \ 115 (indent+"delta", self.deltas["total"], self.deltas["text"], 116 self.deltas["data"], self.deltas["bss"])) 117 print("\n") 118 119 def __lt__(this, that): 120 if that is None: 121 return 1 122 if not isinstance(that, Report): 123 raise TypeError 124 return this.sizes.total < that.sizes.total 125 126 def __cmp__(this, that): 127 if that is None: 128 return 1 129 if not isinstance(that, Report): 130 raise TypeError 131 if this.sizes.total < that.sizes.total: 132 return -1 133 if this.sizes.total > that.sizes.total: 134 return 1 135 return 0 136 137 138def main(): 139 try: 140 opts, args = getopt.getopt(sys.argv[1:], "dh", ["help"]) 141 except getopt.GetoptError as err: 142 print('%s' % str(err)) 143 usage() 144 sys.exit(2) 145 146 driver_detail = False 147 for o, a in opts: 148 if o == '-d': 149 driver_detail = True 150 elif o in ('-h', '--help'): 151 usage() 152 sys.exit(0) 153 else: 154 assert False, "unhandled option" 155 156 glob = "arch/*/built-in.o */built-in.o" 157 vmlinux = Report.create("vmlinux", "Linux Kernel", glob) 158 159 vmlinux.show() 160 for b in vmlinux.parts: 161 if b.totals["total"] > 0 and len(b.parts) > 1: 162 b.show() 163 if b.title == "drivers" and driver_detail: 164 for d in b.parts: 165 if d.totals["total"] > 0 and len(d.parts) > 1: 166 d.show(" ") 167 168 169if __name__ == "__main__": 170 main() 171