!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 .. ; 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); !comment Moved by AI05-0246-1 from D.13.1(4/2) to !corrigendum D.13(5/2) @drepl @xcode<@b Task_Dispatching_Policy (FIFO_Within_Priorities); @b Locking_Policy (Ceiling_Locking); @b Detect_Blocking; @b 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);> @dby @xcode<@b Task_Dispatching_Policy (FIFO_Within_Priorities); @b Locking_Policy (Ceiling_Locking); @b Detect_Blocking; @b 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);> @s8<@i> 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. @s8<@i> 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) @dinsc This clause allows implementations on multiprocessor platforms to be configured. @s8<@i> The following language-defined library package exists: @xcode<@b System.Multiprocessors @b @b Preelaborate(Multiprocessors); @b CPU_Range @b 0 .. @ft<@i>; Not_A_Specific_CPU : @b CPU_Range := 0; @b CPU @b CPU_Range @b 1 .. CPU_Range'Last; @b Number_Of_CPUs @b CPU; @b 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. @s8<@i> The form of a @fa CPU is as follows: @xcode< @ft<@b CPU (@fa);>> @s8<@i> The expected type for the @fa is System.Multiprocessors.CPU_Range. @s8<@i> A CPU pragma is allowed only immediately within a @fa, or the @fa of a @fa. At most one such pragma shall appear within a given construct. For a CPU pragma that appears in the @fa of a @fa, the @fa shall be static. @s8<@i> The @fa of a CPU pragma that appears in a @fa is evaluated for each task object (see 9.1). The CPU value is then associated with the task object whose @fa contains the pragma. A CPU pragma has no effect if it occurs immediately within the @fa of a @fa 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 @fa 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. **************************************************************** From: Brad Moore Sent: Sumday, February 20, 2011 7:03 AM I have a few suggestions regarding the System.Multiprocessors package that I think might be worth considering. 1) Package Name Multiprocessors is a bit of a mouthful, it strikes me that this functionality is centered around parallelism capabilities. Would it make sense to call this package System.Parallel instead? 2) Synchronous_Barriers are really tied to parallelism also. It seems it would make sense for this package to be a child of System.Parallel (System.Multiprocessors) as in System.Parallel.Synchronous_Barriers. 3) I see the Barrier_Limit defined in Synchronous_Barriers as something that more generally can be thought of as a Worker_Count. Moreover, I see this type being potentially being used in other parallelism packages that we might add down the road for Ada 2017. I am wondering if it makes sense to define Worker_Count as an implementation defined range in System.Parallel (System.Multiprocessors), and then it would simplify the declarations in System.Parallel.Synchronous_Barriers. The type for the Release_Threshold discriminant in Synchronous_Barriers would be Worker_Count, which makes sense to me. 4) I have raised this point before, but I think now I have a better understanding of the issue. The uses of Synchronous_Barriers that I have seen are used in parallel algorithms that need to interleave some sequential processing in the middle of parallel processing. To do this, two barrier objects are needed. One to transistion from parallel processing to sequential, and another to transition back from sequential to parallel. When transitioning from parallel to sequential, that is when you need the Notified parameter, because only one of the tasks will be continuing out of the parallelism. That is the task that performs the sequential bit. However, when you transition back from sequential to parallel, you dont need/want a Notified parameter. All tasks will be continuing past that point. That is why I say there should really be two different calls to Synchronous_Barriers.Wait_For_Release. One that hasa notified parameter, and one that doesn't. It strikes me that this would be a common usage for the Synchronous_Barriers package. Forcing the use of a Notified parameter when it isnt needed is annoying. **************************************************************** From: Alan Burns Sent: Monday, February 21, 2011 5:20 AM > 1) Package Name > Multiprocessors is a bit of a mouthful, it strikes me that this functionality > is centered around parallelism capabilities. Would it make sense to call this > package System.Parallel instead? I disagree. There are different forms of parallel hardware (GPUs for example) , the facilities provided in the CPU and Dispatching Domain packages are to do with multiprocessors and multi-cores (and task based exploitation of such architectures). And hence the name System.Multiprocessors seems appropriate. I agree than the Synchronous_Barriers facilities are concerned with difference forms of parallelism and hence they do not necessarily fit within the System.Multiprocessors hierarchy. **************************************************************** From: Brad Moore Sent: Monday, February 21, 2011 7:05 AM My thoughts are that Parallel might be a better umbrella to cover a wider range of parallelism. I agree that Dispatching_Domains is a multicore-specific concept, but then that should be fairly well understood by users of that package, I would think. Parallel as a package name is an adjective that works nicely to describe the child packages. eg. Parallel.Dispatching_Domains Parallel.Synchronous_Barriers or possible future packages maybe for Ada 2017? Parallel.Iteration -- facilities for parallel loops Parallel.Recursion -- facilities for parallel recursion I see your point however about the type CPU, as that type is specifically referring to multicore CPU's , and wouldn't cover other CPU's in the system, such as GPU's, DSP's, etc. If that were a type defined in Parallel, then there might need to be a modification to the name to make it clear it is multicore-specific. Also as a slight refinement/improvement to what I proposed yesterday.... I think system specific univeral integer constants for Max_CPUs and Max_Workers could be defined in a system package. (System.Multiprocessors?) Then Parallel could be defined as a child of Ada. eg with System.Multiprocessors; package Ada.Parallel is pragma Preelaborate (Parallel); type Multicore_CPU_Range is range 0 .. System.Multiprocessors.Max_CPUs; Not_A_Specific_CPU : constant CPU_Range := 0; subtype Multicore_CPU is Multicore_CPU_Range 1 .. Multicore_CPU_Range'Last; function Number_Of_CPUs return Multicore_CPU; type Multicore_Worker_Count is range 0 .. System.Multiprocessors.Max_Workers; end Ada.Parallel; Parallel might also be a word that might draw more people to have a closer look at Ada. **************************************************************** From: Randy Brukardt Sent: Wednesday, March 9, 2011 11:41 PM >I have a few suggestions regarding the System.Multiprocessors package >that I think might be worth considering. We've finished work on that package; moreover, we just had a discussion about the name (ending January 31st). It is pointless to force yet another re-discussion of that again. [Editor's note: you can find that discussion filed in AI05-0167-1.] [The only reason that I'm answering this now is that you are an HoD, meaning that there is a significant chance that you'll bring it up again during NB review -- and that means I will have to write a response sooner or later, and sooner is better.] >1) Package Name >Multiprocessors is a bit of a mouthful, it strikes me that this >functionality is centered around parallelism capabilities. Would it >make sense to call this package System.Parallel instead? Alan answered this adequately. CPU is a multicore/multiprocessor idea. >My thoughts are that Parallel might be a better umbrella to cover a >wider range of parallelism. But we're not looking for an "umbrella". It is way too late for that; if such a package was a good idea, it should have been introduced in Ada 95 (when the other "umbrellas" were created). Ada itself is all about parallelism; we don't separate those features from the others; they're sprinkled throughout the standard. ... >Parallel as a package name is an adjective that works nicely to >describe the child packages. >eg. >Parallel.Dispatching_Domains >Parallel.Synchronous_Barriers OK, but why should Synchronous_Barriers be under Parallel, and things like Synchronous_Task_Control and Dynamic_Priorities not be under Parallel?? >or possible future packages maybe for Ada 2017? > Parallel.Iteration -- facilities for parallel loops > Parallel.Recursion -- facilities for parallel recursion These seem like very general things. OTOH, the other things are fairly specialized; people would rarely use them. (Hardly any programs need the Dispatching_Domain or even the CPU capabilities.) ... >Parallel might also be a word that might draw more people to have a >closer look at Ada. Maybe, but Ada has *always* been about tasking. Besides, if we're going to do that, we should call the package "multicore", that's much more of a buzzword. >3) I see the Barrier_Limit defined in Synchronous_Barriers as something > that more generally can be thought of as a Worker_Count. Moreover, I > see this type being potentially being used in other > parallelism packages that we might add down the road for Ada 2017. This sounds like a bad idea to me. Unless the operations actually interoperate, you would want separate subtypes as the limits are likely to depend on the underlying implementation. And there is no reason to think that barriers would have the same limit as some other parallelism features. If it does turn out to be valuable, it is easy to move compatibly (subtypes of Positive can be defined anywhere and will have the same semantics), so there is no urgency to change this now. **************************************************************** From: Brad Moore Sent: Sunday, March 13, 2011 9:43 AM >> I have a few suggestions regarding the System.Multiprocessors package >> that I think might be worth considering. > We've finished work on that package; moreover, we just had a > discussion about the name (ending January 31st). It is pointless to > force yet another re-discussion of that again. Not sure I'd agree with it being pointless, if something new is being brought to the table. > [The only reason that I'm answering this now is that you are an HoD, > meaning that there is a significant chance that you'll bring it up > again during NB review -- and that means I will have to write a > response sooner or later, and sooner is better.] And thanks for your comments. I much prefer receiving them sooner rather than later. I threw the idea out there thinking that it might receive some traction. So far it hasn't received any, so that tells me it is not a good idea. > Ada itself is all about parallelism; we don't separate those features > from the others; they're sprinkled throughout the standard. Good point. ****************************************************************