M1750 Ada Technical Summary: For mission-critical applications | ||
---|---|---|
Prev | Chapter 5. Performance and Capacity | Next |
The target code performance of M1750 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 the simulator, with a 10 MHz generic 1750A. [1]
Table 5-1. Benchmark Results
Benchmark | Basic memory | Expanded memory |
---|---|---|
Ackermann | 948 mSec | 1913 mSec |
Sieve | 483 mSec | 483 mSec |
Whetstone | 2862 KWIPS | 2064 KWIPS |
Table 5-2 gives timings for several task-related features. The clock frequency is 10 MHz.
Table 5-2. Task-Related Metrics
Metric | Clock Cycles | Time in Microseconds at 10 MHz |
---|---|---|
Interrupt latency (C.3.1 (15)) | 1500 | 150 |
From call of trivial protected procedure to return from entry | 1500 | 150 |
Call of Clock (D.8 (44)) | 170 | 17 |
Lateness of a delay (D.9 (13)) | 2000 | 200 |
Suspend_Until_True, where state is already True | 800 | 80 |
Set_True to return from Suspend_Until_True | 1900 | 190 |
Trivial protected procedure call (D.12 (6)) | 820 | 82 |
M1750 Ada uses many traditional optimizations to improve the size and execution speed of the generated code. The following list includes some of the optimizations.
Sub-expression commoning
Loop unrolling
Loop variable induction
Strength reduction
Constraint check elimination
Loop invariant hoisting
Load and store elimination
Register allocation
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 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.
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 = 60 bytes
Instructions executed per call = 14
Stack overflow checking adds 7 instructions to the size of the generated code.
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 74 bytes are allocated for the task control block. In addition, there are 6 bytes for each task entry. The stack size is either the default size of 1024 bytes, or the value given in the task type's length clause.
The space overhead for a protected object is 14 bytes.
The size of a null program is approximately 1548 bytes. The size of a minimal program that uses tasking (tasks, protected objects and delay statements) is approximately 4K bytes. These sizes include code, read-only data and variables, but exclude stack space.
[1] | The generic 1750A runs with one clock cycle per instruction plus one clock cycle per memory access. |