Dynamic data race detection in concurrent Java programs

45
8 th Central and Eastern European Software Engineering Conference in Russia - CEE-SECR 2012 November 1 - 2, Moscow Vitaly Trifanov, Dmitry Tsitelov Dynamic data race detection in concurrent Java programs Devexperts LLC

description

 

Transcript of Dynamic data race detection in concurrent Java programs

Page 1: Dynamic data race detection in concurrent Java programs

8th Central and Eastern European Software Engineering Conference in Russia - CEE-SECR 2012November 1 - 2, Moscow

Vitaly Trifanov, Dmitry Tsitelov

Dynamic data race detection in concurrent Java programs

Devexperts LLC

Page 2: Dynamic data race detection in concurrent Java programs

Agenda

What are data races and why they are dangerous

Automatic races detectionapproaches, pros & cons

Happens-before race detection algorithmVector clocks

Our dynamic race detectorimplementationsolved problems

Page 3: Dynamic data race detection in concurrent Java programs

Data Race Examplepublic class Account {

private int amount = 0;

public void deposit(int x) {amount += x;}

public int getAmount() {return amount;}

}

public class TestRace {

public static void main (String[] args) {

final Account a = new Account();

Thread t1 = depositAccountInNewThread(a, 5);

Thread t2 = depositAccountInNewThread(a, 6);

t1.join();

t2.join();

System.out.println(account.getAmount()); //may print 5, 6, 11.

}

}

Page 4: Dynamic data race detection in concurrent Java programs

Expected Execution

Page 5: Dynamic data race detection in concurrent Java programs

Racy Execution

Page 6: Dynamic data race detection in concurrent Java programs

Data Races

Data race occurs when many threads access the same shared data concurrently; at least one writes

Usually it’s a bug

Page 7: Dynamic data race detection in concurrent Java programs

Data Races Are Dangerous

Hard to detect if occurredno immediate effectsprogram continues to workdamage global data structures

Hard to find manuallyNot reproducible - depends on threads timingDev & QA platforms are not so multicore

Page 8: Dynamic data race detection in concurrent Java programs

Automatic Race Detection

20+ years of research

Staticanalyze program code offlinedata races prevention (extend type system, annotations)

Dynamic: analyze real program executionsOn-the-flyPost-mortem

Page 9: Dynamic data race detection in concurrent Java programs

Dynamic Detectors vs Static

Page 10: Dynamic data race detection in concurrent Java programs

Static Approach

ProsDoesn’t require program executionAnalyzes all codeDoesn’t depend on program input, environment, etc.

ConsUnsolvable in common caseHas to reduce depth of analysis

A lot of existing tools for JavaFindBugs, jChord, etc

Page 11: Dynamic data race detection in concurrent Java programs

Dynamic Approach

ProsComplete information about program flowLower level of false alarms

ConsVery large overhead

No existing stable dynamic detectors for Java

Page 12: Dynamic data race detection in concurrent Java programs

Static vs Dynamic: What To Do?

Use both approaches

Static (FindBugs/Sonar, jChord, …)Eliminate provable synchronization inconsistencies

on the early stage

DynamicTry existing tools, but they are unstable

IBM MSDK, Thread Sanitizer for JavaThat’s why we’ve developed our own!

Page 13: Dynamic data race detection in concurrent Java programs

Data Race Detector Concept

Application uses libraries and frameworks via APIAt least JRE

API is well documented“Class XXX is thread-safe”“Class YYY is not thread-safe”“XXX.get() is synchronized with preceding call of XXX.set()”

Describe behavior of API and exclude library from analysis

Page 14: Dynamic data race detection in concurrent Java programs

DRD: How It’s Organized

Page 15: Dynamic data race detection in concurrent Java programs

What Operations to Intercept?

Synchronization operationsthread start/join/interruptsynchronizedvolatile read/writejava.util.concurrent

Accesses to shared datafieldsobjects

Page 16: Dynamic data race detection in concurrent Java programs

How It Works

ConfigRace

detection module

Instrumented app classes

interceptor

Application classes DRD agent

Page 17: Dynamic data race detection in concurrent Java programs

JLS: Publishing Data

Publish changes

Receive changes

Page 18: Dynamic data race detection in concurrent Java programs

JLS: Synchronized-With Relation

“Synchronized-with” relationunlock monitor M ↦ all subsequent locks on Mvolatile write ↦ all subsequent volatile reads…

Notation: send ↦ receive

Page 19: Dynamic data race detection in concurrent Java programs

JLS: Happens-Before & Data Races

X happens-before Y, whenX, Y - in same thread, X before Y in program orderX is synchronized-with YTransitivity: exists Z: hb(X, Z) && hb(Z, Y)

Data race: 2 conflicting accesses, not ordered by happens-before relation

Page 20: Dynamic data race detection in concurrent Java programs

Happens-Before Example

No data race

Page 21: Dynamic data race detection in concurrent Java programs

Vector Clock

Page 22: Dynamic data race detection in concurrent Java programs

Vector Clock

Page 23: Dynamic data race detection in concurrent Java programs

Vector Clock

Page 24: Dynamic data race detection in concurrent Java programs

Vector Clock

Page 25: Dynamic data race detection in concurrent Java programs

Vector Clock

Page 26: Dynamic data race detection in concurrent Java programs

Vector Clock

Page 27: Dynamic data race detection in concurrent Java programs

Vector Clock

Page 28: Dynamic data race detection in concurrent Java programs

Vector Clock

Page 29: Dynamic data race detection in concurrent Java programs

Vector Clock

Not ordered!

A: 3 > 2B: 3 < 4

Page 30: Dynamic data race detection in concurrent Java programs

How It Works. No Data Race Example

Page 31: Dynamic data race detection in concurrent Java programs

How It Works. Data Race Example

Page 32: Dynamic data race detection in concurrent Java programs

Code Instrumentation

Check everything => huge overhead

Race detection scopeAccesses to our fieldsForeign calls (treat them as read or write)

Sync scopeDetect sync events in our codeDescribe contracts of excluded classesTreat these contracts as synchronization events

Page 33: Dynamic data race detection in concurrent Java programs

Race Detectionprivate class Storage { private Map<Integer, Item> items = new HashMap<Integer, Item> ();

public void store(Item item) { items.put(item.getId(), item);}

public void saveToDisk() { for (Item item : items.values()) {

//serialize and save saveItem(item); //...

}}

public Item getItem(int id) { return items.get(id);}

public void reload() { items = deserealizeFromFile(); }}

On each access of “items” field we check race on this field

On each access of “items” field we check race on this field

On each call of “items” method we check race on this object

On each call of “items” method we check race on this object

Each field of class Item is protected the same way as field “items” of class Storage

Each field of class Item is protected the same way as field “items” of class Storage

Page 34: Dynamic data race detection in concurrent Java programs

Synchronization Contract Example

Page 35: Dynamic data race detection in concurrent Java programs

Clocks Storing

Thread clockThreadLocal<VectorClock>

Field XXXvolatile transient VectorClock XXX_vc;

Foreign objects, monitors WeakIdentityConcurrentHashMap<Object,VectorClock>

Volatiles, synchronization contractsConcurrentHashMap <???, VectorClock>

Page 36: Dynamic data race detection in concurrent Java programs

Composite Keys AtomicLongFieldUpdater.CAS(Object o, long offset, long v)param 0 + param 1

Volatile field “abc” of object oobject + field name

AtomicInteger.set() & AtomicInteger.get()object

ConcurrentMap.put(key, value) & ConcurrentMap.get(key)object + param 0

Page 37: Dynamic data race detection in concurrent Java programs

Solved Problems

Composite keys for contracts and volatilesGenerate them on-the-fly

Avoid unnecessary keys creationThreadLocal<MutableKeyXXX> for each CompositeKeyXXX

Loading of classes, generated on-the-flyInstrument ClassLoader.loadClass()

Page 38: Dynamic data race detection in concurrent Java programs

Solved Problems

Don’t break serializationcompute serialVersiodUid before instrumentation

Caching components of dead clockswhen thread dies, its time frames doesn’t grow anymorecache frames of dead threads to avoid memory leakslocal last-known generation & global generation

Page 39: Dynamic data race detection in concurrent Java programs

DRD in Real Life: QD

QD + DRD

QD

✔ 6 races found

Page 40: Dynamic data race detection in concurrent Java programs

DRD in Real Life: MARS UI

MARS + DRD

MARS

✔ 5 races found

Page 41: Dynamic data race detection in concurrent Java programs

DRD Race Report Example

WRITE_READ data race between current thread Thread-12(id = 33) and thread Thread-11(id = 32)

Race target : field my/app/DataServiceImpl.stopped

Thread 32 accessed it in my/app/DataServiceImpl.access$400(line : 29)

--------------------------------Stack trace for racing thread (id = 32) is not available.---------------------------

-------------------------------------Current thread's stack trace (id = 33) : ------------------------------------------

at my.app.DataServiceImpl.stop(DataServiceImpl.java:155)

at my.app.DataManager.close(DataManager.java:201)

...

Page 42: Dynamic data race detection in concurrent Java programs

DRD Advantages

Doesn’t break serialization

No memory leaks

Few garbage

No JVM modification

Synchronization contractsvery important: Unsafe, AbstractQueuedSynchronizer

Page 43: Dynamic data race detection in concurrent Java programs

Links

Devexperts DRD site: documentation, links, etcContact us: [email protected]

IBM MSDKThreadSanitizer for JavajChordFindBugs

JLS «Threads and locks» chapter

Page 44: Dynamic data race detection in concurrent Java programs

Q & A

Page 45: Dynamic data race detection in concurrent Java programs

Synchronization contracts: interfaces

Usually interface contract is described (ConcurrentMap)

Instrumentation stage: specified interface might even not been loaded yetget “potential contracts” from method name & signaturecode path for each potential contract

Runtime:is potential contract real?caching: {class, contract_id} → boolean