Self-Adjusting Stack Machines

advertisement
Self-Adjusting Stack Machines
Matthew A. Hammer
Georg Neis Yan Chen Umut A. Acar
Max Planck Institute for Software Systems
OOPSLA 2011 — October 27, 2011
Portland, Oregon, USA
Static Computation Versus Dynamic Computation
Static Computation:
Fixed Input
Compute
Fixed Output
Dynamic Computation:
Changing Input
Read
Changes
Matthew A. Hammer
Compute
Update
Self-Adjusting Stack Machines
Changing Output
Write
Updates
2
Dynamic Data is Everywhere
Software systems often consume/produce dynamic data
Reactive Systems
Scientific
Simulation
Matthew A. Hammer
Analysis of
Internet data
Self-Adjusting Stack Machines
3
Tractability Requires Dynamic Computations
Changing Input
Compute
Changing Output
Static Case
(Re-evaluation “from scratch”)
compute
# of changes
Total time
Matthew A. Hammer
1 sec
1 million
11.6 days
Self-Adjusting Stack Machines
4
Tractability Requires Dynamic Computations
Changing Input
Read
Changes
Compute
compute
# of changes
Total time
Matthew A. Hammer
Write
Updates
Update
Static Case
(Re-evaluation “from scratch”)
1 sec
1 million
11.6 days
Changing Output
Dynamic Case
(Uses update mechanism)
compute
update
# of changes
Total time
Speedup
Self-Adjusting Stack Machines
10 sec
1 × 10−3 sec
1 million
16.7 minutes
1000x
4
Dynamic Computations can be Hand-Crafted
As an input sequence changes, maintain a sorted output.
Changing Input
Changing Output
1,7,3,6,5,2,4
compute
1,2,3,4,5,6,7
Remove 6
1,7,3,6/,5,2,4
update
1,2,3,4,5,6/,7
Reinsert 6,
Remove 2
1,7,3,6,5,2/,4
update
1,2/,3,4,5,6,7
A binary search tree would suffice here (e.g., a splay tree)
What about more exotic/complex computations?
Matthew A. Hammer
Self-Adjusting Stack Machines
5
How to Program Dynamic Computations?
Can this programming be systematic?
What are the right abstractions?
1. How to describe dynamic computations?
I
I
Usability: Are these descriptions easy to write?
Generality: How much can they describe?
2. How to implement these descriptions?
I
I
Efficiency: Are updates faster than re-evaluation?
Consistency: Do updates provide the correct result?
Matthew A. Hammer
Self-Adjusting Stack Machines
6
In Self-Adjusting Computation,
Ordinary programs describe dynamic computations.
C Source
Compiler
C Target
+
Run-time
Self-Adjusting Program
The self-adjusting program:
1. Computes initial output from initial input
2. Automatically updates output when input changes
Matthew A. Hammer
Self-Adjusting Stack Machines
7
Self-Adjusting Programs
Input
Read
Changes
Read
Compute
Trace
Write
Output
Write
Updates
Update
I
I
Self-adjusting program maintains dynamic
dependencies in an execution trace.
Key Idea: Reusing traces
efficient update
Matthew A. Hammer
Self-Adjusting Stack Machines
8
Challenges
Existing work targets functional languages:
I Library support for SML and Haskell
I DeltaML extends MLton SML compiler
Our work targets low-level languages (e.g., C)
I stack-based
I imperative
I no strong type system
I no automatic memory management
Matthew A. Hammer
Self-Adjusting Stack Machines
9
Challenges Low-Level Self-Adj. Computation
Efficient update
complex resource interactions:
I execution trace, call stack, memory manager
Input
Read
Changes
Read
Compute
Trace
Write
Output
Write
Updates
Update
Matthew A. Hammer
Self-Adjusting Stack Machines
10
Challenges Low-Level Self-Adj. Computation
Efficient update
complex resource interactions:
I execution trace, call stack, memory manager
Input
Read
Changes
Read
Compute
Trace
Write
Output
Write
Updates
Update
Matthew A. Hammer
Self-Adjusting Stack Machines
10
Challenges Low-Level Self-Adj. Computation
Efficient update
complex resource interactions:
I execution trace, call stack, memory manager
make new trace,
search old trace
code
revaluation
found change
found match
change
propagation
Matthew A. Hammer
repair + edit
old trace
Self-Adjusting Stack Machines
10
Example: Dynamic Expression Trees
Objective: As tree changes, maintain its valuation
+
+
−
+
3
−
0
5
−
+
6
4
3
((3 + 4) − 0) + (5 − 6) = 6
Matthew A. Hammer
+
−
0
4
5
5
6
((3+4)−0)+((5−6)+5) = 11
Self-Adjusting Stack Machines
11
Example: Dynamic Expression Trees
Objective: As tree changes, maintain its valuation
+
+
−
+
3
−
0
5
−
+
6
4
3
((3 + 4) − 0) + (5 − 6) = 6
+
−
0
4
5
5
6
((3+4)−0)+((5−6)+5) = 11
Consistency: Output is correct valuation
Efficiency: Update time is O(#affected intermediate results)
Matthew A. Hammer
Self-Adjusting Stack Machines
11
Expression Tree Evaluation in C
1
2
3
4
5
6
7
8
typedef struct node s* node t;
struct node s {
enum { LEAF, BINOP } tag;
union { int leaf;
struct { enum { PLUS, MINUS } op;
node t left, right;
} binop;
} u; }
1
2
3
4
5
6
7
8
9
int eval (node t root) {
if (root->tag == LEAF)
return root->u.leaf;
else {
int l = eval (root->u.binop.left);
int r = eval (root->u.binop.right);
if (root->u.binop.op == PLUS) return (l + r);
else return (l - r);
} }
Matthew A. Hammer
Self-Adjusting Stack Machines
12
The Stack “Shapes” the Computation
int eval (node t root) {
if (root->tag == LEAF)
return root->u.leaf;
else {
int l = eval (root->u.binop.left);
int r = eval (root->u.binop.right);
if (root->u.binop.op == PLUS) return (l + r);
else return (l - r);
} }
Stack usage breaks computation into three parts:
Matthew A. Hammer
Self-Adjusting Stack Machines
13
The Stack “Shapes” the Computation
int eval (node t root) {
if (root->tag == LEAF)
return root->u.leaf;
else {
int l = eval (root->u.binop.left);
int r = eval (root->u.binop.right);
if (root->u.binop.op == PLUS) return (l + r);
else return (l - r);
} }
Stack usage breaks computation into three parts:
I Part A: Return value if LEAF
Otherwise, evaluate BINOP, starting with left child
Matthew A. Hammer
Self-Adjusting Stack Machines
13
The Stack “Shapes” the Computation
int eval (node t root) {
if (root->tag == LEAF)
return root->u.leaf;
else {
int l = eval (root->u.binop.left);
int r = eval (root->u.binop.right);
if (root->u.binop.op == PLUS) return (l + r);
else return (l - r);
} }
Stack usage breaks computation into three parts:
I Part A: Return value if LEAF
Otherwise, evaluate BINOP, starting with left child
I Part B: Evaluate the right child
Matthew A. Hammer
Self-Adjusting Stack Machines
13
The Stack “Shapes” the Computation
int eval (node t root) {
if (root->tag == LEAF)
return root->u.leaf;
else {
int l = eval (root->u.binop.left);
int r = eval (root->u.binop.right);
if (root->u.binop.op == PLUS) return (l + r);
else return (l - r);
} }
Stack usage breaks computation into three parts:
I Part A: Return value if LEAF
Otherwise, evaluate BINOP, starting with left child
I Part B: Evaluate the right child
I Part C: Apply BINOP to intermediate results; return
Matthew A. Hammer
Self-Adjusting Stack Machines
13
Dynamic Execution Traces
Input Tree
+
−
+
3
−
0
5
6
4
Execution Trace
A+
B+
A−
B−
A+
B+
A3
A4
Matthew A. Hammer
C+
C−
A0
Self-Adjusting Stack Machines
C+
A−
B−
A5
A6
C−
14
How to Update the Output?
Original Input
+
−
+
3
Changed Input
+
−
0
5
−
+
6
4
3
+
−
0
4
5
5
6
Goals:
I Consistency: Respect the (static) program’s meaning
I Efficiency: Reuse original computation when possible
Matthew A. Hammer
Self-Adjusting Stack Machines
15
How to Update the Output?
Original Input
+
−
+
3
Changed Input
+
−
0
5
−
+
6
4
3
+
−
0
4
5
5
6
Goals:
I Consistency: Respect the (static) program’s meaning
I Efficiency: Reuse original computation when possible
Idea: Transform the first trace into second trace
Matthew A. Hammer
Self-Adjusting Stack Machines
15
+
−
+
3
+
−
0
4
5
5
6
Affected/Re-eval Affected/Re-eval
A+
B+
A−
B−
A+
B+
A3
A4
C+
A0
Unaffected/Reuse
Matthew A. Hammer
C−
C+
A+
B+
A−
B−
A5
A6
C−
C+
A5
New Evaluation
Unaffected/Reuse
Self-Adjusting Stack Machines
16
Before Update
A+
A−
B+
B−
A+
B+
A3
A4
C+
C−
A0
After Update
A+
A−
B+
A3
A4
C+
Matthew A. Hammer
A−
B−
A5
A6
C−
B+
B−
A+
C+
A0
C−
C+
A+
B+
A−
B−
A5
A6
Self-Adjusting Stack Machines
C−
C+
A5
17
How to Program Dynamic Computations?
1. How to describe dynamic computations?
X Usability: Are these descriptions easy to write?
X Generality: How much can they describe?
2. How to implement this description?
? Correctness: Do updates provide the correct result?
? Efficiency: Are updates faster than re-evaluation?
Matthew A. Hammer
Self-Adjusting Stack Machines
18
Overview of Formal Semantics
I
I
IL: Intermediate language for C-like programs
IL has instructions for:
I
I
I
Mutable memory: alloc, read, write
Managing local state via a stack: push, pop
Saving/restoring local state: memo, update
Matthew A. Hammer
Self-Adjusting Stack Machines
19
Overview of Formal Semantics
I
I
IL: Intermediate language for C-like programs
IL has instructions for:
I
I
I
I
Transition semantics: two abstract stack machines:
I
I
I
Mutable memory: alloc, read, write
Managing local state via a stack: push, pop
Saving/restoring local state: memo, update
Reference machine: defines “normal” semantics
Tracing machine: defines self-adjusting semantics
Can compute an output and a trace
Can update output/trace when memory changes
Automatically marks garbage in memory
We prove that these stack machines are consistent
Matthew A. Hammer
Self-Adjusting Stack Machines
19
Consistency theorem, Part 1: No Reuse
Trace
Input
Tracing Machine Run (P)
q
Input
Output
q
Reference Machine Run (P)
Output
Tracing machine is consistent with reference machine
(when tracing machine runs “from-scratch”, with no reuse)
Matthew A. Hammer
Self-Adjusting Stack Machines
20
Consistency theorem, Part 2: Reuse vs No Reuse
Trace0
Input
Tracing Machine Run (P)
Trace
Output
q
Input
q
Tracing Machine Run (P)
Trace
Output
Tracing machine is consistent with from-scratch runs
(When it reuses some existing trace Trace0 )
Matthew A. Hammer
Self-Adjusting Stack Machines
21
Consistency theorem: Main result
Trace0
Input
Trace
Tracing Machine Run (P)
q
Input
Output
q
Reference Machine Run (P)
Output
Main result uses Part 1 and Part 2 together:
Tracing machine is consistent with reference machine
Matthew A. Hammer
Self-Adjusting Stack Machines
22
How to Program Dynamic Computations?
1. How to describe dynamic computations?
X Usability: Are these descriptions easy to write?
X Generality: How much can they describe?
2. How to implement this description?
X Correctness: Do updates provide the correct result?
? Efficiency: Are updates faster than re-evaluation?
Matthew A. Hammer
Self-Adjusting Stack Machines
23
Overview of Our Implementation
Translate
C
Transform
IL
Translate
IL
C + RT
CEAL Compiler
I
I
Compiler: produces C targets from C-like source code
Run-time: maintains traces, performs efficient updates
Matthew A. Hammer
Self-Adjusting Stack Machines
24
Dynamic Expression Trees: From-Scratch Time
Time (s)
Exptrees From-Scratch
1.6
1.4
1.2
1.0
0.8
0.6
0.4
0.2
0.0
Self-Adj
Static
0
Matthew A. Hammer
250K
500K
Input Size
Self-Adjusting Stack Machines
750K
25
Dynamic Expression Trees: Ave Update Time
Time (ms)
Exptrees Ave Update
0.022
0.021
0.020
0.019
0.018
0.017
0.016
0.015
0.014
0.013
0.012
0.011
Self-Adj
250K 500K
Input Size
Matthew A. Hammer
Self-Adjusting Stack Machines
750K
26
Dynamic Expression Trees: Speed up
Exptrees Speedup
2.5 x 104
Self-Adj
4
Speedup
2.0 x 10
4
1.5 x 10
4
1.0 x 10
3
5.0 x 10
0
0.0 x 10
Matthew A. Hammer
0
250K 500K 750K
Input Size
Self-Adjusting Stack Machines
27
Summary of Empirical Results
Benchmark
N
Initial Overhead
(Compute / Static)
Speed-up
(Static / Update)
exptrees
map
reverse
filter
sum
minimum
quicksort
mergesort
quickhull
diameter
distance
106
106
106
106
106
106
105
105
105
105
105
8.5
18.4
18.4
10.7
9.6
7.7
8.2
7.2
3.7
3.4
3.4
1.4 × 104
3.0 × 104
3.8 × 104
4.9 × 104
1.5 × 103
1.4 × 104
6.9 × 102
7.8 × 102
2.2 × 103
1.8 × 103
7.9 × 102
Matthew A. Hammer
Self-Adjusting Stack Machines
28
Our Contributions
A consistent self-adjusting semantics for low-level programs
Matthew A. Hammer
Self-Adjusting Stack Machines
29
Our Contributions
A consistent self-adjusting semantics for low-level programs
Our abstract machine semantics
I Describes trace editing & memory management
implementation of run-time system
I But requires programs with a particular structure
implementation of compiler transformations
Matthew A. Hammer
Self-Adjusting Stack Machines
29
Our Contributions
A consistent self-adjusting semantics for low-level programs
Our abstract machine semantics
I Describes trace editing & memory management
implementation of run-time system
I But requires programs with a particular structure
implementation of compiler transformations
Our intermediate language is low-level, yet abstract
I orthogonal annotations for self-adjusting behavior
I no type system needed
implementation of C front end
Matthew A. Hammer
Self-Adjusting Stack Machines
29
Thank You! Questions?
Self-adjusting computation is a language-based technique
to derive dynamic programs from static programs.
Summary of contributions:
I A self-adjusting semantics for low-level programs.
This semantics defines self-adjusting stack machines.
I
I
A compiler and run-time that implement the semantics.
A front end that embeds much of C.
Matthew A. Hammer
Self-Adjusting Stack Machines
30
Download