Source code instrumentation overview

Source code insertion (SCI) technology uses instrumentation techniques that automatically add specific code to the source files under analysis. After compilation, execution of the code produces dump data for runtime analysis or component testing.

HCL® OneTest Embedded makes extensive use of source code insertion technology to transparently produce test and analysis reports on both native and embedded target platforms.

Instrumentation overhead

Instrumentation overhead is the increase in the binary size or the execution time of the instrumented application, which is due to source code insertion (SCI) generated by the Runtime Analysis features. Source code insertion technology is designed to reduce both types of overhead to a bare minimum. However, this overhead may still impact your application. The following table provides a quick estimate of the overhead generated by the product.
  • Code Coverage Overhead: Overhead generated by the Code Coverage feature depends largely on the coverage types selected for analysis.

    A 48-byte structure is declared at the beginning of the instrumented file. Depending on the information mode selected, each covered branch is referenced by an array that uses
    • 1 byte in Default mode
    • 1 bit in Compact mode
    • 4 bytes in Hit Count mode
    The actual size of this array may be rounded up by the compiler, especially in Compact mode because of the 8-bit minimum integral type found in C . See Information Modes for more information. Other Specifics:
    • Loops, switch and case statements: a 1-byte local variable is declared for each instance.
    • Modified/multiple conditions: one n-byte local array is declared at the beginning of the enclosing routine, where n is the number of conditions belonging to a decision in the routine I/O is either performed at the end of the execution or when the end-user decides (please refer to Coverage Snapshots in the documentation).

    In summary, hit count mode and modified/multiple conditions produce the greatest data and execution time overhead. In most cases you can select each coverage type independently and use pass mode by default in order to reduce this overhead. The source code can also be partially instrumented.

  • Memory and Performance Profiling and Runtime Tracing: Any source file containing an instrumented routine receives a declaration for a 16 byte structure. Within each instrumented routine, a n byte structure is locally declared, where n is 16 bytes +4 bytes for Runtime Tracing, +4 bytes for Memory Profiling, and +3*t bytes for Performance Profiling, where t is the size of the type returned by the clock-retrieving function.

    For example, if t is 4 bytes, each instrumented routine is increased of 20 bytes for Memory Profiling only, 20 bytes for Runtime Tracing only, 28 bytes for Performance Profiling only, or 36 bytes for all Runtime Analysis features together

  • Memory Profiling Overhead: Any call to an allocation function is replaced by a call to the Memory Profiling Library. These calls aim to track allocated blocks of memory. For each memory block, 16+12*n bytes are allocated to contain a reference to it, as well as to contain link references and the call stack observed at allocation time. n depends on the Call Stack Size Setting, which is 6 by default. If ABWL errors are to be detected, the size of each tracked, allocated block is increased by 2*s bytes where s is the Red Zone Size Setting (16 by default). If FFM or FMWL errors are to be detected, a Free Queue is created whose size depends on the Free Queue Length and Free Queue Size Settings. Queue Length is the maximum number of tracked memory blocks in the queue. Queue Size is the maximum number of bytes, which is the sum of the sizes of all tracked blocks in the queue.

  • Performance Profiling Overhead: For any source file containing at least one observed routine, a 24 byte structure is declared at the beginning of the file. The size of the global data storing the profiling results of an instrumented routine is 4+3*t bytes where t is the size of the type returned by the clock retrieving function.

  • Runtime Tracing Overhead: Implicit default constructors, implicit copy constructors and implicit destructors are explicitly declared in any instrumented classes that permits it. Where C++ rules forbid such explicit declarations, a 4 byte class is declared as an attribute at the end of the class.

Instrumentation technology is designed to reduce both performance and memory overhead to a minimum. Nevertheless, for certain cross-platform targets, it may need to be reduced still further. There are three ways to do this.
  • Limiting code coverage types: When using the Code Coverage feature, procedure input and simple and implicit block code coverage are enabled by default. You can reduce instrumentation overhead by limiting the number of coverage types.
    Note: The Code Coverage report can only display coverage types among those selected for instrumentation.
  • Limiting instrumented calls: When calls are instrumented, any instruction that calls a C user function or library function constitutes a branch and thus generates overhead. You can disable call instrumentation on a set of C functions using the Selective Code Coverage Instrumentation Settings. For example, you can usually exclude calls to standard C library functions such as printf or fopen.
  • Optimizing the information mode: When using Code Coverage, you can specify the information mode, which defines how much coverage data is produced and therefore stored in memory.