Upload
randolf-warren
View
225
Download
0
Embed Size (px)
Citation preview
PHALANXParallel Checking of Expressive Heap Assertions
Greta Yorsh Martin VechevEran Yahav Bard Bloom
IBM T.J. Watson Research Center
Motivation
Unrestricted use of aliasing is evil Unrestricted use of aliasing in the
presence of concurrency is ultimate evil
Runtime Errororg.eclipse.swt.SWTException: Graphic is disposed
at org.eclipse.swt.SWT.error(SWT.java:3744) at org.eclipse.swt.SWT.error(SWT.java:3662) at org.eclipse.swt.SWT.error(SWT.java:3633) at org.eclipse.swt.graphics.GC.getClipping(GC.java:2266) at com.aelitis.azureus.ui.swt.views.list.ListRow.doPaint(ListRow.java:260) at com.aelitis.azureus.ui.swt.views.list.ListRow.doPaint(ListRow.java:237) at com.aelitis.azureus.ui.swt.views.list.ListView.handleResize(ListView.java:867) at com.aelitis.azureus.ui.swt.views.list.ListView$5$2.runSupport(ListView.java:406) at org.gudy.azureus2.core3.util.AERunnable.run(AERunnable.java:38) at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35) at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:130) at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3323) at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:2985) at org.gudy.azureus2.ui.swt.mainwindow.SWTThread.<init>(SWTThread.java:183) at org.gudy.azureus2.ui.swt.mainwindow.SWTThread.createInstance(SWTThread.java:67)….
What Happened?
protected void handleRefresh(boolean bForce) {
// ... gc.dispose(); }
protected void handleResize(boolean bForce) {
// ... myGC.getClipping(…) }
GC
gc myGC
Nativeresourc
e
If only I could check…
protected void handleRefresh(boolean bForce) { // ...
// @assert object pointed to by gc is not shared gc.dispose(); }
protected void handleResize(boolean bForce) {
// ... myGC.getClipping(…) }
GC
gc myGC
Nativeresourc
e
Motivating Example II: jdbfpublic class Database {
private ConnectionManager cm; public int insert(...) throws MappingEx { Connection c = cm.getConnection(...); ... } ...}public class ConnectionManager { private Map conns = Collections.synchronizedMap(new HashMap()); public Connection getConnection(String s) throws MappingException { try { ConnectionSource c = conns.get(s); if (c != null) return c.getConnection(); throw new MappingException(...); } catch (SQLEx e) { ... } }}}
public class ConnectionSource { private Connection conn; private boolean used; public Connection getConnection() throws SQLEx { if (!used) { used = true; return conn; } throw new SQLEx(...); }
Running
Thread
Stack
Database
Root
Running
Thread
Stack
HashMap
ConnectionSource
ConnectionSource
Connection Connection
Static
ConnectionSource
Connection
ConnectionManager
ct
Motivating Example II: jdbf
If only I could check…
@invariant: every conncetion is only
reachable from one thread
(avoiding connection manager)
Phalanx Challenges
Expressing heap queries Is object shared? Is object reachable? Is object reachable when avoiding paths
through some other objects? Is object owned? …
Checking heap queries at runtime
Expressing Heap Queries
Use JML Extended with additional primitives
reach(Object o, Object[] avoiding) pred(Object o) dom(Object o1,Object o2) …
Examples
Object o is shared
pred(o).size() > 1
Set of threads that can reach o, while avoiding objects in avoid:
{ Thread t | running().has(t) && (reach(t,avoid).has(o) || reach(stack(t),avoid).has(o)) }
Checking Heap Queries: Wish List
Support wide range of queries We have a nice extended JML +
primitives Overhead low enough to permit
running realistic applications Debugging Program understanding Maybe even production
Checking Heap Queries: First Attempt
We need to traverse the heap to answer our queries
The garbage collector (GC) already traverses the heap periodically
GC can be parallel and leverage available system cores
Piggyback the GC !
Checking Heap Queries:How can we use the GC? reach(o)
Know that objects are reachable, but not whether they are reachable from o
reach(o1,o2) With GC I would only know o1,o2 are
reachable from roots Now what?
reach(o1) reach(o2) = Requires two marked sets Now what?
…
Supported Primitives?
reach(Object o) pred(Object o) reach(Object o, Object[] avoiding) dom(Object o1,Object o2)
Some primitives cannot be computed by piggybacking a GC traversal
What can we do in parallel? Is object o shared?
pred(o).size() > 1
Disjoint reach set? reach(o1) reach(o2) =
Checking Heap Queries:Second Attempt
We need new parallel algorithms
We can use components of a parallel GC as building blocks for our parallel algorithms
New Algorithms Based on GC components
New parallel algorithms for common queries
New operations performed on GC steps New synchronization structures for
computing answers to heap queries
Leverage available system cores
Modified JMLC maps common queries to parallel implementations
Back to our example: isShared
isShared(tm, o)
tm.sources ;
mark-threads(tm, Ta)
trace(tm)
lock(allsources)
allsources allsources tm.sources
unlock(allsources)
if barrier-and-release-master()
if |allsources| > 1 result true
else result false
release-blocked-evaluators()
trace-step(s; t) if (o = t) tm.sources tm.sources { s }
Parallel Checking of isShared
r1
r2
Thread 1
Thread 2
Is shared?
t1.sources = { A }
A
B
t2.sources = { B }
allsources = { A, B }
isShared = true
isObjectOwned(source,target)
isObjectOwned(tm, source, target) { tag-object(tm, source) result false phase skip barrier() mark-roots(tm, Ta) barrier() phase none trace(tm) barrier() if (target Marked) barrier() push-object(tm; source) trace(tm) if barrier-and-release-master() if (target Marked) result true release-blocked-evaluators()}
tag-step(t) if (phase = skip t = target) return false
Parallel Algorithms Query Description Probe
pred(o).size() > 0 Is o pointed to by a heap object?
isHeap(Object o)
pred(o).size() > 1 Is o pointed to by two or more heap objects?
isShared(Object o)
reach(src).has(dst) Is dst reachable from src?
isReachable(Object src, Object dst)
!(exists Object v; reach(o1).has(v) ; reach(o2).has(v))
Is there an object reachable from both o1 and o2?
isDisjoint(Object o1, Object o2)
!(exists Object v ; reach(o).has(v) ; !dom(o,v))
Does o dominate all objects reachable from it?
isUniqueOwner(Object o)
!reach(o1,cut).has(o2) Does every path from o1 to o2 go through an object in cut
reachThrough(Object o1, o2, Object[] cut)
dom(Thread.currentThread(), o)
Does the current thread dominate o?
isObjectOwned(Object o1, Object o2)
…
Experimental Evaluation
Implemented on top of QVM platform IBM J9 production virtual machine Can leverage QVM adaptive overhead
manager (not in this talk) Provide a portable reference
implementation based on JVMTI Less efficient, no parallel algorithms Still useful in some cases
Modified JML Compiler
Speedup / #objects
0 2,000,000 4,000,000 6,000,000 8,000,000 10,000,000 0.00
1.00
2.00
3.00
4.00
5.00
6.00
7.00
JVMTI
QVM 1CPU
QVM 2CPU
QVM 3CPU
QVM 4CPU
QVM 5 CPU
QVM 6 CPU
QVM 7 CPU
QVM 8 CPU
# Objects
Speedup
Time / #cores
1 2 3 4 5 6 7 8 -
2,000
4,000
6,000
8,000
10,000
12,000
10,539
4,906
3,474
2,757 2,301
2,007 1,786 1,631
# Cores
Time (ms)
Probes in Real Applications Disposal of Shared SWT Resources replace code of the form:
exp.dispose();
with code of the form
if (Phalanx.isShared(exp)) Phalanx.warning(”disposal of \ shared resource”+exp) ;
exp.dispose();
Probes in Real Applications Redundant Synchronization
replace code of the form:
synchronized(exp) { ... }
with code of the form
synchronized(exp) {
if(Phalanx.dom(Thread.currentThread(),exp)) Phalanx.warning(”synchronziation on \ an owned object”+exp) ;
...
}
Probes in Real ApplicationsApplicati
on LOC Probe
sViolatio
ns
AOI111,33
3 10 0
Azureus425,36
7 334 16
Freemind 70,483 16 2
Frostwire245,95
9 184 2
JEdit 93,790 66 0
jrisk 20,807 45 12
rssowl 74,280 95 3
tvbrowser105,47
1 40 1
TVLA 57,594 10 0