Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 Resource Bound Certification Stephanie Weirich Cornell University Joint work with Karl Crary, CMU.

Similar presentations


Presentation on theme: "1 Resource Bound Certification Stephanie Weirich Cornell University Joint work with Karl Crary, CMU."— Presentation transcript:

1 1 Resource Bound Certification Stephanie Weirich Cornell University Joint work with Karl Crary, CMU

2 2 Problem Sometimes code runs too long How do we prevent it?

3 3 Enforcement Methods Run the code, and if it takes too long, kill it Look at the code and decide how long it will take  Annotations on the code can makes this process decidable

4 4 Dynamic Method Can decide how long is too long on the fly (even while the code is running) Code producer does not have to write code in any particular language (or include annotations) May be expensive to enforce

5 5 Static Method Guarantee to the user that code will run without being prematurely terminated May provide faster execution Can encompass dynamic checking Static verification that the code executes dynamic checks Makes policy enforcement part of the model

6 6 Annotations What annotations can we use for execution time verification?

7 7 Base Language Type-Safe version of C all pointer accesses checked for NULL no pointer arithmetic safe memory-management (garbage- collection or region-based) tagged unions

8 8 Caveat Most examples in this talk will look like functional programming Intension is to verify a low-level language (such as type-safe assembly language) Don’t have to trust the compiler Hopefully annotation methodologies are general enough that people can be clever

9 9 Certification of Running Time Simplification: Only count function calls and loop iterations Functions and loops annotated with the cost of execution int add1(int x) { return x+1; } int add3(int x) { x = add1(x); return add1(x); }

10 10 Example Function-typed arguments can influence the running time int foo(int f(int x) ) { return f(1)*f(3); } But can restrict how the code is used  foo(add1); foo(add3);

11 11 Abstract Time Useful to abstract the time annotation int foo (int f(int x) ) { return f(1) * f(3); } foo (add1); // k=0, takes 2 steps + 1 for call foo (add3); // k=3, takes 8 steps + 1 for call

12 12 Static Dependent Cost What if the time depends on a non-function argument? Essential for recursive functions uint fact (uint n) { if (n == 0) return 1; else return (fact (n-1) * n); } Note : Time annotation must be non-negative Ignore underflow/overflow

13 13 Size What if the argument is not a uint or a function? Option: Pre-defined mapping from structured data values to their “sizes”

14 14 Example - List struct list { const uint val; const struct list* next; } The size of a list is its length Simplifying assumption - The members of the struct are const so that we do not have to track aliasing.

15 15 Sumf int sumf (uint f(uint) ; struct list* x; int acc) { if (x == NULL) return acc; else { int acc2 = acc + f (x->val); struct list* x2 = x -> next; sumf (f, x2, acc2); }

16 16 Calling Sumf sumf(add3, NULL,0); // 0*(3+2) + 1 struct list* x = new { val = 5; next = NULL }; sumf(add3, x,0) // 1*(3+2) + 1

17 17 Size What if the time of f is dependent? uint sumf (uint f(uint y) ; struct list* x; uint acc) { if (x == null) return acc; else { uint acc2 = acc + f (x->val); struct list* x2 = x -> next; sumf (f, x2, acc2); }

18 18 User-defined size Need a programming language to express the mapping between datatypes and the time to iterate over them Expressive enough to represent structured data, and functions over that data Not so expressive that equivalence is undecidable Need a way to connect dynamic data with a representation in this language

19 19 Decidable, Expressive Language Typed-lambda calculus with products, sums and primitive recursion over inductive types Syntax of functional programming language ML Terminology Dynamic language -- Type-safe C Static language -- this annotation language

20 20 Static Language Natural numbers (of type nat) and arithmetic operations 3+4, 5*x Higher-order functions fn (x : nat) => (fn (y :nat) => x+y) (of type nat  (nat  nat) ) Tuples (3,5) : nat  nat

21 21 Static Language Sums and recursive types notated with datatypes datatype bool = False | True fun not (b:bool) = case b of True => False | False => True

22 22 Primitive Recursion datatypes can recursively mention name only in positive positions datatype foo = Bar of foo | Baz of foo * foo  datatype foo = Bar of foo  foo datatype foo = Bar of (foo  int)  foo

23 23 Primitive Recursion Recursive functions over these datatypes can only call themselves on subterms of their arguments datatype foo = Bar of foo | Baz of foo * foo fun iter (x : foo) = case x of Bar(w) => iter(x)  | Baz(y,z) => iter(y)

24 24 List Representation datatype list = Null | Cons of nat * list fun time(m : list) = case m of Nil => 0 | Cons(val, next) => val+2+time(next)

25 25 Decision Procedure We must be able to decide if two terms in the static language are equivalent Algorithm: convert each term to a normal form and compare Need a reduction system for terms that is confluent and strongly normalizing

26 26 Reduction Rules Sample Reduction rules 3 + 4 --> 7 M + 0 --> M case Ci M of C1 x1 => N1 | C2 x2 => N2 --> Ni [M/xi] (fun f x => M ) N --> M[N/x, (fun f x => M)/f]

27 27 Connecting the Languages We must be able to use this static language to describe the values of the dynamic language Use the type system to enforce that a dynamic term matches a static description

28 28 Singleton Types nat represents unsigned ints Connect constants in the two languages If m : nat, form singleton type uint uint x; x = 3;  x = 4;

29 29 Using fact New type of factorial uint fact(uint x) ; fact(3); // takes time 3+1 uint x; fact(x); // takes time n+1

30 30 Pointer Types Consider pointer types int* Either a reference to an int or null int@ Must be a reference int Must be a null pointer Want to refine the type of a variable // x has type int* if (x == NULL) { // x has type int } else { // x has type int@ }

31 31 Enforcement types Static representation of integer pointers datatype ptr = Null | Ptr intptr(m) = case m of Null => int | Ptr => int@ If x : intptr(Ptr) then we know x is not NULL

32 32 Refinement // suppose x : intptr(m) if (x == NULL) { // here we know that x : int // so therefore m must be Null, or // we’d get a contradiction } else { // know that m is Ptr }

33 33 List Enforcement Type datatype list = Null | Cons( nat, list) replist(m) = case m of Null => int | Cons(val,next) => struct { const uint val; const replist(next) rest }@

34 34 Using Enforcement Types // if x has type replist(m) if (x == NULL) { // again x : int } else { // m must be Cons (val, next) // x: {const int val; // const replist(next) rest }@ } We’ve used a comparison in the dynamic code to increase our knowledge of the static representation

35 35 User-defined Size Iterate over list, calculating a nat to represent execution time fun time(m : list) = case m of Nil => 0 | Cons(val, next) => val+2+time(next)

36 36 Example : Code uint sumf (uint f(uint y) ; replist(m) x; uint acc) { if (x == null) return acc; else { // m must Cons( val, next) // call to f takes time val + 1 uint acc2 = acc + f (x->val); struct list* x2 = x -> next; // recursive call takes time(next) + 1 sumf (f, x2, acc2); }

37 37 Other Resources “Effect notation” int f(int ) doesn’t generalize to resources that can be recovered (e.g. space) Alternative: Augment the operational semantics with a virtual clock that winds down as the program executes

38 38 Virtual Clocks Function types specify starting and ending times (int,12) f(int, 15) starts at time 15 and finishes at time 12 Use polymorphism to abstract starting times (int, n) f(int,n+3) runs in 3 steps - it is equivalent to int f(int)

39 39 Recoverable Resources Consider: (int, n+12) f (int, n+15) vs. (int, n) f (int,n+3) If the resource is free-space: the first function may allocate as many as 15 units, as long as it releases 12 of them before returning. The second function only requires a minimum of 3 units of free-space to execute.

40 40 Upper Bound Sometimes it is enough just to know an upper bound of the running time. It is an approximation to help when static analysis fails. Add the instruction waste to the language to increment the virtual clock No run-time effect

41 41 Waste example bool member (int x; replist(m) w) { if (w == NULL) return false; else // m=Cons( val, next) if (x == w->val) { waste ; return true; } else { return member( w->next ); }

42 42 TALres We have implemented a similar system within the Typed Assembly Language framework Clock contained in a virtual register, decremented on backwards jumps TAL already has a sophisticated type constructor language Added sum and inductive kinds and refinement procedure for comparison instructions Operations on static natural numbers

43 43 Source Language Prototype implementation: PopCron Resembles C + timing annotations No separation between static and dynamic languages Compiler to TALres creates representations of datatypes and their enforcement types

44 44 The real details Static and dynamic language are really two levels of the same language Static language is embedded in the dynamic language as a language of type constructors Types of dynamic language are constants in the static language Types of static language are referred to as kinds

45 45 More details Building block for refinement is “virtual case analysis”

46 46 Another Example Dynamic trees union tree { uint Leaf; struct node Node; } struct Node { const tree@ left; const tree@ right; } Static representation datatype tree = Leaf of nat | Node of tree * tree

47 47 Tree example size (t : tree) = case t of Leaf(x) => x +1 | Node (left, right) => size(left) + size(right) + 2 uint sumf (uint f(uint ) ; reptree(t) t) { switch t { case Leaf(x): return f(x); case Node(x): return sumf(x.left) + sumf(x.right); }

48 48 Enforcement type for trees reptree (tree) = case tree of Leaf x => union { uint Leaf; empty Node;} | Node (left, right) => union { empty Leaf; struct { const reptree(left)@ left; const reptree(right)@ right; } Node; }

49 49 Virtual Case switch t { case Leaf(x): // Suppose at runtime we could examine the static // representation case t of Leaf (x) => This is the only branch that could occur Node (x) => … as here x is of type empty

50 50 Virtual Case switch t { case Leaf(x): // Since one branch is impossible we don’t need to // specify it vcase t of Leaf(x) => // binds x in following code This case statement is virtual because we know what branch will be taken -- no run time effect

51 51 Related Work FX Reistad and Gifford, 94 Sized Types Hughes, Pareto, Sabry, 96 Chin Khoo, 00 PCC Necula and Lee, 97 DML Xi and Pfenning, 98

52 52 Future Work Extension of implementation to other resources More flexible enforcement types Stronger equational logic Inference and analysis in source language


Download ppt "1 Resource Bound Certification Stephanie Weirich Cornell University Joint work with Karl Crary, CMU."

Similar presentations


Ads by Google