|M68K Ada Technical Summary: For mission-critical applications on Motorola M68000 family computers|
|Prev||Chapter 5. Performance and Capacity||Next|
The target code performance of M68K Ada is generally very good. The compiler generates code that compares well with other compilers, and which the assembly language programmer would find difficult to beat. See the examples of generated code in Appendix A.
The results of running the three benchmark programs Sieve, Ackermann and Whetstone are given in Table 5-1. These programs were run on a simulated MC68040, with a 25 MHz clock.
Table 5-1. Benchmark Results
|Benchmark||Result at 25 MHz|
Table 5-2 gives timings for several task-related features. The clock frequency is 25 MHz.
Table 5-2. Task-Related Metrics
|Metric||Time in Microseconds|
|Interrupt latency (C.3.1 (15))||tbd|
|From call of trivial protected procedure to return from entry||tbd|
|Call of Clock (D.8 (44))||3|
|Lateness of a delay (D.9 (13))||50|
|Suspend_Until_True, where state is already True||8|
|Set_True to return from Suspend_Until_True||55|
|Trivial protected procedure call (D.12 (6))||6|
M68K Ada uses many traditional optimizations to improve the size and execution speed of the generated code. The following list includes some of the optimizations.
Loop variable induction
Constraint check elimination
Loop invariant hoisting
Load and store elimination
Unreachable code elimination
Tail recursion optimization
The overall level of optimization is controlled by the -O option. The default is optimization level 2. Also many of the optimizations are tied to a further compile-time option and can be enabled or disabled as necessary.
In general, constraint checks are eliminated wherever possible, and constraint check expressions are subject to all the usual optimizations.
Most redundant checks are eliminated. In the example that follows, constraint checks such as those at (1), (2) and (3) are generally eliminated.
I : Integer range -2 .. 2; J : Integer range 0 .. 10; type BT is access T; V : BT; I := 22 mod 3; -- (1) no checks needed at run time I := J; -- (2) check on top limit only V := new T (...); if V.L = ... then -- (3) no null access check -- (4) current variant is correct
In the example shown, the run-time checks performed are as follows:
A check on the top limit only is performed for (2).
A discriminant check is performed for (4).
No space is allocated for scalar variables that are unused. Space for arrays and records is always allocated.
Subprograms that are declared in a package but unused in a program are always loaded if the package is loaded.
Static expressions are always evaluated according to the rules of the Ada 95 Reference Manual Section 4.8. Other compile-time-constant expressions may be evaluated at compile time too.
In most cases code that is unreachable is eliminated.
In the following code example, the address of the element of the array is computed once.
In the following matrix code, the address of the element A(I, J) is computed for the first iteration, then for subsequent iterations the address is incremented by the size of the element.
In general, redundant array bounds checks are eliminated.
The pragma Inline is supported, except where the subroutine mentioned in the pragma is ineligible. Inlining across compilation units may be disabled using a compile-time option.
As an example of the subprogram calling overhead, the code sizes for Ackermann's function are as follows:
Total code size for Ackermann's function = 66 bytes, or 72 bytes with stack overflow check.
Instructions executed per call = 20, or 22 with stack overflow check.
In a rendezvous, the accept statement body is executed by the owning task, never by the calling task. No tasking optimizations are performed but the special case of a null accept statement is handled separately.
For a task 114 bytes are allocated for the task control block. In addition, there are 14 bytes for each task entry. The stack size is either the default size of 4096 bytes, or the value given in the task type's length clause.
The space overhead for a protected object is 25 bytes.
The size of a null program is approximately 2.5K bytes. The size of a minimal program that uses tasking (tasks, protected objects and delay statements) is approximately 7K bytes. These sizes include code, read-only data and variables, but exclude stack space.