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.