diff -r 4a8ba65fdec9 README.txt
--- a/README.txt	Wed May 19 12:52:28 2010 +1000
+++ b/README.txt	Thu Jun 17 21:16:57 2010 +1000
@@ -1,3 +1,40 @@
+This is pjbb2005, a fixed workload version of SPECjbb2005.  pjbb2005
+is based on and improves upon a similar modification to SPECjbb2000.
+Contributors to pjbb2000 and pjbb2005 include:
+
+   Steve Blackburn, ANU (maintainer)
+   Martin Hirzel, IBM
+   Robin Garner, ANU
+   Darko Stefanovic, UNM
+
+The original benchmark has been modified in the following ways:
+
+  - to run for a fixed number of transactions (rather than fixed time)
+
+  - to run a number of iterations of the benchmark (specified using
+    the "-n" flag)
+
+  - to call a user-defined callback method at the start and end of
+    each iteration (specified using the "-c" flag)
+
+  - to use a temporary directory for all generated output (so that the
+    benchmark directory does not need to be writeable)
+  
+  - to allow the benchmark to be run from a directory other than the
+    benchmark root
+
+The benchmark harness follows the same API as the DaCapo benchmark
+suite.
+
+The following will run pjbb2005 for two iterations with 8 warehouses
+and 50000 transactions per warehouse:
+
+    java -cp <path to jbb>/jbb.jar:<path to jbb>/check.jar spec.jbb.JBBmain -propfile SPECjbb-8x50000.props -n 2
+
+
+The oringal SPECjbb2005 README follows:
+---
+
   SPECjbb2005 (Java Server Benchmark)
 Release 1.07                  03/15/2006
 
diff -r 4a8ba65fdec9 SPECjbb-4x100.props
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SPECjbb-4x100.props	Thu Jun 17 21:16:57 2010 +1000
@@ -0,0 +1,24 @@
+# pseudojbb05 options
+
+# modify these
+input.starting_number_warehouses=4
+input.increment_number_warehouses=1
+input.ending_number_warehouses=4
+input.pseudojbb_transactions=100
+
+# keep these as is
+input.jvm_instances=1
+input.show_warehouse_detail=false
+input.include_file=SPECjbb_config.props
+input.output_directory=results
+input.suite=SPECjbb
+input.log_level=INFO
+input.deterministic_random_seed=false
+
+# these apply for multi-jvm mode only (seconds)
+input.per_jvm_warehouse_rampup=3
+input.per_jvm_warehouse_rampdown=20
+
+# ramp_up_seconds must be zero, measurement_seconds gets ignored
+input.ramp_up_seconds=0
+input.measurement_seconds=20
diff -r 4a8ba65fdec9 SPECjbb-4x2000.props
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SPECjbb-4x2000.props	Thu Jun 17 21:16:57 2010 +1000
@@ -0,0 +1,24 @@
+# pseudojbb05 options
+
+# modify these
+input.starting_number_warehouses=4
+input.increment_number_warehouses=1
+input.ending_number_warehouses=4
+input.pseudojbb_transactions=2000
+
+# keep these as is
+input.jvm_instances=1
+input.show_warehouse_detail=false
+input.include_file=SPECjbb_config.props
+input.output_directory=results
+input.suite=SPECjbb
+input.log_level=INFO
+input.deterministic_random_seed=false
+
+# these apply for multi-jvm mode only (seconds)
+input.per_jvm_warehouse_rampup=3
+input.per_jvm_warehouse_rampdown=20
+
+# ramp_up_seconds must be zero, measurement_seconds gets ignored
+input.ramp_up_seconds=0
+input.measurement_seconds=20
diff -r 4a8ba65fdec9 SPECjbb-4x50000.props
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SPECjbb-4x50000.props	Thu Jun 17 21:16:57 2010 +1000
@@ -0,0 +1,24 @@
+# pseudojbb05 options
+
+# modify these
+input.starting_number_warehouses=4
+input.increment_number_warehouses=1
+input.ending_number_warehouses=4
+input.pseudojbb_transactions=50000
+
+# keep these as is
+input.jvm_instances=1
+input.show_warehouse_detail=false
+input.include_file=SPECjbb_config.props
+input.output_directory=results
+input.suite=SPECjbb
+input.log_level=INFO
+input.deterministic_random_seed=false
+
+# these apply for multi-jvm mode only (seconds)
+input.per_jvm_warehouse_rampup=3
+input.per_jvm_warehouse_rampdown=20
+
+# ramp_up_seconds must be zero, measurement_seconds gets ignored
+input.ramp_up_seconds=0
+input.measurement_seconds=20
diff -r 4a8ba65fdec9 SPECjbb-8x100.props
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SPECjbb-8x100.props	Thu Jun 17 21:16:57 2010 +1000
@@ -0,0 +1,24 @@
+# pseudojbb05 options
+
+# modify these
+input.starting_number_warehouses=8
+input.increment_number_warehouses=1
+input.ending_number_warehouses=8
+input.pseudojbb_transactions=100
+
+# keep these as is
+input.jvm_instances=1
+input.show_warehouse_detail=false
+input.include_file=SPECjbb_config.props
+input.output_directory=results
+input.suite=SPECjbb
+input.log_level=INFO
+input.deterministic_random_seed=false
+
+# these apply for multi-jvm mode only (seconds)
+input.per_jvm_warehouse_rampup=3
+input.per_jvm_warehouse_rampdown=20
+
+# ramp_up_seconds must be zero, measurement_seconds gets ignored
+input.ramp_up_seconds=0
+input.measurement_seconds=20
diff -r 4a8ba65fdec9 SPECjbb-8x10000.props
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SPECjbb-8x10000.props	Thu Jun 17 21:16:57 2010 +1000
@@ -0,0 +1,24 @@
+# pseudojbb05 options
+
+# modify these
+input.starting_number_warehouses=8
+input.increment_number_warehouses=1
+input.ending_number_warehouses=8
+input.pseudojbb_transactions=10000
+
+# keep these as is
+input.jvm_instances=1
+input.show_warehouse_detail=false
+input.include_file=SPECjbb_config.props
+input.output_directory=results
+input.suite=SPECjbb
+input.log_level=INFO
+input.deterministic_random_seed=false
+
+# these apply for multi-jvm mode only (seconds)
+input.per_jvm_warehouse_rampup=3
+input.per_jvm_warehouse_rampdown=20
+
+# ramp_up_seconds must be zero, measurement_seconds gets ignored
+input.ramp_up_seconds=0
+input.measurement_seconds=20
diff -r 4a8ba65fdec9 SPECjbb-8x50000.props
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SPECjbb-8x50000.props	Thu Jun 17 21:16:57 2010 +1000
@@ -0,0 +1,24 @@
+# pseudojbb05 options
+
+# modify these
+input.starting_number_warehouses=8
+input.increment_number_warehouses=1
+input.ending_number_warehouses=8
+input.pseudojbb_transactions=50000
+
+# keep these as is
+input.jvm_instances=1
+input.show_warehouse_detail=false
+input.include_file=SPECjbb_config.props
+input.output_directory=results
+input.suite=SPECjbb
+input.log_level=INFO
+input.deterministic_random_seed=false
+
+# these apply for multi-jvm mode only (seconds)
+input.per_jvm_warehouse_rampup=3
+input.per_jvm_warehouse_rampdown=20
+
+# ramp_up_seconds must be zero, measurement_seconds gets ignored
+input.ramp_up_seconds=0
+input.measurement_seconds=20
diff -r 4a8ba65fdec9 build.xml
--- a/build.xml	Wed May 19 12:52:28 2010 +1000
+++ b/build.xml	Thu Jun 17 21:16:57 2010 +1000
@@ -20,6 +20,9 @@
     <copy file="${xml}/template-document.xml" tofile="${dist}/xml/template-document.xml"/>
     <copy file="${xml}/jbb-document.dtd" tofile="${dist}/xml/jbb-document.dtd"/>
     <copy file="SPECjbb.props" tofile="${dist}/SPECjbb.props"/>
+    <copy todir="${dist}">
+      <fileset dir="${basedir}" includes="SPECjbb-*.props"/>
+    </copy>
     <copy file="SPECjbb_config.props" tofile="${dist}/SPECjbb_config.props"/>
     <copy file="run.sh" tofile="${dist}/run.sh"/>
     <copy file="run_multi.sh" tofile="${dist}/run_multi.sh"/> 
@@ -42,7 +45,7 @@
     <!-- Put everything in ${tmp} into the jar files -->
 
     <jar jarfile="${jarname1}" basedir="${tmp}"
-         includes="spec/**"
+         includes="*,spec/**,harness/**"
          excludes="spec/jbb/validity/**">
         <manifest>
 	  <attribute name="Main-Class" value="spec.jbb.JBBmain"/>
diff -r 4a8ba65fdec9 runjbb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/runjbb	Thu Jun 17 21:16:57 2010 +1000
@@ -0,0 +1,33 @@
+BMS=build/dist
+VM=$1
+HEAP=${2:-256}
+SIZE=${3:-4x50000}
+PROCS=${4:-all}
+INTERVAL=32m
+shift 4
+OPTS=$*
+
+JIKESRVM=$HOME/jikesrvm/trunk/dist/production_ia32-linux/rvm
+XML=-X:gc:xmlStats=true
+COMPILER="-X:aos:initial_compiler=base -X:aos:enable_recompilation=false"
+RVMEXTRA=-X:processors=$PROCS
+RVMCALLBACK="-c MMTkCallback"
+
+case $VM in
+  measure) JAVA="$JIKESRVM -X:gc:stressFactor=$INTERVAL -X:gc:cohortSize=$INTERVAL $XML $COMPILER $RVMEXTRA $OPTS" ;;
+  markcons) JAVA="$JIKESRVM -X:gc:fixedNursery=4m $XML $COMPILER $RVMEXTRA $OPTS" ;;
+  rvm) JAVA="$JIKESRVM $COMPILER $RVMEXTRA $OPTS" ;;
+  jdk15) JAVA=/opt/jdk1.5.0_07/bin/java ;;
+  jdk16) JAVA=/opt/jdk1.6.0/bin/java ;;
+  j9)    JAVA=/opt/ibm-java2-i386-50/bin/java ;;
+  *)     echo "unrecognised java vm \"$1\""
+         exit 1;;
+esac
+
+PROPS=SPECjbb-${SIZE}.props
+
+export DISPLAY=:0.0
+( cd $BMS
+  echo $JAVA >> /dev/stderr
+  $JAVA -Xms${HEAP}m -Xmx${HEAP}m -cp jbb.jar:check.jar spec.jbb.JBBmain -propfile $PROPS -n 2 $RVMCALLBACK
+)
diff -r 4a8ba65fdec9 src/MMTkCallback.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/MMTkCallback.java	Thu Jun 17 21:16:57 2010 +1000
@@ -0,0 +1,63 @@
+
+
+
+/*
+ * (C) Copyright Department of Computer Science,
+ * Australian National University. 2005
+ */
+
+import harness.Callback;
+
+import java.lang.reflect.Method;
+
+public class MMTkCallback extends Callback {
+  private final String callbackClass = "org.mmtk.plan.Plan";
+    
+  private Method beginMethod, endMethod;
+  private boolean found = false;
+    
+  /**
+   * Locate the class where the harness resides in various versions
+   * of JikesRVM, and then retain Method references to the correct one.
+   */
+  public MMTkCallback() {
+    try {
+      Class<?> harnessClass = Class.forName(callbackClass);
+      beginMethod = harnessClass.getMethod("harnessBegin", (Class[])null);
+      endMethod = harnessClass.getMethod("harnessEnd", (Class[])null); 
+      found = true;
+    } catch (ClassNotFoundException c) {
+      System.err.println("Could not locate "+callbackClass);
+    } catch (SecurityException e) {
+      System.err.println("harness method of "+callbackClass+" is not accessible");
+    } catch (NoSuchMethodException e) {
+      System.err.println("harness method of "+callbackClass+" not found");
+    }
+    if (!found)
+      System.err.println("WARNING: MMTk harness not found.");
+  }
+  
+  @Override
+  public void begin(int iteration, boolean warmup) {
+    super.begin(iteration, warmup);
+    if (!found) return;
+    try {
+      beginMethod.invoke(null, (Object[])null);
+    } catch (Exception e) {
+      throw new RuntimeException("Error running MMTk begin",e);
+    }
+  }
+  
+  @Override
+  public void end(int iteration, boolean warmup) {
+    if (found) {
+      try {
+        endMethod.invoke(null, (Object[])null);
+      } catch (Exception e) {
+        throw new RuntimeException("Error running MMTk end",e);
+      }
+    }
+    super.end(iteration, warmup);
+  }
+}
+  
diff -r 4a8ba65fdec9 src/harness/Callback.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/harness/Callback.java	Thu Jun 17 21:16:57 2010 +1000
@@ -0,0 +1,25 @@
+package harness;
+
+public class Callback {
+  private static final long MS = 1000000;
+  long startTime;
+  long duration;
+
+  public void begin(int iteration, boolean warmup) {
+    startTime = System.nanoTime();
+    System.err.print("===== pjbb2005 starting ");
+    System.err.println((warmup ? "warmup " + iteration : "") + " =====");
+    System.err.flush();
+  }
+
+  public void end(int iteration, boolean warmup) {
+    duration = System.nanoTime() - startTime;
+  }
+
+  public void report(int iteration, boolean warmup) {
+    System.err.print("===== pjbb2005");
+    System.err.print(warmup ? " completed warmup " + iteration : " PASSED");
+    System.err.println(" in " + (duration/MS) + " msec =====");
+    System.err.flush();
+  }
+}
diff -r 4a8ba65fdec9 src/spec/jbb/Company.java
--- a/src/spec/jbb/Company.java	Wed May 19 12:52:28 2010 +1000
+++ b/src/spec/jbb/Company.java	Thu Jun 17 21:16:57 2010 +1000
@@ -45,7 +45,7 @@
     // timing variables:
     private long               rampup_time;
 
-    private long               measurement_time;
+    private long               pseudojbbTransactions;
 
     private TimerData          companyTimerData;
 
@@ -222,14 +222,14 @@
     }
 
     public synchronized void startAutomated(short inWarehouseId,
-            int rampup_time, int measurement_time) {
+            int rampup_time, int pseudojbbTransactions) {
         companyTimerData.zeroTimerData();
         this.rampup_time = rampup_time;
-        this.measurement_time = measurement_time;
+        this.pseudojbbTransactions = pseudojbbTransactions;
         TimerData warehouseTimerData = getTimerDataPtr(inWarehouseId);
         warehouseTimerData.zeroTimerData();
         warehouseTimerData.setRampUpTime(rampup_time);
-        warehouseTimerData.setMeasurementTime(measurement_time);
+        warehouseTimerData.setPseudojbbTransactions(pseudojbbTransactions);
     }
 
     public synchronized void startValidation(short inWarehouseId) {
@@ -443,15 +443,24 @@
             System.out.println(msg); // display rampup start time
             JBButil.SecondsToSleep((int) rampup_time);
         }
-        if (measurement_time > 0) {
+        if (pseudojbbTransactions > 0) {
             msg = "Timing Measurement began " + new Date().toString() + " for "
-                    + df.format(measurement_time / 60.) + " minutes";
+                   + pseudojbbTransactions + " transactions per thread";
             setrunMode(runModes.RECORDING);
             start_time = System.currentTimeMillis();
             JBButil.getLog().info(msg);
             System.out.println(msg); // display start time
             // Wait while user threads do the recorded run
-            JBButil.SecondsToSleep((int) measurement_time);
+            System.out.println("pseudojbb waiting for threads");
+	    synchronized (threadsDoneCountMonitor) {
+                while (threadsDoneCount != MaxWarehouses) {
+                    try {
+                        threadsDoneCountMonitor.wait();
+                    }
+                    catch (InterruptedException e) {
+                    }
+                }
+            }
         }
         end_time = System.currentTimeMillis();
         msg = "Timing Measurement ended " + new Date().toString();
@@ -471,15 +480,7 @@
         setrunMode(runModes.RAMP_DOWN);
         elapsed_time = end_time - start_time;
         System.out.println("");
-        synchronized (threadsDoneCountMonitor) {
-            while (threadsDoneCount != MaxWarehouses) {
-                try {
-                    threadsDoneCountMonitor.wait();
-                }
-                catch (InterruptedException e) {
-                }
-            }
-        }
+        System.out.println("pseudojbb ramped down");
         setrunMode(runModes.STOP);
         synchronized (stopThreadsCountMonitor) {
             while (stopThreadsCount != MaxWarehouses) {
@@ -490,6 +491,7 @@
                 }
             }
         }
+        System.out.println("pseudojbb stopped");
         // print results
         outPropFile.println(propPrefix + "warehouses=" + MaxWarehouses);
         if (JBBmain.multiJVMMode) {
diff -r 4a8ba65fdec9 src/spec/jbb/JBBProperties.java
--- a/src/spec/jbb/JBBProperties.java	Wed May 19 12:52:28 2010 +1000
+++ b/src/spec/jbb/JBBProperties.java	Thu Jun 17 21:16:57 2010 +1000
@@ -46,6 +46,8 @@
 
     public boolean               showWarehouseDetail                       = false;
 
+    public int                   pseudojbbTransactions;
+
     public int                   startingNumberWarehouses;
 
     public int                   incrementNumberWarehouses;
@@ -98,6 +100,16 @@
 
     public JBBProperties(String propertiesFileName) {
         System.out.println("");
+	if (!(new File(propertiesFileName).canRead())) {
+	    String altProps = JBBmain.jbbDirectory.getAbsolutePath() + File.separator + propertiesFileName;
+	    if (!(new File(altProps).canRead())) {
+		JBButil.getLog().log(Level.WARNING,
+				     "ERROR:  Could not load properties from "+propertiesFileName+" or "+altProps+"; please start again");
+		return;
+	    } else {
+		propertiesFileName = altProps;
+	    }
+	}
         System.out.println("Loading properties from " + propertiesFileName);
         try {
             FileInputStream PropertiesFile = new FileInputStream(
@@ -112,6 +124,9 @@
         }
         val = getOptionalProperty("input.include_file");
         if (val != null) {
+	    if (!(new File(val).canRead())) {
+		val = JBBmain.jbbDirectory.getAbsolutePath() + File.separator + val;
+	    }
             try {
                 FileInputStream IncludedPropertiesFile = new FileInputStream(
                         val);
@@ -263,38 +278,25 @@
         if (val != null) {
             tmpValue = Integer.parseInt(val);
             if (tmpValue == 0) {
-                tmpValue = Runtime.getRuntime().availableProcessors();
+                expectedPeakWarehouse = Runtime.getRuntime().availableProcessors();
                 if (jvm_instances > 1 && tmpValue > 1)
-                    expectedPeakWarehouse = Runtime.getRuntime()
-                            .availableProcessors()
+                    expectedPeakWarehouse = Runtime.getRuntime().availableProcessors()
                             / jvm_instances;
                 else
-                    expectedPeakWarehouse = Runtime.getRuntime()
-                            .availableProcessors();
+                    expectedPeakWarehouse = Runtime.getRuntime().availableProcessors();
             }
             else{
-                if(tmpValue == Runtime.getRuntime().availableProcessors()){
-                    System.out.println("Warning: Explicitly setting " + prefix + "expected_peak_warehouse");
-                    System.out.println("requires submission and review by SPEC in order to publish the result.");
-                }
                 expectedPeakWarehouse = tmpValue;
             }
         }
         else {
-            tmpValue = Runtime.getRuntime().availableProcessors();
-            if (jvm_instances > 1 && tmpValue > 1)
-                expectedPeakWarehouse = Runtime.getRuntime()
-                        .availableProcessors()
-                        / jvm_instances;
-            else
-                expectedPeakWarehouse = Runtime.getRuntime()
-                        .availableProcessors();
+            expectedPeakWarehouse = 4;
         }
         PropertiesForBatch.put(prefix + "expected_peak_warehouse", String
                 .valueOf(expectedPeakWarehouse));
         val = getRequiredProperty(prefix + "deterministic_random_seed");
         if (val != null) {
-            deterministicRandomSeed = Boolean.parseBoolean(val);
+            deterministicRandomSeed = val.equals("true");
         }
         else {
             retval = false;
@@ -362,6 +364,10 @@
                 retval = false;
             }
         }
+	val = getOptionalProperty(prefix + "pseudojbb_transactions");
+        if (val != null) {
+            pseudojbbTransactions = Integer.parseInt(val);
+        }
         val = getOptionalProperty(prefix + "starting_number_warehouses");
         if (val != null) {
             startingNumberWarehouses = Integer.parseInt(val);
@@ -456,6 +462,8 @@
         // System.out.println(" forcegc = " + forceGC);
         // System.out.println("steady_state = " + steadyStateFlag);
         // System.out.println("screen_write = " + screenWriteFlag);
+        System.out.println("  pseudojbb_transactions = "
+                + pseudojbbTransactions);
         if (sequenceOfWarehouses == null) {
             System.out.println("  starting_number_warehouses = "
                     + startingNumberWarehouses);
@@ -495,7 +503,8 @@
                 "suite", "log_level", "warehouse_population",
                 "orderlines_per_order", "ramp_up_seconds",
                 "measurement_seconds", "wait_time_percent", "screen_write",
-                "steady_state", "starting_number_warehouses",
+                "steady_state", "pseudojbb_transactions",
+                "starting_number_warehouses",
                 "increment_number_warehouses", "ending_number_warehouses",
                 "sequence_of_number_of_warehouses", "include_file",
                 "override_itemtable_size", "uniform_random_items",
@@ -562,10 +571,7 @@
                 String svalue = PropertiesForBatch.getProperty(propsKey);
                 outRawFile.println(propsKey + "=" + svalue);
             }
-            Integer procsAvail = new Integer(Runtime.getRuntime()
-                    .availableProcessors());
-            outRawFile.println("config.sw.procsAvailtoJava" + "="
-                    + procsAvail.toString());
+            outRawFile.println("config.sw.procsAvailtoJava" + "=" + 4);
         }
         return retval;
     }
diff -r 4a8ba65fdec9 src/spec/jbb/JBBmain.java
--- a/src/spec/jbb/JBBmain.java	Wed May 19 12:52:28 2010 +1000
+++ b/src/spec/jbb/JBBmain.java	Thu Jun 17 21:16:57 2010 +1000
@@ -10,6 +10,8 @@
 
 import spec.jbb.validity.Check;
 import spec.jbb.validity.digest;
+import harness.Callback;
+
 import java.io.*;
 import java.util.*;
 import java.util.logging.ConsoleHandler;
@@ -21,6 +23,7 @@
 import spec.reporter.*;
 import java.net.Socket;
 
+
 public class JBBmain implements Runnable {
     // This goes right after each class/interface statement
     static final String          COPYRIGHT             = "SPECjbb2005,"
@@ -97,6 +100,10 @@
 
     static private PrintStream   outDeliveriesFile     = null;
 
+    static private File          tmpDirectory          = null;
+
+    static public  File          jbbDirectory          = null;
+
     // multi-JVM variables
     static public boolean        multiJVMMode          = false;
 
@@ -114,6 +121,10 @@
 
     JBBProperties                prop;
 
+    /* pseudojbb2005 mods */
+    static private int harnessIteration = 1;
+    static private Callback harness = new Callback();
+
     public void run() {
         TransactionManager transMgr = null;
         // Vector.remove(n) method returns n-element and deletes it
@@ -165,7 +176,7 @@
     }
 
     public void DoARun(Company myCompany, short number_of_warehouses,
-            int rampup_time, int measurement_time) {
+            int rampup_time, int pseudojbbTransactions) {
         JBButil.getLog().entering("spec.jbb.JBBmain", "DoARun");
         short whID;
         testnum++;
@@ -175,7 +186,8 @@
         myCompany.prepareForStart();
         try {
             for (whID = 1; whID <= number_of_warehouses; whID++) {
-                myCompany.startAutomated(whID, rampup_time, measurement_time);
+                myCompany.startAutomated(whID, rampup_time, 
+                                         pseudojbbTransactions);
                 startJBBthread(whID);
                 String msg = "  started user thread for Warehouse " + whID;
                 System.out.println(msg);
@@ -269,6 +281,7 @@
                 cur_warehouses = num_wh;
             }
         }
+	myCompany = null; // RJG
         JBButil.getLog().exiting("spec.jbb.JBBmain", "DOIT");
     }
 
@@ -310,7 +323,7 @@
         }
         else {
             DoARun(myCompany, (short) myCompany.getMaxWarehouses(), 0,
-                    prop.measurementSeconds);
+                    prop.pseudojbbTransactions);
         }
         if (prop.checkThroughput) {
             TimerData companyTimerDataPtr = myCompany
@@ -326,7 +339,56 @@
         return true;
     }
 
-    public String commandLineParser(String args[]) {
+    public String newImprovedCommandLineParser(String args[]) {
+      String propsFileName = defaultPropsFileName;
+      for (int i=0; i < args.length; i++) {
+        if (args[i].charAt(0) == '-') {
+	  if (args[i].equals("-id")) {
+	    i++;
+	    if (i == args.length) {
+              System.out.println("Missing instance ID");
+	      return null;
+	    }
+	    JBBmain.instanceId = Integer.parseInt(args[i]);
+	  } else if (args[i].equals("-propfile")) {
+	    i++;
+	    if (i == args.length) {
+	      System.out.println("Missing iproperties file name");
+              return null;
+            }
+            propsFileName = args[i];
+	  } else if (args[i].equals("-n")) {
+	    i++;
+	    if (i == args.length) {
+	      System.out.println("Missing number of iterations after \"-n\" flag");
+	      return null;
+	    }
+	    JBBmain.harnessIteration = Integer.valueOf(args[i]);
+	  } else if (args[i].equals("-c")) {
+	    i++;
+	    if (i == args.length) {
+	      System.out.println("Missing callback class name after \"-c\" flag");
+	      return null;
+	    }
+	    try {
+	      Class<Callback> harnessClass = (Class<Callback>)Class.forName(args[i]);
+	      JBBmain.harness = harnessClass.newInstance();
+	    } catch (Exception e) {
+	      throw new RuntimeException("Exception thrown while creating harness class "+args[i],e);
+	    }
+	  } else {
+	    System.out.println("Unrecognized parameter "+args[i]);
+	    return null;
+	  }
+	} else {
+	  System.out.println("Unrecognized parameter "+args[i]);
+	  return null;
+	}
+      }
+      return propsFileName;
+    }
+
+    private String commandLineParser(String args[]) {
         String s = null;
         if (args.length == 0) {
             s = defaultPropsFileName;
@@ -480,6 +542,19 @@
     }
 
     public static void main(String args[]) {
+	String jar = JBBmain.class.getProtectionDomain().getCodeSource().getLocation().getPath();
+	if (jar.endsWith("jbb.jar")) {
+	    jbbDirectory = new File(jar.substring(0, jar.length() - "jbb.jar".length()));
+	} else {
+	    System.err.println("Could not discover the path to the jbb jar");
+	    return;
+	}
+        try { 
+	    tmpDirectory = createTempDir();
+	} catch  (IOException e) {
+            System.err.println("Could not create temporary directory");
+	    return;
+	}
         JBBmain main;
         TransactionManager transMgr;
         short whID = 0;
@@ -514,9 +589,9 @@
         try {
             try {
                 scratch1 = new PrintStream(new FileOutputStream(
-                        "JBB.temp.scratch1"));
+			 tmpDirectory.getAbsolutePath() + File.separator + "JBB.temp.scratch1"));
                 scratch2 = new PrintStream(new FileOutputStream(
-                        "JBB.temp.scratch2"));
+                         tmpDirectory.getAbsolutePath() + File.separator + "JBB.temp.scratch2"));
             }
             catch (IOException e) {
                 JBButil.getLog().log(Level.WARNING,
@@ -532,7 +607,8 @@
             tfile = new File("JBB.temp.scratch2");
             tfile.delete();
             main = new JBBmain();
-            main.prop = new JBBProperties(main.commandLineParser(args));
+            //main.prop = new JBBProperties(main.commandLineParser(args));
+            main.prop = new JBBProperties(main.newImprovedCommandLineParser(args));
             if (!main.prop.getProps()) {
                 System.out
                         .println("ERROR:  Properties File error; please start again");
@@ -550,7 +626,7 @@
                 JBBmain.multiJVMMode = true;
             }
             if (!multiJVMMode) {
-                output_directory = main.prop
+                output_directory = tmpDirectory.getAbsolutePath() + File.separator +  main.prop
                         .getOptionalProperty("input.output_directory")
                         + File.separator + "SPECjbbSingleJVM";
                 if (!main.initOutputDir(output_directory)) {
@@ -558,7 +634,7 @@
                 }
             }
             else {
-                String parentDir = main.prop
+                String parentDir = tmpDirectory.getAbsolutePath() + File.separator + main.prop
                         .getOptionalProperty("input.output_directory");
                 RunSequencer currentDirRS = new RunSequencer(parentDir,
                         "SPECjbbMultiJVM.", "");
@@ -701,7 +777,17 @@
                     return;
                 }
             }
+	    for (int i=1; i < harnessIteration; i++) {
+	      harness.begin(i, true);
+              main.doIt();
+              harness.end(i,true);
+              harness.report(i, true);
+              main.flushLog();
+	    }
+	    harness.begin(harnessIteration, false);
             main.doIt();
+	    harness.end(harnessIteration, false);
+            harness.report(harnessIteration, false);
             // And again right after we are finished
             main.flushLog();
             if (JBBProperties.printPropertiesAndArgs) {
@@ -722,8 +808,8 @@
                 }
                 outRawFile.println();
             }
-            main.callReporter(output_directory, outRawFile_name, outRawPrefix,
-                    sequenceNumber);
+            //main.callReporter(output_directory, outRawFile_name, outRawPrefix,
+            //        sequenceNumber);
             outDeliveriesFile.close();
             outRawFile.close();
             // elian: sending FINISHED state
@@ -763,6 +849,8 @@
             for (Handler logHandler : handlers) {
                 logHandler.close();
             }
+	    // Delete the temp directory
+	    recursiveDelete(tmpDirectory);
         }
         //outResultsFile.close();
         System.exit(0);
@@ -810,4 +898,49 @@
             logHandler.flush();
         }
     }
+
+   /**
+     * Create a new temporary directory. Use something like
+     * {@link #recursiveDelete(File)} to clean this directory up since it isn't
+     * deleted automatically
+     * @return  the new directory
+     * @throws IOException if there is an error creating the temporary directory
+     */
+    public static File createTempDir() throws IOException {
+        final File sysTempDir = new File(System.getProperty("java.io.tmpdir"));
+        File newTempDir;
+        final int maxAttempts = 9;
+        int attemptCount = 0;
+        do {
+            attemptCount++;
+            if (attemptCount > maxAttempts) {
+                throw new IOException("The highly improbable has occurred! Failed to create a unique temporary directory after " + maxAttempts + " attempts.");
+            }
+            String dirName = UUID.randomUUID().toString();
+           newTempDir = new File(sysTempDir, dirName);
+        } while (newTempDir.exists());
+        if (newTempDir.mkdirs()) {
+            return newTempDir;
+        } else {
+            throw new IOException("Failed to create temp dir " + newTempDir.getAbsolutePath());
+       }
+   }
+
+   /**
+     * Recursively delete file or directory
+     * @param fileOrDir
+     *          the file or dir to delete
+     * @return
+     *          true iff all files are successfully deleted
+     */
+    public static boolean recursiveDelete(File fileOrDir) {
+        if (fileOrDir.isDirectory()) {
+            // recursively delete contents
+            for (File innerFile: fileOrDir.listFiles()) {
+                if (!recursiveDelete(innerFile))
+                    return false;
+            }
+        }
+        return fileOrDir.delete();
+    }
 }
diff -r 4a8ba65fdec9 src/spec/jbb/TimerData.java
--- a/src/spec/jbb/TimerData.java	Wed May 19 12:52:28 2010 +1000
+++ b/src/spec/jbb/TimerData.java	Thu Jun 17 21:16:57 2010 +1000
@@ -73,7 +73,7 @@
     private long                 rampup_time;                                                            // time
 
     // to run before measuring
-    private long                 measurement_time;                                                       // time
+    private long                 pseudojbbTransactions;                                                       // time
 
     // to run while measuring
     private double               tpmc;                                                                   // transactions
@@ -102,7 +102,7 @@
         standardDeviationTime = new double[Transaction.maxTxnTypes];
         coefficientOfVariationTime = new double[Transaction.maxTxnTypes];
         rampup_time = 0;
-        measurement_time = 0;
+        pseudojbbTransactions = 0;
         useWaits = false;
         tpmc = 0;
         btps = 0;
@@ -138,7 +138,7 @@
         standardDeviationTime = new double[Transaction.maxTxnTypes];
         coefficientOfVariationTime = new double[Transaction.maxTxnTypes];
         rampup_time = 0;
-        measurement_time = 0;
+        pseudojbbTransactions = 0;
         useWaits = false;
         tpmc = 0;
         btps = 0;
@@ -200,9 +200,9 @@
         rampup_time = in_rampup_time;
     }
 
-    public synchronized void setMeasurementTime(long in_measurement_time) {
+    public synchronized void setPseudojbbTransactions(long in_pseudojbbTransactions) {
         // convert seconds to milliseconds
-        measurement_time = in_measurement_time;
+        pseudojbbTransactions = in_pseudojbbTransactions;
     }
 
     public synchronized long getRampUpTime() {
@@ -210,8 +210,8 @@
         return temp;
     }
 
-    public synchronized long getMeasurementTime() {
-        long temp = measurement_time;
+    public synchronized long getPseudojbbTransactions() {
+        long temp = pseudojbbTransactions;
         return temp;
     }
 
diff -r 4a8ba65fdec9 src/spec/jbb/TransactionManager.java
--- a/src/spec/jbb/TransactionManager.java	Wed May 19 12:52:28 2010 +1000
+++ b/src/spec/jbb/TransactionManager.java	Thu Jun 17 21:16:57 2010 +1000
@@ -186,7 +186,7 @@
         int i = 0;
         TimerData warehouseTimerDataPtr = company.getTimerDataPtr(warehouseId);
         long rampup_time = warehouseTimerDataPtr.getRampUpTime();
-        long measurement_time = warehouseTimerDataPtr.getMeasurementTime();
+        long pseudojbbTransactions = warehouseTimerDataPtr.getPseudojbbTransactions();
         // create object to store timer data for this process
         TimerData myTimerData = new TimerData();
         // copy wait times from warehouseTimerData to myTimerData
@@ -206,7 +206,7 @@
             catch (InterruptedException e) {
             }
         }
-        if ((rampup_time > 0) || (measurement_time > 0)) {
+        if ((rampup_time > 0) || (pseudojbbTransactions > 0)) {
             timed = true;
         }
         if (JBButil.getLog().isLoggable(Level.FINEST)) {
@@ -214,7 +214,7 @@
                     "Benchmark " + JBBmain.Version + ": warehouse "
                             + warehouseId);
         }
-        while (this.getrunMode() != Company.runModes.STOP) {
+	for (int iTrans=0; iTrans<pseudojbbTransactions; iTrans++) {
             if ((!timed)
                     && (this.getrunMode() == Company.runModes.DEFAULT_MODE)) {
                 manualSelection();
@@ -247,7 +247,12 @@
                 }
             }
         }
-        if (timed && (this.getrunMode() == Company.runModes.STOP)) {
+	synchronized(company.threadsDoneCountMonitor) {
+            company.threadsDoneCount++;
+            company.threadsDoneCountMonitor.notify();
+            signaled_done = true;
+        }	
+	if (true) {
             elapsed_time = company.getElapsedTime();
             myTimerData.calculateResponseTimeStats();
             double tpmc = myTimerData.updateTPMC(elapsed_time);
diff -r 4a8ba65fdec9 src/spec/jbb/infra/Util/XMLTransactionLog.java
--- a/src/spec/jbb/infra/Util/XMLTransactionLog.java	Wed May 19 12:52:28 2010 +1000
+++ b/src/spec/jbb/infra/Util/XMLTransactionLog.java	Thu Jun 17 21:16:57 2010 +1000
@@ -8,6 +8,7 @@
  */
 package spec.jbb.infra.Util;
 
+import java.io.File;
 import java.io.FileOutputStream;
 import java.io.FileDescriptor;
 import java.util.ArrayList;
@@ -60,7 +61,7 @@
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         try {
             builder = factory.newDocumentBuilder();
-            templateDocument = builder.parse("xml/template-document.xml");
+            templateDocument = builder.parse(spec.jbb.JBBmain.jbbDirectory.getAbsolutePath() + File.separator + "xml/template-document.xml");
         }
         catch (SAXException sxe) {
             // Error generated during parsing)
diff -r 4a8ba65fdec9 src/spec/jbb/validity/Check.java
--- a/src/spec/jbb/validity/Check.java	Wed May 19 12:52:28 2010 +1000
+++ b/src/spec/jbb/validity/Check.java	Thu Jun 17 21:16:57 2010 +1000
@@ -117,7 +117,7 @@
             builder = factory.newDocumentBuilder();
             document = builder.newDocument();
             boolean result = false;
-            result = document.getStrictErrorChecking(); // Comment this line out
+//             result = document.getStrictErrorChecking(); // Comment this line out
             // if compiling with a
             // 1.4 JDK.
             // strictErrorChecking must be true.
diff -r 4a8ba65fdec9 src/spec/reporter/Metrics.java
--- a/src/spec/reporter/Metrics.java	Wed May 19 12:52:28 2010 +1000
+++ b/src/spec/reporter/Metrics.java	Thu Jun 17 21:16:57 2010 +1000
@@ -699,7 +699,8 @@
             // right edge of the graph.
             int x = (int) ((double) result[i].warehouses() * x_factor) - 1;
             int y = (int) (result[i].score() * y_factor);
-            xy[x][y] = 1;
+	    if (0 <= x && x < xy.length && 0 <= y && y < xy[x].length)
+                xy[x][y] = 1;
         }
         if (metrics_2 != null) {
             for (int i = 0; i < metrics_2.result.length; i++) {
@@ -708,7 +709,8 @@
                 // right edge of the graph.
                 int x = (int) ((double) metrics_2.result[i].warehouses() * x_factor) - 1;
                 int y = (int) (metrics_2.result[i].score() * y_factor);
-                xy[x][y] = 2;
+                if (0 <= x && x < xy.length && 0 <= y && y < xy[x].length)
+                    xy[x][y] = 2;
             }
         }
         // 08/25/2000 JG v1.01
@@ -1001,6 +1003,7 @@
             buf.append(dotsGraph(null));
         }
         else {
+            if (true) throw new Error();
             try {
                 Class.forName("java.awt.image.BufferedImage");
                 // 08/30/00 WRR -- v 1.01
diff -r 4a8ba65fdec9 src/spec/reporter/TextiReport.java
--- a/src/spec/reporter/TextiReport.java	Wed May 19 12:52:28 2010 +1000
+++ b/src/spec/reporter/TextiReport.java	Thu Jun 17 21:16:57 2010 +1000
@@ -227,7 +227,6 @@
             testBar(out);
             out.println(metrics.ratioTable());
             out.println();
-            out.println(configSection());
             out.println(metrics.detail());
             out.println("\nSPECjbb2005 Version: ["
                     + results.get("config.benchmark_version", "N/A") + ", "
		     