/* HeliDB -- A simple database for Java, http://www.helidb.org
* Copyright (C) 2008, 2009 Karl Gustafsson
*
* This file is a part of HeliDB.
*
* HeliDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeliDB 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, see <http://www.gnu.org/licenses/>.
*/
package org.helidb.resources.perf;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
import org.entityfs.support.exception.WrappedIOException;
import org.entityfs.support.log.LogAdapterHolder;
import org.entityfs.support.log.StdOutLogAdapter;
import org.helidb.Database;
import org.helidb.lang.Record;
import org.helidb.lang.serializer.IntegerSerializer;
import org.helidb.lang.serializer.LongSerializer;
import org.helidb.lang.serializer.StringSerializer;
import org.helidb.txn.Transaction;
import org.helidb.txn.TransactionalDatabase;
public class PerformanceTestRunner
{
private static final Random RANDOM = new Random(System.currentTimeMillis());
public static final int TESTDATA_SIZE = 5000100;
private static final Charset UTF8 = Charset.forName("UTF-8");
private static final int LINE_HEIGHT = 16;
private static final int GRAPH_HEIGHT = 300;
private static final int TITLE_HEIGHT = 2 * LINE_HEIGHT;
private static final int GRAPH_WIDTH = 400;
private static final int TABLE_WIDTH = 150;
private static int[] s_crs_keys;
private static long[] s_crs_values;
private static String[] s_vrs_keys;
private static String[] s_vrs_values;
private static List<DataPoint> s_initialInserts = new ArrayList<DataPoint>();
private static List<DataPoint> s_findRecords = new ArrayList<DataPoint>();
private static List<DataPoint> s_iterateOverKeys = new ArrayList<DataPoint>();
private static List<DataPoint> s_iterateOverRecords = new ArrayList<DataPoint>();
private static List<DataPoint> s_insertAdditionalRecords = new ArrayList<DataPoint>();
private static List<DataPoint> s_updateAdditionalRecords = new ArrayList<DataPoint>();
private static List<DataPoint> s_deleteAdditionalRecords = new ArrayList<DataPoint>();
private static List<DataPoint> s_updateRecords = new ArrayList<DataPoint>();
private static List<DataPoint> s_deleteRecords = new ArrayList<DataPoint>();
private static List<DataPoint> s_compact = new ArrayList<DataPoint>();
private static boolean s_createGraphs = false;
private static String s_graphFileNamePrefix;
private static String s_database;
private static String[] s_databaseBackends;
private static String s_additionalInfo;
private static boolean s_loadTestData = false;
private static File s_testDataFile;
private static class DataPoint
{
private final int m_x;
private final double m_y;
private DataPoint(int x, double y)
{
m_x = x;
m_y = y;
}
}
private static class DoubleAndInt
{
private final double m_double;
private final int m_int;
private DoubleAndInt(double d, int i)
{
m_double = d;
m_int = i;
}
}
private static void saveTestData()
{
try
{
File f = File.createTempFile("perfTest", ".dat");
System.out.println("Saving test data to " + f);
OutputStream os = new BufferedOutputStream(new FileOutputStream(f));
try
{
for (int i = 0; i < TESTDATA_SIZE; i++)
{
os.write(IntegerSerializer.INSTANCE.serialize(s_crs_keys[i]));
os.write(LongSerializer.INSTANCE.serialize(s_crs_values[i]));
byte[] barr = StringSerializer.INSTANCE.serialize(s_vrs_keys[i]);
os.write(IntegerSerializer.INSTANCE.serialize(barr.length));
os.write(barr);
barr = StringSerializer.INSTANCE.serialize(s_vrs_values[i]);
os.write(IntegerSerializer.INSTANCE.serialize(barr.length));
os.write(barr);
}
}
finally
{
os.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
private static void loadTestData(File f) throws IOException
{
System.out.print("Loading test data from " + f);
InputStream is = new BufferedInputStream(new FileInputStream(f));
try
{
for (int i = 0; i < TESTDATA_SIZE; i++)
{
s_crs_keys[i] = IntegerSerializer.INSTANCE.readInteger(is);
s_crs_values[i] = LongSerializer.INSTANCE.readLong(is);
int arrLen = IntegerSerializer.INSTANCE.readInteger(is);
s_vrs_keys[i] = StringSerializer.INSTANCE.read(is, arrLen);
arrLen = IntegerSerializer.INSTANCE.readInteger(is);
s_vrs_values[i] = StringSerializer.INSTANCE.read(is, arrLen);
}
}
finally
{
is.close();
}
}
private static void prepareTestData()
{
System.out.print("Preparing test data");
int i = 0;
Set<Integer> is = new HashSet<Integer>(TESTDATA_SIZE);
s_crs_keys = new int[TESTDATA_SIZE];
while (i < TESTDATA_SIZE)
{
int n = RANDOM.nextInt();
if (!is.contains(n))
{
is.add(n);
s_crs_keys[i++] = n;
}
}
is = null;
System.out.print(".");
Set<Long> ls = new HashSet<Long>(TESTDATA_SIZE);
s_crs_values = new long[TESTDATA_SIZE];
i = 0;
while (i < TESTDATA_SIZE)
{
long n = RANDOM.nextLong();
if (!ls.contains(n))
{
ls.add(n);
s_crs_values[i++] = n;
}
}
ls = null;
System.out.print(".");
Set<String> ss = new HashSet<String>(TESTDATA_SIZE);
s_vrs_keys = new String[TESTDATA_SIZE];
i = 0;
while (i < TESTDATA_SIZE)
{
byte[] barr = new byte[16];
RANDOM.nextBytes(barr);
String s = new String(barr);
if (!ss.contains(s))
{
ss.add(s);
s_vrs_keys[i++] = s;
}
}
System.out.print(".");
ss = null;
// The values are the keys offset by 13333 positions
s_vrs_values = new String[TESTDATA_SIZE];
System.arraycopy(s_vrs_keys, 13333, s_vrs_values, 0, TESTDATA_SIZE - 13333);
System.arraycopy(s_vrs_keys, 0, s_vrs_values, TESTDATA_SIZE - 13333, 13333);
System.out.println(".");
System.gc();
}
private static List<TestConfiguration<?, ?>> createTestConfigurations()
{
List<TestConfiguration<?, ?>> res = new ArrayList<TestConfiguration<?, ?>>();
int[][] sizes = new int[][] { { 500, 0, 5 }, { 500, 10, 5 }, { 500, 50, 5 }, { 200, 100, 5 }, { 100, 500, 10 }, { 100, 1000, 10 }, { 20, 5000, 50 }, { 10, 10000, 50 }, { 1, 50000, 100 }, { 1, 100000, 100 }, { 1, 500000, 100 }, { 1, 1000000, 100 }, { 1, 5000000, 100 } };
int lowCeil = 8;
int medCeil = 11;
int highCeil = sizes.length - 1;
for (int i = 0; i <= lowCeil; i++)
{
int[] sz = sizes[i];
res.add(new SimpleDatabaseHeapConfiguration(sz[0], sz[1], sz[2]));
}
// Marks the end of a test configuration suite
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new SimpleDatabaseHeapWBPlusTreeIndexConfiguration(sz[0], sz[1], sz[2], 0, 4096));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new SimpleDatabaseHeapWBPlusTreeIndexConfiguration(sz[0], sz[1], sz[2], 30, 4096));
}
res.add(null);
for (int i = 0; i <= lowCeil; i++)
{
int[] sz = sizes[i];
res.add(new LoggingTransactionalDatabaseHeapConfiguration(sz[0], sz[1], sz[2]));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new LoggingTransactionalDatabaseHeapWBPlusTreeIndexConfiguration(sz[0], sz[1], sz[2], 0, 4096));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new LoggingTransactionalDatabaseHeapWBPlusTreeIndexConfiguration(sz[0], sz[1], sz[2], 30, 4096));
}
res.add(null);
for (int i = 0; i <= lowCeil; i++)
{
int[] sz = sizes[i];
res.add(new ShadowCopyTransactionalDatabaseHeapConfiguration(sz[0], sz[1], sz[2]));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new ShadowCopyTransactionalDatabaseHeapWBPlusTreeIndexConfiguration(sz[0], sz[1], sz[2], 0, 4096));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new ShadowCopyTransactionalDatabaseHeapWBPlusTreeIndexConfiguration(sz[0], sz[1], sz[2], 30, 4096));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new SimpleDatabaseCRSHeapWBPlusTreeIndexConfiguration(sz[0], sz[1], sz[2], 0, 4096));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new SimpleDatabaseCRSHeapWBPlusTreeIndexConfiguration(sz[0], sz[1], sz[2], 30, 4096));
}
res.add(null);
for (int i = 0; i <= highCeil; i++)
{
int[] sz = sizes[i];
res.add(new SimpleDatabaseCRSBPlusTreeConfiguration(sz[0], sz[1], sz[2], 0, 4096));
}
res.add(null);
for (int i = 0; i <= highCeil; i++)
{
int[] sz = sizes[i];
res.add(new SimpleDatabaseCRSBPlusTreeConfiguration(sz[0], sz[1], sz[2], 10, 4096));
}
res.add(null);
for (int i = 0; i <= highCeil; i++)
{
int[] sz = sizes[i];
res.add(new SimpleDatabaseCRSBPlusTreeConfiguration(sz[0], sz[1], sz[2], 30, 4096));
}
res.add(null);
for (int i = 0; i <= highCeil; i++)
{
int[] sz = sizes[i];
res.add(new SimpleDatabaseCRSBPlusTreeConfiguration(sz[0], sz[1], sz[2], 50, 4096));
}
res.add(null);
for (int i = 0; i <= lowCeil; i++)
{
int[] sz = sizes[i];
res.add(new SimpleDatabaseCRSHeapConfiguration(sz[0], sz[1], sz[2]));
}
res.add(null);
for (int i = 0; i <= lowCeil; i++)
{
int[] sz = sizes[i];
res.add(new LoggingTransactionalDatabaseCRSHeapConfiguration(sz[0], sz[1], sz[2]));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new LoggingTransactionalDatabaseCRSHeapWBPlusTreeIndexConfiguration(sz[0], sz[1], sz[2], 0, 4096));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new LoggingTransactionalDatabaseCRSHeapWBPlusTreeIndexConfiguration(sz[0], sz[1], sz[2], 30, 4096));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new LoggingTransactionalDatabaseCRSBPlusTreeConfiguration(sz[0], sz[1], sz[2], 0, 4096));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new LoggingTransactionalDatabaseCRSBPlusTreeConfiguration(sz[0], sz[1], sz[2], 30, 4096));
}
res.add(null);
for (int i = 0; i <= lowCeil; i++)
{
int[] sz = sizes[i];
res.add(new ShadowCopyTransactionalDatabaseCRSHeapConfiguration(sz[0], sz[1], sz[2]));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new ShadowCopyTransactionalDatabaseCRSHeapWBPlusTreeIndexConfiguration(sz[0], sz[1], sz[2], 0, 4096));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new ShadowCopyTransactionalDatabaseCRSHeapWBPlusTreeIndexConfiguration(sz[0], sz[1], sz[2], 30, 4096));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new ShadowCopyTransactionalDatabaseCRSBPlusTreeConfiguration(sz[0], sz[1], sz[2], 0, 4096));
}
res.add(null);
for (int i = 0; i <= medCeil; i++)
{
int[] sz = sizes[i];
res.add(new ShadowCopyTransactionalDatabaseCRSBPlusTreeConfiguration(sz[0], sz[1], sz[2], 30, 4096));
}
res.add(null);
return res;
}
private static double crsInsertRecords(CRSTestConfiguration tc, Collection<? extends Database<Integer, Long>> dbs)
{
final int noOfRecords = tc.getNoOfBaseRecords();
System.out.println("Inserting " + noOfRecords + " records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
for (Database<Integer, Long> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(false);
}
for (int i = 0; i < noOfRecords; i++)
{
db.insert(s_crs_keys[i], s_crs_values[i]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per insert)");
return res;
}
private static double crsFindRecords(CRSTestConfiguration tc, Collection<? extends Database<Integer, Long>> dbs)
{
final int noOfRecords = tc.getNoOfBaseRecords();
System.out.println("Selecting " + noOfRecords + " records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
for (Database<Integer, Long> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(true);
}
for (int i = 0; i < noOfRecords; i++)
{
db.get(s_crs_keys[i]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per select)");
return res;
}
private static double iterateOverKeys(TestConfiguration<?, ?> tc, Collection<? extends Database<?, ?>> dbs)
{
final int noOfRecords = tc.getNoOfBaseRecords();
System.out.print("Iterating over " + noOfRecords + " keys in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
for (Database<?, ?> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(true);
}
Iterator<?> itr = db.keyIterator();
while (itr.hasNext())
{
itr.next();
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per itr.hasNext + itr.next)");
return res;
}
private static double iterateOverRecords(TestConfiguration<?, ?> tc, Collection<? extends Database<?, ?>> dbs)
{
final int noOfRecords = tc.getNoOfBaseRecords();
System.out.print("Iterating over " + noOfRecords + " records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
for (Database<?, ?> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(true);
}
Iterator<? extends Record<?, ?>> itr = db.iterator();
while (itr.hasNext())
{
itr.next();
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per itr.hasNext + itr.next)");
return res;
}
private static double crsInsertAdditionalRecords(CRSTestConfiguration tc, Collection<? extends Database<Integer, Long>> dbs)
{
final int noOfBaseRecords = tc.getNoOfBaseRecords();
final int noOfAdditionalRecords = tc.getNoOfAdditionalRecords();
System.out.println("Inserting " + noOfAdditionalRecords + " additional records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
for (Database<Integer, Long> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(false);
}
for (int i = noOfBaseRecords; i < noOfBaseRecords + noOfAdditionalRecords; i++)
{
db.insert(s_crs_keys[i], s_crs_values[i]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfAdditionalRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per insert)");
return res;
}
private static double crsUpdateAdditionalRecords(CRSTestConfiguration tc, Collection<? extends Database<Integer, Long>> dbs)
{
final int noOfBaseRecords = tc.getNoOfBaseRecords();
final int noOfAdditionalRecords = tc.getNoOfAdditionalRecords();
System.out.println("Updating " + noOfAdditionalRecords + " additional records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
final int crsValuesLen = s_crs_values.length;
for (Database<Integer, Long> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(false);
}
for (int i = noOfBaseRecords; i < noOfBaseRecords + noOfAdditionalRecords; i++)
{
db.update(s_crs_keys[i], s_crs_values[crsValuesLen - i - 1]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfAdditionalRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per update)");
return res;
}
private static double crsDeleteAdditionalRecords(CRSTestConfiguration tc, Collection<? extends Database<Integer, Long>> dbs)
{
final int noOfBaseRecords = tc.getNoOfBaseRecords();
final int noOfAdditionalRecords = tc.getNoOfAdditionalRecords();
System.out.println("Deleting " + noOfAdditionalRecords + " additional records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
for (Database<Integer, Long> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(false);
}
for (int i = noOfBaseRecords; i < noOfBaseRecords + noOfAdditionalRecords; i++)
{
db.delete(s_crs_keys[i]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfAdditionalRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per delete)");
return res;
}
private static double crsUpdateRecords(CRSTestConfiguration tc, Collection<? extends Database<Integer, Long>> dbs)
{
final int noOfRecords = tc.getNoOfBaseRecords();
System.out.println("Updating " + noOfRecords + " (all) records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
final int crsValuesLen = s_crs_values.length;
for (Database<Integer, Long> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(false);
}
for (int i = 0; i < noOfRecords; i++)
{
db.update(s_crs_keys[i], s_crs_values[crsValuesLen - i - 1]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per update)");
return res;
}
private static double crsDeleteOneThirdOfAllRecords(CRSTestConfiguration tc, Collection<? extends Database<Integer, Long>> dbs)
{
final int noOfRecords = tc.getNoOfBaseRecords();
System.out.println("Deleting 1/3rd of " + noOfRecords + " (all) records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
for (Database<Integer, Long> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(false);
}
for (int i = 0; i < noOfRecords / 3; i++)
{
db.delete(s_crs_keys[3 * i]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / ((noOfRecords / 3) * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per delete)");
return res;
}
private static double compact(TestConfiguration<?, ?> tc, Collection<? extends Database<?, ?>> dbs)
{
System.out.println("Compacting " + dbs.size() + " databases");
long start = System.currentTimeMillis();
for (Database<?, ?> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(false);
}
db.compact();
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per database)");
return res;
}
private static void addRecord(List<DataPoint> l, int x, double y)
{
Double f = Double.valueOf(y);
if ((!f.isInfinite()) && (!f.isNaN()))
{
l.add(new DataPoint(x, y));
}
}
private static void runTestsFor(CRSTestConfiguration tc)
{
Collection<? extends Database<Integer, Long>> dbs = tc.getDatabases();
int nob = tc.getNoOfBaseRecords();
addRecord(s_initialInserts, nob, crsInsertRecords(tc, dbs));
addRecord(s_findRecords, nob, crsFindRecords(tc, dbs));
addRecord(s_iterateOverKeys, nob, iterateOverKeys(tc, dbs));
addRecord(s_iterateOverRecords, nob, iterateOverRecords(tc, dbs));
addRecord(s_insertAdditionalRecords, nob, crsInsertAdditionalRecords(tc, dbs));
addRecord(s_updateAdditionalRecords, nob, crsUpdateAdditionalRecords(tc, dbs));
addRecord(s_deleteAdditionalRecords, nob, crsDeleteAdditionalRecords(tc, dbs));
addRecord(s_updateRecords, nob, crsUpdateRecords(tc, dbs));
addRecord(s_deleteRecords, nob, crsDeleteOneThirdOfAllRecords(tc, dbs));
addRecord(s_compact, nob, compact(tc, dbs));
}
private static double vrsInsertRecords(VRSTestConfiguration tc, Collection<? extends Database<String, String>> dbs)
{
final int noOfRecords = tc.getNoOfBaseRecords();
System.out.println("Inserting " + noOfRecords + " records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
for (Database<String, String> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(false);
}
for (int i = 0; i < noOfRecords; i++)
{
db.insert(s_vrs_keys[i], s_vrs_values[i]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per insert)");
return res;
}
private static double vrsFindRecords(VRSTestConfiguration tc, Collection<? extends Database<String, String>> dbs)
{
final int noOfRecords = tc.getNoOfBaseRecords();
System.out.println("Selecting " + noOfRecords + " records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
for (Database<String, String> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(true);
}
for (int i = 0; i < noOfRecords; i++)
{
db.get(s_vrs_keys[i]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per select)");
return res;
}
private static double vrsInsertAdditionalRecords(VRSTestConfiguration tc, Collection<? extends Database<String, String>> dbs)
{
final int noOfBaseRecords = tc.getNoOfBaseRecords();
final int noOfAdditionalRecords = tc.getNoOfAdditionalRecords();
System.out.println("Inserting " + noOfAdditionalRecords + " additional records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
for (Database<String, String> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(false);
}
for (int i = noOfBaseRecords; i < noOfBaseRecords + noOfAdditionalRecords; i++)
{
db.insert(s_vrs_keys[i], s_vrs_values[i]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfAdditionalRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per insert)");
return res;
}
private static double vrsUpdateAdditionalRecords(VRSTestConfiguration tc, Collection<? extends Database<String, String>> dbs)
{
final int noOfBaseRecords = tc.getNoOfBaseRecords();
final int noOfAdditionalRecords = tc.getNoOfAdditionalRecords();
System.out.println("Updating " + noOfAdditionalRecords + " additional records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
final int crsValuesLen = s_crs_values.length;
for (Database<String, String> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(false);
}
for (int i = noOfBaseRecords; i < noOfBaseRecords + noOfAdditionalRecords; i++)
{
db.update(s_vrs_keys[i], s_vrs_values[crsValuesLen - i - 1]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfAdditionalRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per update)");
return res;
}
private static double vrsDeleteAdditionalRecords(VRSTestConfiguration tc, Collection<? extends Database<String, String>> dbs)
{
final int noOfBaseRecords = tc.getNoOfBaseRecords();
final int noOfAdditionalRecords = tc.getNoOfAdditionalRecords();
System.out.println("Deleting " + noOfAdditionalRecords + " additional records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
for (Database<String, String> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(false);
}
for (int i = noOfBaseRecords; i < noOfBaseRecords + noOfAdditionalRecords; i++)
{
db.delete(s_vrs_keys[i]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfAdditionalRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per delete)");
return res;
}
private static double vrsUpdateRecords(VRSTestConfiguration tc, Collection<? extends Database<String, String>> dbs)
{
final int noOfRecords = tc.getNoOfBaseRecords();
System.out.println("Updating " + noOfRecords + " (all) records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
final int vrsValuesLen = s_vrs_values.length;
int dbNo = 0;
int i = 0;
for (Database<String, String> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(false);
}
for (i = 0; i < noOfRecords; i++)
{
db.update(s_vrs_keys[i], s_vrs_values[vrsValuesLen - i - 1]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
catch (RuntimeException e)
{
System.err.println("DB #" + dbNo);
System.err.println("Entry " + i);
throw e;
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
dbNo++;
}
long time = System.currentTimeMillis() - start;
double res = (float) time / (noOfRecords * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per update)");
return res;
}
private static double vrsDeleteOneThirdOfAllRecords(VRSTestConfiguration tc, Collection<? extends Database<String, String>> dbs)
{
final int noOfRecords = tc.getNoOfBaseRecords();
System.out.println("Deleting 1/3rd of " + noOfRecords + " (all) records in " + dbs.size() + " databases");
long start = System.currentTimeMillis();
for (Database<String, String> db : dbs)
{
Transaction txn = null;
try
{
if (db instanceof TransactionalDatabase<?, ?>)
{
txn = Transaction.startTransaction(false);
}
for (int i = 0; i < noOfRecords / 3; i++)
{
db.delete(s_vrs_keys[3 * i]);
}
if (db instanceof TransactionalDatabase<?, ?>)
{
txn.commit();
txn = null;
}
}
finally
{
if (txn != null)
{
txn.rollback();
}
}
}
long time = System.currentTimeMillis() - start;
double res = (float) time / ((noOfRecords / 3) * dbs.size());
System.out.println("Total time: " + time + " ms. (" + res + " ms per delete)");
return res;
}
private static void runTestsFor(VRSTestConfiguration tc)
{
Collection<? extends Database<String, String>> dbs = tc.getDatabases();
int nob = tc.getNoOfBaseRecords();
addRecord(s_initialInserts, nob, vrsInsertRecords(tc, dbs));
addRecord(s_findRecords, nob, vrsFindRecords(tc, dbs));
addRecord(s_iterateOverKeys, nob, iterateOverKeys(tc, dbs));
addRecord(s_iterateOverRecords, nob, iterateOverRecords(tc, dbs));
addRecord(s_insertAdditionalRecords, nob, vrsInsertAdditionalRecords(tc, dbs));
addRecord(s_updateAdditionalRecords, nob, vrsUpdateAdditionalRecords(tc, dbs));
addRecord(s_deleteAdditionalRecords, nob, vrsDeleteAdditionalRecords(tc, dbs));
addRecord(s_updateRecords, nob, vrsUpdateRecords(tc, dbs));
addRecord(s_deleteRecords, nob, vrsDeleteOneThirdOfAllRecords(tc, dbs));
addRecord(s_compact, nob, compact(tc, dbs));
}
private static String getDataPoints(List<DataPoint> c)
{
boolean first = true;
StringBuilder res = new StringBuilder();
for (DataPoint dp : c)
{
if (!first)
{
res.append(',');
}
res.append("(x=").append(dp.m_x).append(",y=").append(dp.m_y).append(" ms)");
first = false;
}
return res.toString();
}
private static DoubleAndInt calculateYCeiling(double maxValue, int precision)
{
double mxLg10 = Math.log10(maxValue);
int base = (int) Math.ceil(Math.pow(10, precision) * (Math.pow(10, mxLg10 - (int) mxLg10)));
double ceil = base * Math.pow(10, (int) mxLg10 - precision);
if ((maxValue / ceil) < 0.75)
{
return calculateYCeiling(maxValue, precision + 1);
}
else
{
int noOfNotches = base;
while (noOfNotches > 12)
{
noOfNotches = noOfNotches / 4;
}
if (noOfNotches < 3)
{
noOfNotches = noOfNotches * 4;
}
return new DoubleAndInt(ceil, noOfNotches);
}
}
/**
* Calculate the scale of the Y axis.
* @param data
* @return
*/
private static DoubleAndInt calculateYCeiling(List<DataPoint> data)
{
double maxValue = 0;
for (DataPoint dp : data)
{
maxValue = Math.max(maxValue, dp.m_y);
}
return calculateYCeiling(maxValue, 1);
}
private static int calculateXCeiling(List<DataPoint> data)
{
int maxValue = 0;
for (DataPoint dp : data)
{
maxValue = Math.max(maxValue, dp.m_x);
}
return maxValue;
}
private static void drawCrossAt(PrintWriter w, int x, int y)
{
w.printf("<line stroke=\"blue\" stroke-width=\"1\" x1=\"%s\" y1=\"%s\" x2=\"%s\" y2=\"%s\"/>", x - 3, y - 3, x + 3, y + 3);
w.println();
w.printf("<line stroke=\"blue\" stroke-width=\"1\" x1=\"%s\" y1=\"%s\" x2=\"%s\" y2=\"%s\"/>", x - 3, y + 3, x + 3, y - 3);
w.println();
}
private static void createLogarithmicalXAxis(PrintWriter w, int x1, int y1, int x2, int xCeiling)
{
double x = xCeiling;
double xScale = (x2 - x1) / Math.log10(xCeiling);
int i = 0;
while (x >= 10)
{
int xpos = x1 + (int) Math.round(Math.log10(x) * xScale);
int textYPos = y1 + 5 + (i++ % 2 == 0 ? 0 : LINE_HEIGHT - 3);
w.printf("<line x1=\"%s\" y1=\"%s\" x2=\"%s\" y2=\"%s\" stroke=\"black\" stroke-width=\"1\"/>", xpos, y1 - 3, xpos, y1 + 3);
w.println();
w.printf("<text style=\"text-anchor:middle;dominant-baseline:hanging\" x=\"%s\" y=\"%s\">%s</text>", xpos, textYPos, new DecimalFormat("#").format(Math.round(x)));
w.println();
x = x / 10;
}
}
private static void createLinearXAxis(PrintWriter w, int x1, int y1, int x2, int xCeiling)
{
double pixsPerXNotch = (x2 - x1) / 5;
for (int i = 0; i <= 5; i++)
{
int xpos = x1 + (int) Math.round(i * pixsPerXNotch);
int textYPos = y1 + 5 + (i % 2 == 0 ? 0 : LINE_HEIGHT - 3);
w.printf("<line x1=\"%s\" y1=\"%s\" x2=\"%s\" y2=\"%s\" stroke=\"black\" stroke-width=\"1\"/>", xpos, y1 - 3, xpos, y1 + 3);
w.println();
w.printf("<text style=\"text-anchor:middle;dominant-baseline:hanging\" x=\"%s\" y=\"%s\">%s</text>", xpos, textYPos, xCeiling * i / 5);
w.println();
}
}
private static void createLinearYAxis(PrintWriter w, int x1, int y1, int y2, double yCeiling, int noOfYNotches)
{
// Notches on the vertical axis
double pixsPerYNotch = (y1 - y2) / noOfYNotches;
for (int i = 1; i <= noOfYNotches; i++)
{
int ypos = y1 - (int) Math.round(i * pixsPerYNotch);
w.printf("<line x1=\"%s\" y1=\"%s\" x2=\"%s\" y2=\"%s\" stroke=\"black\" stroke-width=\"1\"/>", x1 - 3, ypos, x1 + 3, ypos);
w.println();
// String text = new StringBuffer(new
// DecimalFormat("#.###").format(yCeiling * i /
// noOfYNotches)).reverse().toString();
String text = new DecimalFormat("#.###").format(yCeiling * i / noOfYNotches);
w.printf("<text style=\"text-anchor:end;dominant-baseline:central\" x=\"%s\" y=\"%s\">%s</text>", x1 - 6, ypos, text);
}
}
private static void createLogarithmicalYAxis(PrintWriter w, int x1, int y1, int y2, double yCeiling, double yBase, double yScale)
{
double y = yCeiling;
for (int i = 0; i < 5; i++)
{
int ypos = y1 - (int) Math.round(yScale * (Math.log10(y) - yBase));
w.printf("<line x1=\"%s\" y1=\"%s\" x2=\"%s\" y2=\"%s\" stroke=\"black\" stroke-width=\"1\"/>", x1 - 3, ypos, x1 + 3, ypos);
w.println();
// String text = new StringBuffer(new
// DecimalFormat("#.###").format(yCeiling * i /
// noOfYNotches)).reverse().toString();
String text = new DecimalFormat("#.#####").format(y);
w.printf("<text style=\"text-anchor:end;dominant-baseline:central\" x=\"%s\" y=\"%s\">%s</text>", x1 - 6, ypos, text);
y = y / 10;
}
}
private static void createGraph(List<DataPoint> data, String fileName, String title1, String title2, boolean lgX, boolean lgY)
{
File f = new File(System.getProperty("java.io.tmpdir") + File.separator + s_graphFileNamePrefix + fileName + ".svg");
try
{
PrintWriter w = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), UTF8)));
try
{
int gw10 = GRAPH_WIDTH / 10;
int gw20 = GRAPH_WIDTH / 20;
int gh10 = GRAPH_HEIGHT / 10;
int gh20 = GRAPH_HEIGHT / 20;
int x1 = 3 * gw20;
int x2 = 17 * gw20;
int y1 = 9 * gh10 + TITLE_HEIGHT;
int y2 = 3 * gh20 + TITLE_HEIGHT;
int xCeiling = calculateXCeiling(data);
double xScale = (x2 - x1) / (lgX ? Math.log10(xCeiling) : (double) xCeiling);
DoubleAndInt yc = calculateYCeiling(data);
double yCeiling = yc.m_double;
int noOfYNotches = Math.max(1, yc.m_int);
double yBase = lgY ? Math.log10(yCeiling / 100000) : 0;
double yScale = (y1 - y2) / (lgY ? Math.log10(yCeiling) - yBase : yCeiling);
w.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
w.println("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">");
w.printf("<svg width=\"%s\" height=\"%s\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">", GRAPH_WIDTH + TABLE_WIDTH, GRAPH_HEIGHT + TITLE_HEIGHT);
w.println();
w.println("<defs>");
// Define the line arrow marker
w.println("<marker id=\"line-arrow\" viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\" markerUnits=\"strokeWidth\" orient=\"auto\" markerWidth=\"4\" markerHeight=\"3\">");
w.println("<polyline points=\"0,0 10,5 0,10 1,5\"/>");
w.println("</marker>");
w.println();
w.println("</defs>");
// A group setting the default font attributes
w.println("<g font-family=\"sans-serif\" font-size=\"9pt\">");
// The title
w.printf("<text style=\"text-anchor:middle;font-weight:bold\" x=\"%s\" y=\"%s\">%s</text>", (GRAPH_WIDTH + TABLE_WIDTH) / 2, LINE_HEIGHT, title1);
w.println();
w.printf("<text style=\"text-anchor:middle;font-weight:bold\" x=\"%s\" y=\"%s\">%s</text>", (GRAPH_WIDTH + TABLE_WIDTH) / 2, 2 * LINE_HEIGHT, title2);
w.println();
// The vertical axis
w.printf("<line x1=\"%s\" y1=\"%s\" x2=\"%s\" y2=\"%s\" stroke=\"black\" stroke-width=\"2\" marker-end=\"url(#line-arrow)\"/>", x1, y1, x1, y2 - gh10);
w.println();
w.printf("<text style=\"text-anchor:end;dominant-baseline:central\" x=\"%s\" y=\"%s\">t (ms)</text>", x1 - 6, y2 - gh10);
w.println();
if (lgY)
{
createLogarithmicalYAxis(w, x1, y1, y2, yCeiling, yBase, yScale);
}
else
{
createLinearYAxis(w, x1, y1, y2, yCeiling, noOfYNotches);
}
// The horizontal axis
w.printf("<line x1=\"%s\" y1=\"%s\" x2=\"%s\" y2=\"%s\" stroke=\"black\" stroke-width=\"2\" marker-end=\"url(#line-arrow)\"/>", x1 - 1, y1, x2 + gw10, y1);
w.println();
w.printf("<text style=\"text-anchor:middle;dominant-baseline:hanging\" x=\"%s\" y=\"%s\">x</text>", x2 + gw10 + 2, y1 + 6);
w.println();
if (lgX)
{
createLogarithmicalXAxis(w, x1, y1, x2, xCeiling);
}
else
{
createLinearXAxis(w, x1, y1, x2, xCeiling);
}
// Crosses over the data points
StringBuilder dataPointString = new StringBuilder();
boolean first = true;
for (DataPoint dp : data)
{
if (lgX && (dp.m_x < 10))
{
continue;
}
int x = x1 + (int) Math.round((lgX ? Math.log10(dp.m_x) : dp.m_x) * xScale);
int y = y1 - (int) Math.round((lgY ? Math.log10(dp.m_y) - yBase : dp.m_y) * yScale);
drawCrossAt(w, x, y);
if (!first)
{
dataPointString.append(' ');
}
dataPointString.append(x).append(',').append(y);
first = false;
}
// The graph
w.printf("<polyline points=\"%s\" fill-opacity=\"0\" stroke=\"blue\" stroke-width=\"1\"/>", dataPointString);
w.println();
// Table
int t10 = TABLE_WIDTH / 10;
int tableStartX = GRAPH_WIDTH;
int tableStartY = TITLE_HEIGHT + LINE_HEIGHT;
// The horizontal table line
w.printf("<line stroke=\"black\" stroke-width=\"1\" x1=\"%s\" y1=\"%s\" x2=\"%s\" y2=\"%s\"/>", tableStartX + t10, tableStartY, tableStartX + TABLE_WIDTH - t10, tableStartY);
w.println();
// The table column labels
w.printf("<text style=\"text-anchor:middle\" x=\"%s\" y=\"%s\">x</text>", tableStartX + 3 * t10, tableStartY - LINE_HEIGHT / 4);
w.println();
w.printf("<text style=\"text-anchor:middle\" x=\"%s\" y=\"%s\">t (ms)</text>", tableStartX + 7 * t10, tableStartY - LINE_HEIGHT / 4);
w.println();
// The table data (x)
w.printf("<text style=\"text-anchor:end\" y=\"%s\">", tableStartY);
w.println();
int lastY = tableStartY;
for (DataPoint dp : data)
{
w.printf("<tspan dy=\"%s\" x=\"%s\">%s</tspan>", LINE_HEIGHT, tableStartX + 5 * t10 - 12, dp.m_x);
w.println();
lastY += 16;
}
w.println("</text>");
// The vertical table line
w.printf("<line stroke=\"black\" stroke-width=\"1\" x1=\"%s\" y1=\"%s\" x2=\"%s\" y2=\"%s\"/>", tableStartX + 5 * t10, tableStartY - LINE_HEIGHT - LINE_HEIGHT / 4, tableStartX + 5 * t10, lastY + LINE_HEIGHT / 4);
w.println();
// The table data (t)
w.printf("<text style=\"text-anchor:start\" y=\"%s\">", tableStartY);
w.println();
for (DataPoint dp : data)
{
String text = new DecimalFormat("#.#####").format(dp.m_y);
w.printf("<tspan dy=\"%s\" x=\"%s\">%s</tspan>", LINE_HEIGHT, tableStartX + 5 * t10 + 12, text);
w.println();
}
w.println("</text>");
// Legend
int legendYPos = lastY + LINE_HEIGHT;
// Legend line with crosses
w.printf("<line stroke=\"blue\" stroke-width=\"1\" x1=\"%s\" y1=\"%s\" x2=\"%s\" y2=\"%s\"/>", tableStartX + 4 * t10, legendYPos, tableStartX + 6 * t10, legendYPos);
w.println();
drawCrossAt(w, tableStartX + 4 * t10, legendYPos);
drawCrossAt(w, tableStartX + 6 * t10, legendYPos);
// Legend text
w.printf("<text style=\"text-anchor:middle;font-size:8pt\" y=\"%s\">", legendYPos + LINE_HEIGHT / 2);
w.println();
w.printf("<tspan x=\"%s\" dy=\"%s\">%s</tspan>", tableStartX + 5 * t10, LINE_HEIGHT, s_database);
w.println();
for (String backend : s_databaseBackends)
{
w.printf("<tspan x=\"%s\" dy=\"%s\">%s</tspan>", tableStartX + 5 * t10, LINE_HEIGHT, backend);
w.println();
}
w.println();
if (s_additionalInfo != null)
{
w.printf("<tspan x=\"%s\" dy=\"%s\">%s</tspan>", tableStartX + 5 * t10, LINE_HEIGHT, s_additionalInfo);
w.println();
}
if (lgX)
{
w.printf("<tspan x=\"%s\" dy=\"%s\">Logarithmical x-axis</tspan>", tableStartX + 5 * t10, LINE_HEIGHT);
}
if (lgY)
{
w.printf("<tspan x=\"%s\" dy=\"%s\">Logarithmical y-axis</tspan>", tableStartX + 5 * t10, LINE_HEIGHT);
}
w.println("</text>");
w.println("</g></svg>");
}
finally
{
w.close();
}
}
catch (IOException e)
{
throw new WrappedIOException(e);
}
System.out.println("Wrote graph in " + f.getAbsolutePath());
}
private static void createGraphs(List<DataPoint> data, String fileName, String title1, String title2)
{
createGraph(data, fileName, title1, title2, false, false);
createGraph(data, fileName + "_lgx", title1, title2, true, false);
createGraph(data, fileName + "_lgy", title1, title2, false, true);
createGraph(data, fileName + "_lgxy", title1, title2, true, true);
}
private static void createGraphs()
{
createGraphs(s_initialInserts, "initial_insert", "Insert x records in an initially empty database", "t = average time per insert");
createGraphs(s_findRecords, "find", "Find x records using Database.get", "t = average time per search");
createGraphs(s_iterateOverKeys, "key_iteration", "Iterate over x keys", "t = average time per key");
createGraphs(s_iterateOverRecords, "record_iteration", "Iterate over x records", "t = average time per record");
createGraphs(s_insertAdditionalRecords, "additional_insert", "Insert 5 new records in a database with x records", "t = average time per insert");
createGraphs(s_updateAdditionalRecords, "additional_update", "Update last 5 records in a database with x + 5 records", "t = average time per update");
createGraphs(s_deleteAdditionalRecords, "additional_delete", "Delete last 5 records from a database with x + 5 records", "t = average time per delete");
createGraphs(s_updateRecords, "update", "Update x (all) records in a database with x records", "t = average time per update");
createGraphs(s_deleteRecords, "delete", "Delete every 3rd record from a database with x records", "t = average time per delete");
createGraphs(s_compact, "compact", "Compact database with 2x/3 records and x/3 holes", "t = total time");
System.out.println();
}
private static void endTestConfigurationSuite()
{
System.out.println("Initial inserts: | " + getDataPoints(s_initialInserts));
System.out.println("Find records: | " + getDataPoints(s_findRecords));
System.out.println("Iterate over keys | " + getDataPoints(s_iterateOverKeys));
System.out.println("Iterate over records | " + getDataPoints(s_iterateOverRecords));
System.out.println("Insert addl records | " + getDataPoints(s_insertAdditionalRecords));
System.out.println("Update addl records | " + getDataPoints(s_updateAdditionalRecords));
System.out.println("Delete addl records | " + getDataPoints(s_deleteAdditionalRecords));
System.out.println("Update records | " + getDataPoints(s_updateRecords));
System.out.println("Delete records | " + getDataPoints(s_deleteRecords));
System.out.println("Compact | " + getDataPoints(s_compact));
System.out.println();
if (s_createGraphs)
{
createGraphs();
}
s_initialInserts.clear();
s_findRecords.clear();
s_iterateOverKeys.clear();
s_iterateOverRecords.clear();
s_insertAdditionalRecords.clear();
s_updateAdditionalRecords.clear();
s_deleteAdditionalRecords.clear();
s_updateRecords.clear();
s_deleteRecords.clear();
s_compact.clear();
}
private static void parseInputArguments(String[] args)
{
for (int i = 0; i < args.length; i++)
{
if (args[i].equals("-g"))
{
System.out.println("Will create graphs");
s_createGraphs = true;
}
else if (args[i].equals("-f"))
{
s_loadTestData = true;
s_testDataFile = new File(args[++i]);
}
else
{
throw new RuntimeException("Unknown argument " + args[i]);
}
}
}
public static void main(String[] args) throws IOException
{
parseInputArguments(args);
if (s_loadTestData)
{
loadTestData(s_testDataFile);
}
else
{
prepareTestData();
}
LogAdapterHolder lah = new LogAdapterHolder(new StdOutLogAdapter());
List<TestConfiguration<?, ?>> testConfigurations = createTestConfigurations();
for (TestConfiguration<?, ?> tc : testConfigurations)
{
if (tc == null)
{
// The end of a test configuration suite
endTestConfigurationSuite();
}
else
{
s_graphFileNamePrefix = tc.getGraphFileNamePrefix();
s_database = tc.getDatabaseImplementationName();
s_databaseBackends = tc.getBackendImplementationNames();
s_additionalInfo = tc.getAdditionalInfo();
tc.setup(lah);
try
{
System.out.println(tc.getHeader());
System.out.println("================================================================================");
if (tc instanceof CRSTestConfiguration)
{
runTestsFor((CRSTestConfiguration) tc);
}
else if (tc instanceof VRSTestConfiguration)
{
runTestsFor((VRSTestConfiguration) tc);
}
else
{
System.out.println("Error " + tc);
return;
}
System.out.println();
}
catch (RuntimeException e)
{
saveTestData();
throw e;
}
finally
{
tc.tearDown();
}
}
}
}
}