740 likes | 914 Views
Incrementalized Pointer and Escape Analysis. Martin Rinard MIT LCS. Context. Unsafe languages (C, C++, …) Safe languages (Java, ML, Scheme, …) Big difference: garbage collection Goal: analyze program to safely allocate objects on the call stack instead of in garbage-collected heap.
E N D
Incrementalized Pointer and Escape Analysis Martin Rinard MIT LCS
Context • Unsafe languages (C, C++, …) • Safe languages (Java, ML, Scheme, …) • Big difference: garbage collection Goal: analyze program to safely allocate objects on the call stack instead of in garbage-collected heap Advantages • No dangling references • No memory leaks Disadvantages • Collection overhead • Collection pauses
Program With Allocation Sites void main(i,j) ——————— ——————— ——————— void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Program With Allocation Sites When program runs void main(i,j) ——————— ——————— ——————— void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Program With Allocation Sites When program runs void main(i,j) ——————— ——————— ——————— void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Program With Allocation Sites When program runs It allocates objects in heap void main(i,j) ——————— ——————— ——————— void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Program With Allocation Sites Program With Allocation Sites When program runs It allocates objects in heap void main(i,j) ——————— ——————— ——————— void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Program With Allocation Sites Program With Allocation Sites When program runs It allocates objects in heap void main(i,j) ——————— ——————— ——————— void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Program With Allocation Sites Program With Allocation Sites When program runs It allocates objects in heap void main(i,j) ——————— ——————— ——————— void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Program With Allocation Sites When objects become unreachable void main(i,j) ——————— ——————— ——————— void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Program With Allocation Sites When objects become unreachable Garbage collector (eventually) reclaims memory void main(i,j) ——————— ——————— ——————— void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Stack Allocation Correlate lifetimes of objects with lifetimes of procedures void main(i,j) ——————— ——————— ——————— void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Stack Allocation Allocate object on activation record of procedure void main(i,j) ——————— ——————— ——————— void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Stack Allocation When procedure returns void main(i,j) ——————— ——————— ——————— void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Stack Allocation When procedure returns Object automatically deallocated void main(i,j) ——————— ——————— ——————— void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Problem • How does compiler determine if it is safe to allocate objects on stack? • Classic problem in program analysis • Standard approach • Analyze whole program • Use information to find “captured” objects • Allocate captured objects on stack
Stack Allocation Percentage of Memory Allocated on Stack 100 80 60 40 20 0 barnes water jlex db raytrace compress Whole-Program Analysis
Normalized Execution Times Reference: execution time without optimization 100 80 60 40 20 0 barnes water jlex db raytrace compress Whole-Program Analysis
Analysis Times 223 645 150 125 100 75 Analysis Time (seconds) 50 25 0 barnes water jlex db raytrace compress Whole-Program Analysis
Key Observation Number One: void main(i,j) ——————— ——————— ——————— Most optimizations require only the analysis of a small part of program surrounding the object allocation site void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— ——————
Key Observation Number Two: void main(i,j) ——————— ——————— ——————— Most of the optimization benefit comes from a small percentage of the allocation sites void compute(d,e) ———— ———— ———— void evaluate(i,j) —————— —————— —————— void multiplyAdd(a,b,c) ————————— ————————— ————————— void abs(r) ———— ———— ———— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— —————— 99% of objects allocated at these two sites
void main(i,j) ——————— ——————— ——————— void evaluate(i,j) —————— —————— —————— void compute(d,e) ———— ———— ———— void abs(r) ———— ———— ———— void multiplyAdd(a,b,c) ————————— ————————— ————————— void scale(n,m) —————— —————— void multiply(m) ———— ———— ———— void add(u,v) —————— —————— 99% of objects allocated at these two sites Intuition for Better Analysis Locate important allocation sites Use demand-driven approach to analyze region surrounding site Somehow avoid sinking analysis resources into unprofitable sites
Vector John Doe Ben Bit Jane Roe $45,000 $30,000 $55,000 Employee Database Example Traverse database, extract max salary Name Salary max salary = $55,000 highest paid = Jane Roe
Coding Max Computation (in Java) class EmployeeDatabase { Vector database = new Vector(); Employee highestPaid; void computeMax() { int max = 0; Enumeration enum = database.elements(); while (enum.hasMoreElements()) { Employee e = enum.nextElement(); if (max < e.salary()) { max = e.salary(); highestPaid = e; } } } }
Coding Max Computation (in Java) class EmployeeDatabase { Vector database = new Vector(); Employee highestPaid; void computeMax() { int max = 0; Enumeration enum = database.elements(); while (enum.hasMoreElements()) { Employee e = enum.nextElement(); if (max < e.salary()) { max = e.salary(); highestPaid = e; } } } } Would like to allocate enum object on stack, not on the heap
Bottom Up and Compositional void printStatistics() ——————— ——————— ——————— Currently analyzed procedure void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ———— Currently analyzed part of the program
Bottom Up and Compositional void printStatistics() ——————— ——————— ——————— Currently analyzed procedure void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ———— Currently analyzed part of the program
Points-to Graph in Example void computeMax() { int max = 0; Enumeration enum = database.elements(); while (enum.hasMoreElements()) { Employee e = enum.nextElement(); if (max < e.salary()) { max = e.salary(); highestPaid = e; } } } [ ] vector elementData enum database highestPaid this e
Escape Information • Escaped nodes • parameter nodes • returned nodes • nodes reachable from other escaped nodes • Captured is the opposite of escaped [ ] vector elementData enum database highestPaid green = escaped this e white = captured
Stack Allocation Optimization • Examine graph from end of procedure • If a node is captured in this graph • Allocate corresponding objects on stack (may need to inline procedures to apply optimization) Can allocate enum object on stack [ ] vector elementData enum database highestPaid green = escaped this e white = captured
Whole Program Analysis void printStatistics() ——————— ——————— ——————— void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ————
Whole Program Analysis void printStatistics() ——————— ——————— ——————— void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ————
Whole Program Analysis void printStatistics() ——————— ——————— ——————— void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ————
Whole Program Analysis void printStatistics() ——————— ——————— ——————— void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ————
Whole Program Analysis void printStatistics() ——————— ——————— ——————— void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ————
Whole Program Analysis void printStatistics() ——————— ——————— ——————— void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ————
Whole Program Analysis void printStatistics() ——————— ——————— ——————— void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ————
Whole Program Analysis void printStatistics() ——————— ——————— ——————— void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ————
Incrementalized Analysis Requirements Must be able to • Analyze procedure independently of callers • Whole-program analysis is compositional • Already does this • Skip analysis of invoked procedures • But later incrementally integrate analysis results if desirable to do so
First Extension to Whole-Program Analysis • Skip the analysis of invoked procedures • Parameters are marked as escaping into skipped call site Assume analysis skips enum.nextElement() 1 vector enum database highestPaid Node 1 escapes into enum.nextElement() this e
First Extension Almost Works • Can skip analysis of invoked procedures • If allocation site is captured, great! • If not, escape information tells you what procedures you should have analyzed… Should have analyzed enum.nextElement() 1 vector enum database highestPaid Node 1 escapes into enum.nextElement() this e
Second Extension to Base Algorithm • Record enough information to undo skip and incorporate analysis into existing result • Parameter mapping at call site • Ordering information for call sites
Incrementalized Analysis void printStatistics() ——————— ——————— ——————— void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ————
Incrementalized Analysis void printStatistics() ——————— ——————— ——————— Attempt to stack allocate Enumeration object from elements void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ————
Incrementalized Analysis void printStatistics() ——————— ——————— ——————— Analyze elements (intraprocedurally) void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ————
Incrementalized Analysis void printStatistics() ——————— ——————— ——————— Analyze elements (intraprocedurally) void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ————
Incrementalized Analysis void printStatistics() ——————— ——————— ——————— Analyze elements (intraprocedurally) Escapes only into the caller void computeMax() ———— ———— ———— Enumeration elements() ——— ——— ——— boolean hasMoreElements() —————— —————— —————— Employee nextElement() —————— —————— int salary() —————— —————— Vector elementData() ———— ———— ————