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