get-footprint.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. #
  2. # This file is used to generate PJSIP/PJMEDIA footprint report.
  3. # To use this file, just run it in pjsip-apps/build directory, to
  4. # produce footprint.txt and footprint.htm report files.
  5. #
  6. import os
  7. import sys
  8. import string
  9. import time
  10. compile_flags1 = [
  11. # Base
  12. ['BASE', 'Empty application size'],
  13. ['', 'Subtotal: Empty application size'],
  14. ['HAS_PJLIB', 'Minimum PJLIB only'],
  15. # Subtotal
  16. ['', 'Subtotal'],
  17. # PJLIB-UTIL
  18. ['HAS_PJLIB_STUN', 'STUN client'],
  19. ['HAS_PJLIB_GETOPT', 'getopt() functionality'],
  20. # Subtotal
  21. ['', 'TOTAL']
  22. ]
  23. compile_flags = [
  24. # Base
  25. ['BASE', 'Empty application size'],
  26. ['', 'Subtotal: empty application size on this platform'],
  27. ['HAS_PJLIB', 'PJLIB (pool, data structures, hash tables, ioqueue, socket, timer heap, etc.). ' +
  28. 'For targets that statically link application with LIBC, the size includes ' +
  29. 'various LIBC functions that are used by PJLIB.'],
  30. ['', 'Subtotal: Application linked with PJLIB'],
  31. # PJLIB-UTIL
  32. ['HAS_PJLIB_STUN', 'PJLIB-UTIL STUN client'],
  33. ['HAS_PJLIB_GETOPT', 'PJLIB-UTIL getopt() functionality'],
  34. ['HAS_PJLIB_SCANNER', 'PJLIB-UTIL text scanner (needed by SIP parser)'],
  35. ['HAS_PJLIB_XML', 'PJLIB-UTIL tiny XML (parsing and API) (needs text scanner)'],
  36. ['HAS_PJLIB_DNS', 'PJLIB-UTIL DNS packet and parsing'],
  37. ['HAS_PJLIB_RESOLVER', 'PJLIB-UTIL Asynchronous DNS resolver/caching engine'],
  38. ['HAS_PJLIB_CRC32', 'PJLIB-UTIL CRC32 algorithm'],
  39. ['HAS_PJLIB_HMAC_MD5', 'PJLIB-UTIL HMAC-MD5 algorithm'],
  40. ['HAS_PJLIB_HMAC_SHA1', 'PJLIB-UTIL HMAC-SHA1 algorithm'],
  41. # PJSIP
  42. ['HAS_PJSIP_CORE_MSG_ELEM', 'PJSIP Core - Messaging Elements and Parsing (message, headers, SIP URI, TEL URI/RFC 3966, etc.)'],
  43. ['HAS_PJSIP_CORE', 'PJSIP Core - Endpoint (transport management, module management, event distribution, etc.)'],
  44. ['HAS_PJSIP_CORE_MSG_UTIL', 'PJSIP Core - Stateless operations, SIP SRV, server resolution and fail-over'],
  45. ['HAS_PJSIP_UDP_TRANSPORT', 'PJSIP UDP transport'],
  46. ['', 'Subtotal: A minimalistic SIP application (parsing, UDP transport+STUN, no transaction)'],
  47. ['HAS_PJSIP_TCP_TRANSPORT', 'PJSIP TCP transport'],
  48. ['HAS_PJSIP_TLS_TRANSPORT', 'PJSIP TLS transport'],
  49. ['HAS_PJSIP_INFO', 'PJSIP INFO support (RFC 2976) (no special treatment, thus the zero size)'],
  50. ['HAS_PJSIP_TRANSACTION', 'PJSIP transaction and stateful API'],
  51. ['HAS_PJSIP_AUTH_CLIENT', 'PJSIP digest authentication client'],
  52. ['HAS_PJSIP_UA_LAYER', 'PJSIP User agent layer and base dialog and usage management (draft-ietf-sipping-dialogusage-01)'],
  53. ['HAS_PJMEDIA_SDP', 'PJMEDIA SDP Parsing and API (RFC 2327), needed by SDP negotiator'],
  54. ['HAS_PJMEDIA_SDP_NEGOTIATOR','PJMEDIA SDP negotiator (RFC 3264), needed by INVITE session'],
  55. ['HAS_PJSIP_INV_SESSION', 'PJSIP INVITE session API'],
  56. ['HAS_PJSIP_REGC', 'PJSIP client registration API'],
  57. ['', 'Subtotal: Minimal SIP application with registration (including digest authentication)'],
  58. ['HAS_PJSIP_EVENT_FRAMEWORK','PJSIP Event/SUBSCRIBE framework, RFC 3265 (needed by call transfer, and presence)'],
  59. ['HAS_PJSIP_CALL_TRANSFER', 'PJSIP Call Transfer/REFER support (RFC 3515)'],
  60. ['', 'Subtotal: Minimal SIP application with call transfer'],
  61. ['HAS_PJSIP_PRESENCE', 'PJSIP Presence subscription, including PIDF/X-PIDF support (RFC 3856, RFC 3863, etc) (needs XML)'],
  62. ['HAS_PJSIP_MESSAGE', 'PJSIP Instant Messaging/MESSAGE support (RFC 3428) (no special treatment, thus the zero size)'],
  63. ['HAS_PJSIP_IS_COMPOSING', 'PJSIP Message Composition indication (RFC 3994)'],
  64. # Subtotal
  65. ['', 'Subtotal: Complete PJSIP package (call, registration, presence, IM) +STUN +GETOPT (+PJLIB), no media'],
  66. # PJNATH
  67. ['HAS_PJNATH_STUN', 'PJNATH STUN'],
  68. ['HAS_PJNATH_ICE', 'PJNATH ICE'],
  69. # PJMEDIA
  70. ['HAS_PJMEDIA_EC', 'PJMEDIA accoustic echo cancellation'],
  71. ['HAS_PJMEDIA_SND_DEV', 'PJMEDIA sound device backend (platform specific)'],
  72. ['HAS_PJMEDIA_SILENCE_DET', 'PJMEDIA Adaptive silence detector'],
  73. ['HAS_PJMEDIA', 'PJMEDIA endpoint'],
  74. ['HAS_PJMEDIA_PLC', 'PJMEDIA Packet Lost Concealment implementation (needed by G.711, GSM, and sound device port)'],
  75. ['HAS_PJMEDIA_SND_PORT', 'PJMEDIA sound device media port'],
  76. ['HAS_PJMEDIA_RESAMPLE', 'PJMEDIA resampling algorithm (large filter disabled)'],
  77. ['HAS_PJMEDIA_G711_CODEC', 'PJMEDIA G.711 codec (PCMA/PCMU, including PLC) (may have already been linked by other module)'],
  78. ['HAS_PJMEDIA_CONFERENCE', 'PJMEDIA conference bridge (needs resampling and silence detector)'],
  79. ['HAS_PJMEDIA_MASTER_PORT', 'PJMEDIA master port'],
  80. ['HAS_PJMEDIA_RTP', 'PJMEDIA stand-alone RTP'],
  81. ['HAS_PJMEDIA_RTCP', 'PJMEDIA stand-alone RTCP and media quality calculation'],
  82. ['HAS_PJMEDIA_JBUF', 'PJMEDIA stand-alone adaptive jitter buffer'],
  83. ['HAS_PJMEDIA_STREAM', 'PJMEDIA stream for remote media communication (needs RTP, RTCP, and jitter buffer)'],
  84. ['HAS_PJMEDIA_TONEGEN', 'PJMEDIA tone generator'],
  85. ['HAS_PJMEDIA_UDP_TRANSPORT','PJMEDIA UDP media transport'],
  86. ['HAS_PJMEDIA_FILE_PLAYER', 'PJMEDIA WAV file player'],
  87. ['HAS_PJMEDIA_FILE_CAPTURE', 'PJMEDIA WAV file writer'],
  88. ['HAS_PJMEDIA_MEM_PLAYER', 'PJMEDIA fixed buffer player'],
  89. ['HAS_PJMEDIA_MEM_CAPTURE', 'PJMEDIA fixed buffer writer'],
  90. ['HAS_PJMEDIA_ICE', 'PJMEDIA ICE transport'],
  91. # Subtotal
  92. ['', 'Subtotal: Complete SIP and all PJMEDIA features (G.711 codec only)'],
  93. # Codecs
  94. ['HAS_PJMEDIA_GSM_CODEC', 'PJMEDIA GSM codec (including PLC)'],
  95. ['HAS_PJMEDIA_SPEEX_CODEC', 'PJMEDIA Speex codec (narrowband, wideband, ultra-wideband)'],
  96. ['HAS_PJMEDIA_ILBC_CODEC', 'PJMEDIA iLBC codec'],
  97. # Total
  98. ['', 'TOTAL: complete libraries (+all codecs)'],
  99. ]
  100. # Executable size report, tuple of:
  101. # <all flags>, <flags added>, <text size>, <data>, <bss>, <description>
  102. exe_size = []
  103. #
  104. # Write the report to text file
  105. #
  106. def print_text_report(filename):
  107. output = open(filename, 'w')
  108. output.write('PJSIP and PJMEDIA footprint report\n')
  109. output.write('Auto-generated by pjsip-apps/build/get-footprint.py\n')
  110. output.write('\n')
  111. # Write Revision info.
  112. f = os.popen('svn info | grep Revision')
  113. output.write(f.readline())
  114. output.write('Date: ')
  115. output.write(time.asctime())
  116. output.write('\n')
  117. output.write('\n')
  118. # Write individual module size
  119. output.write('Footprint (in bytes):\n')
  120. output.write(' .text .data .bss Module Description\n')
  121. output.write('==========================================================\n')
  122. for i in range(1, len(exe_size)):
  123. e = exe_size[i]
  124. prev = exe_size[i-1]
  125. if e[1]<>'':
  126. output.write(' ')
  127. output.write( string.rjust(`string.atoi(e[2]) - string.atoi(prev[2])`, 8) )
  128. output.write( string.rjust(`string.atoi(e[3]) - string.atoi(prev[3])`, 8) )
  129. output.write( string.rjust(`string.atoi(e[4]) - string.atoi(prev[4])`, 8) )
  130. output.write(' ' + e[5] + '\n')
  131. else:
  132. output.write(' ------------------------\n')
  133. output.write(' ')
  134. output.write( string.rjust(e[2], 8) )
  135. output.write( string.rjust(e[3], 8) )
  136. output.write( string.rjust(e[4], 8) )
  137. output.write(' ' + e[5] + '\n')
  138. output.write('\n')
  139. # Done
  140. output.close()
  141. #
  142. # Write the report to HTML file
  143. #
  144. def print_html_report():
  145. # Get Revision info.
  146. f = os.popen('svn info | grep Revision')
  147. revision = f.readline().split()[1]
  148. # Get Machine, OS, and CC name
  149. f = os.popen('make -f Footprint.mak print_name')
  150. names = f.readline().split()
  151. m = names[0]
  152. o = names[1]
  153. cc = names[2]
  154. cc_ver = names[3]
  155. # Open HTML file
  156. filename = 'footprint-' + m + '-' + o + '.htm'
  157. output = open(filename, 'w')
  158. title = 'PJSIP and PJMEDIA footprint report for ' + m + '-' + o + ' target'
  159. output.write('<HTML><HEAD>\n');
  160. output.write(' <TITLE>' + title + '</TITLE>\n')
  161. output.write(' <LINK href="/style/style.css" type="text/css" rel="stylesheet">\n')
  162. output.write('</HEAD>\n');
  163. output.write('<BODY bgcolor="white">\n');
  164. output.write('<!--#include virtual="/header.html" -->')
  165. output.write(' <H1>' + title + '</H1>\n')
  166. output.write('Auto-generated by pjsip-apps/build/get-footprint.py script\n')
  167. output.write('<p>Date: ' + time.asctime() + '<BR>\n')
  168. output.write('Revision: r' + revision + '</p>\n\n')
  169. output.write('<HR>\n')
  170. output.write('\n')
  171. # Info
  172. output.write('<H2>Build Configuration</H2>\n')
  173. # build.mak
  174. output.write('\n<H3>build.mak</H3>\n')
  175. output.write('<tt>\n')
  176. f = open('../../build.mak', 'r')
  177. s = f.readlines()
  178. for l in s:
  179. output.write(l + '<BR>\n')
  180. output.write('</tt>\n')
  181. output.write('<p>Using ' + cc + ' version ' + cc_ver +'</p>\n')
  182. # user.mak
  183. output.write('\n<H3>user.mak</H3>\n')
  184. output.write('<tt>\n')
  185. f = open('../../user.mak', 'r')
  186. s = f.readlines()
  187. for l in s:
  188. output.write(l + '<BR>\n')
  189. output.write('</tt>\n')
  190. # config_site.h
  191. output.write('\n<H3>&lt;pj/config.site.h&gt;</H3>\n')
  192. output.write('<tt>\n')
  193. f = os.popen('cpp -dM -I../../pjlib/include ../../pjlib/include/pj/config_site.h | grep PJ')
  194. s = f.readlines()
  195. for l in s:
  196. output.write(l + '<BR>\n')
  197. output.write('</tt>\n')
  198. # Write individual module size
  199. output.write('<H2>Footprint Report</H2>\n')
  200. output.write('<p>The table below shows the footprint of individual feature, in bytes.</p>')
  201. output.write('<TABLE border="1" cellpadding="2" cellspacing="0">\n' +
  202. '<TR bgcolor="#e8e8ff">\n' +
  203. ' <TD align="center"><strong>.text</strong></TD>\n' +
  204. ' <TD align="center"><strong>.data</strong></TD>\n' +
  205. ' <TD align="center"><strong>.bss</strong></TD>\n' +
  206. ' <TD align="center"><strong>Features/Module Description</strong></TD>\n' +
  207. '</TR>\n')
  208. for i in range(1, len(exe_size)):
  209. e = exe_size[i]
  210. prev = exe_size[i-1]
  211. output.write('<TR>\n')
  212. if e[1]<>'':
  213. output.write( ' <TD align="right">' + `string.atoi(e[2]) - string.atoi(prev[2])` + '</TD>\n')
  214. output.write( ' <TD align="right">' + `string.atoi(e[3]) - string.atoi(prev[3])` + '</TD>\n')
  215. output.write( ' <TD align="right">' + `string.atoi(e[4]) - string.atoi(prev[4])` + '</TD>\n' )
  216. output.write( ' <TD>' + e[5] + '</TD>\n')
  217. else:
  218. empty_size = exe_size[1]
  219. output.write('<TR bgcolor="#e8e8ff">\n')
  220. output.write( ' <TD align="right">&nbsp;</TD>\n')
  221. output.write( ' <TD align="right">&nbsp;</TD>\n')
  222. output.write( ' <TD align="right">&nbsp;</TD>\n')
  223. output.write( ' <TD><strong>' + e[5] + ': .text=' + e[2]+ ', .data=' + e[3] + ', .bss=' + e[4] )
  224. output.write( '\n </strong> <BR>(Size minus empty application size: ' + \
  225. '.text=' + `string.atoi(e[2]) - string.atoi(empty_size[2])` + \
  226. ', .data=' + `string.atoi(e[3]) - string.atoi(empty_size[3])` + \
  227. ', .data=' + `string.atoi(e[4]) - string.atoi(empty_size[4])` + \
  228. ')\n' )
  229. output.write( ' </TD>\n')
  230. output.write('</TR>\n')
  231. output.write('</TABLE>\n')
  232. output.write('<!--#include virtual="/footer.html" -->')
  233. output.write('</BODY>\n')
  234. output.write('</HTML>\n')
  235. # Done
  236. output.close()
  237. #
  238. # Get the size of individual feature
  239. #
  240. def get_size(all_flags, flags, desc):
  241. file = 'footprint.exe'
  242. # Remove file
  243. rc = os.system("make -f Footprint.mak FCFLAGS='" + all_flags + "' clean")
  244. # Make the executable
  245. cmd = "make -f Footprint.mak FCFLAGS='" + all_flags + "' all"
  246. #print cmd
  247. rc = os.system(cmd)
  248. if rc <> 0:
  249. sys.exit(1)
  250. # Run 'size' against the executable
  251. f = os.popen('size ' + file)
  252. # Skip header of the 'size' output
  253. f.readline()
  254. # Get the sizes
  255. size = f.readline()
  256. f.close()
  257. # Split into tokens
  258. tokens = size.split()
  259. # Build the size tuple and add to exe_size
  260. elem = all_flags, flags, tokens[0], tokens[1], tokens[2], desc
  261. exe_size.append(elem)
  262. # Remove file
  263. rc = os.system("make -f Footprint.mak FCFLAGS='" + all_flags + "' clean")
  264. # Main
  265. elem = '', '', '0', '0', '0', ''
  266. exe_size.append(elem)
  267. all_flags = ''
  268. for elem in compile_flags:
  269. if elem[0] <> '':
  270. flags = '-D' + elem[0]
  271. all_flags += flags + ' '
  272. get_size(all_flags, elem[0], elem[1])
  273. else:
  274. e = exe_size[len(exe_size)-1]
  275. n = all_flags, '', e[2], e[3], e[4], elem[1]
  276. exe_size.append(n)
  277. #print_text_report('footprint.txt')
  278. print_html_report()