codesize.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. #!/usr/bin/env python3
  2. # Copyright (C) 2018 RDA Technologies Limited and/or its affiliates("RDA").
  3. # All rights reserved.
  4. #
  5. # This software is supplied "AS IS" without any warranties.
  6. # RDA assumes no responsibility or liability for the use of the software,
  7. # conveys no license or title under any patent, copyright, or mask work
  8. # right to the product. RDA reserves the right to make changes in the
  9. # software without notification. RDA also make no representation or
  10. # warranty that such application will be suitable for the specified use
  11. # without further testing or modification.
  12. import os
  13. import sys
  14. import re
  15. import optparse
  16. import fnmatch
  17. # section types
  18. section_text = [".text", ".text.*", ".ram", "RESET", "VECTORS",
  19. ".sramboottext", '.sramtext', '.ramtext', ".boot_sector_start",
  20. ".boottext", ".irqtext", ".romtext", ".bootsramtext",
  21. ".ram", ".start_entry", ".exception", ".tlb_exception",
  22. ".tlbtext", ".syssram_L1_text", ".nbsram_patch_text",
  23. ".init", ".sramTEXT", ".noinit",
  24. ".ramtext.*", ".sramtext.*"]
  25. section_ro = [".rodata", ".rodata.*",
  26. ".bootrodata", ".roresdata", ".robsdata", ".extra"]
  27. section_rw = [".data", ".data.*",
  28. ".rwkeep", ".bootsramdata", ".sramdata", ".sramucdata",
  29. ".srroucdata", ".ucdata"]
  30. section_zi = [".bss", ".bss.*", "COMMON", ".scommon", ".sdata", ".sdata.*",
  31. ".sbss", ".sbss.*", ".nbsram_globals",
  32. ".sramuninit", ".sramucuninit", ".dsp_iq_data", ".ramucbss",
  33. ".backup", ".bootsrambss", ".ucbss", ".srambss", ".sramucbss",
  34. ".ucbackup", ".xcv_reg_value", ".abb_reg_value", ".pmu_reg_value",
  35. ".hal_boot_sector_reload_struct", ".boot_sector_reload_struct_ptr",
  36. ".boot_sector_struct", ".boot_sector_struct_ptr",
  37. ".fixptr", ".dbgfunc", ".sram_overlay", ".TTBL1", ".TTBL2",".trace_sn"]
  38. section_ignore = [".ARM.exidx", ".ARM.attributes", ".comment", ".debug_*",
  39. ".iplt", ".rel.iplt", ".igot.plt", '.reginfo', ".mdebug.*",
  40. ".pdr", '.rel.dyn', '.noinit']
  41. # check a name matches a list of patterns
  42. def name_match(name, patterns):
  43. return any(fnmatch.fnmatch(name, pattern) for pattern in patterns)
  44. # section type by section name
  45. def section_type(section_name):
  46. if name_match(section_name, section_ignore):
  47. stype = "ignore"
  48. elif name_match(section_name, section_text):
  49. stype = "text"
  50. elif name_match(section_name, section_ro):
  51. stype = "rodata"
  52. elif name_match(section_name, section_rw):
  53. stype = "data"
  54. elif name_match(section_name, section_zi):
  55. stype = "bss"
  56. else:
  57. stype = "ignore"
  58. # print("unknown section:", section_name)
  59. # sys.exit(1)
  60. return stype
  61. # make an entry, a section in one object file
  62. def make_entry(section_name, size, obj):
  63. stype = section_type(section_name)
  64. r = re.compile(r'(\S+)\((\S+)\)')
  65. m = r.fullmatch(obj)
  66. fobj = obj
  67. if m:
  68. lib = m.group(1)
  69. obj = m.group(2)
  70. else:
  71. lib = obj
  72. lib = lib.split("/")[-1]
  73. obj = obj.split("/")[-1]
  74. return {"section": section_name, "stype": stype, "size": size,
  75. "lib": lib, "obj": obj, 'fobj': fobj}
  76. # parse map file
  77. def parse_map(fname):
  78. fh = open(fname, 'r')
  79. # "SECTION ADDRESS SIZE OBJ"
  80. r2 = re.compile(
  81. r"\s+(\S+)\s+0x([0-9a-fA-F]{8,16})\s+0x([0-9a-fA-F]+)\s+(\S+)")
  82. # "SECTION"
  83. r3 = re.compile(r"\s+(\S+)")
  84. # "ADDRESS SIZE OBJ"
  85. r4 = re.compile(r"\s+0x([0-9a-fA-F]{8,16})\s+0x([0-9a-fA-F]+)\s+(\S+)")
  86. ents = []
  87. map_found = False
  88. section_name = None
  89. for line in fh.readlines():
  90. if line.startswith("Linker script and memory map"):
  91. map_found = True
  92. continue
  93. if not map_found:
  94. continue
  95. if line.startswith('OUTPUT('):
  96. break
  97. line = line.rstrip()
  98. if section_name:
  99. m = r4.fullmatch(line)
  100. if m:
  101. size = int(m.group(2), 16)
  102. obj = m.group(3)
  103. ents.append(make_entry(section_name, size, obj))
  104. section_name = None
  105. continue
  106. m = r2.fullmatch(line)
  107. if m:
  108. name = m.group(1)
  109. size = int(m.group(3), 16)
  110. obj = m.group(4)
  111. ents.append(make_entry(name, size, obj))
  112. continue
  113. m = r3.fullmatch(line)
  114. if m:
  115. section_name = m.group(1)
  116. continue
  117. return ents
  118. def sizelist(f):
  119. sl = [f["text"],
  120. f["rodata"],
  121. f["data"],
  122. f["bss"],
  123. f["text"] + f["rodata"],
  124. f["text"] + f["rodata"] + f["data"],
  125. f["data"] + f["bss"]]
  126. ss = [str(s) for s in sl]
  127. return ",".join(ss)
  128. def main(argv):
  129. opt = optparse.OptionParser(usage="""usage %prog [options]
  130. This utility will analyze code size from map file. Code size are expressed
  131. in concept of: text, rodata, data, bss. There is a map inside this script
  132. to map each section name to section type. When there is an unknown section
  133. name, it is needed to add the section name to this script.
  134. """)
  135. opt.add_option("--map", action="store", dest="map",
  136. help="map file created at linking.")
  137. opt.add_option("--outobj", action="store", dest="outobj", default="outobj.csv",
  138. help="detailed information by object file (default: outobj.csv)")
  139. opt.add_option("--outlib", action="store", dest="outlib", default="outlib.csv",
  140. help="detailed information by library (default: outlib.csv)")
  141. opt.add_option("--outsect", action="store", dest="outsect", default="outsect.csv",
  142. help="detailed information by section (default: outsect.csv)")
  143. opt, argv = opt.parse_args(argv)
  144. if not opt.map:
  145. print("No map file specified!")
  146. return 1
  147. ents = parse_map(opt.map)
  148. stype_total = {"text": 0, "rodata": 0,
  149. "data": 0, "bss": 0, 'ignore': 0}
  150. for ent in ents:
  151. stype = ent['stype']
  152. size = ent['size']
  153. stype_total[stype] += size
  154. print("total: text,rodata,data,bss,code,flash,ram")
  155. print(" ", sizelist(stype_total))
  156. lib_total = {}
  157. for ent in ents:
  158. lib = ent['lib']
  159. stype = ent['stype']
  160. size = ent['size']
  161. if lib not in lib_total:
  162. lib_total[lib] = {"text": 0, "rodata": 0,
  163. "data": 0, "bss": 0, 'ignore': 0}
  164. lib_total[lib][stype] += size
  165. print("size by library to %s ..." % (opt.outlib))
  166. fh = open(opt.outlib, "w")
  167. fh.write("library name,text,rodata,data,bss,code,flash,ram\n")
  168. for n, l in lib_total.items():
  169. fh.write("%s,%s\n" % (n, sizelist(l)))
  170. fh.close()
  171. obj_total = {}
  172. for ent in ents:
  173. fobj = ent['fobj']
  174. lib = ent['lib']
  175. obj = ent['obj']
  176. stype = ent['stype']
  177. size = ent['size']
  178. if fobj not in obj_total:
  179. obj_total[fobj] = {"lib": lib, "obj": obj, "text": 0, "rodata": 0,
  180. "data": 0, "bss": 0, 'ignore': 0}
  181. obj_total[fobj][stype] += size
  182. print("size by object to %s ..." % (opt.outobj))
  183. fh = open(opt.outobj, "w")
  184. fh.write("object name,library name,text,rodata,data,bss,code,flash,ram\n")
  185. for n, l in obj_total.items():
  186. fh.write("%s,%s,%s\n" % (l['obj'], l["lib"], sizelist(l)))
  187. fh.close()
  188. section_total = {}
  189. for ent in ents:
  190. section = ent['section']
  191. stype = ent['stype']
  192. size = ent['size']
  193. if section not in section_total:
  194. section_total[section] = {"type": stype, "size": 0}
  195. section_total[section]['size'] += size
  196. print("size by section to %s ..." % (opt.outsect))
  197. fh = open(opt.outsect, "w")
  198. fh.write("section name,section type,size\n")
  199. for n, l in section_total.items():
  200. fh.write("%s,%s,%s\n" % (n, l['type'], l['size']))
  201. fh.close()
  202. return 0
  203. if __name__ == '__main__':
  204. sys.exit(main(sys.argv[1:]))