radar: dataflow analysis for concurrent programs using datarace detection ravi chugh, jan voung,...

49
RADAR: Dataflow Analysis for Concurrent Programs using Datarace Detection Ravi Chugh, Jan Voung, Ranjit Jhala, Sorin Lerner {rchugh, jvoung, jhala, lerner} @ cs.ucsd.edu UC San Diego

Post on 21-Dec-2015

237 views

Category:

Documents


0 download

TRANSCRIPT

RADAR: Dataflow Analysis for Concurrent Programs using

Datarace Detection

Ravi Chugh, Jan Voung, Ranjit Jhala, Sorin Lerner{rchugh, jvoung, jhala, lerner} @ cs.ucsd.edu

UC San Diego

Studying Concurrency is Important

Studying Concurrency is Important

Studying Concurrency is Important

Studying Concurrency is Important

• A “counting argument”• > wget

http://pldi2008.cs.ucr.edu/program_schedule.html• > grep –i “concurr” program_schedule.html | wc –l

• 6

All Jokes Aside…

Architectural Trends Devilish Bugs

Pressing Issue

Our Approach

Leverage sequential work

SequentialDataflowAnalysis

Concurrent Dataflow Analysis

Sequential Reasoning is Incorrect

if (p != null) {

use(p);

p = null;

}

p = new_or_die();

p != null

x = compute();

p != null

*p = x;

Sequential Optimization is Incorrect

g = compute();

flag = 1;

flag = 0;

while (flag == 0) { /* spin */ }

use(g);

0

Constant propagation would be incorrect

• Compilers forced to be conservative• Optimization opportunities missed

Our Approach

SequentialDataflowAnalysis

ConcurrentDataflowAnalysis

RADAR

ConcurrencyAnalysis

RaceDetector

Our Approach

ConcurrentDataflowAnalysis

SequentialDataflowAnalysis

RADAR

RaceDetector

Modular Framework

SequentialNon-NullAnalysis

SequentialConstantAnalysis

SequentialDataflowAnalysis

ConcurrentDataflowAnalysis

RADARConcurrent

Non-NullAnalysis

ConcurrentConstantAnalysis

Modular Framework

RADAR

RaceDetector

SequentialConstantAnalysis

ConcurrentConstantAnalysis

precise scalable

RADAR: Results

• Concurrent non-null analysis

• Scales to:– Apache (~130 KLOC)– OpenSSL (~210 KLOC)– subset of Linux kernel (~830 KLOC)

Example with Locks

lock(l);

if (p != null) {

use(p);

p = null;

}

unlock(l);

lock(l);

p = new_or_die();

x = compute();

*p = x;

unlock(l);

lock(l);

if (p != null) {

use(p);

p = null;

}

unlock(l);

Can this be Optimized?

lock(l);

p = new_or_die();

unlock(l);

x = compute();

lock(l);

*p = x;

unlock(l);

Optimized Version is Race-free

lock(l);

if (p != null) {

use(p);

p = null;

}

unlock(l);

lock(l);

p = new_or_die();

unlock(l);

x = compute();

lock(l);

*p = x;

unlock(l);

lock(l);

if (p != null) {

use(p);

p = null;

}

unlock(l);

Oops…

lock(l);

p = new_or_die(); unlock(l); x = compute();

lock(l);

*p = x;

unlock(l);

lock(l);

p = new_or_die(); p != nullunlock(l); p != nullx = compute(); p != nulllock(l); p != null*p = x; p != nullunlock(l);

Sequential Non-Null Analysis

lock(l);

if (p != null) { p != null use(p); p != null p = null; p != null}

unlock(l);

RADAR on Example

lock(l);

if (p != null) { p != null use(p); p != null p = null; p != null}

unlock(l);

lock(l);

p = new_or_die(); p != nullunlock(l); p != nullx = compute(); p != nulllock(l); p != null*p = x; p != nullunlock(l);

lock(l);

p = new_or_die(); p != nullunlock(l);

x = compute();

lock(l);

*p = x;

unlock(l);

RADAR on Example

Can fact be invalidated by concurrent thread?

Can p be written by a concurrent thread?

lock(l);

p = new_or_die(); p != nullunlock(l);

x = compute();

lock(l);

*p = x;

unlock(l);

RADAR on Example

pseudo-read(p) RaceDetector

Can p be written by a concurrent thread?

Race

No Race

lock(l);

p = new_or_die(); p != nullunlock(l); x = compute();

lock(l);

*p = x;

unlock(l);

RADAR on Example

pseudo-read(p)

Can p be written by a concurrent thread?

Race

No RaceRace

Detector

lock(l);

p = new_or_die(); p != nullunlock(l); p != nullx = compute();

lock(l);

*p = x;

unlock(l);

RADAR on Example

pseudo-read(p)

RaceDetector

Race

No Race

lock(l);

p = new_or_die(); p != nullunlock(l); p != nullx = compute(); p != nulllock(l); p != null*p = x;

unlock(l);

RADAR on Example

UNSAFE

RADAR on Safe Example

lock(l);

p = new_or_die();

p != null

x = compute();

*p = x;

unlock(l);

RaceDetector

Race

No Race

pseudo-read(p)

RADAR on Safe Example

lock(l);

p = new_or_die();

p != null

x = compute();

p != null

*p = x;

unlock(l);

RaceDetector

Race

No Race

pseudo-read(p)

RADAR on Safe Example

lock(l);

p = new_or_die();

p != null

x = compute();

p != null

*p = x;

unlock(l);

SAFE

More on RADAR

1. Round trip queries to race detector

2. Inter-procedural analysis

(1) Round-trip Queries

lock(l);

p = new_or_die(); p != nullunlock(l); p != nullx = compute(); p != nulllock(l); p != null*p = x; p != nullunlock(l);

Possible Race

Allow sequential analysis to run

pseudo-read(p) RaceDetector

Race

No Race

Get superset of (concurrent) facts

pseudo-read(p)

lock(l);

p = new_or_die(); p != nullunlock(l); p != nullx = compute(); p != nulllock(l); p != null*p = x; p != nullunlock(l);

(1) Round-trip Queries

Insert all pseudo-reads at once

pseudo-read(p)

pseudo-read(p)

pseudo-read(p)

pseudo-read(p)

pseudo-read(p)

RaceDetector

Send whole program to race detector

(1) Round-trip Queries

lock(l);

p = new_or_die(); p != nullunlock(l); p != nullx = compute(); p != nulllock(l); p != null*p = x; p != nullunlock(l);

pseudo-read(p)

pseudo-read(p)

pseudo-read(p)

pseudo-read(p)

pseudo-read(p)

Get results back from Race Detector

(1) Round-trip Queries

lock(l);

p = new_or_die(); unlock(l);

x = compute();

lock(l);

*p = x;

unlock(l);

pseudo-read(p)

pseudo-read(p)

pseudo-read(p)

pseudo-read(p)

pseudo-read(p)

Get results back from Race Detector

Rerun analysis using race results

(1) Round-trip Queries

lock(l);

p = new_or_die(); p != nullunlock(l); p != nullx = compute();

lock(l);

*p = x;

unlock(l);

Rerun analysis using race results

(1) Round-trip Queries

lock(l);

p = new_or_die(); p != nullunlock(l); p != nullx = compute(); p != nulllock(l); p != null*p = x;

unlock(l);

UNSAFE

(2) Handling Procedures

Unlock in foo allows interference

lock(l);

if (p != null) {

foo();

*p = 10;

}

unlock(l);

void foo () {

if (*) {

unlock(l);

compute();

lock(l);

}

}

lock(l);

p = null;

unlock(l);

Want to summarize effect of calling foo

(2) Handling Procedures

lock(l);

if (p != null) {

foo();

*p = 10;

}

unlock(l);

void foo () {

if (*) {

unlock(l);

compute();

lock(l);

}

}

lock(l);

p = null;

unlock(l);

lock(l);

if (p != null) {

foo();

*p = 10;

}

unlock(l);

(2) Handling Procedures

pseudo-unlock(l);pseudo-read(p);pseudo-lock(l);

In the caller, RADAR inserts:• pseudo-unlock for every unlock in foo• pseudo-reads

Evaluation

• Is RADAR scalable?

• Is RADAR precise?

• Where can we do better?

Experiments: Benchmarks

• Apache 2.2.6 (130 KLOC)– worker threads + modules (e.g., caches)

• OpenSSL 0.9.8g (210 KLOC)– model a multi-threaded client

• Linux 2.6.15 (830 KLOC)– subset from RELAY experiments

50

60

70

80

90

100

Apache SSL Linux

Sequential Race Detector+ =

Non-Null Never raceOptimistic

(sequential)

Non-Null

Non-Null

Non-Null Escapes ⇒ race Conservative

50

60

70

80

90

100

Apache SSL Linux

GAP

Sequential Race Detector+ =

Non-Null

Non-Null

Non-Null

Non-Null

Never raceOptimistic

(sequential)

Escapes ⇒ race Conservative

Shared ⇒ race

No locks ⇒ race

50

60

70

80

90

100

Apache SSL Linux

Sequential Race Detector+ =

Non-Null

Non-Null

Non-Null

Non-Null

Optimistic (sequential)

Conservative

Never race

Escapes ⇒ race

Shared ⇒ race

No locks ⇒ race

Sources of Imprecision

• Alias analysis– affects sequential dataflow and race detection

• Lockset-based race analysis– ignores fork, join, condition variables

• RADAR framework– pseudo-read (for non-null fact) races with – “x = NonNullAddress;”

Related Work

• Programming-model-based approaches– [Knoop et al 96], [Grunwald et al 93], …– par-begin / par-end– handles introduction of facts between threads

• Thread-modular– [Owicki et al 76], [Jones 83], [Flanagan et al 03], …– more precise (use environment assumption)– inference not as scalable

Conclusion

RADAR

RaceDetector

SequentialDataflowAnalysis

ConcurrentDataflowAnalysis

precise scalable

THANKS!

What is filtered for non-null?

if (a->f != null) {

b->f = null;

deref(a->f); //filter if warned

deref(b->f); //don’t filter

}