/*
* Copyright 2008 Network Engine for Objects in Lund AB [neotechnology.com]
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.graphalgo.benchmark;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.neo4j.api.core.EmbeddedNeo;
import org.neo4j.api.core.NeoService;
/**
* Base class for benchmarks done on a NeoSevice. The method neoAlgoBenchMarkRun
* will call the abstract methods setUpGlobal and tearDownGlobal and in between
* them call the three methods setUp, runBenchMark and tearDown a number of
* times defined by the numberOfRuns variable. An average time is calculated and
* saved for later inspection.
* @author Patrik Larsson
*/
abstract public class NeoAlgoBenchmark
{
protected NeoService neo;
protected int numberOfWarmupRuns = 3;
protected int numberOfRuns = 10;
protected List<Object> internalIds;
protected Object currentInternalId;
private Map<Object,Double> results = new HashMap<Object,Double>();
/**
* Method called for setting up the global benchmark environment, such as
* starting a NeoService and maybe generating graphs.
* @param neoStoreDir
*/
protected void setUpGlobal( String neoStoreDir )
{
neo = new EmbeddedNeo( neoStoreDir );
}
protected void setUpGlobal()
{
setUpGlobal( "target/benchmarkdata" );
}
protected void tearDownGlobal()
{
neo.shutdown();
}
abstract public String getTestId();
/**
* Method called before every single run of the runBenchMark method.
*/
abstract protected void setUp();
/**
* Method called after every single run of the runBenchMark method.
*/
abstract protected void tearDown();
/**
* Method called to run the benchmark once. This is the called that is
* timed.
*/
abstract protected void runBenchMark();
public void neoAlgoBenchMarkRun()
{
if ( internalIds == null )
{
neoAlgoBenchMarkRunInternal();
}
else
{
for ( Object id : internalIds )
{
currentInternalId = id;
neoAlgoBenchMarkRunInternal();
}
System.out.println( " --- Results ---" );
for ( Object object : internalIds )
{
System.out
.println( object + ": " + results.get( object ) + "s" );
}
}
}
private void neoAlgoBenchMarkRunInternal()
{
System.out.println( "Starting benchmark " + getTestId() );
setUpGlobal();
// Warmup
System.out.println( "Running warmup" );
for ( int i = 0; i < numberOfWarmupRuns; ++i )
{
runBenchMark();
}
System.out.println( "Running benchmarks" );
long start, end;
long averageTime = 0;
for ( int i = 0; i < numberOfRuns; ++i )
{
setUp();
start = System.currentTimeMillis();
runBenchMark();
end = System.currentTimeMillis();
tearDown();
averageTime += end - start;
System.out.println( "Time: " + ((end - start) / 1000.0) + "s" );
}
System.out.print( "Average time" );
if ( currentInternalId != null )
{
System.out.print( " for " + currentInternalId );
results.put( currentInternalId,
(averageTime / numberOfRuns / 1000.0) );
}
System.out.println( ": " + (averageTime / numberOfRuns / 1000.0) + "s" );
tearDownGlobal();
if ( !saveStatistic( averageTime / numberOfRuns, true ) )
{
System.out.println( "Failed to save statistics" );
}
}
/**
* This method saves the measured time, by appending it to a normal text
* file whose name is decided by getTestId().
* @param milliSeconds
* @param print
* If true, the time will be printed, together with a number of
* previous results.
* @return False if something goes wrong, like no write permission to the
* file etc.
*/
protected boolean saveStatistic( long milliSeconds, boolean print )
{
String fileName = "target/benchmarkstatistics/" + getTestId();
String data = "";
// Make directory
new File( "target/benchmarkstatistics/" ).mkdirs();
// Read
try
{
BufferedReader reader = new BufferedReader( new FileReader(
fileName ) );
data = reader.readLine();
reader.close();
}
catch ( Exception exception )
{
}
// Print it
if ( print && !data.equals( "" ) )
{
System.out.println( "Previous results: " + data );
}
// Append new data and write
try
{
if ( !data.equals( "" ) )
{
data += ", ";
}
data += (milliSeconds / 1000.0);
BufferedWriter writer = new BufferedWriter( new FileWriter(
fileName ) );
writer.write( data );
writer.newLine();
writer.close();
}
catch ( Exception exception )
{
return false;
}
return true;
}
/**
* @return the numberOfRuns
*/
public int getNumberOfRuns()
{
return numberOfRuns;
}
/**
* @param numberOfRuns
* the numberOfRuns to set
*/
public void setNumberOfRuns( int numberOfRuns )
{
this.numberOfRuns = numberOfRuns;
}
/**
* @return the numberOfWarmupRuns
*/
public int getNumberOfWarmupRuns()
{
return numberOfWarmupRuns;
}
/**
* @param numberOfWarmupRuns
* the numberOfWarmupRuns to set
*/
public void setNumberOfWarmupRuns( int numberOfWarmupRuns )
{
this.numberOfWarmupRuns = numberOfWarmupRuns;
}
}