(90) Values of all Metrics.
OC Systems does not provide the "values" of any metrics here. Given the nature of the platform that our compiler and runtime is targetted at any values would be completly useles. Consider that:
- The hardware comes in three major archetetures:
- Power - Older RS/6000
- PowerPC - Newer RS/6000, embedded, etc.
- Power2 - SP type servers
- Many of the target machines are Semmetric Multi-Processors with between 2 and 8 processors.
- There are a wide varity of cache schemes used. L1 and L2 cache sizes very widely across the product line and have a significat affect on program performance.
- Most PowerPC processors are super-scalar meaning that they execute instructions in parallel.
Thus a given execution of a single instruction can take from 0 clock cycles ( it overlapped with other instructions) to 10's of cycles (it was in main memory and had to wait for data from a previous instruction), to 100's of cycles (the page of code was swapped out to disk).
What we do provide in this section is an overview of the processing steps invloved with each of the operations for which metrics are specified.
C.3.1:15 - The following metric shall be documented by the implementation:
The worst case overhead for an interrupt handler that is a parameterless protected procedure, in clock cycles. This is the execution time not directly attributable to the handler procedure or the interrupted execution. It is estimated as C - (A+B), where A is how long it takes to complete a given sequence of instructions without any interrupt, B is how long it takes to complete a normal call to a given protected procedure, and C is how long it takes to complete the same sequence of instructions when it is interrupted by one execution of the same procedure called via an interrupt.
Signal handling on AIX Version 4.3.0 is not Posix. When a thread registers for a signal the given signal may be delivered to any thread in the process. The PowerAda runtime performs the following actions:
- When the main program is elaborated a separate "interrupt thread" is created. The interrupt thread waits on a sigwait call.
- When a signal occurs the receiving thread checks to see if it is the interrupt thread. If it is it records the signal and returns, if it is not the interrupt thread it forwards the signal to the interrupt thread and returns.
- The interrupt thread (which is running at system.interrupt_priority'last) returns from it's sigwait call and either calls the task entry that registered for the signal or calls the protected object procedure that was registered for the signal.
C.7.2:20 - The implementation shall document the following metrics:
A task calling the following subprograms shall execute in a sufficiently high priority as to not be preempted during the measurement period. This period shall start just before issuing the call and end just after the call completes. If the attributes of task T are accessed by the measurement tests, no other task shall access attributes of that task during the measurement period. For all measurements described here, the Attribute type shall be a scalar whose size is equal to the size of the predefined integer size. For each measurement, two cases shall be documented: one where the accessed attributes are of the calling task (that is, the default value for the T parameter is used), and the other, where T identifies another, non-terminated, task.
The following calls (to subprograms in the Task_Attributes package) shall be measured:
- a call to Value, where the return value is Initial_Value;
- a call to Value, where the return value is not equal to Initial_Value;
- a call to Reference, where the return value designates a value equal to Initial_Value;
- a call to Reference, where the return value designates a value not equal to Initial_Value;
- a call to Set_Value where the Val parameter is not equal to Initial_Value and the old attribute value is equal to Initial_Value.
- a call to Set_Value where the Val parameter is not equal to Initial_Value and the old attribute value is not equal to Initial_Value.
The Task_Attributes package is implemented as follows:
Each task has a pointer to an attribute_array in its TCB. This pointer is initialized to NULL when the task is created. The first time an attribute is set for a given task the attribute_array is allocated. The task is also added to a list of tasks with attribute_arrays.
The attributes themselves are allocated from the heap (thus any finalization can be called automatically when they are deallocated).
D.5:13 - The implementation shall document the following metric:
The execution time of a call to Set_Priority, for the nonpreempting case, in processor clock cycles. This is measured for a call that modifies the priority of a ready task that is not running (which cannot be the calling one), where the new base priority of the affected task is lower than the active priority of the calling task, and the affected task is not on any entry queue and is not executing a protected operation.
Calls to set the priority of a task call the AIX routine: Pthread_Setschedparam
D.6:4 - The implementation shall document the following metrics:
- The execution time, in processor clock cycles, that it takes for an abort_statement to cause the completion of the aborted task. This is measured in a situation where a task T2 preempts task T1 and aborts T1. T1 does not have any finalization code. T2 shall verify that T1 has terminated, by means of the Terminated attribute.
- On a multiprocessor, an upper bound in seconds, on the time that the completion of an aborted task can be delayed beyond the point that it is required for a single processor.
- An upper bound on the execution time of an asynchronous_select, in processor clock cycles. This is measured between a point immediately before a task T1 executes a protected operation Pr.Set that makes the condition of an entry_barrier Pr.Wait true, and the point where task T2 resumes execution immediately after an entry call to Pr.Wait in an asynchronous_select. T1 preempts T2 while T2 is executing the abortable part, and then blocks itself so that T2 can execute. The execution time of T1 is measured separately, and subtracted.
- An upper bound on the execution time of an asynchronous_select, in the case that no asynchronous transfer of control takes place. This is measured between a point immediately before a task executes the asynchronous_select with a nonnull abortable part, and the point where the task continues execution immediately after it. The execution time of the abortable part is subtracted.
In some cases the PowerAda runtime must send a signal to a thread in order to cause it to abort. The delivery of this signal is entirely dependant on how AIX chooses to perform signal delivery. See the AIX documentation for more information.
D.8:37 - For the purpose of the metrics defined in this clause, real time is defined to be the International Atomic Time (TAI).
The implementation shall document the following metrics:
- An upper bound on the real-time duration of a clock tick. This is a value D such that if t1 and t2 are any real times such that t1 < t2 and Clock[t1] = Clock[t2] then t2 - t1 <= D.
RESPONSE: On current versions of AIX D=0.000001 seconds (1 microsecond).
- An upper bound on the size of a clock jump.
RESPONSE: This is entirely system dependant. Please see the discussion of the timed demon in your AIX documentation.
- An upper bound on the drift rate of Clock with respect to real time. This is a real number D such that
E*(1-D) <= (Clock[t+E] - Clock[t]) <= E*(1+D)
provided that: Clock[t] + E*(1+D) <= Time_Last.
where Clock[t] is the value of Clock at time t, and E is a real time duration not less than 24 hours. The value of E used for this metric shall be reported.
RESPONSE: This is entirely system dependant. Please see the discussion of
the timed demon in your AIX documentation.
- An upper bound on the execution time of a call to the Clock function, in processor clock cycles.
RESPONSE: The PowerAda runtime uses the AIX Gettimeofday call when the Clock function is called.
- Upper bounds on the execution times of the operators of the types Time and Time_Span, in processor clock cycles.
RESPONSE: These types are implemented in terms of a record with two 32 bit fields (Seconds since 1970 and nanoseconds). The operations on these types are very fast. Conversions to type duration go through a floating point temporary and thus are a bit slower.
D.9:9 -The implementation shall document the following metrics:
- An upper bound on the execution time, in processor clock cycles, of a delay_relative_statement whose requested value of the delay expression is less than or equal to zero.
- An upper bound on the execution time, in processor clock cycles, of a delay_until_statement whose requested value of the delay expression is less than or equal to the value of Real_Time.Clock at the time of executing the statement. Similarly, for Calendar.Clock.
- An upper bound on the lateness of a delay_relative_statement, for a positive value of the delay expression, in a situation where the task has sufficient priority to preempt the processor as soon as it becomes ready, and does not need to wait for any other execution resources. The upper bound is expressed as a function of the value of the delay expression. The lateness is obtained by subtracting the value of the delay expression from the actual duration. The actual duration is measured from a point immediately before a task executes the delay_statement to a point immediately after the task resumes execution following this statement.
- An upper bound on the lateness of a delay_until_statement, in a situation where the value of the requested expiration time is after the time the task begins executing the statement, the task has sufficient priority to preempt the processor as soon as it becomes ready, and it does not need to wait for any other execution resources. The upper bound is expressed as a function of the difference between the requested expiration time and the clock value at the time the statement begins execution. The lateness of a delay_until_statement is obtained by subtracting the requested expiration time from the real time that the task resumes execution following this statement.
For situations where a zero delay amount is called for the PowerAda runtime calls the AIX routine Pthread_Yield. All positive non-zero length delays are done with the AIX routine Ptherad_Cond_Timedwait.
D.12:6 - The implementation shall document the following metric:
- The overhead associated with obtaining a mutual-exclusive access to an entry-less protected object. This shall be measured in the following way:
For a protected object of the form:
protected Lock is procedure Set; function Read return Boolean; private Flag : Boolean := False; end Lock; protected body Lock is procedure Set is begin Flag := True; end Set; function Read return Boolean Begin return Flag; end Read; end Lock;
The execution time, in processor clock cycles, of a call to Set. This shall be measured between the point just before issuing the call, and the point just after the call completes. The function Read shall be called later to verify that Set was indeed called (and not optimized away). The calling task shall have sufficiently high priority as to not be preempted during the measurement period. The protected object shall have sufficiently high ceiling priority to allow the task to call Set.
For a multiprocessor, if supported, the metric shall be reported for the case where no contention (on the execution resource) exists from tasks executing on other processors.
The PowerAda runtime uses AIX (POSIX) mutexes to guard protected objects. The above situation would involve two calls to Pthread_Mutex_Lock and two calls to Pthread_Mutex_Unlock.