Version 1.9 of ai05s/ai05-0170-1.txt
!standard D.14(9/2) 10-10-20 AI05-0170-1/06
!standard D.14(11/2)
!standard D.14(13/2)
!standard D.14(18/2)
!standard D.14.3(0)
!class Amendment 09-10-22
!status Amendment 2012 10-08-09
!status WG9 Approved 10-10-28
!status ARG Approved 10-0-0 10-06-18
!status work item 09-10-22
!status received 09-10-22
!priority Medium
!difficulty Easy
!subject Monitoring the time spent in Interrupt Handlers
!summary
Facilities are added to enable the time spent in interrupt handlers to be
accounted for separately from time spent in tasks.
!problem
Ada 2005 defines execution-time clocks to monitor execution times and
execution-time timers and group budgets to trigger actions when the
execution time of a task or a task group reaches a specific
value. This functionality is very useful to detect timing violations
as well as to implement advanced scheduling policies such as those
making resource reservations.
The Ada standard leaves as "implementation defined" the way in which
the execution time of interrupt handlers is accounted for:
"It is implementation defined which task, if any, is charged the
execution time that is consumed by interrupt handlers and run-time
services on behalf of the system." (RM D.14 (11/2))
A common and simple implementation will charge the time consumed by
the interrupt handlers to the task executing when the interrupt is
generated. This is done under the assumption that the effect of
interrupt handlers on the execution time clocks is negligible since
the interrupt handlers are usually very sort pieces of code. However,
in real-time systems that undertake an intensive use of interrupts this
assumption may not be realistic. For example, Ada 2005 introduced
timed events that can execute handlers in interrupt context. The
facility is convenient and has low overheads, and therefore
programmers are tempted to put more code into these handlers.
As is shown in two papers at the 14th IRTAW it is possible with moderate
effort to monitor and manage the execution time of interrupt handlers
separately from the execution time of the tasks. With this modification
Execution Time Clocks provide a more realistic value of the time a
task has executed and, what is more important, execution time overruns
detected using Execution Time Timers and Group Execution Time Budgets
are more accurate. Therefore, the proposal rewords the definition of
execution time to make it clear that the execution time of interrupts
can be accounted for separately.
If execution time of interrupts is monitored separately from that of
the tasks, it is easy to make the accounting of these execution times
available to the application. This information is useful to real-time
analysis; therefore this proposal adds facilities to allow the
application to obtain the execution time of interrupts.
!proposal
(See wording.)
!wording
Add to package Ada.Execution_Time after D.14(9/2):
Interrupt_Clocks_Supported : constant Boolean := <implementation-defined>;
Separate_Interrupt_Clocks_Supported : constant Boolean :=
<implementation-defined>;
function Clock_For_Interrupts return CPU_Time;
Replace D.14(11/2) with:
The 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 its behalf. The mechanism used to measure execution time
is implementation defined. The Boolean constant Interrupt_Clocks_Supported is
set to True if the implementation separately accounts for the execution time
of interrupt handlers. If it is set to False it is implementation defined which
task, if any, is charged the execution time that is consumed by interrupt
handlers. The Boolean constant Separate_Interrupt_Clocks_Supported is set to
True if the implementation separately accounts for the execution time of
individual interrupt handlers.
Add to end of D.14(13/2):
The execution time value for the function Clock_For_Interrupts is initialized
to zero.
Add to after D.14(18/2):
The function Clock_For_Interrupts returns the total cumulative time spent
executing within all interrupt handlers. This time is not allocated to any
task execution time clock. If Interrupt_Clocks_Supported is set to False
the function raises Program_Error.
Add a new D.14.3
Execution Time of Interrupt Handlers
This clause describes a language-defined package to measure the execution
time of interrupt handlers.
Static Semantics
The following language-defined library package exists:
with Ada.Interrupts;
package Ada.Execution_Time.Interrupts is
function Clock (Interrupt : Ada.Interrupts.Interrupt_Id)
return CPU_Time;
function Supported (Interrupt : Ada.Interrupts.Interrupt_Id)
return Boolean;
end Ada.Execution_Time.Interrupts;
The execution time or CPU time of a given interrupt Interrupt is defined as the
time spent by the system executing interrupt handlers identified by Interrupt,
including the time spent executing run-time or system services on its behalf.
The mechanism used to measure execution time is implementation defined. Time
spent executing interrupt handlers is distinct from time spent executing any
task.
For each interrupt, the execution time value is initially set to zero.
Dynamic Semantics
The function Clock returns the current cumulative execution time of the
interrupt identified by Interrupt. If Separate_Interrupt_Clocks_Supported is
set to False the function raises Program_Error.
The function Supported returns True if the implementation is monitoring the
execution time of the interrupt identified by Interrupt. Otherwise it returns
False. For any interrupt_Id Interrupt for which Supported(Interrupt) returns
False, the function Clock(Interrupt) will return a value equal to
Ada.Execution_Time.Time_Of(0).
!discussion
This AI allows the measurement of the execution time of interrupt handlers
separately from the execution time of user tasks. Doing so can
significantly enhance the accuracy of the execution time clocks and
timers of user tasks, because they are not arbitrarily charged with
the execution times of interrupt service handlers.
Allowing separate measurement of the execution time of interrupt handlers
does not require the addition of any new API. However, once the interrupt
execution time is measured, it ought to be made available to Ada applications,
so new facilities are needed for that purpose.
Since all this functionality may not be available on all platforms,
we also provide the ability to test whether it is present.
In [1] and [2] the overheads incurred by the implementation of these
new services have been measured, and found that they are very low in
comparison with the execution times of common interrupt
handlers.
Regarding the proposed API, it would be possible to define a Task_Id
for pseudo tasks representing interrupt handlers, but this would
create conflicts because they are not normal Ada tasks. Services
such as Set_Priority would need to treat them as a special case,
adding the need for new checks in potentially many places.
We believe that using Interrupt_Id for identifying the execution time
clocks is compatible with the proposed approach for attaching
interrupts to a specific processor in multiprocessor systems. It seems
that using pseudo-task IDs instead would require defining these for
each processor, which would add complexity to the API.
The new package is always present (even though its operations may
just raise Program_Error), in order that programs can be written that
depend on its services if the Separate_Interrupt_Clocks_Supported
value is True, and falls back to some other technique if it is not
supported. Such a program will need to with the new package, and
that requires it exists even if it is not usefully implemented.
The third part of the original proposal (to allow notification of
execution time overruns in interrupt handlers) was dropped, as it
seems to add overhead to interrupt handlers even when not used.
The original IRTAW Proposal follows:
This proposal contains three parts, listed in order
of importance. Each one is based on the previous one and adds new
services that are useful to real-time applications.
Part 1. Accounting of execution time of interrupts
--------------------------------------------------
Add the following "Implementation Advice" in RM D.14, "Execution Time"
When appropriate, the execution time consumed by interrupt handlers
and run-time services on behalf of the system should not be charged
to the execution time of application tasks.
Part 2. Interrupt execution time clocks
---------------------------------------
Add the following implementation advice in RM D.14, "Execution Time"
If the execution time consumed by interrupt handlers is accounted
for separately from the execution time of application tasks, the
time consumed should be made available to the application by means
of the following language-defined package:
with Ada.Interrupts;
package Ada.Execution_Time.Interrupts is
function Clock
(I : Ada.Interrupts.Interrupt_ID)
return CPU_Time;
private
. . .
end Ada.Execution_Time.Interrupts;
The Ada.Execution_Time.Interrupts package defines one
execution-time clock for each Interrupt_ID. The Clock function
returns the execution time spent by interrupt handlers while
handling the interrupt specified by I.
Part 3. Interrupt execution time timers
---------------------------------------
Add the following implementation advice in RM D.14.1, "Execution Time
Timers":
If the execution time consumed by interrupt handlers is accounted
for separately from the execution time of application tasks, and if
package Ada.Execution_Time.Interrupts is implemented, execution
time timers based on the execution time of interrupt handlers
should be made available to the application by means of the
following language-defined package:
with Ada.Interrupts;
package Ada.Execution_Time.Timers.Interrupts is
type Timer ( I : Ada.Interrupts.Interrupt_ID)
is new Ada.Execution_Time.Timers.Timer
(Ada.Task_Identification.Null_Task_Id'access )
with private;
private
. . .
end Ada.Execution_Time.Timers.Interrupts;
The Ada.Execution_Time.Timers.Interrupts defines execution time
timers based on the execution-time clocks defined in package
Ada.Execution_Time.Interrupts.
The Timer type extends the Timer type defined in the Timers
package and inherits and/or overrides all of its primitive
operations, including the ability to set handlers that will be
executed if the execution-time clock associated with the interrupt
identified by I reaches a specific value or consumes a specified
interval.
The Set_Handler procedures have the same effect as for regular
execution time timers except that their expiration is associated
with the execution time of the interrupt handlers that are
handling the interrupt identified by I.
Note that according to the scheduling rules for interrupts, the
handler of an interrupt execution-time timer may not be able to
execute until the interrupt handler that triggers it (and possibly
other interrupt handlers) has completed its own execution.
Implementation Permissions: Implementations may limit the number
of timers that can be defined for each interrupt Id. If this limit is
exceeded then Timer_Resource_Error is raised.
Note: This proposal uses constant Null_Task_Id as the Task_ID
discriminant, since a task Id is not needed for interrupt execution
time timers. This would require making the Null_Task_Id constant
"aliased" in the Ada.Task_Identification package.
References
----------
[1] Kristoffer Nyborg Gregertsen, Amund Skavhaug "Execution-time
control for interrupt handling". 14th International Real-Time Ada
Workshop, Portovenere, Italy, October 2009.
[2] Mario Aldea Rivas and Michael Gonzalez Harbour "Execution time
monitoring and interrupt handlers". 14th International Real-Time Ada
Workshop, Portovenere, Italy, October 2009.
!example
!corrigendum D.14(9/2)
Insert after the paragraph:
function Time_Of (SC : Seconds_Count;
TS : Time_Span := Time_Span_Zero) return CPU_Time;
the new paragraphs:
Interrupt_Clocks_Supported : constant Boolean := implementation-defined;
Separate_Interrupt_Clocks_Supported : constant Boolean :=
implementation-defined;
function Clock_For_Interrupts return CPU_Time;
!corrigendum D.14(11/2)
Replace the paragraph:
The 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 its behalf. The mechanism used to measure execution time is
implementation defined. It is implementation defined which task, if any, is
charged the execution time that is consumed by interrupt handlers and run-time
services on behalf of the system.
by:
The 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 its behalf. The mechanism used to measure execution time
is implementation defined. The Boolean constant Interrupt_Clocks_Supported is
set to True if the implementation separately accounts for the execution time
of interrupt handlers. If it is set to False it is implementation defined which
task, if any, is charged the execution time that is consumed by interrupt
handlers. The Boolean constant Separate_Interrupt_Clocks_Supported is set to
True if the implementation separately accounts for the execution time of
individual interrupt handlers.
!corrigendum D.14(13/2)
Insert after the paragraph:
CPU_Time_First and CPU_Time_Last are the smallest
and largest values of the CPU_Time type, respectively.
the new paragraph:
The execution time value for the function Clock_For_Interrupts is initialized
to zero.
!corrigendum D.14(18/2)
Insert after the paragraph:
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.
the new paragraph:
The function Clock_For_Interrupts returns the total cumulative time spent
executing within all interrupt handlers. This time is not allocated to any
task execution time clock. If Interrupt_Clocks_Supported is set to False
the function raises Program_Error.
!corrigendum D.14.3
Insert new clause:
This clause describes a language-defined package to measure the execution
time of interrupt handlers.
Static Semantics
The following language-defined library package exists:
with Ada.Interrupts;
package Ada.Execution_Time.Interrupts is
function Clock (Interrupt : Ada.Interrupts.Interrupt_Id)
return CPU_Time;
function Supported (Interrupt : Ada.Interrupts.Interrupt_Id)
return Boolean;
end Ada.Execution_Time.Interrupts;
The execution time or CPU time of a given interrupt Interrupt is defined as the
time spent by the system executing interrupt handlers identified by Interrupt,
including the time spent executing run-time or system services on its behalf.
The mechanism used to measure execution time is implementation defined. Time
spent executing interrupt handlers is distinct from time spent executing any
task.
For each interrupt, the execution time value is initially set to zero.
Dynamic Semantics
The function Clock returns the current cumulative execution time of the
interrupt identified by Interrupt. If Separate_Interrupt_Clocks_Supported is
set to False the function raises Program_Error.
The function Supported returns True if the implementation is monitoring the
execution time of the interrupt identified by Interrupt. Otherwise it returns
False. For any interrupt_Id Interrupt for which Supported(Interrupt) returns
False, the function Clock(Interrupt) will return a value equal to
Ada.Execution_Time.Time_Of(0).
!ACATS test
Add an ACATS C-Test of this package.
!appendix
From: Randy Brukardt
Sent: Tuesday, October 19, 2010 7:06 PM
Brad Moore sent an editorial comment on AI05-0170-1:
>!wording and !corrigendum sections:
>
>Replace the "I" of "Ada.Interrupts.Interrupt_ID" with "Interrupt" to be
>consistent with the rest on the RM (such as C.3.2)
I tend to agree with this comment, but as it is a significant amount of work to change ("I" appears throughout the wording of this AI, and I'll also have to update the RM draft, and of course search and replace won't do any good for "I"), I wanted to check
if there were any objections before proceeding with the change. If there are any, I'll put the AI on the agenda for Fairfax, and we can decide what to do then.
****************************************************************
From: Alan Burns
Sent: Wednesday, October 20, 2010 3:02 AM
I feel
Interrupt : Ada.Interrupts.Interrupt_ID
has just too many interrupts - my vote would be to keep it as I
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 20, 2010 6:43 AM
I would change to Interrupt. I personally dislike ANY use of the identifier I (we don't allow it in our style guidelines), because depending on the font, it can be far to close to the digit 1.
Of course one of the extra Interrupts comes from the entirely unnecessary qualification. A name like Interrupt_Id is designed IMO to be used with use clauses. You want either
Interrupts.ID
if you are not going to use USE clauses, or
Interrupt_ID
if you are going to use USE clauses.
Interrupt.Interrupt_Id is plain annoying in itself
****************************************************************
From: Bob Duff
Sent: Wednesday, October 20, 2010 8:14 AM
> I feel
>
> Interrupt : Ada.Interrupts.Interrupt_ID
>
> has just too many interrupts - my vote would be to keep it as I
Alan was about to type " eschew redundancy.", but he was Interrupted by martians who snatched him from the keyboard in midsenten
****************************************************************
From: Randy Brukardt
Sent: Wednesday, October 20, 2010 1:08 PM
...
> I would change to Interrupt. I personally dislike ANY use of the
> identifier I (we don't allow it in our style guidelines), because
> depending on the font, it can be far to close to the digit 1.
Our guidelines only allow I to be used as a for loop index. Since I started programming in FORTRAN, I get uncomfortable with loop indexes that aren't "I", then "J", then "K". :-) But in other circumstances, I agree with Robert.
After all, one of the important uses of parameter names is in calls. Which would you rather see in code:
Clock (I => Overflow);
or
Clock (Interrupt => Overflow);
???
> Of course one of the extra Interrupts comes from the entirely
> unnecessary qualification. A name like Interrupt_Id is designed IMO to
> be used with use clauses. You want either
>
> Interrupts.ID
>
> if you are not going to use USE clauses, or
>
> Interrupt_ID
>
> if you are going to use USE clauses.
>
> Interrupt.Interrupt_Id is plain annoying in itself
Ada library packages almost never use "use" clauses, but generally they are designed so it doesn't matter. (Either the declarations are local or they are in parents.) In this case, there are only two uses, so it probably would be more confusing than helpfu
l to use a "use" clause.
As to the general problem of naming, it's unfortunate that it is so hard to find good names that work both ways. When you are building a general purpose library, you really don't want to be making that decision for clients. We struggled with this with Claw
, and there are places where we ended up with some redundancy (mostly for the type declarations) because the alternative was names that couldn't be meaningfully used with use clauses. (Just because I don't like or use use clauses much doesn't mean I want t
o make it hard for those who do.)
P.S. What to do here?? So far, we have 3 votes to change to Interrupt and one to stay as I. Please weight in if you care at all (else this will have to go back to the ARG to make a decision).
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 20, 2010 1:54 PM
> Our guidelines only allow I to be used as a for loop index. Since I
> started programming in FORTRAN, I get uncomfortable with loop indexes
> that aren't "I", then "J", then "K". :-) But in other circumstances,
> I agree with Robert.
I start at J, and Fortran allows you to go further than K if you have to :-)
****************************************************************
From: Bob Duff
Sent: Wednesday, October 20, 2010 1:20 PM
> ...Please weight in if you care at all (else this will have to go back
> to the ARG to make a decision).
I slightly prefer Interrupt.
I'd prefer you flip a coin, over having a big discussion at an ARG meeting. ;-)
****************************************************************
From: Gary Dismukes
Sent: Wednesday, October 20, 2010 1:40 PM
> After all, one of the important uses of parameter names is in calls.
> Which would you rather see in code:
>
> Clock (I => Overflow);
>
> or
>
>
> Clock (Interrupt => Overflow);
>
> ???
I definitely prefer the latter.
> P.S. What to do here?? So far, we have 3 votes to change to Interrupt
> and one to stay as I. Please weight in if you care at all (else this
> will have to go back to the ARG to make a decision).
I vote for changing to Interrupt.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 20, 2010 1:56 PM
Well we have 4-1 vote for interrupt, which I would say is decisive unless there is a last minute groundswell of s support for I :)
****************************************************************
From: Edmond Schonberg
Sent: Wednesday, October 20, 2010 2:00 PM
> ...Please weight in if you care at all (else this will have to go back
> to the ARG to make a decision).
Ban the I, go with Interrupt.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 20, 2010 2:03 PM
sounds like an executive decision from the chair to me :-)
****************************************************************
From: Steve Baird
Sent: Wednesday, October 20, 2010 2:08 PM
> Ban the I, go with Interrupt.
Agreed.
****************************************************************
From: Jean-Pierre Rosen
Sent: Wednesday, October 20, 2010 3:51 PM
Count me for Interrupt too. I think that named notation in calls is the strongest argument.
****************************************************************
From: Erhard Ploedereder
Sent: Wednesday, October 20, 2010 5:09 PM
Count me for "Interrupt".
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 20, 2010 5:36 PM
I think we can count this as decided!
****************************************************************
From: Randy Brukardt
Sent: Wednesday, October 20, 2010 6:02 PM
I agree. Consider this issue closed; I'll update the AI and draft RM accordingly
and send the AI on to WG 9.
****************************************************************
From: Alan Burns
Sent: Thursday, October 21, 2010 2:24 AM
By AI assume you mean Ada_Issue!
Are you sure you do not want: Interrupt_From_An_External_Hardware_Device
to be sure people understand!!
PS no replies please
****************************************************************
Questions? Ask the ACAA Technical Agent