ksize.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #!/usr/bin/env python3
  2. #
  3. # Copyright (c) 2011, Intel Corporation.
  4. #
  5. # SPDX-License-Identifier: GPL-2.0-or-later
  6. #
  7. # Display details of the kernel build size, broken up by built-in.[o,a]. Sort
  8. # the objects by size. Run from the top level kernel build directory.
  9. #
  10. # Author: Darren Hart <dvhart@linux.intel.com>
  11. #
  12. import sys
  13. import getopt
  14. import os
  15. from subprocess import *
  16. def usage():
  17. prog = os.path.basename(sys.argv[0])
  18. print('Usage: %s [OPTION]...' % prog)
  19. print(' -d, display an additional level of drivers detail')
  20. print(' -h, --help display this help and exit')
  21. print('')
  22. print('Run %s from the top-level Linux kernel build directory.' % prog)
  23. class Sizes:
  24. def __init__(self, glob):
  25. self.title = glob
  26. p = Popen("size -t " + str(glob), shell=True, stdout=PIPE, stderr=PIPE, universal_newlines=True)
  27. output = p.communicate()[0].splitlines()
  28. if len(output) > 2:
  29. sizes = output[-1].split()[0:4]
  30. self.text = int(sizes[0])
  31. self.data = int(sizes[1])
  32. self.bss = int(sizes[2])
  33. self.total = int(sizes[3])
  34. else:
  35. self.text = self.data = self.bss = self.total = 0
  36. def show(self, indent=""):
  37. print("%-32s %10d | %10d %10d %10d" % \
  38. (indent+self.title, self.total, self.text, self.data, self.bss))
  39. class Report:
  40. def create(filename, title, subglob=None):
  41. r = Report(filename, title)
  42. path = os.path.dirname(filename)
  43. p = Popen("ls " + str(path) + "/*.o | grep -v built-in.o",
  44. shell=True, stdout=PIPE, stderr=PIPE, universal_newlines=True)
  45. glob = ' '.join(p.communicate()[0].splitlines())
  46. oreport = Report(glob, str(path) + "/*.o")
  47. oreport.sizes.title = str(path) + "/*.o"
  48. r.parts.append(oreport)
  49. if subglob:
  50. p = Popen("ls " + subglob, shell=True, stdout=PIPE, stderr=PIPE, universal_newlines=True)
  51. for f in p.communicate()[0].splitlines():
  52. path = os.path.dirname(f)
  53. r.parts.append(Report.create(f, path, str(path) + "/*/built-in.[o,a]"))
  54. r.parts.sort(reverse=True)
  55. for b in r.parts:
  56. r.totals["total"] += b.sizes.total
  57. r.totals["text"] += b.sizes.text
  58. r.totals["data"] += b.sizes.data
  59. r.totals["bss"] += b.sizes.bss
  60. r.deltas["total"] = r.sizes.total - r.totals["total"]
  61. r.deltas["text"] = r.sizes.text - r.totals["text"]
  62. r.deltas["data"] = r.sizes.data - r.totals["data"]
  63. r.deltas["bss"] = r.sizes.bss - r.totals["bss"]
  64. return r
  65. create = staticmethod(create)
  66. def __init__(self, glob, title):
  67. self.glob = glob
  68. self.title = title
  69. self.sizes = Sizes(glob)
  70. self.parts = []
  71. self.totals = {"total":0, "text":0, "data":0, "bss":0}
  72. self.deltas = {"total":0, "text":0, "data":0, "bss":0}
  73. def show(self, indent=""):
  74. rule = str.ljust(indent, 80, '-')
  75. print("%-32s %10s | %10s %10s %10s" % \
  76. (indent+self.title, "total", "text", "data", "bss"))
  77. print(rule)
  78. self.sizes.show(indent)
  79. print(rule)
  80. for p in self.parts:
  81. if p.sizes.total > 0:
  82. p.sizes.show(indent)
  83. print(rule)
  84. print("%-32s %10d | %10d %10d %10d" % \
  85. (indent+"sum", self.totals["total"], self.totals["text"],
  86. self.totals["data"], self.totals["bss"]))
  87. print("%-32s %10d | %10d %10d %10d" % \
  88. (indent+"delta", self.deltas["total"], self.deltas["text"],
  89. self.deltas["data"], self.deltas["bss"]))
  90. print("\n")
  91. def __lt__(this, that):
  92. if that is None:
  93. return 1
  94. if not isinstance(that, Report):
  95. raise TypeError
  96. return this.sizes.total < that.sizes.total
  97. def __cmp__(this, that):
  98. if that is None:
  99. return 1
  100. if not isinstance(that, Report):
  101. raise TypeError
  102. if this.sizes.total < that.sizes.total:
  103. return -1
  104. if this.sizes.total > that.sizes.total:
  105. return 1
  106. return 0
  107. def main():
  108. try:
  109. opts, args = getopt.getopt(sys.argv[1:], "dh", ["help"])
  110. except getopt.GetoptError as err:
  111. print('%s' % str(err))
  112. usage()
  113. sys.exit(2)
  114. driver_detail = False
  115. for o, a in opts:
  116. if o == '-d':
  117. driver_detail = True
  118. elif o in ('-h', '--help'):
  119. usage()
  120. sys.exit(0)
  121. else:
  122. assert False, "unhandled option"
  123. glob = "arch/*/built-in.[o,a] */built-in.[o,a]"
  124. vmlinux = Report.create("vmlinux", "Linux Kernel", glob)
  125. vmlinux.show()
  126. for b in vmlinux.parts:
  127. if b.totals["total"] > 0 and len(b.parts) > 1:
  128. b.show()
  129. if b.title == "drivers" and driver_detail:
  130. for d in b.parts:
  131. if d.totals["total"] > 0 and len(d.parts) > 1:
  132. d.show(" ")
  133. if __name__ == "__main__":
  134. main()