/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Feb 21, 2007
*/
package com.bigdata.testutil;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Vector;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import junit.framework.TestCase2;
import org.apache.log4j.Logger;
import org.apache.system.SystemUtil;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ext.DefaultHandler2;
import org.xml.sax.ext.EntityResolver2;
import com.bigdata.util.NV;
import com.bigdata.util.PropertyUtil;
import com.bigdata.util.config.NicUtil;
/**
* A harness for running comparison of different configurations.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public class ExperimentDriver {
/**
* Logger.
*/
protected static final Logger log = Logger.getLogger(ExperimentDriver.class);
protected static final boolean INFO = log.isInfoEnabled();
/**
* Interface for a result, which is a set of ordered name-value pairs.
*/
public static class Result extends TreeMap<String,String>{
/**
*
*/
private static final long serialVersionUID = 5726970069639981728L;
/**
* Converts an exception into a result containing an "Error" column
* having {@link Throwable#getMessage()} as its value and a "StackTrace"
* colukn and having the stack trace (with newlines replaced by ";" and
* carrige returns and tabs removed) as its value.
*
* @param t
* The exception.
*/
public static Result errorFactory(Throwable t) {
StringWriter w = new StringWriter();
t.printStackTrace(new PrintWriter(w));
String trace = w.toString();
trace = trace.replace("\n", "; ");
trace = trace.replace("\r", "");
trace = trace.replace("\t", "");
Result result = new Result();
result.put("Error", t.getMessage() );
result.put("StackTrace", trace );
return result;
}
public String toString() {
return toString(false);
}
/**
* Converts to a human readable representation using {name=value, ...}.
* The attributes are listed in sorted order.
*/
public String toString(boolean newline) {
StringBuilder sb = new StringBuilder();
Iterator<Map.Entry<String,String>> itr = entrySet().iterator();
boolean first = true;
while(itr.hasNext()) {
if(!first) {
sb.append(newline?"\n":", ");
}
Map.Entry<String,String> entry = itr.next();
sb.append(entry.getKey()+"="+entry.getValue());
first = false;
}
return sb.toString();
}
}
/**
* Interface for tests that can be run by {@link ExperimentDriver}.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public static interface IComparisonTest {
/**
* ala JUnit, but allows us to run {@link com.bigdata.journal.ProxyTestCase}s as well.
*
* @param properties May be used to configure the test fixture.
*
* @throws Exception
*/
public void setUpComparisonTest(Properties properties) throws Exception;
/**
* Run a test.
*
* @param properties
* The properties used to configure the test.
*
* @return The test result to report.
*/
public Result doComparisonTest(Properties properties) throws Exception;
/**
* ala JUnit, but allows us to run {@link com.bigdata.journal.ProxyTestCase}s as well.
*
* @throws Exception
*/
public void tearDownComparisonTest() throws Exception;
}
/**
* Converts a map to human readable representation using a tab delimited
* format. The attributes are listed in order by the given column names. If
* an attribute is not present then an empty cell is output.
*
* @param cols
* The column names.
* @param showAll
* When true, any attributes not named in <i>cols</i> are added
* after the last column named in <i>cols</i>. Since there are
* no declared columns for these attributes they are written as
* [name=value].
*/
static public String toString(Map<? extends Object,? extends Object> data,String[] cols,boolean showAll) {
final StringBuilder sb = new StringBuilder();
/*
* Build a map in which all keys and values are converted to strings. We
* will remove entries from this temporary map as they are emitted under
* the appropriate column. This is an ordered map so that [showAll] will
* place any additional columns into an order.
*/
final Map<String,String> tmp = new TreeMap<String,String>();
{
Iterator itr = data.entrySet().iterator();
while(itr.hasNext()) {
Map.Entry entry = (Map.Entry)itr.next();
tmp.put(""+entry.getKey(), ""+entry.getValue());
}
}
/*
* Handle the columns that were named by the caller.
*/
for(int i=0; i<cols.length; i++) {
String col = cols[i];
String val = tmp.remove(col); // remove as we go.
if (val != null)
sb.append(val); // iff value defined for that col.
sb.append("\t"); // tab delimited.
}
/*
* Process any remaining columns.
*/
if(showAll) {
Iterator<Map.Entry<String,String>> itr = tmp.entrySet().iterator();
while(itr.hasNext()) {
Map.Entry<String,String> entry = itr.next();
sb.append(entry.getKey()+"="+entry.getValue()+"\t");
}
}
return sb.toString();
}
/**
* An experimental condition.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public static class Condition {
public final Properties properties;
public Result result;
public Condition(Properties properties) {
this.properties = PropertyUtil.flatCopy(properties);
}
public Condition(Map<String,String> properties) {
this.properties = new Properties();
Iterator<Map.Entry<String,String>> itr = properties.entrySet().iterator();
while(itr.hasNext()) {
Map.Entry<String,String> entry = itr.next();
this.properties.setProperty(entry.getKey(),entry.getValue());
}
}
}
/**
* Accepts a list of conditions and an array of NV[]s and returns a new list
* of conditions in each original condition has been expanded into N new
* conditions, one per element of the NV[]s array. This can be used to
* systematically build up hypercubes in the experimental design that can
* then be analyzed with a pivot table.
*
* @param conditions
* @param a
* @return
*/
public static List<Condition> apply(List<Condition> conditions, NV[]a) {
List<Condition> ret = new LinkedList<Condition>();
for(int i=0; i<a.length; i++) {
Iterator<Condition> itr = conditions.iterator();
while(itr.hasNext()) {
Condition c = itr.next();
Properties properties = new Properties(c.properties);
properties.put(a[i].getName(),a[i].getValue());
ret.add(new Condition(properties));
}
}
System.err.println("There are now "+ret.size()+" conditions");
return ret;
}
/**
* Variant that allows multiple factors to vary at a time.
* @param conditions
* @param a
* @return
*/
public static List<Condition> apply(List<Condition> conditions, NV[][]a) {
List<Condition> ret = new LinkedList<Condition>();
for(int i=0; i<a.length; i++) {
Iterator<Condition> itr = conditions.iterator();
while(itr.hasNext()) {
Condition c = itr.next();
Properties properties = new Properties(c.properties);
for(int j=0; j<a[i].length; j++) {
properties.put(a[i][j].getName(),a[i][j].getValue());
}
ret.add(new Condition(properties));
}
}
System.err.println("There are now "+ret.size()+" conditions");
return ret;
}
/**
* Returns a list that contains N copies of the original conditions.
*
* @param nruns
* The #of copies to make.
*
* @return The new set of conditions.
*/
static public Collection<Condition> replicateConditions(int nruns,
Collection<Condition> conditions) {
List<Condition> ret = new LinkedList<Condition>();
for (Condition c : conditions) {
for(int i=0; i<nruns; i++) {
ret.add( c );
}
}
return ret;
}
/**
* Randomize the conditions.
*
* @param conditions
* @return
*/
static public Collection<Condition> randomize(Collection<Condition> conditions) {
Condition[] a = conditions.toArray(new Condition[conditions.size()]);
int[] order = TestCase2.getRandomOrder(a.length);
List<Condition> ret = new ArrayList<Condition>(a.length);
// add to result in permutated order.
for( int i : order ) {
ret.add(a[i]);
}
return ret;
}
/**
* Models an experiment.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
protected static class Experiment {
public final String className;
public final Map<String,String> defaultProperties;
public final Collection<Condition> _conditions;
public Experiment(String className,
Map<String, String> defaultProperties,
Collection<Condition> conditions) {
if (className == null)
throw new IllegalArgumentException();
if (defaultProperties == null)
throw new IllegalArgumentException();
if (conditions == null)
throw new IllegalArgumentException();
this.className = className;
this.defaultProperties = defaultProperties;
this._conditions = conditions;
}
/**
* Serialize as XML.
*/
public String toXML() {
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" ?>\n");
sb.append("<!DOCTYPE experiment PUBLIC"+
" \"" + DTDValidationHelper.PUBLIC_EXPERIMENT_0_1 + "\""+
" \"" + DTDValidationHelper.SYSTEM_EXPERIMENT_FILENAME_0_1 + "\""+
">\n");
sb.append("<!-- There are "+_conditions.size()+" conditions. -->\n");
sb.append("<experiment class=\""+className+"\">\n");
if(!defaultProperties.isEmpty()) {
sb.append(" <defaults>\n");
Iterator<Map.Entry<String,String>> itr = defaultProperties.entrySet().iterator();
while(itr.hasNext()) {
Map.Entry<String,String> entry = itr.next();
sb.append(" <property name=\""+entry.getKey()+"\">"+entry.getValue()+"</property>\n");
}
sb.append(" </defaults>\n");
}
Iterator<Condition> conditr = _conditions.iterator();
int n = 0;
while(conditr.hasNext()) {
Condition cond = conditr.next();
sb.append(" <!-- condition#"+(n+1)+" -->\n");
sb.append(" <condition>\n");
{
Iterator itr = cond.properties.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry entry = (Map.Entry) itr.next();
String name = ""+entry.getKey();
String value = ""+entry.getValue();
if(defaultProperties.get(name)!=null && defaultProperties.get(name).equals(value)) {
// Skip defaults that have not been overriden.
continue;
}
sb.append(" <property name=\"" + entry.getKey()
+ "\">" + entry.getValue() + "</property>\n");
}
}
/*
* Write out results when they are available.
*/
if (cond.result != null) {
Iterator itr = cond.result.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry entry = (Map.Entry) itr.next();
sb.append(" <result name=\"" + entry.getKey()
+ "\">" + entry.getValue() + "</result>\n");
}
}
sb.append(" </condition>\n");
n++;
}
sb.append("</experiment>\n");
return sb.toString();
}
/**
* Run the experiment, writing the results onto a CSV file.
*
* @param randomize
* When true, the {@link Condition}s will be executed in a
* random ordering.
* @param nruns
* The #of times to execute all of the {@link Condition}s.
*/
public void run(boolean randomize,int nruns) throws Exception {
if (nruns < 1)
throw new IllegalArgumentException(
"nruns must be at least one, not " + nruns);
// replicate for multiple runs.
Collection<Condition> conditions = replicateConditions(nruns, _conditions);
if(randomize) {
// randomize across all runs.
conditions = randomize(conditions);
}
File outFile = new File(className+".exp.csv");
final boolean exists = outFile.exists();
if (exists) {
System.err.println("Will append to existing file: "
+ outFile.getAbsolutePath());
}
FileWriter writer = new FileWriter(outFile,true/*append*/);
final long runStartTime = System.currentTimeMillis();
final int nconditions = conditions.size();
final Properties systemProperties = getInterestingSystemProperties();
try {
for (int run = 0; run < nruns; run++) {
System.err.println("Running comparison of " + nconditions
+ " conditions for " + className);
// show interesting system properties.
systemProperties.list(System.err);
Class cl = Class.forName(className);
Iterator<Condition> itr = conditions.iterator();
int i = 0;
while (itr.hasNext()) {
Condition condition = itr.next();
IComparisonTest test = (IComparisonTest) cl
.newInstance();
System.err.println("Run " + run + " of " + nruns
+ ", Running condition " + i + " of "
+ nconditions);
try {
// setup
test.setUpComparisonTest(condition.properties);
// run and record the result.
condition.result = test
.doComparisonTest(condition.properties);
} catch (Throwable t) {
log.warn("Error running condition: " + t, t);
// record error result.
condition.result = Result.errorFactory(t);
}
try {
// tear down.
test.tearDownComparisonTest();
} catch (Throwable t) {
System.err.println("Could not tear down test: "
+ t.getMessage());
}
// add the run date for the condition.
condition.properties.setProperty("Date", new Date(
System.currentTimeMillis()).toString());
// add the run number
condition.properties.setProperty("Run", "" + i);
// add the sequence number
condition.properties.setProperty("Sequence", "" + i);
// add the "interesting" system properties.
condition.properties.putAll(systemProperties);
// the memory currently in use.
condition.result.put("java.Runtime.totalMemory", ""
+ Runtime.getRuntime().totalMemory());
// the memory currently in use.
condition.result.put("java.Runtime.freeMemory", ""
+ Runtime.getRuntime().freeMemory());
System.err.println(condition.result.toString());
i++;
}
} // next run.
}
catch(Throwable t) {
t.printStackTrace(System.err);
}
finally {
/*
* Always write the summary onto the file.
*/
if(exists) {
// separate each run in the file with some blank lines.
writer.write("\n\n");
}
writer.write("Run: "+new Date(runStartTime)+"\n\n");
/*
* Collect the distinct condition and result columns.
*
* Note: This extracts all columns whose values are constants
* for a given run and write them out once at the top of the
* run. This simplifies looking for invariants, conditions and
* variables in the results.
*/
Set<Object> conditionColumns = new TreeSet<Object>();
Set<Object> resultColumns = new TreeSet<Object>();
Map<Object,Object> invariants = new HashMap<Object,Object>();
{
boolean first = true;
Iterator<Condition> itr = conditions.iterator();
while (itr.hasNext()) {
Condition condition = itr.next();
Map<Object, Object> conditionProperties = PropertyUtil
.flatten(condition.properties);
// collect unique condition columns.
conditionColumns.addAll(conditionProperties.keySet());
// collect unique result columns.
resultColumns.addAll(condition.result.keySet());
if(first) {
invariants.putAll(conditionProperties);
invariants.putAll(condition.result);
} else {
// disprove invariants from conditions.
{
Iterator<Map.Entry<Object,Object>> itr2 = conditionProperties.entrySet().iterator();
while(itr2.hasNext()) {
Map.Entry entry = itr2.next();
Object key = entry.getKey();
Object val = entry.getValue();
if(!val.equals(invariants.get(key))) {
// proven not to be an invariant.
invariants.remove(key);
}
}
}
// disprove invariants from results.
{
final Iterator<Map.Entry<String, String>> itr2 = condition.result
.entrySet().iterator();
while(itr2.hasNext()) {
final Map.Entry<?,?> entry = itr2.next();
final Object key = entry.getKey();
final Object val = entry.getValue();
if(!val.equals(invariants.get(key))) {
// proven not to be an invariant.
invariants.remove(key);
}
}
}
}
first = false;
}
/*
* Remove column headings that were identified as invariants.
*/
{
Iterator<Object> itr2 = invariants.keySet().iterator();
while(itr2.hasNext()) {
Object key = itr2.next();
conditionColumns.remove(key);
resultColumns.remove(key);
}
}
}
/*
* Write out the invariants across the runs.
*/
{
writer.write("Invariants:\n");
Iterator<Map.Entry<Object, Object>> itr = invariants.entrySet().iterator();
while(itr.hasNext()) {
writer.write(itr.next().getKey()+"\t");
}
writer.write("\n");
itr = invariants.entrySet().iterator();
while(itr.hasNext()) {
writer.write(invariants.get(itr.next().getKey())+"\t");
}
writer.write("\n\n");
}
// write the condition column headings, building cols[] as we go.
final String[] conditionCols = new String[conditionColumns.size()];
{
Iterator<Object> colitr = conditionColumns.iterator();
int i = 0;
while(colitr.hasNext()) {
String col = ""+colitr.next();
writer.write(col+(colitr.hasNext()?"\t":""));
conditionCols[i++] = col;
}
}
// delimiter between the condition col headings and the result col headings.
writer.write("\t");
final String[] resultCols = new String[resultColumns.size()];
{
Iterator<Object> colitr = resultColumns.iterator();
int i = 0;
while(colitr.hasNext()) {
String col = ""+colitr.next();
writer.write(col+(colitr.hasNext()?"\t":""));
resultCols[i++] = col;
}
}
// end of the columns.
writer.write("\n");
// write each condition and its outcome (if any).
{
Iterator<Condition> itr = conditions.iterator();
while (itr.hasNext()) {
Condition condition = itr.next();
writer.write(ExperimentDriver.toString(PropertyUtil
.flatten(condition.properties), conditionCols,
false));
writer.write(ExperimentDriver.toString(
condition.result, resultCols, false));
writer.write("\n");
}
}
writer.flush();
writer.close();
}
// @todo this is using a different representation from the file which
// is more difficult to read.
{
System.err.println("Result summary:");
Iterator<Condition> itr = conditions.iterator();
while (itr.hasNext()) {
Condition condition = itr.next();
System.err.println(condition.result.toString());
}
}
}
}
/**
* Helper class for validating {@link Experiment} documents.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
static class DTDValidationHelper extends DefaultHandler2 implements EntityResolver2 {
/**
* The PUBLIC identifier for the inline-mention-form DTD, version 0.1.
*/
public static final String PUBLIC_EXPERIMENT_0_1 = "-//systap.com//DTD BIGDATA EXPERIMENT 0.1//EN";
/**
* The name of the file containing the DTD (without any path
* information).
*/
public static final String SYSTEM_EXPERIMENT_FILENAME_0_1 = "Experiment.dtd";
// /**
// * The Java resource containing the inline-mention-form DTD, version
// * 0.1.
// */
// public static final String SYSTEM_EXPERIMENT_RESOURCE_0_1 = "com/bigdata/journal/"
// + SYSTEM_EXPERIMENT_FILENAME_0_1;
/**
* Validate an inline-mention-form document against a DTD.
*
* @param source
* The source from which the document will be read.
*
* @throws SAXException
* If validation fails.
* @throws ParserConfigurationException
* If there is a problem configuring the parser.
* @throws IOException
* If there is an IO problem.
*/
public static void validate(InputSource source) throws SAXException,
ParserConfigurationException, IOException {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
SAXParser parser = factory.newSAXParser();
parser.parse( source, new DTDValidationHelper() );
}
/**
* Resolve the inline-mention-form DTD.
*/
public InputSource resolveEntity(String name, String publicId,
String baseURI, String systemId) throws SAXException,
IOException {
if(INFO) log.info("resolveEntity(name=" + name + ", publicId=" + publicId
+ ", baseURI=" + baseURI + ", systemId=" + systemId);
if (publicId.equals(PUBLIC_EXPERIMENT_0_1)) {
if(INFO) log.info("Resolving DTD using PUBLIC identifier: " + publicId);
InputStream is = getClass().getResourceAsStream(
SYSTEM_EXPERIMENT_FILENAME_0_1);
if (is == null) {
throw new AssertionError("Could not locate resource: "
+ SYSTEM_EXPERIMENT_FILENAME_0_1);
}
return new InputSource(is);
} else {
// use the default behaviour
if(INFO) log.info("Using default resolver behavior.");
return super.resolveEntity(name, publicId, baseURI, systemId);
}
}
/**
* Log the warning.
*/
public void warning(SAXParseException e) throws SAXException {
log.warn(e);
}
/**
* Re-throws exception in order to cause a validation error to halt
* processing (the default behavior ignores errors).
*/
public void error(SAXParseException e) throws SAXException {
throw e;
}
}
/**
* Parses an XML representation of an {@link Experiment}.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
protected static class DTDParserHelper extends DTDValidationHelper {
protected String className;
protected Map<String,String> defaultProperties = null;
protected Collection<Condition> conditions = new Vector<Condition>();
public Experiment parse(InputSource source) throws SAXException, IOException, ParserConfigurationException {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
SAXParser parser = factory.newSAXParser();
parser.parse( source, this );
return new Experiment(className,defaultProperties,conditions);
}
/*
* used to track partial state during the parse.
*/
private boolean inDefaults = false;
private boolean inCondition = false;
private Map<String,String> properties = null;
private String pname = null;
private StringBuilder pvalue = new StringBuilder();
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
if( qName.equals("experiment")) {
className = atts.getValue("class");
} else if (qName.equals("defaults")) {
inDefaults = true;
properties = new HashMap<String,String>();
} else if( qName.equals("condition")) {
inCondition = true;
properties = new HashMap<String,String>();
} else if( qName.equals("property")) {
pname = atts.getValue("name");
}
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (qName.equals("defaults")) {
inDefaults = false;
defaultProperties = properties;
properties = null;
} else if (qName.equals("condition")) {
inCondition = false;
Map<String,String> tmp = new HashMap<String,String>();
tmp.putAll(defaultProperties);
tmp.putAll(properties);
Condition condition = new Condition(tmp);
conditions.add(condition);
properties = null;
} else if( qName.equals("property")) {
properties.put(pname,pvalue.toString());
// clear the buffer.
pvalue.setLength(0);
}
}
/**
* Collect the property value.
*/
public void characters(char[] ch, int start, int length)
throws SAXException {
pvalue.append(ch, start, length);
}
public void endDocument() throws SAXException {
super.endDocument();
if (className == null)
throw new SAXException("'class' attribute not recovered.");
if (defaultProperties == null)
throw new SAXException("defaults not recovered.");
if (conditions.size() == 0) {
log.warn("There are no conditions in this experiment");
}
}
}
/**
* Return a {@link Properties} object that inherits defaults from
* <i>properties</i> and sets/overrides properties identified in <i>entries</i>.
*
* @param properties
* The inherited properties (this object is NOT modified).
* @param params
* The overriden properties.
*
* @return A new {@link Properties}.
*/
protected static Condition getCondition(Map<String,String>properties, NV[] params) throws IOException {
properties = new HashMap<String,String>(properties);
for(int i=0; i<params.length; i++) {
properties.put(params[i].getName(),params[i].getValue());
}
return new Condition(properties);
}
/**
* Runs a comparison of various an {@link IComparisonTest} under various
* conditions and writes a CSV representation of the reported results.
*
* @param args
* The name of the XML file describing the experiment to be run.
*/
public static void main(final String[] args) throws Exception {
if (args.length == 0) {
System.err.println("usage: <experiment.xml> (#runs? (randomize?))");
System.exit(1);
}
int nruns = 1;
if (args.length == 2) {
nruns = Integer.parseInt(args[1]);
}
boolean randomize = true;
if (args.length == 3) {
randomize = Boolean.parseBoolean(args[2]);
}
doMain(new File(args[0]), nruns, randomize);
}
/**
* Run an experiment.
*
* @param file
* The file describing the experiment.
* @param nruns
* The #of runs.
* @param randomize
* <code>true</code> if the run order should be randomized.
*
* @throws Exception
*/
public static void doMain(File file, int nruns, boolean randomize)
throws Exception {
final Experiment exp = new DTDParserHelper().parse(new InputSource(
new FileReader(file)));
exp.run(randomize, nruns);
}
/**
* Filter the system properties to report only those that are interesting
* summaries of the execution environment.
*/
static public Properties getInterestingSystemProperties() {
Properties props = new Properties();
{
Iterator itr = PropertyUtil.flatten(System.getProperties()).entrySet().iterator();
while( itr.hasNext() ) {
Map.Entry entry = (Map.Entry) itr.next();
String pname = (String)entry.getKey();
String pvalue = (String) entry.getValue();
if( pname.startsWith("line.")) continue;
if( pname.startsWith("path.")) continue;
if( pname.startsWith("os.")) continue;
if( pname.startsWith("java.") && !(
pname.equals("java.vm.vendor") ||
pname.equals("java.vm.version") ||
pname.equals("java.vm.name")
)) continue;
if( pname.startsWith("sun.")) continue;
if( pname.startsWith("file.")) continue;
if( pname.startsWith("user.")) continue;
if( pname.startsWith("maven.")) continue;
if( pname.startsWith("awt.")) continue;
if( pname.startsWith("junit.")) continue;
if( pname.startsWith("cactus.")) continue;
if( pname.startsWith("tag")) continue; // tag1, tag2, etc. (maven).
props.setProperty(pname, pvalue);
itr.remove();
}
}
// report unused properties.
{
Iterator itr = PropertyUtil.flatten(System.getProperties()).entrySet().iterator();
while(itr.hasNext()) {
Map.Entry entry = (Map.Entry) itr.next();
String pname = (String)entry.getKey();
String pvalue = (String) entry.getValue();
System.err.println("Property not reported: "+pname+"="+pvalue);
}
}
/*
* Set some other properties that are interesting.
*/
// maximum memory the system will attempt to use.
props.setProperty("java.Runtime.maxMemory", ""+Runtime.getRuntime().maxMemory());
props.setProperty("os.arch.cpus", ""+SystemUtil.numProcessors());
try {
props.setProperty( "host", NicUtil.getIpAddress("default.nic", "default", true) );
} catch(Throwable t) {
t.printStackTrace();
}
return props;
}
}