Version 1.7 of ai05s/ai05-0171-1.txt
!standard D.13.1(4/2) 10-10-15 AI05-0171-1/06
!standard D.16
!class Amendment 09-10-22
!status Amendment 2012 10-08-12
!status ARG Approved 8-0-2 10-06-18
!status work item 09-10-22
!status received 09-10-22
!priority Medium
!difficulty Easy
!subject Pragma CPU and Ravenscar Profile
!summary
The Ravenscar Profile, originally designed for single processors, has
proven remarkably useful for modelling verifiable real-time
single-processor systems. It is extended to support
multiprocessor systems using a fully partitioned approach. The
implementation of this scheme is simple, and it can be used to develop
applications amenable to schedulability analysis.
To specify the required Ravenscar behaviour on a multiprocessor
platform requires the definition of a pragma that will statically
set the affinity of a task. This pragma has utility outside its
use with the Ravenscar profile.
!problem
The Ravenscar Profile defines a deterministic and analysable tasking
model for single processors which can be supported with a run-time
system of reduced size and complexity. For multiprocessor systems,
the Ravenscar Profile could be extended using a fully partitioned
approach, with each task allocated statically to a physical processor.
This scheme could be supported by a streamlined run-time system, and
applications built following this approach can apply timing analysis
techniques on each processor separately.
!proposal
We propose to allow the implementation of the Ravenscar Profile on
multiprocessor systems following a fully partitioned approach.
The first part of the proposal contains the definition of a
pragma for controlling task affinity, a general package is
then defined that will be used by the Ravenscar profile.
!wording
Add a new clause:
D.16 Multiprocessor Implementation
This clause allows implementations on multiprocessor platforms to
be configured.
Static Semantics
The following language-defined library package exists:
package System.Multiprocessors is
pragma Preelaborate(Multiprocessors);
type CPU_Range is range 0 .. <implementation-defined>;
Not_A_Specific_CPU : constant CPU_Range := 0;
subtype CPU is CPU_Range range 1 .. CPU_Range'Last;
function Number_Of_CPUs return CPU;
end System.Multiprocessors;
A call of Number_Of_CPUs returns the number of processors available
to the program. Within a given partition, each call on Number_Of_CPUs
will return the same value.
Syntax
The form of a pragma CPU is as follows:
pragma CPU (expression);
Name Resolution Rules
The expected type for the expression is System.Multiprocessors.CPU_Range.
Legality Rules
A CPU pragma is allowed only immediately within a task_definition, or the
declarative_part of a subprogram_body. At most one such pragma shall appear
within a given construct.
For a CPU pragma that appears in the declarative_part of a subprogram_body,
the expression shall be static.
Dynamic Semantics
The expression of a CPU pragma that appears in a task_definition is
evaluated for each task object (see 9.1). The CPU value is then associated
with the task object whose task_definition contains the pragma.
A CPU pragma has no effect if it occurs immediately within the
declarative_part of a subprogram_body other than the main subprogram;
the CPU value is not associated with any task.
The CPU value is associated with the environment task if the pragma
appears in the declarative_part of the main subprogram.
If a pragma CPU does not apply to the main subprogram it is implementation
defined on which processor the environment task executes.
The CPU value determines the processor on which the task will
activate and execute; the task is said to be assigned to
that processor. If the CPU value is Not_A_Specific_CPU
then the task is not assigned to a processor.
A task without a CPU pragma will activate and execute on the same
processor as its activating task if the activating task is assigned
a processor. If the CPU value is not in the range of
System.Multiprocessors.CPU_Range or is greater than Number_Of_CPUs
the task is defined to have failed, and it becomes a completed task (see
9.2).
---
Add to D.13.1(4/2) a new restriction:
No_Dependence => System.Multiprocessors.Dispatching_Domains,
---
Add after D.13.1(4/2):
Implementation Requirements
A task shall only be on the ready queues of one processor, and the
processor to which a task belongs shall be defined statically.
Whenever a task running on a processor reaches a task dispatching point,
it goes back to the ready queues of the same processor. A task with
a CPU value of Not_A_Specific_CPU will execute on an implementation
defined processor. A task without a CPU pragma will activate and execute
on the same processor as its activating task.
Implementation Advice
On a multiprocessor system, an implementation should support a fully
partitioned approach. Each processor should have separate and disjoint
ready queues.
!discussion
Although there are many dispatching approaches that make use of
task migration this significantly complicates the run-time
and adds overheads. For Ravenscar and its focus on static properties
it is in keeping to disallow migration. The scheduling problem for
partitioned allocation is a combination of bin packing followed
by single processor dispatching. These are known techniques and
do not add complications to the Ravenscar model.
!example
A task type that defines worker tasks to be allocated to different CPUs
would have the form:
task type Worker (W : CPU_Range) is
pragma CPU(W);
end Worker;
Alan : Worker(1);
!corrigendum D.13.1(4/2)
Replace the paragraph:
pragma Task_Dispatching_Policy (FIFO_Within_Priorities);
pragma Locking_Policy (Ceiling_Locking);
pragma Detect_Blocking;
pragma Restrictions (
No_Abort_Statements,
No_Dynamic_Attachment,
No_Dynamic_Priorities,
No_Implicit_Heap_Allocations,
No_Local_Protected_Objects,
No_Local_Timing_Events,
No_Protected_Type_Allocators,
No_Relative_Delay,
No_Requeue_Statements,
No_Select_Statements,
No_Specific_Termination_Handlers,
No_Task_Allocators,
No_Task_Hierarchy,
No_Task_Termination,
Simple_Barriers,
Max_Entry_Queue_Length => 1,
Max_Protected_Entries => 1,
Max_Task_Entries => 0,
No_Dependence => Ada.Asynchronous_Task_Control,
No_Dependence => Ada.Calendar,
No_Dependence => Ada.Execution_Time.Group_Budget,
No_Dependence => Ada.Execution_Time.Timers,
No_Dependence => Ada.Task_Attributes);
by:
pragma Task_Dispatching_Policy (FIFO_Within_Priorities);
pragma Locking_Policy (Ceiling_Locking);
pragma Detect_Blocking;
pragma Restrictions (
No_Abort_Statements,
No_Dynamic_Attachment,
No_Dynamic_Priorities,
No_Implicit_Heap_Allocations,
No_Local_Protected_Objects,
No_Local_Timing_Events,
No_Protected_Type_Allocators,
No_Relative_Delay,
No_Requeue_Statements,
No_Select_Statements,
No_Specific_Termination_Handlers,
No_Task_Allocators,
No_Task_Hierarchy,
No_Task_Termination,
Simple_Barriers,
Max_Entry_Queue_Length => 1,
Max_Protected_Entries => 1,
Max_Task_Entries => 0,
No_Dependence => Ada.Asynchronous_Task_Control,
No_Dependence => Ada.Calendar,
No_Dependence => Ada.Execution_Time.Group_Budget,
No_Dependence => Ada.Execution_Time.Timers,
No_Dependence => Ada.Task_Attributes,
No_Dependence => System.Multiprocessors.Dispatching_Domains);
Implementation Requirements
A task shall only be on the ready queues of one processor, and the
processor to which a task belongs shall be defined statically.
Whenever a task running on a processor reaches a task dispatching point,
it goes back to the ready queues of the same processor. A task with
a CPU value of Not_A_Specific_CPU will execute on an implementation
defined processor. A task without a CPU pragma will activate and execute
on the same processor as its activating task.
Implementation Advice
On a multiprocessor system, an implementation should support a fully
partitioned approach. Each processor should have separate and disjoint
ready queues.
!corrigendum D.16(0)
Insert new clause:
This clause allows implementations on multiprocessor platforms to
be configured.
Static Semantics
The following language-defined library package exists:
package System.Multiprocessors is
pragma Preelaborate(Multiprocessors);
type CPU_Range is range 0 .. implementation-defined;
Not_A_Specific_CPU : constant CPU_Range := 0;
subtype CPU is CPU_Range range 1 .. CPU_Range'Last;
function Number_Of_CPUs return CPU;
end System.Multiprocessors;
A call of Number_Of_CPUs returns the number of processors available
to the program. Within a given partition, each call on Number_Of_CPUs
will return the same value.
Syntax
The form of a pragma CPU is as follows:
pragma CPU (expression);
Name Resolution Rules
The expected type for the expression is System.Multiprocessors.CPU_Range.
Legality Rules
A CPU pragma is allowed only immediately within a task_definition, or the
declarative_part of a subprogram_body. At most one such pragma shall appear
within a given construct.
For a CPU pragma that appears in the declarative_part of a subprogram_body,
the expression shall be static.
Dynamic Semantics
The expression of a CPU pragma that appears in a task_definition is
evaluated for each task object (see 9.1). The CPU value is then associated
with the task object whose task_definition contains the pragma.
A CPU pragma has no effect if it occurs immediately within the
declarative_part of a subprogram_body other than the main subprogram;
the CPU value is not associated with any task.
The CPU value is associated with the environment task if the pragma
appears in the declarative_part of the main subprogram.
If a pragma CPU does not apply to the main subprogram it is implementation
defined on which processor the environment task executes.
The CPU value determines the processor on which the task will
activate and execute; the task is said to be assigned to
that processor. If the CPU value is Not_A_Specific_CPU
then the task is not assigned to a processor.
A task without a CPU pragma will activate and execute on the same
processor as its activating task if the activating task is assigned
a processor. If the CPU value is not in the range of
System.Multiprocessors.CPU_Range or is greater than Number_Of_CPUs
the task is defined to have failed, and it becomes a completed task (see
9.2).
!ACATS test
Add an ACATS C-Test of this package.
!appendix
From: Bob Duff
Sent: Sunday, July 18, 2010 8:20 AM
Minor comments on AI-171 and 167, processor affinity, etc.
I think the package name should be Processors instead of Multiprocessors.
Some computers still only have one, you know. ;-)
And I think all the "CPU"s should be "Processor" (e.g. Number_Of_CPUs -->
Number_Of_Processors). CPU seems sort of archaic, to me (room-sized computers
with spinning tape drives), "processor" more modern. Also, CPU seems illogical
-- if there's more than one of it, how can it be "central"?
****************************************************************
From: Alan Burns
Sent: Monday, July 19, 2010 8:17 AM
Is this view generally agreed with? It would be useful to know before editing
the text.
I'm happy to make these changes.
****************************************************************
From: Tucker Taft
Sent: Monday, July 19, 2010 8:34 AM
Bob's suggestions are fine with me. I think also relevant is what terminology
is used within the real-time community, if there is one that is used
consistently.
****************************************************************
From: John Barnes
Sent: Monday, July 19, 2010 11:45 AM
We should certainly check consistency of terminology. It is sometimes the case
that historic terminology is used even though the technology has moved on. Thus
the states onhook and offhook are I believe still used in telecommunications
although it is a long time since I saw a telphone with a hook.
****************************************************************
From: Randy Brukardt
Sent: Monday, July 19, 2010 12:17 PM
I have no significant problem with this, but Ada already has the concept of
CPU_Time (see D.14(11/2) etc.) Probably that should have been called
Processor_Time, but it seems too late to do that. (We could of course add a
subtype of Processor_Time called CPU_Time and add duplicate constants to
Ada.Execution_Time to compatibly change the names of this type and the
associated constants, but that seems way over the top.)
We did discuss this at the ARG meeting in St. Petersburg; here's the notes:
Is CPU appropriate; should this be "processor"? CPU is ancient but short.
Someone suggests "core". We don't seem to have a conclusion. Randy notes later
that D.14 uses "CPU_Time".
****************************************************************
From: Bob Duff
Sent: Monday, July 19, 2010 3:16 PM
> I have no significant problem with this, but Ada already has the
> concept of CPU_Time (see D.14(11/2) etc.) Probably that should have
> been called Processor_Time, but it seems too late to do that.
Hmm. Somehow "CPU time" seems fine to me, and "processor time" seems odd. But
"number of CPUs" seems archaic and illogical, whereas "number of processors"
seems fine.
I won't claim to have any logical reason for this opinion. ;-)
>...(We could of course add a
> subtype of Processor_Time called CPU_Time and add duplicate constants
>to Ada.Execution_Time to compatibly change the names of this type and
>the associated constants, but that seems way over the top.)
>
> We did discuss this at the ARG meeting in St. Petersburg; here's the notes:
>
> Is CPU appropriate; should this be "processor"? CPU is ancient but short.
> Someone suggests "core". We don't seem to have a conclusion. Randy
> notes later that D.14 uses "CPU_Time".
OK, well it's certainly not worth a huge argument. Let's decide one way or
'tother, so GNAT can go ahead and implement it.
One more question (sorry if I'm being a trouble maker...):
Why is it System.Multiprocessors (or as I suggested System.Processors)?
Why not Ada.Processors?
****************************************************************
From: Robert Dewar
Sent: Monday, July 19, 2010 3:32 PM
> Hmm. Somehow "CPU time" seems fine to me, and "processor time" seems
> odd. But "number of CPUs" seems archaic and illogical, whereas
> "number of processors" seems fine.
>
> I won't claim to have any logical reason for this opinion. ;-)
I agree with Bob and hold the same slightly illogical view point
****************************************************************
From: Tucker Taft
Sent: Monday, July 19, 2010 3:36 PM
> One more question (sorry if I'm being a trouble maker...):
> Why is it System.Multiprocessors (or as I suggested System.Processors)?
> Why not Ada.Processors?
We debated this. The number of processors seems closer to
target-environment-related things like the size of the memory and the bits per
word than to something that is language-related such as Ada.Tags or Ada.Text_IO.
****************************************************************
From: Randy Brukardt
Sent: Monday, July 19, 2010 3:40 PM
Isn't this a low-level thing more like an Address than something higher-level?
Surely the majority of Ada programs will work just fine without changing the
CPU/processor affinities. That seems to be something that would be done only for
critical tuning, much like Address is only used for low-level hardware access.
Assuming that you agree with this, then it seems appropriate for it to be in
System, as opposed to Ada. After all, you could argue that Address should be in
Ada as well: every computer has addresses.
****************************************************************
From: Robert Dewar
Sent: Monday, July 19, 2010 4:02 PM
> Isn't this a low-level thing more like an Address than something
> higher-level? Surely the majority of Ada programs will work just fine
> without changing the CPU/processor affinities. That seems to be
> something that would be done only for critical tuning, much like
> Address is only used for low-level hardware access.
Actually no, the switch from one processor to two has profound semantic
implications, and I can easily see a program that only runs on a monoprocessor
using this function to guard itself.
> Assuming that you agree with this, then it seems appropriate for it to
> be in System, as opposed to Ada. After all, you could argue that
> Address should be in Ada as well: every computer has addresses.
I think that everything should be in Ada, but given the contrary choice of the
past, system seems more consistent.
****************************************************************
From: Alan Burns
Sent: Monday, July 20, 2010 2:28 AM
The Linux literature talks mostly of CPU affinity, with CPUSETS (or
CPU_Sets) being used
extensively.
So I think given the comments so far, I'll stay with CPU.
****************************************************************
Questions? Ask the ACAA Technical Agent