Footprint Optimization

Note

Although this article is very old (was written in 2007) and the numbers have changed, most of the principles for reducing footprint still apply.

Overview

With the default settings, PJSIP is not heavily optimized for size (nor speed), since the main objective is to have sufficient information for troubleshooting. Taking Windows as reference platform, the executable size of Release build with Visual C++ 6 is as follows:

pjsua_vc6.exe: file size=749,672 bytes

    241664 .data
    102400 .rdata
     24576 .reloc
    536576 .text

(all numbers in decimal, bytes)

Note

With default settings, pjsua includes as many features as available in the source distribution, for example, all the codecs, statically linked with the application. Hence the executable size is a bit large for pjsua.

The heap usage with 2 connected calls using Speex wideband codec and AEC enabled (press dd in pjsua menu, and scroll up to the portion where it dumps the memory pool statistic):

>>> dd
..
  Total    908508 of   1046304 (86 %) used!
..

Reducing executable size

To reduce the executable size, the following settings can be applied by declaring the settings in config_site.h:

  1. Disable Speex AEC. If AEC is provided by the hardware, Speec AEC can be disabled by setting PJMEDIA_HAS_SPEEX_AEC to 0, to reduce executable size by 32 KB.

  2. Disable resampling. If all media components are running at the same clock rate, disable resampling by setting PJMEDIA_HAS_LIBRESAMPLE to 0, to reduce executable size by 45 KB.

  3. Disable unused codecs. For example, disable speex by declaring PJMEDIA_HAS_SPEEX_CODEC to 0, disable iLBC by declaring PJMEDIA_HAS_ILBC_CODEC to 0, disable GSM codec by declaring PJMEDIA_HAS_GSM_CODEC to 0, and disable L16 codecs by declaring PJMEDIA_HAS_L16_CODEC to 0. This will reduce executable size by approximately 114 KB.

    Note

    Latest PJSIP version contains more codecs. See pjmedia/include/pjmedia-codec/config.h to see what built-in codecs are available and how to disable them, using code similar to above.

  4. Disable alaw/ulaw table. By default, a table based alaw/ulaw implementation is used. You can disable this by setting PJMEDIA_HAS_ALAW_ULAW_TABLE to 0, which makes PJMEDIA calculates the alaw/ulaw value rather than using the table. This will reduce executable size by approximately 28 KB, at the expense of more CPU processing.

  5. Disable error string. All libraries keep the description of the error codes in some static variables. You can omit this error description by setting PJ_HAS_ERROR_STRING to 0. When the error description is omitted, pj_strerror() will just print the error code rather than the error message. You can then look for the error description in libraries source codes. Omitting the error description will reduce executable size by approximately 20 KB.

  6. Disable run-time checks. All the libraries are equipped with run-time checks to prevent bad parameters from crashing the software. Although this is not recommended, it can be disabled by setting PJ_ENABLE_EXTRA_CHECK to 0. This will reduce executable size by approximately 20 KB.

  7. Disable stack checks. PJLIB is equipped with stack overflow detection. This can be disabled by setting PJ_OS_HAS_CHECK_STACK to 0, to reduce executable size by approximately 4 KB.

  8. Disable CRC32 table, by setting PJ_CRC32_HAS_TABLES to 0, to reduce executable size by about 1 KB, only if you use ICE. Note the non-table based is more than an order of magnitude slower.

  9. Use your own sound device abstraction, rather than PortAudio. If you are porting PJSIP to an embedded platform, you will need to create your own sound device abstraction. So supposing we don’t use PortAudio and use the NULL sound device implementation (by declaring PJMEDIA_SOUND_IMPLEMENTATION to PJMEDIA_SOUND_NULL_SOUND), we will reduce executable size by approximately 49 KB.

    Note

    This has been deprecated since the use of PJMEDIA-AudioDev API. See pjmedia/include/pjmedia-audiodev/config.h for supported audio device backends.

  10. Reduce logging verbosity. The default logging level is 5, to provide enough information for debugging. If price is really really tight, the logging verbosity level can be decreased, for example to level 3 so that only vital information is displayed, by setting PJ_LOG_MAX_LEVEL macro to 3. This will reduce executable size by approximately 28 KB.

  11. Turn off logging. Alternatively you can disable logging altogether, by setting PJ_LOG_MAX_LEVEL to 0. This is not recommended, and will reduce executable size by another 28 KB.

With all above optimizations set, we now have pjsua size (still with ICE/PJNATH and many media goodies like conference, WAV, etc. statically linked in the executable):

pjsua_vc6.exe: file size= 381,032 bytes

 184320 .data
   8192 .rdata
  16384 .reloc
 319488 .text

Using the same settings, if we take the executable size of simpleua.exe (this is a sample program to do simple call with audio, without conference bridge nor ICE/STUN):

simpleua.exe: file size= 155,648 bytes

  28672 .data
   4096 .rdata
 139264 .text

At this point, the heap memory usage of pjsua with 2 calls has been reduced by about 100 KB:

>>> dd
..
 Total    793624 of    909024 (87 %) used!
..

Reducing heap memory usage

Now, assuming that the product will only need to support, say, 8 calls, we can apply these settings to reduce heap memory usage:

  1. Transaction/dialog/call count. Set the maximum number of concurrent transactions/dialogs/calls with

    #   define PJSIP_MAX_TSX_COUNT      31
    #   define PJSIP_MAX_DIALOG_COUNT   31
    #   define PJSUA_MAX_CALLS          31
    

    For reference: see PJSIP_MAX_TSX_COUNT, PJSIP_MAX_DIALOG_COUNT, PJSUA_MAX_CALLS in pjsip/include/pjsip/sip_config.h

  2. Optimize pool sizes. These settings not only will reduce heap memory usage, but will also prevent the libraries from allocating too many large memory blocks. With the default settings, most memory pools are configured to allocate memory in 4KB blocks, and some system like Symbian will have difficulties in providing these blocks to PJSIP. Use the following setting to reduce the memory block size used by memory pools, at the expense of more calls to system’s memory allocators (new or malloc) to allocate memory:

    #   define PJSIP_POOL_LEN_ENDPT     1000
    #   define PJSIP_POOL_INC_ENDPT     1000
    #   define PJSIP_POOL_RDATA_LEN     2000
    #   define PJSIP_POOL_RDATA_INC     2000
    #   define PJSIP_POOL_LEN_TDATA     2000
    #   define PJSIP_POOL_INC_TDATA     512
    #   define PJSIP_POOL_LEN_UA        2000
    #   define PJSIP_POOL_INC_UA        1000
    #   define PJSIP_POOL_TSX_LAYER_LEN 256
    #   define PJSIP_POOL_TSX_LAYER_INC 256
    #   define PJSIP_POOL_TSX_LEN       512
    #   define PJSIP_POOL_TSX_INC       128
    #   define PJMEDIA_SESSION_SIZE     1000
    #   define PJMEDIA_SESSION_INC      1000
    

    With these settings applied, heap memory usage will be reduced very significantly. Looking at heap memory usage of pjsua with two G.711 calls:

    pjsua_vc6 --clock-rate 8000 --ec-tail 0 --max-calls 2 --no-tcp
    
    >>> dd
    ..
    Total    120532 of    150344 (80 %) used!
    ..
    

At this stage, the heap usage is about 150 KB for two calls, which should be affordable.