Date post: | 04-Jan-2016 |
Category: |
Documents |
Upload: | warren-may |
View: | 216 times |
Download: | 2 times |
A Framework for Testing A Framework for Testing Concurrent ProgramsConcurrent Programs
MS Thesis DefenseMS Thesis Defense
Mathias RickenMathias Ricken
Rice UniversityRice University
June 14, 2007June 14, 2007
OrganizationOrganization
IntroductionIntroduction– Unit Testing and ConcurrencyUnit Testing and Concurrency– TractabilityTractability– ContributionsContributions
Improvements to JUnitImprovements to JUnitAnnotations for Concurrency InvariantsAnnotations for Concurrency InvariantsBytecode Rewriting FrameworkBytecode Rewriting Framework– Other ContributionsOther Contributions
ConclusionConclusion– Future WorkFuture Work
Unit TestingUnit Testing
Program
?
Difficult
Sub-program
Sub-program
Sub-program
? ? ?
Less difficultEven less difficult
Unit TestingUnit Testing
Unit tests…Unit tests…– Test a part, not the whole programTest a part, not the whole program– Occur earlierOccur earlier– Automate testingAutomate testing– Serve as documentationServe as documentation– Prevent bugs from reoccurringPrevent bugs from reoccurring– Help keep the shared repository cleanHelp keep the shared repository clean
Effective with a single thread of controlEffective with a single thread of control
Foundation of Unit TestingFoundation of Unit Testing
Unit tests depend on deterministic Unit tests depend on deterministic behaviorbehavior
Known input, expected output…Known input, expected output…
SuccessSuccess correct behaviorcorrect behaviorFailureFailure flawed codeflawed code
Outcome of test is meaningfulOutcome of test is meaningful
Problems Due to ConcurrencyProblems Due to Concurrency
Thread scheduling is nondeterministic and Thread scheduling is nondeterministic and machine-dependentmachine-dependent– Code may be executed under different schedulesCode may be executed under different schedules– Different schedules may produce different resultsDifferent schedules may produce different results
Known input, expected output…Known input, expected output…
SuccessSuccess correct behaviorcorrect behavior in this schedulein this schedule, , may be may be flawedflawed in other schedule in other schedule
FailureFailure flawed codeflawed code
Success of unit test is meaninglessSuccess of unit test is meaningless
Timeliness of the ProblemTimeliness of the Problem
Many programs already use concurrencyMany programs already use concurrency– Often hidden, as part of GUIOften hidden, as part of GUI
Clock speeds have not increased muchClock speeds have not increased much– Most speed increases are due to multiple Most speed increases are due to multiple
cores on one chipcores on one chip
Concurrency must be used to benefit from Concurrency must be used to benefit from newer CPUsnewer CPUs– Increased use of concurrency in the futureIncreased use of concurrency in the future
Possible SolutionsPossible Solutions
Programming Language FeaturesProgramming Language Features– Race FreedomRace Freedom– Deadlock Freedom, Safe LockingDeadlock Freedom, Safe Locking– Atomicity, TransactionsAtomicity, Transactions
– Usually require changes in type systemUsually require changes in type system– Fundamental changeFundamental change
C++ standards: 1998, 2003, 200xC++ standards: 1998, 2003, 200xJava major changes: 1997 (1.0), 2002 (1.4), 2004 Java major changes: 1997 (1.0), 2002 (1.4), 2004 (1.5)(1.5)
Possible SolutionsPossible Solutions
Lock-Free AlgorithmsLock-Free Algorithms– Work on copy and assume no concurrency is Work on copy and assume no concurrency is
present (or current thread will finish first)present (or current thread will finish first)– If there was interference, threads that don’t If there was interference, threads that don’t
finish first redo their workfinish first redo their work
– Require some system support (e.g. compare-Require some system support (e.g. compare-and-swap), then done in librariesand-swap), then done in libraries
– Not all common data structures are practical Not all common data structures are practical and efficient to implement as lock-freeand efficient to implement as lock-free
Possible SolutionsPossible Solutions
Programming Language FeaturesProgramming Language Features– Ensuring that bad things cannot happenEnsuring that bad things cannot happen– May restrict programmersMay restrict programmers
Lock-Free AlgorithmsLock-Free Algorithms– Ensuring that if bad things happen, it’s okEnsuring that if bad things happen, it’s ok– May limit data structures availableMay limit data structures available
Comprehensive TestingComprehensive Testing– Testing if bad things happen in any scheduleTesting if bad things happen in any schedule– Does not prevent problems, but does not limit Does not prevent problems, but does not limit
solutions eithersolutions either
Deciding whether any given program Deciding whether any given program contains an error is undecidablecontains an error is undecidable– Reduction to the halting problemReduction to the halting problem
Program expected to meet an assertionProgram expected to meet an assertion Requires that the program halts first Requires that the program halts first
Program expected to not haltProgram expected to not halt Requires inverse of halting problem Requires inverse of halting problem
Does not imply undecidable for all Does not imply undecidable for all programsprograms
Tractability of Comprehensive TestingTractability of Comprehensive Testing
Test all possible schedulesTest all possible schedules– Concurrent unit tests meaningful againConcurrent unit tests meaningful again
Number of schedules (Number of schedules (NN))– tt: # of threads, : # of threads, ss: # of slices per thread: # of slices per thread
detail
Tractability of Comprehensive TestingTractability of Comprehensive Testing
If program is race-free, we do not have to If program is race-free, we do not have to simulate all thread switchessimulate all thread switches– Threads interfere only at “critical points”: lock Threads interfere only at “critical points”: lock
operations, shared or volatile variables, etc.operations, shared or volatile variables, etc.– Code between critical points cannot affect outcomeCode between critical points cannot affect outcome– Simulate all possible arrangements of blocks Simulate all possible arrangements of blocks
delimited by critical pointsdelimited by critical points
Run dynamic race detection in parallelRun dynamic race detection in parallel– Lockset algorithm (e.g. Eraser by Savage et al)Lockset algorithm (e.g. Eraser by Savage et al)
Tractability of Comprehensive TestingTractability of Comprehensive Testing
Critical Points ExampleCritical Points Example
Thread 1
Thread 2
Local Var 1
Local Var 1
Shared Var
Lock
lock access unlock
lock access unlock
lock access unlock
All accesses protected by
lock
Local variables don’t need
locking
All accesses protected by
lock
All accesses protected by
lock
Fewer critical points than thread switchesFewer critical points than thread switches– Reduces number of schedulesReduces number of schedules– Example:Example: Two threads, but no communicationTwo threads, but no communication
NN = 1 = 1
Unit tests are smallUnit tests are small– Reduces number of schedulesReduces number of schedules
Hopefully comprehensive simulation is tractableHopefully comprehensive simulation is tractable– If not, heuristics are still better than nothingIf not, heuristics are still better than nothing
FeFewer Scheduleswer Schedules
ContributionsContributions
Improvements to JUnitImprovements to JUnit– Detect exceptions and failed assertions in Detect exceptions and failed assertions in
threads other than the main threadthreads other than the main thread
Annotations for Concurrency InvariantsAnnotations for Concurrency Invariants– Express complicated requirements about Express complicated requirements about
locks and threadslocks and threads
Tools for Schedule-Based ExecutionTools for Schedule-Based Execution– Record, deadlock monitorRecord, deadlock monitor– Random delays, random yieldsRandom delays, random yields
OrganizationOrganization
IntroductionIntroduction– Unit Testing and ConcurrencyUnit Testing and Concurrency– TractabilityTractability– ContributionsContributions
Improvements to JUnitImprovements to JUnitAnnotations for Concurrency InvariantsAnnotations for Concurrency InvariantsBytecode Rewriting FrameworkBytecode Rewriting Framework– Other ContributionsOther Contributions
ConclusionConclusion– Future WorkFuture Work
Improvements to JUnitImprovements to JUnit
Uncaught exceptions and failed assertionsUncaught exceptions and failed assertions– Not caught in child threadsNot caught in child threads
Sample JUnit TestsSample JUnit Tests
publicpublic class class Test Test extends extends TestCase {TestCase { public void public void testException() {testException() { throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!"); }} public void public void testAssertion() {testAssertion() { assertEquals(0, 1);assertEquals(0, 1); }}}}
if (0!=1) throw new AssertionFailedError();
}}Both tests
fail.Both tests
fail.
Problematic JUnit TestsProblematic JUnit Tests
publicpublic class class Test Test extends extends TestCase {TestCase { public void public void testException() {testException() { newnew Thread(new Runnable() { Thread(new Runnable() { public void run() {public void run() { throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!"); }} }).start();}).start(); }}}}
newnew Thread(new Runnable() { Thread(new Runnable() { public void run() {public void run() { throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!"); }}}).start();}).start();
throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!");
Main thread
Child thread
Main thread
Child thread
spawns
uncaught!
end of test
success!
Problematic JUnit TestsProblematic JUnit Tests
publicpublic class class Test Test extends extends TestCase {TestCase { public void public void testException() {testException() { newnew Thread(new Runnable() { Thread(new Runnable() { public void run() {public void run() { throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!"); }} }).start();}).start(); }}}}
newnew Thread(new Runnable() { Thread(new Runnable() { public void run() {public void run() { throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!"); }}}).start();}).start();
throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!");
Main thread
Child threadUncaught exception,
test should fail but does not!
Improvements to JUnitImprovements to JUnit
Uncaught exceptions and failed assertionsUncaught exceptions and failed assertions– Not caught in child threadsNot caught in child threads
Thread group with exception handlerThread group with exception handler– JUnit test runs in a separate thread, not main threadJUnit test runs in a separate thread, not main thread– Child threads are created in same thread groupChild threads are created in same thread group– When test ends, check if handler was invokedWhen test ends, check if handler was invoked
Thread Group for JUnit TestsThread Group for JUnit Tests
publicpublic class class Test Test extends extends TestCase {TestCase { public void public void testException() {testException() { newnew Thread(new Runnable() { Thread(new Runnable() { public void run() {public void run() { throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!"); }} }).start();}).start(); }}}}
newnew Thread(new Runnable() { Thread(new Runnable() { public void run() {public void run() { throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!"); }}}).start();}).start();
throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!");
Test thread
Child thread
invokeschecks
TestGroup’s Uncaught Exception Handler
Thread Group for JUnit TestsThread Group for JUnit Tests
publicpublic class class Test Test extends extends TestCase {TestCase { public void public void testException() {testException() { newnew Thread(new Runnable() { Thread(new Runnable() { public void run() {public void run() { throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!"); }} }).start();}).start(); }}}}
newnew Thread(new Runnable() { Thread(new Runnable() { public void run() {public void run() { throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!"); }}}).start();}).start();
throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!");
Test thread
Child thread
Test thread
Child thread
spawns
uncaught!
end of testfailure!
invokes group’s handler
Main thread
spawns and waits resumes
check group’s handler
Improvements to JUnitImprovements to JUnit
Uncaught exceptions and failed assertionsUncaught exceptions and failed assertions– Not caught in child threadsNot caught in child threads
Thread group with exception handlerThread group with exception handler– JUnit test runs in a separate thread, not main threadJUnit test runs in a separate thread, not main thread– Child threads are created in same thread groupChild threads are created in same thread group– When test ends, check if handler was invokedWhen test ends, check if handler was invoked
Detection of uncaught exceptions and failed Detection of uncaught exceptions and failed assertions in child threads that occurred before assertions in child threads that occurred before test’s endtest’s end
Past tense: occurred!
Child Thread Outlives ParentChild Thread Outlives Parent
publicpublic class class Test Test extends extends TestCase {TestCase { public void public void testException() {testException() { newnew Thread(new Runnable() { Thread(new Runnable() { public void run() {public void run() { throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!"); }} }).start();}).start(); }}}}
newnew Thread(new Runnable() { Thread(new Runnable() { public void run() {public void run() { throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!"); }}}).start();}).start();
throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!");
Test thread
Child thread
Test thread
Child thread
spawns
uncaught!
end of testfailure!
invokes group’s handler
Main thread
spawns and waits resumes
check group’s handler
Child Thread Outlives ParentChild Thread Outlives Parent
publicpublic class class Test Test extends extends TestCase {TestCase { public void public void testException() {testException() { newnew Thread(new Runnable() { Thread(new Runnable() { public void run() {public void run() { throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!"); }} }).start();}).start(); }}}}
newnew Thread(new Runnable() { Thread(new Runnable() { public void run() {public void run() { throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!"); }}}).start();}).start();
throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!");
Test thread
Child thread
Test thread
Child thread
spawns
uncaught!end of test
success!
invokes group’s handler
Main thread
spawns and waits resumescheck group’s
handler
Too late!
Improvements to JUnitImprovements to JUnit
Child threads are not required to terminateChild threads are not required to terminate– A test may pass before an error is reachedA test may pass before an error is reached
Detect if any child threads are still aliveDetect if any child threads are still alive– Declare failure if test thread has not waitedDeclare failure if test thread has not waited– Ignore daemon threads, system threads (AWT, RMI, Ignore daemon threads, system threads (AWT, RMI,
garbage collection, etc.)garbage collection, etc.)
Previous schedule is a test failurePrevious schedule is a test failure– Should be prevented by using Should be prevented by using Thread.join()Thread.join()
Enforced JoinEnforced Join
publicpublic class class Test Test extends extends TestCase {TestCase {
public void public void testException() {testException() {
newnew Thread(new Runnable() { Thread(new Runnable() {
public void run() {public void run() {
throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!");
}}
});});
t.start(); … t.join();t.start(); … t.join();
}}
}}
Thread t = Thread t = newnew Thread(new Runnable() { Thread(new Runnable() {
public void run() {public void run() {
throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!");
}}
});});
t.start(); … t.join(); …t.start(); … t.join(); …
throwthrow newnew RuntimeException("booh!"); RuntimeException("booh!");
Test thread
Child thread
LimitationsLimitations
Improvements only check chosen Improvements only check chosen scheduleschedule– A different schedule may still failA different schedule may still fail– Requires comprehensive testing to be Requires comprehensive testing to be
meaningfulmeaningful
May still miss uncaught exceptionsMay still miss uncaught exceptions– Specify absolute parent thread group, not Specify absolute parent thread group, not
relative Cannot detect uncaught exceptions in relative Cannot detect uncaught exceptions in a program’s uncaught exception handler (JLS a program’s uncaught exception handler (JLS limitation)limitation)
details
Testing ConcJUnitTesting ConcJUnit
Replacement for junit.jar or as plugin JAR for Replacement for junit.jar or as plugin JAR for JUnit 4.2JUnit 4.2
Available as binary and source at Available as binary and source at http://www.concutest.org/http://www.concutest.org/
Results from DrJava’s unit testsResults from DrJava’s unit tests– Child thread for communication with slave VM still Child thread for communication with slave VM still
alive in testalive in test– Several reader and writer threads still alive in low Several reader and writer threads still alive in low
level test (calls to level test (calls to join()join() missing) missing)
OrganizationOrganization
IntroductionIntroduction– Unit Testing and ConcurrencyUnit Testing and Concurrency– TractabilityTractability– ContributionsContributions
Improvements to JUnitImprovements to JUnitAnnotations for Concurrency InvariantsAnnotations for Concurrency InvariantsBytecode Rewriting FrameworkBytecode Rewriting Framework– Other ContributionsOther Contributions
ConclusionConclusion– Future WorkFuture Work
Concurrency InvariantsConcurrency Invariants
Has to be called in event threadHas to be called in event thread– TableModelTableModel, , TreeModelTreeModel
May not be called in event threadMay not be called in event thread– invokeAndWait()invokeAndWait()
Have to acquire readers/writers lockHave to acquire readers/writers lock– AbstractDocumentAbstractDocument– DrJava’s documentsDrJava’s documents
Invariants Difficult to DetermineInvariants Difficult to Determine
May be found inMay be found in– Javadoc commentsJavadoc comments– Only in internal commentsOnly in internal comments– WhitepapersWhitepapers
Often not documented at allOften not documented at all
Errors not immediately evidentErrors not immediately evident
Impossible to check automaticallyImpossible to check automatically
Java AnnotationsJava Annotations
Add invariants as annotationsAdd invariants as annotations
@NotEventThread@NotEventThreadpublic static void invokeAndWait(public static void invokeAndWait( Runnable r) { … } Runnable r) { … }
Process class filesProcess class files– Find uses of annotationsFind uses of annotations– Insert bytecode to check invariants at method Insert bytecode to check invariants at method
beginningbeginning
Advantages of AnnotationsAdvantages of Annotations
Java Language constructsJava Language constructs– Syntax checked by compilerSyntax checked by compiler
Easy to apply to part of the programEasy to apply to part of the program– e.g. when compared to a type system changee.g. when compared to a type system change
Light-weightLight-weight– Negligible runtime impact if not debugging (slightly Negligible runtime impact if not debugging (slightly
bigger class files)bigger class files)
Automatic CheckingAutomatic Checking
Predicate AnnotationsPredicate Annotations
In annotation definition, specify In annotation definition, specify static static
booleanboolean Java method Java method– Method must be callable from every contextMethod must be callable from every context
completely static and public completely static and public
Data in annotation, method arguments and Data in annotation, method arguments and value of value of thisthis passed when method passed when method invokedinvoked
Predicate Annotation ExamplePredicate Annotation Example
@PredicateLink(value=Predicates.class,@PredicateLink(value=Predicates.class,
method="example",method="example",
arguments=true)arguments=true)
publicpublic @ @interfaceinterface ExampleAnnotation { ExampleAnnotation {
String foo;String foo;
}}
Definition
Refers to Predicates.example
Predicate Annotation ExamplePredicate Annotation Example
public class public class TestCode {TestCode {
@ExampleAnnotation(foo="test")@ExampleAnnotation(foo="test")
public void public void test(test(intint param) { … } param) { … }
}}
……
TestCode t = TestCode t = newnew TestCode(); t.test(5); TestCode(); t.test(5);
Usage
Call
Predicate Annotation ExamplePredicate Annotation Example
public class public class Predicates {Predicates {
public static boolean public static boolean example(example(
Object this0,Object this0,
intint param, param,
String foo) {String foo) {
returnreturn (foo.length()<param); (foo.length()<param);
}}
Predicate Annotation ExamplePredicate Annotation Examplepublic class public class TestCode {TestCode { @ExampleAnnotation(foo="@ExampleAnnotation(foo="testtest")") public void public void test(test(intint param){…} param){…}}}……TestCode TestCode tt = = newnew TestCode(); TestCode();tt.test(.test(55););
@PredicateLink(value=@PredicateLink(value=PredicatesPredicates.class,.class,
method="method="exampleexample",",
arguments=true)arguments=true)
publicpublic @ @interfaceinterface ExampleAnnotation { ExampleAnnotation {
String foo;String foo;
}}
public class public class PredicatesPredicates { {
public static boolean public static boolean exampleexample((
Object Object this0this0,,
intint paramparam,,
String String foofoo) {) {
returnreturn (foo.length()<param); // (foo.length()<param); // this0==tthis0==t, , param==5param==5, , foo=="test"foo=="test"
}}
Invariant Annotation LibraryInvariant Annotation Library
@OnlyEventThread@OnlyEventThread, , @NotEventThread@NotEventThread@OnlyThreadWithName@OnlyThreadWithName@NotNullArgument@NotNullArgument
@DistinctArguments@DistinctArguments, , @SameArguments@SameArguments
@OnlySynchronizedThis@OnlySynchronizedThis, , @NotSynchronizedThis@NotSynchronizedThis
@OnlySynchronizedArgument@OnlySynchronizedArgument,, @NotSynchronizedArgument@NotSynchronizedArgument
etc. (ca. 80 annotations)etc. (ca. 80 annotations)
Problem: Multiple AnnotationsProblem: Multiple Annotations
Java does not allow the same annotation Java does not allow the same annotation class multiple timesclass multiple times
@@OnlyThreadWithNameOnlyThreadWithName("foo")("foo")
@@OnlyThreadWithNameOnlyThreadWithName("bar") // error("bar") // error
void void testMethod() { … }testMethod() { … }
Conjunctions, disjunctions and negations?Conjunctions, disjunctions and negations?
Annotation Subclasses?Annotation Subclasses?
Let annotation extend a supertype?Let annotation extend a supertype?
publicpublic @ @interfaceinterface Invariant { } Invariant { }publicpublic @ @interfaceinterface OnlyThreadWithName OnlyThreadWithName extendsextends Invariant { String name(); } Invariant { String name(); }publicpublic @ @interfaceinterface And And extendsextends Invariant { Invariant { Invariant[] terms();Invariant[] terms();}}
Subtyping not allowed for annotationsSubtyping not allowed for annotations
Work-AroundWork-Around
Different meta-annotation, Different meta-annotation, @Combine@Combine
@Combine@Combine(Combine.Mode.AND)(Combine.Mode.AND)publicpublic @ @interfaceinterface SeveralNames { SeveralNames { OnlyThreadWithName[] value();OnlyThreadWithName[] value();}}
@SeveralNames({@OnlyThreadWithName("foo"),@SeveralNames({@OnlyThreadWithName("foo"), @OnlyThreadWithName("bar")})@OnlyThreadWithName("bar")})void void testMethod() { … }testMethod() { … }
Combine AnnotationsCombine Annotations
May only contain invariant annotationsMay only contain invariant annotations– Predicate annotationsPredicate annotations– Combine annotationsCombine annotations– Arrays of the aboveArrays of the above
Predicate method automatically generatedPredicate method automatically generated– Calls member predicate methodsCalls member predicate methods– Accumulates using AND, OR or NOTAccumulates using AND, OR or NOT
NOT first negates, then uses ANDNOT first negates, then uses AND
Default mode is ORDefault mode is OR
De Morgan’s Law: NOT (a OR b) = (NOT a) AND (NOT b)De Morgan’s Law: NOT (a OR b) = (NOT a) AND (NOT b)
Invariants As Class AnnotationInvariants As Class Annotation
Short-hand for annotating all methodsShort-hand for annotating all methods
What about methods already introduced in a What about methods already introduced in a super class, e.g. super class, e.g. Object.notify()Object.notify()??What about methods introduced in subclasses?What about methods introduced in subclasses?
@Invariant@Invariantclassclass A { A { voidvoid foo() { … } foo() { … } voidvoid bar() { … } bar() { … }}}
classclass A { A { @Invariant@Invariant voidvoid foo() { … } foo() { … } @Invariant@Invariant voidvoid bar() { … } bar() { … }}}
Invariants As Class AnnotationInvariants As Class Annotation
Apply invariants on a class only to methods Apply invariants on a class only to methods introduced in the class or subclassesintroduced in the class or subclasses
classclass A { A {
public voidpublic void foo() { … } foo() { … }
}}
@Invariant // only applies to bar()@Invariant // only applies to bar()
classclass B extends A { B extends A {
public voidpublic void bar() { … } bar() { … }
}}
Invariant InheritanceInvariant Inheritance
Invariants on a methodInvariants on a method– Apply to the method and all overriding methods in Apply to the method and all overriding methods in
subclassessubclasses
Invariants on a classInvariants on a class– Apply to all methods introduced in that class or Apply to all methods introduced in that class or
subclassessubclasses
Methods can have invariants defined elsewhereMethods can have invariants defined elsewhere
All annotations describe requirements for the All annotations describe requirements for the client (and, due to subclassing, for subclasses)client (and, due to subclassing, for subclasses)– Allows frameworks to describe requirementsAllows frameworks to describe requirements– Description “thread-safe” is often wrongDescription “thread-safe” is often wrong
Invariant SubtypingInvariant Subtyping
To maintain substitutability, subclasses may not To maintain substitutability, subclasses may not strengthen invariantsstrengthen invariants
Invariants can be modeled as special input Invariants can be modeled as special input parameterparameter– Tuple of invariants (“record” in λ calculus [Pierce])Tuple of invariants (“record” in λ calculus [Pierce])– Subtyping rules for records declare the “wider” record Subtyping rules for records declare the “wider” record
as subtypeas subtype– In function types, parameter types are contravariant In function types, parameter types are contravariant
II00 = {}, I = {}, I11 = {inv = {inv11}, I}, I22 = {inv = {inv11,inv,inv22}, I}, I22 <: I <: I11 <: I <: I00
FF0 = 0 = II00 →→ ·, F ·, F1 = 1 = II11 →→ ·, F ·, F2 = 2 = II22 →→ ·, F ·, F00 <: F <: F11 <: F <: F22
Invariant SubtypingInvariant SubtypingAnalyze methods with invariants as parameterAnalyze methods with invariants as parameter
Invariants subtyping: A Invariants subtyping: A <@<@ B B <@<@ C C
IIAA = {}, I = {}, IBB = {inv = {inv11}, I}, ICC = {inv = {inv11,inv,inv22}; I}; ICC <: I <: IBB <: I <: IAA
FFA = A = IIAA →→ ·, F ·, FB = B = IIBB →→ ·, F ·, FC = C = IICC →→ ·; F ·; FAA <: F <: FBB <: F <: FCC
Java subtyping:Java subtyping: C <: B <: A C <: B <: A
classclass A { A {
voidvoid f() f() { … };{ … };}}
classclass B B extendsextends A { A { @Inv1@Inv1 voidvoid f() f() { … };{ … };}}
classclass C C extendsextends B { B { @Inv2@Inv2 voidvoid f() f() { … };{ … };}}
Detection of Subtyping ProblemsDetection of Subtyping Problems
If Java subtyping and invariant subtyping If Java subtyping and invariant subtyping disagree (A <: B but B disagree (A <: B but B <@<@ A) A)– Substitutability not maintainedSubstitutability not maintained– Statically emit warningStatically emit warning
Detect if client subclasses do not use Detect if client subclasses do not use framework classes as prescribedframework classes as prescribed– Safer multithreaded frameworksSafer multithreaded frameworks
Java API AnnotationsJava API Annotations
Started to annotate methods in Java APIStarted to annotate methods in Java API– 30 whole classes, 44 individual methods30 whole classes, 44 individual methods
Community project at Community project at http://http://community.concutest.orgcommunity.concutest.org//– Anyone can suggest annotationsAnyone can suggest annotations– Vote on suggested annotationsVote on suggested annotations– Browse by class or annotation typeBrowse by class or annotation type
Annotations can be extracted into XMLAnnotations can be extracted into XML– Share annotationsShare annotations– Add checks without needing source codeAdd checks without needing source code
Testing Invariant CheckerTesting Invariant Checker
Annotated two DrJava versionsAnnotated two DrJava versions– 3/26/20043/26/2004– 9/2/20069/2/2006
Ran test suite, logged invariant violationsRan test suite, logged invariant violations– 2004: 18.83% failed2004: 18.83% failed– 2006: 11.03% failed2006: 11.03% failed
2006 version easier to annotate2006 version easier to annotate– Better documentation of invariantsBetter documentation of invariants
details
OrganizationOrganization
IntroductionIntroduction– Unit Testing and ConcurrencyUnit Testing and Concurrency– TractabilityTractability– ContributionsContributions
Improvements to JUnitImprovements to JUnitAnnotations for Concurrency InvariantsAnnotations for Concurrency InvariantsBytecode Rewriting FrameworkBytecode Rewriting Framework– Other ContributionsOther Contributions
ConclusionConclusion– Future WorkFuture Work
Bytecode RewritingBytecode Rewriting
Except for JUnit, all tools use bytecode rewritingExcept for JUnit, all tools use bytecode rewriting– Class files easier to parse than sourceClass files easier to parse than source– Works for classes without source (Java API)Works for classes without source (Java API)– Can perform changes on-the-flyCan perform changes on-the-fly
Adding code to detect propertiesAdding code to detect properties– ““instrumentation”instrumentation”
Offline and on-the-flyOffline and on-the-fly– Offline:Offline: Class file Class file class file tool class file tool– On-the-fly: On-the-fly: Custom class loaderCustom class loader
Local vs. GlobalLocal vs. Global
Changes can be done byChanges can be done by– modifying one method (local)modifying one method (local)– all code that calls the method (global)all code that calls the method (global)
Local instrumentation usually betterLocal instrumentation usually better– Fewer changes, less bytecodeFewer changes, less bytecode– Harder to make a partial instrumentation if Harder to make a partial instrumentation if
globalglobal
Not all instrumentations can be done locallyNot all instrumentations can be done locally– If method is native, no class file existsIf method is native, no class file exists
Other ContributionsOther Contributions
Recording schedulesRecording schedules– thread ID/typethread ID/type– thread ID/type/object ID/class/method/PCthread ID/type/object ID/class/method/PC
Deadlock detectorDeadlock detector– thread ID/type/object ID recording requiredthread ID/type/object ID recording required– Creates wait graph for each thread and lockCreates wait graph for each thread and lock– Cycle in graph implies deadlockCycle in graph implies deadlock
Random Sleeps/YieldsRandom Sleeps/Yields
Randomly insert sleeps or yield before or after Randomly insert sleeps or yield before or after critical pointscritical pointsExample: If a Example: If a notify()notify() is delayed, a is delayed, a wait()wait() may time out.may time out.
Can detect a number of sample problemsCan detect a number of sample problems
Have not studied probabilities or durations for Have not studied probabilities or durations for sleeps/yieldssleeps/yields– One inserted delay may negatively impact a second One inserted delay may negatively impact a second
inserted delayinserted delayExample: If both Example: If both notify()notify() and and wait()wait() are delayed. are delayed.
OrganizationOrganization
IntroductionIntroduction– Unit Testing and ConcurrencyUnit Testing and Concurrency– TractabilityTractability– ContributionsContributions
Improvements to JUnitImprovements to JUnitAnnotations for Concurrency InvariantsAnnotations for Concurrency InvariantsBytecode Rewriting FrameworkBytecode Rewriting Framework– Other ContributionsOther Contributions
ConclusionConclusion– Future WorkFuture Work
ConclusionConclusion
Improved JUnit now detects problems in Improved JUnit now detects problems in other threadsother threads– Only in chosen scheduleOnly in chosen schedule– Needs schedule-based executionNeeds schedule-based execution
Annotations ease documentation and Annotations ease documentation and checking of concurrency invariantschecking of concurrency invariants– Open-source library of Java API invariantsOpen-source library of Java API invariants
Support programs for schedule-based Support programs for schedule-based executionexecution
Future WorkFuture Work
Schedule-Based ExecutionSchedule-Based Execution– Replay given scheduleReplay given schedule– Generate possible schedulesGenerate possible schedules– Dynamic race detectionDynamic race detection– Probabilities/durations for random Probabilities/durations for random
yields/sleepsyields/sleeps
Extend annotations to Floyd-Hoare logicExtend annotations to Floyd-Hoare logic– Preconditions, postconditionsPreconditions, postconditions– Representation invariantsRepresentation invariants
Many Thanks To…Many Thanks To…
My advisorMy advisor– Corky CartwrightCorky Cartwright
My committee membersMy committee members– Walid TahaWalid Taha– Bill SchererBill Scherer
My friendsMy friends– JavaPLT, CS and RiceJavaPLT, CS and Rice
NFS and Texas ATPNFS and Texas ATP– For partially providing fundingFor partially providing funding
Extra SlidesExtra Slides
Extra: Number of SchedulesExtra: Number of Schedules
back
Product of s-combinations
For thread 1: choose s out of ts time slicesFor thread 2: choose s out of ts-s time slices…For thread t-1: choose s out of 2s time slicesFor thread t-1: choose s out of s time slices
Writing s-combinations using factorial
Cancel out terms in denominator and next numerator
Left with (ts)! in numerator and t numerators with s!
Extra: LimitationsExtra: Limitations
May still miss uncaught exceptionsMay still miss uncaught exceptions– Specify absolute parent thread group, not Specify absolute parent thread group, not
relative (rare)relative (rare)Koders.com: 913 matches Koders.com: 913 matches ThreadGroupThreadGroup vs. vs. 49,329 matches for 49,329 matches for ThreadThread
– Cannot detect uncaught exceptions in a Cannot detect uncaught exceptions in a program’s uncaught exception handler (JLS program’s uncaught exception handler (JLS limitation)limitation)
Koders.com: 32 method definitions for Koders.com: 32 method definitions for uncaughtExceptionuncaughtException method method
back
Generic Annotations?Generic Annotations?
Write Write @And@And as generic annotation? as generic annotation?
publicpublic @ @interfaceinterface And<T> { And<T> { T[] terms();T[] terms();}}publicpublic @ @interfaceinterface OnlyThreadWithName { OnlyThreadWithName { String name();String name();}}
Generics not allowed in annotationsGenerics not allowed in annotations
Extra: DrJava StatisticsExtra: DrJava Statistics
20042004736736
61061036369090
511651164161416196596518.83%18.83%
10710711
Unit testsUnit testspassedpassedfailedfailednot runnot run
InvariantsInvariantsmetmetfailedfailed% failed% failed
KLOCKLOC““event thread”event thread”
20062006881881
8818810000
344123441230616306163796379611.0311.03
1291299999
back