Tag Archives: FAQ

Optimization, Licensing, and Performance

Users evaluating our ASN1C SDK frequently find they don’t get the encoding or decoding performance they hoped for.  The libraries we provide for evaluation have less-than-optimal performance for two reasons: they are not optimized and they include license checking overhead. Customers who need to evaluate performance characteristics can request access to optimized libraries, but without doing that, what are some reasonable expectations?

We recently did some performance analysis to help a potential customer evaluate performance. The analysis was for decoding of LTE RRC messages using C++. We used ASN1C 7.4, the statically-linked ASN1C libraries, and Visual Studio 2019. Due to possible variations in specifications, data sets, and hardware, I don’t report absolute measurements here, but rather relative measurements of elapsed wall clock time.

Non-optimized, limited (license-checked) library (baseline) 100%
Non-optimized (debug), unlimited (license-check free) library 72%
Optimized, limited (license-checked) library 47%
Optimized, unlimited (license-check free) library 20%
Optimized, unlimited (license-check free) library, with code generation changes (see below for details) <2% (8.5% of the time for the same library without the code generation changes)

In this test, we found that the optimized, unlimited library used roughly 20% of the time used by the non-optimized, limited library provided with the evaluation SDK (that’s an 80% reduction in elapsed time).

In this particular case, we did some further experimentation to see what could be done with the generated code to get even better performance using the optimized, unlimited library. We found that by removing some generated diagnostics-related code and using dynamic arrays instead of linked lists, we achieved a tremendous further performance boost. (We generated code using the -dynamicArray option and compiled it with _COMPACT defined). By doing this, we found the time used was less than 2% of the baseline, and only 8.5% of the time used by the optimized, unlimited library.

Link Order Failures

A common set of linkage failures looks something like this:

Undefined                        first referenced
symbol                              in file
rtxCtxtSetMemHeap                   /opt/asn1c-v613/c/libgcc3/libasn1ber.a(obj.o)
rtxFileReadBinary                   /opt/asn1c-v613/c/libgcc3/libasn1ber.a(rtb.o)

The two symbols rtxCtxtSetMemHeap and rtxReadFileBinary are defined in our common runtime library. Users always report these failures with the point that they are, in fact, linking against the common runtime, like this:

gcc -o executable -L/opt/asn1c-v613/c -lasn1rt -lasn1ber

The failure in this case occurs because the link order is incorrect. Link order in gcc is significant:

A library which calls an external function defined in another library should appear before the library containing the function.

In this case, we would want to link the application as follows:

gcc -o executable -L/opt/asn1c-v613/c -lasn1ber -lasn1rt

It is not uncommon for programs that manage makefiles (like Eclipse, for example) to improperly link our libraries, so one of the first places to look is the makefile generated by the IDE.

Stack Check Failures

A number of our Linux users have written to us about linking failures that look something like this:

undefined reference to `__stack_chk_fail'

Link errors of this sort arise when trying to link an application using a version of gcc that is inconsistent with the one we used to compile our runtime libraries.  In version 4.x, GNU introduced stack smashing protection as a built-in feature of the gcc compiler—this security feature makes runtime libraries compiled with gcc 4 incompatible with gcc 3.

If you use gcc 3.x, you’ll need to link against the appropriate set of runtime libraries to avoid this failure.  All that is needed is to update the symlinks in the c and cpp directories:

ln -sf libgcc3 lib
ln -sf platform.gcc3 platform.mk

ln -sf libgpp3 lib
ln -sf platform.gpp3 platform.mk

All platform-specific compilation rules are kept in the platform.* files; if gcc 3.x is the main compiler on your system, you may not need to relink platform.mk, since this will point to a different executable for gcc.

To test whether the change was sufficient, try relinking the application.

It should also be noted that some distributions of Linux don’t enable stack smashing protection in gcc 4.x (probably because it breaks ABI compatibility with gcc 3):

Currently, SSP is standard in OpenBSD, FreeBSD (since 8.0), Ubuntu (since 6.10), DragonFly BSD and the IPCop Linux distribution. It is also available in NetBSD, Debian and Gentoo, disabled by default.

(From the Wikipedia article.)  If you are using one of these distributions, it should be possible to get a newer version of gcc for these distributions:

Debian Sid comes with stack smashing built in; users of Etch or earlier versions may upgrade if they would like.