Parallel Specification and Implementation Language: A Pointer-Free Path to Secure Object-Oriented...
-
Upload
irma-sutton -
Category
Documents
-
view
217 -
download
0
Transcript of Parallel Specification and Implementation Language: A Pointer-Free Path to Secure Object-Oriented...
Parallel Specification and
Implementation Language:
A Pointer-Free Path to
Secure Object-Oriented Parallel Programming
S. Tucker TaftFOOL Workshop, Tuscon, AZ
October 2012
ParaSail
AdaCore © 2012 2
Goals of ParaSail
A simple, safe, pervasively parallel, yet familiar, language for the multi/many-core world
Easier to write parallel algorithms than sequential ones Parallel by default, yet race-free
Have to work harder to get sequential execution
Not an academic exercise More of a human engineering exercise
Presumes advanced static analysis at compile-time
AdaCore © 2012 3
Why a new language? Computers have stopped getting faster
Courtesy IEEE Computer, January 2011, page 33.
AdaCore © 2012 4
A Simplified Approach to Secure Parallel Programming
Simplify/Unify Smaller number of concepts, uniformly applied, all features available to user-
defined types -- generally a good thing
Simplify to make conceptual room for parallelism and formalism
Simplify to make pervasive parallelism easy to verify Remove all the hard problems!
Parallelize Parallel by default, every expression is parallelizable
Have to work harder to force sequential execution
Formalize Assertions, Invariants, Preconditions, Postconditions integrated into the syntax
Compiler complains if it can’t prove the assertion
No run-time exceptions, no run-time exception handling
AdaCore © 2012 5
ParaSail Simplifications
No pointers (the “goto” of data structuring)
No global variables
No global, garbage-collected heap
No parameter aliasing
No special syntax reserved for built-in types
No run-time exception handling
No explicit threads, lock/unlock, wait/signal
No race conditions
No algebraic data types -- use OO polymorphism
No boxing/run-time-type overhead unless explicitly polymorphic
AdaCore © 2012 6
ParaSail Type and Value ModelOO/functional core
Types:
T ::= Tid | Tid+ | Mid <T1, T2, ...> | optional T | new T
FT ::= (Oid1 : T1; Oid2 : T2; ... func Fid1 FT1; ...) -> T3
Values:
V ::= N | L | (V) | FN (V1, V2, ... FV1, FV2, ...)
V ::= (if V1 then V2 else V3) | V is null | V not null
N ::= Oid | N.Oid | Tid :: N // names
L ::= 42 | 3.14159 | “a string” | ‘c’ | #green // literals
L ::= null | (Oid1 => V1, Oid2 => V2, ...)
FV ::= FN | lambda FT is (V) // function values
FN ::= Fid | Tid :: FN // function names
AdaCore © 2012 7
ParaSail Declarations and ModulesOO/functional core
Declarations:
D ::= type Tid is T;
D ::= func Fid FT [is (V)];
D ::= const Oid [ : T ] [ := V ];
D ::= M
Modules:
M ::= [abstract] interface Mid < Tid1 is Mid1<>, ... >
[extends Mid2] [implements Mid3<...>, ...]
is D1; D2; ... end interface Mid;
M ::= class Mid is D11; ... exports D21; ... end class Mid;
AdaCore © 2012 8
ParaSail Syntactic Sugar
X bin-op Y “bin-op”(X, Y)
un-op X “un-op”(X)
Obj.F(X, Y) F(Obj, X, Y)
A[I] “indexing”(A, I)
A[I..J] “slicing”(A, “..”(I, J))
[] “[]”()
[A, B, ...] [] | A | B | ...
#green #green or “from_univ”(#green)
Sugared Syntax Expanded Syntax
AdaCore © 2012 9
Example: Countable_Set
interface Countable_Set <Element_Type is Countable<>> is op "[]"() -> Countable_Set; func Singleton(Elem : Element_Type) -> Countable_Set; op “in”(Element_Type; Countable_Set) -> Boolean; op “|”(Left, Right : Countable_Set) -> Countable_Set; ...end interface Countable_Set;
class Countable_Set is type Elem_Interval is Closed_Interval<Element_Type>; const Items : optional AA_Tree<Elem_Interval>; exports op "[]"() -> Countable_Set is ((Items => [])); func Singleton(Elem : Element_Type) -> Countable_Set is ((Items => [(Low => Elem, High => Elem)] )); ...end class Countable_Set;
AdaCore © 2012 10
How to add Mutability?Why Pointer Free?
Consider F(X) + G(Y) ... We want to be able to safely evaluate F(X) and G(Y) in parallel without
looking inside of F or G Presume X and/or Y might be incoming var (in-out) parameters to the enclosing
operation
No global variables is clearly pretty helpful Otherwise F and G might be stepping on same object
No parameter aliasing is important, so we know X and Y do not refer to the same object; use hand-off semantics
What do we do if X and Y are pointers? Without more information, we must presume that from X and Y you could reach
a common object Z
Parameter modes (in-out vs. in, var vs. non-var) don’t help with objects accessible via pointers; need a more elaborate “permission” system
AdaCore © 2012 11
ParaSail types, values, declarationswith mutable objects
Types and Values with mutable objects:
T ::= ... [as before]
FT ::= ( [locked | queued] [var] Oid1 : T1; ... func Fid1 FT1; ...)
[ -> [Oid3 : ] T3 ]
V ::= ... [as before]
Declarations and Modules with mutable objects:
D ::= type Tid is T;
D ::= func Fid FT [is (V) | is S];
D ::= (const | var) Oid [ : T ] [ := V ];
D ::= M
M ::= [abstract] [concurrent] interface ... [as before]
M ::= [concurrent] class ... [as before]
AdaCore © 2012 12
ParaSail imperative statementspreserve value semantics
S ::= D // declarations interspersed
S ::= N := V | N1 <== N2 | N1 <=> N2 // copy, move, swap
S ::= FN (V1, V2, ... FV1, FV2, ...) // call for effects on params
S ::= if V then S1 else S2 end if
S ::= block S end block
S ::= [while V] loop S end loop
S ::= exit (loop | block)
S ::= return [ V ] // or may assign to named output
S ::= S1 ; S2 // sequential, but OK to parallelize
S ::= S1 || S2 // parallel; error if data dependence
S ::= S1 then S2 // force sequential
AdaCore © 2012 13
Expandable Mutable Objects Instead of Pointers
All types have additional null value; objects can be declared optional (i.e.null is OK) and can grow and shrink Eliminates many of the common uses for pointers, e.g. trees
Assignment (“:=“) is by copy Move (“<==“) and swap (“<=>”) operators also provided
Generalized indexing into containers replaces pointers for cyclic structures for each N in Directed_Graph[I].Successors loop ...
Region-Based Storage Mgmt can replace Global Heap All objects are local with growth/shrinkage using local heap
null value carries indication of region to use on growth
Short-lived references to existing objects are permitted Returned by user-defined indexing functions, for example
AdaCore © 2012 14
Mutable Pointer-Free Trees
interface Tree_Node<Payload_Type is Assignable> is
var Payload : Payload_Type;
var Left : optional Tree_Node := null; // defaults to null
var Right : optional Tree_Node := null; // defaults to null
end interface Tree_Node;
var Root : Tree_Node<Univ_String> :=
(Payload => “Top”, Left => null, Right => null);
Root.Left := (Payload => “L”, Right => (Payload => “LR”));
Root.Right <== Root.Left.Right; // Root.Left.Right now null
AdaCore © 2012 15
Example: Mutable Countable_Set
interface Countable_Set <Element_Type is Countable<>> is op "[]"() -> Countable_Set; op “|=“(var S : Countable_Set; Elem : Element_Type); ...end interface Countable_Set;
class Countable_Set is type Elem_Interval is Closed_Interval<Element_Type>; var Items : optional AA_Tree<Elem_Interval>; exports op "[]"() -> Countable_Set is return (Items => []); end op "[]";
op "|="(var S : Countable_Set; Elem : Element_Type) is const IV : Elem_Interval := (Low => Elem, High => Elem); if not Overlapping(S.Items, IV) then S.Items |= IV; end if; end op "|="; ...
AdaCore © 2012 16
Region-Based Storage Management
Pioneered by Tofte and Talpin Refined in Cyclone language
Region (i.e. local heap) in each scope
Space allocated from, and returned to, associated region when expanding and shrinking object null value identifies region from which to allocate
No garbage accumulates; no asynchronous collector
Region reclaimed in full on exiting scope effectively => stack-based heap management
Move (“<==“) and swap (“<=>”) very cheap when staying within region (analogous to “mv” in Unix) Can declare object and give “hint” to where it will be moved:
var X for Root : Payload_Type := ...
Root.Left.Payload <== X;
AdaCore © 2012 17
Stack of Regions with Region Chunks
Object handles
Region ChunksRegions
(no chunks)
AdaCore © 2012 18
Regions in a Parallel Programming Language
Global garbage-collected heap bad news in parallel language Global lock on allocation is serious bottleneck
Concurrent threads allocate unrelated objects in neighboring locations
Individual object has storage spread all over memory
Worst of both worlds (well, all 3 really)
Region provides attractive alternative Each region can have its own lock
Concurrent threads are allocating in different regions
Individual objects are concentrated in a single region
Better in all dimensions
AdaCore © 2012 19
Overall ParaSail Model
ParaSail has four basic concepts: Module
has an Interface, and Classes that implement it interface M <Formal is Int<>> is ... Supports inheritance of interface and code
Type is an instance of a Module type T is [new] M <Actual>; “T+” is polymorphic type for types inheriting from T’s interface
Object is an instance of a Type var Obj : T := Create(...); mutable value semantics
Operation is defined in a Module, and operates on one or more Objects of specified Types. are visible automatically based on types of parameters/result
AdaCore © 2012 20
Expression and Statement Parallelism
Within an expression, parameters/operands to an operation are evaluated in parallel Max ( F(X), G(Y) * H(Z) )
F(X), G(Y), H(Z) evaluated concurrently
Programmer can force parallelism across statements P(X) || Q(Y)
Programmer can force sequentiality P(X) then Q(Y)
Default is run in parallel if no dependences A := P(X); B := Q(Y) -- can run in parallel
Y := P(X); B := Q(Y) -- cannot run in parallel
Work stealing used to schedule parallel computations
AdaCore © 2012 21
Example: Recursive Parallel Word Count
func Word_Count (S : Univ_String; Separators : Countable_Set<Univ_Character> := [' ']) -> Univ_Integer is // Return count of words separated by given set of separators case Length(S) of [0] => return 0; // Empty string [1] => if S[1] in Separators then return 0; // A single separator else return 1; // A single non-separator end if; [..] => // Multi-character string; divide and conquer const Half_Len := Length(S)/2; const Sum := Word_Count(S[1 .. Half_Len], Separators) + Word_Count(S[Half_Len <.. Length(S)], Separators); if S[Half_Len] in Separators or else S[Half_Len+1] in Separators then return Sum; // At least one separator at border else return Sum-1; // Combine words at border end if; end case; end func Word_Count;
AdaCore © 2012 22
More Examples of ParaSail Parallelism
for X => Root then X.Left || X.Right while X not null
concurrent loop
Process(X.Data); // Process called on each node in parallel
end loop;
concurrent interface Box<Element is Assignable<>> is
func Create() -> Box; // Creates an empty box
func Put(queued var B : Box; E : Element); // waits til empty
func Get(queued var B : Box) -> Element; // waits til full
func Get_Now(locked B : Box) -> optional Element;
end interface Box;
type Item_Box is Box<Item>;
var My_Box : Item_Box := Create();
AdaCore © 2012 23
Synchronizing ParaSail Parallelism
concurrent class Box <Element is Assignable<>> is var Content : optional Element; // starts out null exports func Create() -> Box is // Creates an empty box return (Content => null); end func Create;
func Put(queued var B : Box; E : Element) is // waits until empty queued until B.Content is null then B.Content := E; end func Put;
func Get(queued var B : Box) -> Result : Element is // waits until full queued until B.Content not null then Result <== B.Content; // “move” sets B.Content to null as side-effect end func Get;
func Get_Now(locked B : Box) -> optional Element is return B.Content; end func Get_Now;end class Box;
AdaCore © 2012 24
ParaSail Yin and Yang
Race-Free Parallel Programming
Mutable Value Semantics
Stack-Based Heap Management
Compile-Time Exception Handling
AdaCore © 2012 25
Conclusions and Ongoing Work
Simplified, pointer-free type model can still be flexible safe by construction
Can support new capabilities pervasive parallelism
integrated annotations checked at compile-time
Ongoing ParaSail work Finalizing language, interpreter, and work-stealing scheduler
Integrating language with IDE
Building backend to generate compilable C, Ada, LLVM Assembler
Working With Microsoft Research: ParaSail + Dafny
Read the blog and download the prototype ...
http://parasail-programming-language.blogspot.com
AdaCore © 2012 26
24 Muzzey StreetLexington, MA 02421
Tucker Taft
http://parasail-programming-language.blogspot.com
+1 (781) 750-8068 x220
AdaCore