g - Program Analysis Group

advertisement
Conditional Must Not Aliasing
for
Static Race Detection
Mayur Naik
Alex Aiken
Stanford University
The Concurrency Revolution
• CPU clock speeds have peaked
• Implications for hardware
– CPU vendors are shipping multi-core processors
• Implications for software
– Concurrent programs stand to benefit the most
Debugging Concurrent Programs is Hard
• Concurrency bugs triggered non-deterministically
– Prevalent testing techniques ineffective
• A race condition is a common concurrency bug
– Two threads can simultaneously access a memory location
– At least one access is a write
Locking for Race Freedom
// Thread 1:
sync ( l1) {
… e1.f …
}
// Thread 2:
sync (l2 ) {
… e2.f …
}
Proving Race Freedom: Traditional Alias Analysis
// Thread 1:
sync ( l1) {
… e1.f …
}
// Thread 2:
sync (l2 ) {
… e2.f …
}
• Field f is race-free if:
MUST-NOT-ALIAS(e1,
¬e2
MAY-ALIAS(e1,
e2)
e1 and
never refer toe2)
the
same object
OR
MUST-ALIAS(l1,
l1 and l2
always refer tol2)
the same object
Must Alias Analysis is Hard
• Our previous approach (PLDI’06)
– performed a may alias analysis
– simple approximation of a must alias analysis
– effective but unsound
• New approach
– found must alias analysis unneeded for race detection!
– conditional must not alias analysis is sufficient
– effective and sound
Proving Race Freedom: Conditional Must Not Aliasing
// Thread 1:
sync ( l1) {
… e1.f …
}
// Thread 2:
sync (l2 ) {
… e2.f …
}
• Field f is race-free if:
Whenever l1 and l2 refer to different objects, e1 and e2
also refer to different objects
MUST-NOT-ALIAS(l1, l2) => MUST-NOT-ALIAS(e1, e2)
Example
a = new h0[N];
for (i = 1; i <= N; i++)
a[i] = new h1;
a[i].g = new h2;
for (j = 1; j <= M; j++)
fork {
x = a[*];
sync (?) {
x.g.f = 0;
} }
1
0,h0
N
i
1,h1
…
g
1,h2
i,h1
…
g
g
…
i,h2
N,h1
…
N,h2
Example
a = new h0[N];
for (i = 1; i <= N; i++)
a[i] = new h1;
a[i].g = new h2;
for (j = 1; j <= M; j++)
fork {
x = a[*];
sync (?) {
x1.g.f = 0;
} }
1
0,h0
N
i
1,h1
…
g
1,h2
i,h1
…
g
g
…
i,h2
N,h1
…
sync (?) {
x2.g.f = 0;
}
N,h2
Example: Coarse-grained Locking
a = new h0[N];
for (i = 1; i <= N; i++)
a[i] = new h1;
a[i].g = new h2;
for (j = 1; j <= M; j++)
fork {
x = a[*];
sync (a) {
x1.g.f = 0;
} }
1
0,h0
N
i
1,h1
…
g
1,h2
i,h1
…
g
g
…
i,h2
N,h1
…
sync (a) {
x2.g.f = 0;
}
Field f is race-free if:
true
MUST-NOT-ALIAS(l1,a)l2)
MUST-NOT-ALIAS(a,
=> =>
MUST-NOT-ALIAS(x1.g,
MUST-NOT-ALIAS(e1, x2.g)
e2)
N,h2
Example
a = new h0[N];
for (i = 1; i <= N; i++)
a[i] = new h1;
a[i].g = new h2;
for (j = 1; j <= M; j++)
fork {
x = a[*];
sync (?) {
x1.g.f = 0;
} }
1
0,h0
N
i
1,h1
…
g
1,h2
i,h1
…
g
g
…
i,h2
N,h1
…
sync (?) {
x2.g.f = 0;
}
N,h2
Example: Fine-grained Locking
a = new h0[N];
for (i = 1; i <= N; i++)
a[i] = new h1;
a[i].g = new h2;
for (j = 1; j <= M; j++)
fork {
x = a[*];
sync (x1.g) {
x1.g.f = 0;
} }
1
0,h0
N
i
1,h1
…
g
1,h2
i,h1
…
g
g
…
i,h2
N,h1
…
N,h2
sync (x2.g) {
x2.g.f = 0;
}
Field f is race-free if:
true
MUST-NOT-ALIAS(l1, l2)x2.g)
MUST-NOT-ALIAS(x1.g,
=> MUST-NOT-ALIAS(e1,
=> MUST-NOT-ALIAS(x1.g,
e2)
x2.g)
Example
a = new h0[N];
for (i = 1; i <= N; i++)
a[i] = new h1;
a[i].g = new h2;
for (j = 1; j <= M; j++)
fork {
x = a[*];
sync (?) {
x1.g.f = 0;
} }
1
0,h0
N
i
1,h1
…
g
1,h2
i,h1
…
g
g
…
i,h2
N,h1
…
sync (?) {
x2.g.f = 0;
}
N,h2
Example: Medium-grained Locking
a = new h0[N];
for (i = 1; i <= N; i++)
a[i] = new h1;
a[i].g = new h2;
for (j = 1; j <= M; j++)
fork {
x = a[*];
sync (x1) {
x1.g.f = 0;
} }
1
0,h0
N
i
1,h1
…
g
1,h2
i,h1
…
g
g
…
i,h2
N,h1
…
N,h2
sync (x2) {
x2.g.f = 0;
}
Field f is race-free if:
true
(field g of distinct h1x2)
objects
linked to distinct h2 objects)
MUST-NOT-ALIAS(l1,
MUST-NOT-ALIAS(x1,
l2)
=> MUST-NOT-ALIAS(x1.g,
MUST-NOT-ALIAS(e1,
e2)x2.g)
Disjoint Reachability Property
{ … h2 … } = DR({ … h1 … }) iff in every execution:
– from distinct h1 objects
i,h1
j,h1
k≠l
l,h2
►
►
i≠j
– we can reach (via 1 or more edges)
k,h2
►
►
– only distinct h2 objects
Example: Medium-grained Locking
0,h0
►
a = new h0[N];
for (i = 1; i <= N; i++)
a[i] = new h1;
a[i].g = new h2;
1,h1
…
i,h2
►
1,h2
…
N,h1
…
N,h2
►
i,h1
►
…
Is {h2} ⊆ DR({h1})?
Yes!
Disjoint Reachability Analysis
• Types (a, h):
– a is one of { 0, 1, ⊤ }
– h is an object allocation site
• Effects (a1, h1) ► (a2, h2)
– means left object linked to right object via some field
• Key property of (1, h1) ► (1, h2)
– linked objects created in same loop iteration
Example: Medium-grained Locking
0,h0
►
a = new h0[N];
for (i = 1; i <= N; i++)
a[i] = new h1;
a[i].g = new h2;
1,h1
►
1,h2
Is {h2} ⊆ DR({h1})?
Yes!
Conditional Must Not Alias Analysis using
Disjoint Reachability Analysis
PointsTo(l2)
// Thread 1:
sync (l1) {
… e1.f …
}
// Thread 2:
sync (l2) {
… e2.f …
}
PointsTo(e1)
⊆ DR
PointsTo(l1)
PointsTo(e2)
Field f is race-free if:
– (PointsTo(e1) ∩ PointsTo(e2)) ⊆ DR(PointsTo(l1) ∪ PointsTo(l2))
MUST-NOT-ALIAS(l1, l2) => MUST-NOT-ALIAS(e1, e2)
– l1 is a prefix of e1 and l2 is a prefix of e2
Example: Medium-grained Locking
a = new h0[N];
1
for (i = 1; i <= N; i++)
a[i] = new h1;
h1 …
a[i].g = new h2; PointsTo(x1)
h0
N
i
h1
… PointsTo
h1 (x2)
g
g
g
for (j = 1; j <= M; j++)
fork {
PointsTo(x1.g)
h2 …
h2
h2 (x2.g)
…PointsTo
x = a[*];
sync (x2) {
sync (x1) {
x2.g.f = 0;
x1.g.f = 0;
}
} }
Field f is race-free if:
–
–
–
(true
PointsTo
(x1.g)
∩ PointsTo
∩ PointsTo
(e2))
(x2.g))
⊆ DR(⊆PointsTo
DR(PointsTo
(l1) ∪(x1)
PointsTo
∪ PointsTo
(l2)) (x2))
({h2})
⊆ (e1)
DR({h1})
true
l1
x1 is a prefix of e1
x1.g
andand
l2x2
is aisprefix
a prefix
of of
e2x2.g
Implementation Aspects
• A type is a pair (Π, h) where:
– Π is a vector of { 0, 1, ⊤ } values, one per method
• All loops transformed to tail-recursive methods
• Uniformly handles loops and recursive methods
– h is a k-object-sensitive object allocation site
Implementation Aspects
• Circular dependency between type-and-effect analysis
and race freedom
• Fact (z = y) valid after line 3 only if field f is race-free:
1:
2:
3:
x.f = y;
... // no writes to aliases of x.f
z = x.f;
• Race detection algorithm performs fixpoint computation
– Begins assuming no races
– Type-and-effect analysis kills facts as new races are found
– Terminates when no more races are found
Benchmarks
#classes
app
lib
#lines of Java code
app
lib
time
philo
2
423
84
110,582
3m14s
elevator
5
425
531
111,147
4m43s
tsp
4
426
706
116,026
3m21s
jdbm
11
432
2,190
112,139
4m11s
jdbf
25
437
5,484
121,117
7m12s
pool
22
434
5,531
114,121
5m13s
jtds
98
461
18,190
129,016
10m42s
118
478
21,897
140,221
9m21s
ftp
Experimental Results
old pairs
new pairs
likely unlikely
original pairs real false
real false
philo
13,121
0
0
35
3
0
elevator
59,610
0
0
305
0
0
tsp
98,045
0
4
490
12
18
jdbm
189,853
91
0
331
91
0
jdbf
132,041
130
0
295
130
12
pool
241,876
115
0
355
115
5
jtds
398,031
48
0
571
48
13
ftp
487,019
122
34
1624
187
47
Related Work
• Vectorizing compilers
– loop vectors akin to iteration space and dependence distance
• Disjoint reachability
– ranging from ownership types to theorem-proving approaches
• Race detection
– Dynamic (happens-before, lockset, hybrid)
– Static (type systems, dataflow analyses, model checkers)
• Atomicity checking
– atomicity a higher-level property than race freedom
– but many atomicity checkers do race detection as first step
Summary of Results
• Conditional Must Not Aliasing
– A new aliasing property and analysis
• Disjoint Reachability
– A new lightweight shape property and analysis
• A new race detection algorithm
– Sound
– Effective in practice
The End
http://www.cs.stanford.edu/~mhn/chord.html
Download