!standard 9.6 (00) 03-01-15 AI95-00307/02 !standard D.9 (00) !class amendment 02-08-28 !status work item 02-08-28 !status received 02-08-28 !priority High !difficulty Hard !subject Execution-Time Clocks !summary Modern real-time scheduling policies require that applications have the ability to measure execution time of tasks, and to detect execution time overruns. Two mechanisms were proposed to achieve these requirements. One was based on a library-level package, and the other one was integrated into the Ada 95 language by creating a new Time type that could be used in the languages time constructs such as the delay until statement or various forms of the select statement. Prototype implementations exist for both. After discussion by the ARG it was decided that the package mechanism was preferable, and a few changes were suggested. This document describes the package mechanism only, and includes the changes requested by the ARG. A discussion of these changes can be found at the end of the "Discussion" section. !problem Real-time analysis techniques are always based on the assumption that the application developer can accurately measure the worst-case execution time (WCET) of each task. This measurement is always very difficult, because, with effects like cache misses, pipelined and superscalar processor architectures, etc., the execution time is highly unpredictable. There are models that allow calculation of WCET's for some architectures, but they are generally very complex and not widely available for all architectures. In hard real-time systems it is essential to monitor the execution times of all tasks and detect situations in which the estimated WCET is exceeded. This detection was usually available in systems scheduled with cyclic executives, because the periodic nature of its cycle allowed checking that all initiated work had been completed at each cycle. In event-driven concurrent systems the same capability should be available, and this can be accomplished with execution time clocks and timers. Moreover, many flexible real-time scheduling algorithms require the capability to measure execution time and be able to perform scheduling actions when a certain amount of execution time has been consumed (for example, sporadic servers in fixed priority systems, or the constant bandwidth server in EDF-scheduled systems). Support for execution time clocks and timers would ease implementation of such flexible scheduling algorithms in Ada 95. Ada 95 does not have any support for execution time monitoring and overrun detection. If we want Ada 95 to continue to be the best language in the environment of real-time systems, we need to include this essential functionality into the language. Java is looking to support this feature. !proposal Proposal: Execution time provided as a library package ------------------------------------------------------ A new section D.X is proposed for Annex D: D.X Execution Time ------------------ This clause specifies an execution-time clock package. Static Semantics The following language-defined library package exists: with Ada.Task_Identification; package Ada.Real_Time.Execution_Time is type CPU_Time is private; CPU_Time_First : constant CPU_Time; CPU_Time_Last : constant CPU_Time; CPU_Time_Unit : constant := implementation-defined-real-number; CPU_Tick : constant Time_Span; function Clock (T : Ada.Task_Identification.Task_ID := Ada.Task_Identification.Current_Task) return CPU_Time; function "+" (Left : CPU_Time; Right : Time_Span) return CPU_Time; function "+" (Left : Time_Span; Right : CPU_Time) return CPU_Time; function "-" (Left : CPU_Time; Right : Time_Span) return CPU_Time; function "-" (Left : CPU_Time; Right : CPU_Time) return Time_Span; function "<" (Left, Right : CPU_Time) return Boolean; function "<=" (Left, Right : CPU_Time) return Boolean; function ">" (Left, Right : CPU_Time) return Boolean; function ">=" (Left, Right : CPU_Time) return Boolean; procedure Split (T : CPU_Time; SC : out Seconds_Count; TS : out Time_Span); function Time_Of (SC : Seconds_Count; TS : Time_Span) return CPU_Time; protected type Timer (T : access Ada.Task_Identification.Task_ID) is procedure Arm (Interval : Time_Span); procedure Arm (Abs_Time : CPU_Time); procedure Disarm; entry Time_Exceeded; function Time_Was_Exceeded return Boolean; function Time_Remaining return Time_Span; private ... -- not specified by the language end Timer; Time_Error : exception; -- may be raised by Timer.Time_Exceeded, Timer.Time_Was_exceeded, -- and Timer.Time_Remaining private ... -- not specified by the language end Ada.Real_Time.Execution_Time; In this Annex, execution time or cpu time of a given task is defined as the time spent by the system executing that task, including the time spent executing run-time or system services on behalf of it. The mechanism used to measure execution time is implementation defined. The implementation shall also define to whom will be charged the execution time that is consumed by interrupt handlers and run-time services on behalf of the system. The type CPU_Time represents the execution time of a task. The set of the type CPU_Time corresponds one-to-one with an implementation-defined range of mathematical integers. The CPU_Time value I represents the half-open execution-time interval that starts with I*CPU_Time_Unit and is limited by (I+1)*CPU_Time_Unit, where CPU_Time_Unit is an implementation-defined real number. For each task, the execution time value is set to zero at some unspecified point between the task creation and the end of the task's activation. CPU_Time_First and CPU_Time_Last are the smallest and largest values of the Time type, respectively. CPU_Time_Unit is the smallest amount of execution time representable by the CPU_Time type; it is expressed in seconds. A CPU clock tick is an execution time interval during which the clock value (as observed by calling the Clock function) remains constant. CPU_Tick is the average length of such intervals. The effects of the operators on Time and Time_Span are as for the operators defined for integer values. The function Clock returns the amount of execution time of the task associated with the execution-time clock of the task represented by T. The effects of the Split and Time_Of operations are defined as follows, treating values of type CPU_Time, Time_Span, and Seconds_Count as mathematical integers. The effect of Split (T, SC, TS) is to set SC and TS to values such that T*CPU_Time_Unit = SC*1.0 + TS*CPU_Time_Unit, and 0.0 <= TS*CPU_Time_Unit < 1.0. The value returned by Time_Of(SC,TS) is the execution-time value T such that T*CPU_Time_Unit=SC*1.0 + TS*CPU_Time_Unit. Package Execution_Time contains a protected object type called Timer, which represents a software object that is capable of detecting execution time overruns. Each timer is attached to a specific execution time clock, which is the clock of the task specified by the access discriminant T. This protected object type has visible operations for the application tasks to arm or disarm a timer, and to determine whether a timer has expired or not (Time_Was_Exceeded). In addition, Timer has an entry (Time_Exceeded) that can be used by application tasks to block until an execution time overrun is detected, or as an event that triggers the abortion of the instructions of a select statement with an abortable part. When a Timer is created, the resources required to operate a CPU-time timer based on the associated execution-time clock shall be allocated and initialized. If this operation would exceed the limit of the maximum number of timers in the system, the Storage_Error exception is raised. The timer is initialized in the disarmed state. When a Timer is destroyed, the system resources used by the timer shall be deallocated. The Timer.Arm protected procedure that takes a Time_Span parameter loads the associated timer with the relative value specified by Interval and sets it to the armed state. In this state the timer counts execution time and, when the CPU clock associated with the timer measures the passage of Interval, it is said to have expired. If the timer was already armed, it is rearmed. The Timer.Arm protected procedure that takes a CPU_Time parameter loads the associated timer with the absolute value specified by Abs_Time and sets it to the armed state. In this state the timer counts execution time and, when the CPU clock associated with the timer reaches the value Abs_Time, it is said to have expired. If the value of Abs_Time had already been reached by the clock at the time of the call, the timer is set to the armed state and is said to have expired. If the timer was already armed, it is rearmed. The Timer.Disarm protected procedure sets the timer to the disarmed state. In this state no timer expirations occur. The Timer.Time_Exceeded protected entry suspends the calling task if the timer is in the armed state but has not yet expired. The entry is allowed to complete when the timer is in the armed state and has expired. If the timer is in the disarmed state, the Time_Error exception is raised. The Timer.Time_Was_Exceeded protected function returns True if the timer is in the armed state and has expired, and returns False if the timer is in the armed state but has not yet expired. If the timer is in the disarmed state, the Time_Error exception is raised. The Timer.Time_Remaining protected function returns, when the timer is in the armed state, the CPU time interval that remains until the timer will expire, or a value representing zero if the timer has expired. If the timer is in the disarmed state, the Time_Error exception is raised. The Time_Error exception is raised by Timer.Time_Exceeded, Timer.Time_Was_Exceeded, or Timer.Time_Remaining if an attempt is made to use a timer that is in the disarmed state. Implementation Requirements The range of CPU_Time values shall be sufficient to uniquely represent the range of execution times from the task start-up to 50 years of execution time later. CPU_Tick shall be no greater than 1 millisecond. Documentation Requirements The implementation shall document the values of CPU_Time_First, CPU_Time_Last, CPU_Time_Unit, and CPU_Tick. The implementation shall document the properties of the underlying mechanism used to measure execution times, such as the range of values supported and any relevant aspects of the underlying hardware or operating system facilities used. Metrics The implementation shall document the following metrics: - An upper bound on the execution-time duration of a clock tick. This is a value D such that if t1 and t2 are any execution times of a given task such that t1