= Analyzing the PJMEDIA Tone Generator Algorithms Performance =
This article presents the performance analysis of various back-end algorithms of the tone generator that are implemented in PJMEDIA. We will measure the performance in both speed and accuracy terms.
== The Algorithms ==
The tone generator (tonegen.c) supports several algorithms, and since version 1.0-rc3, the use of these algorithms can be controlled by application by using the {{{PJMEDIA_TONEGEN_ALG}}} macro setting:
'''{{{PJMEDIA_TONEGEN_SINE}}}'''::
The good-old generation using math's sine(), floating point. This has very good precision but it's the slowest and requires floating point support and linking with the math library.
'''{{{PJMEDIA_TONEGEN_FLOATING_POINT}}}''' (default when floating point is enabled)::
Floating point approximation of sine(). This has relatively good precision and much faster than plain sine(), but it requires floating-point support and linking with the math library.
'''{{{PJMEDIA_TONEGEN_FIXED_POINT_CORDIC}}}''' (new in 1.0-rc3, and the default when floating point is disabled)::
Fixed point using sine signal generated by a 28-bit [http://en.wikipedia.org/wiki/CORDIC CORDIC] algorithm. This algorithm can be tuned to provide balance between precision and performance by tuning the {{{PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP}}} setting, and it is suitable for platforms that lack floating-point support.
'''{{{PJMEDIA_TONEGEN_FAST_FIXED_POINT}}}'''::
Fast fixed point using some approximation to generate sine waves. The tone generated by this algorithm is not very precise, however the algorithm is very fast.
== Accuracy ==
For the accuracy test, we setup the tone generator to generate digit A from [http://en.wikipedia.org/wiki/DTMF DTMF], with frequencies of 697 and 1209. We then saved the tone to a WAV file and analyzed the frequency using !CoolEdit (now becomes [http://www.adobe.com/special/products/audition/syntrillium.html Adobe Audition]).
This is simple to do with [http://www.pjsip.org/pjsua.htm pjsua] really:
{{{
pjsua --play-tone 697,1209,200,2000 --rec-file tone.wav
}}}
then issue these commands:
{{{
cc 1 2
sleep 5000
cd 1 2
q
}}}
And here is the graphics from the frequency analysis.
|| PJMEDIA_TONEGEN_SINE:[[BR]] [[Image(sine.JPG)]] || PJMEDIA_TONEGEN_FLOATING_POINT:[[BR]] [[Image(float.JPG)]] ||
|| PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 16 iterations:[[BR]] [[Image(cordic16.JPG)]] || PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 12 iterations:[[BR]][[Image(cordic12.JPG)]] ||
|| PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 10 iterations:[[BR]] [[Image(cordic10.JPG)]] || PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 8 iterations:[[BR]][[Image(cordic8.JPG)]] ||
|| PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 7 iterations:[[BR]] [[Image(cordic7.JPG)]] || PJMEDIA_TONEGEN_FAST_FIXED_POINT: [[BR]][[Image(fast-fixed-point.JPG)]] ||
== Performance ==
Below is the time measurements of the algorithms. The test measures the generation of 1 second worth of dual-tone at 8KHz sampling rate. For single-tone, just divide the results by two, and for 16KHz dual-tone, just multiply the results by two.
The MIPS value uses the same convention as in [wiki:PJMEDIA-MIPS PJMEDIA Performance Measurement] page.
=== Linux, ARM9 (ARM926EJ-S), gcc ===
On this platform we use {{{-O3 -msoft-float -DNDEBUG -DPJ_HAS_FLOATING_POINT=0}}} flags.
|| || time (usec) || CPU (%) || MIPS ||
|| PJMEDIA_TONEGEN_SINE || 506,535 || 50.653 || 100.29 ||
|| PJMEDIA_TONEGEN_FLOATING_POINT || 18,037 || 1.804 || 3.57 ||
|| PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 16 iterations || 17,694 || 1.769 || 3.50 ||
|| PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 12 iterations || 13,561 || 1.356 || 2.69 ||
|| PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 10 iterations || 11,662 || 1.166 || 2.31 ||
|| PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 8 iterations || 9,872 || 0.987 || 1.95 ||
|| PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 7 iterations || 8,943 || 0.894 || 1.77 ||
|| PJMEDIA_TONEGEN_FAST_FIXED_POINT || 1,449 || 0.145 || 0.29 ||
=== Windows, P4 2.66 GHz, Visual Studio 6 ===
|| || time (usec) || CPU (%) || MIPS ||
|| PJMEDIA_TONEGEN_SINE || 1,348 || 0.135 || 10.92 ||
|| PJMEDIA_TONEGEN_FLOATING_POINT || 605 || 0.060 || 4.90 ||
|| PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 16 iterations || 1,372 || 0.137 || 11.12 ||
|| PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 12 iterations || 1,140 || 0.114 || 9.24 ||
|| PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 10 iterations || 998 || 0.100 || 8.09 ||
|| PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 8 iterations || 826 || 0.083 || 6.69 ||
|| PJMEDIA_TONEGEN_FIXED_POINT_CORDIC with 7 iterations || 743 || 0.074 || 6.02 ||
|| PJMEDIA_TONEGEN_FAST_FIXED_POINT || 117 || 0.012 || 0.95 ||
== Conclusion ==
Based on the results above, and as of version 1.0-rc3, we set the tone generator settings in {{{pjmedia/config.h}}} as follows:
- on PC and platforms where floating point '''is''' available:
{{{
#define PJMEDIA_TONEGEN_ALG PJMEDIA_TONEGEN_FLOATING_POINT
}}}
- on platforms where floating point '''is NOT''' available:
{{{
#define PJMEDIA_TONEGEN_ALG PJMEDIA_TONEGEN_FIXED_POINT_CORDIC
#define PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP 10
}}}
These settings of course can be overridden in your {{{config_site.h}}} as usual.
[[BR]]
[[BR]]