USING CALFUZZER
This file is meant to explain how you can use calfuzzer to find data
races or deadlocks for your project.
First, download and install calfuzzer from
http://srl.cs.berkeley.edu/~ksen/calfuzzer. You will need to download
http://srl.cs.berkeley.edu/~ksen/calfuzzer/calfuzzer.tar.gz and unpack
it. You need pre-installed Sun’s JDK 1.5 (or later, hopefully) for
Windows or Linux, or Apple’s latest JDK for Mac OS X. You also need
Apache’s ANT (http://ant.apache.org/) for building and running your
code. On my Mac, all of this was already installed. Follow the
instructions on the web page to build the system and test that it
works.
Next, you need to modify the run.xml file in the root of the calfuzzer
directory so that it can work for your project. Find the part of the
file that reads
and then just below that add the following:
The most important lines are these:
The first line says that calfuzzer is to instrument and run the
program in the XXX directory, which is the "root" of your project.
YOU SHOULD CHANGE XXX TO BE THE FULL PATH OF WHERE YOU KEEP YOUR
PROJECT. For example, my project is kept in
/Users/mwhicks/courses/current/projects/p5 on my Mac, so I would
change XXX to be this directory. If you are using Eclipse to do your
development, you might include the root directory of your Eclipse
project.
The next two lines indicate where to find the class files. This
directory is assumed to be the classes subdirectory of your root
directory. If you are storing your .java files in your root
directory, just make a classes directory and copy your .class files
there after you compile your java source. Note that since the classes
are in the metro package, the classfiles will actually have to be
in the classes/metro directory. If you are using Eclipse
for your project, you want to set the root directory to be the
root directory of your Eclipse project. Then you would change the
above lines to be
This is because classes are stored in the bin directory, not a classes
directory. (In actuality, your classes will be in bin/metro, but
that should be taken care of for you if all works out.)
The next line in run.xml indicates the name of the class whose main()
method should be invoked; we have indicated Simulation.
The last line indicates what arguments to provide to this class when
it is run. These are determined by command-line parameters that you
provide when you run calfuzzer; see below.
Now, from the calfuzzer directory, you should be able to run your
calfuzzed program as follows:
ant -f run.xml -Djavato.app.command=simulate -Djavato.app.file=pub6.in p5
the -Djavato.app.command=simulate indicates that you want to run the
simulate target, and -Djavato.app.file=pub6.in indicates you want to
run it on file pub6.in. If you wanted to display the simulation state
for the output in pub3.in, you'd run
ant -f run.xml -Djavato.app.command=display -Djavato.app.file=pub3.in p5
One note: if you change your .java source files you need to recompile
them (and copy them to your classes directory if necessary); the
run.xml file will not recompile for you. Eclipse always is
recompiling your files in the background, so you should be in good
shape there.
USING CALFUZZER WITH INSTRUMENTED LIBRARY CLASSES
By default, calfuzzer will use the standard library classes.
Therefore, if you introduce a data race that would manifest in one of
these classes (e.g., because you have two threads store into an
ArrayList at the same time) calfuzzer will not notice it. To get
calfuzzer to find such problems, you need to use library classes that
it provides. Here's how you might do that.
First, for each .java source file you need to edit import statements
that refer to library classes to refer to the calfuzzer versions. You
do this by changing all prefixes java.util and java.lang to be
benchmarks.instrumented.java15.util and
benchmarks.instrumented.java15.lang, respectively. For example,
suppose you have the following Foo.java file:
import java.util.Map;
import java.util.HashMap;
public class Foo {
Map map = new HashMap();
public void foo() {
map.put("hello","goodbye");
}
}
Then you simply change the import statements, and leave the rest of
the file alone:
import benchmarks.instrumented.java15.util.Map;
import benchmarks.instrumented.java15.util.HashMap;
public class Foo {
Map map = new HashMap();
public void foo() {
map.put("hello","goodbye");
}
}
Next, you need to recompile these files. To do so, you have to modify
the CLASSPATH to be able to find the instrumented classes. You can do
this by setting the environment variable CLASSPATH to include the
calfuzzer/classes directory. For example, on Linux or MacOS, you
could change to the p5/ directory and then do
CLASSPATH=$CLASSPATH:../../. javac *.java
This extends the classpath with the directory ../../. when invoking
the javac command, so that it finds the necessary files.
If you are using Eclipse to build your project, you can adjust the
project build path. Right-click on the project name then choose Build
Path and then Configure Build Path. Click the "Add External Class
Folder" button on the dialog that appears and browse to and select the
calfuzzer/classes folder. This will allow Eclipse to find the
calfuzzer libraries when it compiles your source.
Once you've recompiled everything, you can go back to the calfuzzer
main directory and redo the run.xml command. Now it may find races
occurring within the instrumented library classes. These will be due
to errors in your code, not due to errors in the library classes.
This often occurs because library classes assume they are being used
in a single-threaded program, and you should be adding appropriate
synchronization if you are using them in a concurrent setting.