package it.cavallium.strangedb.tests; import it.cavallium.strangedb.annotations.*; import it.cavallium.strangedb.functionalinterfaces.RunnableWithIO; import it.cavallium.strangedb.lists.EnhancedObjectStrandeDbList; import it.cavallium.strangedb.lists.ObjectStrandeDbList; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.cavallium.strangedb.database.Database; import it.cavallium.strangedb.EnhancedObject; import it.cavallium.strangedb.database.IDatabaseTools; import it.cavallium.strangedb.VariableWrapper; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; public class Performance { private static boolean FAST_TESTS; private static Path rootDirectory; private static Path dbDataFile; private static Path dbBlocksFile; private static Path dbReferencesFile; private static Database db; /** * * @param args args[0] = true for fast tests * @throws IOException * @throws InterruptedException */ public static void main(String[] args) throws IOException, InterruptedException { FAST_TESTS = args.length > 0 && args[0].equalsIgnoreCase("true"); if (args.length >= 2) { rootDirectory = Paths.get(args[1]); try { Files.createDirectory(rootDirectory); } catch (Exception ex) { } } else { rootDirectory = Files.createTempDirectory("performance-tests"); } generateDb(); System.out.println("Performance test started."); System.out.println("-------------------------------------------------------+-----------------------------------------------------------------"); System.out.println("Test name Total Time | Time at 1 Time at 10 Time at 100 Time at 1K Time at 10K"); System.out.println("-------------------------------------------------------+-----------------------------------------------------------------"); testS("Database creation", 3000, Performance::deleteDb, Performance::generateDb, () -> {}); testS("Database root creation", 3000, Performance::regenDb, () -> db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new), () -> {}); final VariableWrapper preloadedListContainer = new VariableWrapper<>(null); final VariableWrapper simpleEnhancedObjectContainer = new VariableWrapper<>(null); testS("ObjectStrandeDbList creation", 3000, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new); }, () -> preloadedListContainer.var.list = new ObjectStrandeDbList<>(db), () -> {}); testS("ObjectStrandeDbList: Filling with 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrandeDbList<>(db); }, () -> { for (int i = 0; i < 1000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> {}); testS("ObjectStrandeDbList: Filling with 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new); preloadedListContainer.var.listOfEnhancedObj = new EnhancedObjectStrandeDbList<>(db, SimpleEnhancedObject.class); simpleEnhancedObjectContainer.var = new SimpleEnhancedObject(db); simpleEnhancedObjectContainer.var.integerNumber = 10; simpleEnhancedObjectContainer.var.longNumber = 10L; simpleEnhancedObjectContainer.var.object = new ArrayList<>(); simpleEnhancedObjectContainer.var.object.add("XHIghicuiHUCB UIVY"); simpleEnhancedObjectContainer.var.object.add("ioZ>UIHZXGHXYGY"); simpleEnhancedObjectContainer.var.object.add("XJIOUIhcgGuigscwvyv"); }, () -> { for (int i = 0; i < 1000; i++) { preloadedListContainer.var.listOfEnhancedObj.add(simpleEnhancedObjectContainer.var); } }, () -> {}); testS("ObjectStrandeDbList: Filling with 10000 items", 10, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrandeDbList<>(db); }, () -> { for (int i = 0; i < 10000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> {}); testS("ObjectStrandeDbList: Filling with 100000 items", 1, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrandeDbList<>(db); }, () -> { for (int i = 0; i < 100000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> {}); testS("ObjectStrandeDbList: Loading 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrandeDbList<>(db); for (int i = 0; i < 1000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> { for (int i = 0; i < 1000; i++) { preloadedListContainer.var.list.get(i); } }, () -> {}); testS("ObjectStrandeDbList: Loading with 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new); preloadedListContainer.var.listOfEnhancedObj = new EnhancedObjectStrandeDbList<>(db, SimpleEnhancedObject.class); simpleEnhancedObjectContainer.var = new SimpleEnhancedObject(db); simpleEnhancedObjectContainer.var.integerNumber = 10; simpleEnhancedObjectContainer.var.longNumber = 10L; simpleEnhancedObjectContainer.var.object = new ArrayList<>(); simpleEnhancedObjectContainer.var.object.add("XHIghicuiHUCB UIVY"); simpleEnhancedObjectContainer.var.object.add("ioZ>UIHZXGHXYGY"); simpleEnhancedObjectContainer.var.object.add("XJIOUIhcgGuigscwvyv"); for (int i = 0; i < 1000; i++) { preloadedListContainer.var.listOfEnhancedObj.add(simpleEnhancedObjectContainer.var); } }, () -> { for (int i = 0; i < 1000; i++) { preloadedListContainer.var.listOfEnhancedObj.get(i); } }, () -> {}); testS("ObjectStrandeDbList: Loading 10000 items", 10, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrandeDbList<>(db); for (int i = 0; i < 10000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> { for (int i = 0; i < 10000; i++) { preloadedListContainer.var.list.get(i); } }, () -> {}); testS("ObjectStrandeDbList: getLast() with 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrandeDbList<>(db); for (int i = 0; i < 1000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> { preloadedListContainer.var.list.getLast(); }, () -> {}); testS("ObjectStrandeDbList: getLast() with 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new); preloadedListContainer.var.listOfEnhancedObj = new EnhancedObjectStrandeDbList<>(db, SimpleEnhancedObject.class); simpleEnhancedObjectContainer.var = new SimpleEnhancedObject(db); simpleEnhancedObjectContainer.var.integerNumber = 10; simpleEnhancedObjectContainer.var.longNumber = 10L; simpleEnhancedObjectContainer.var.object = new ArrayList<>(); simpleEnhancedObjectContainer.var.object.add("XHIghicuiHUCB UIVY"); simpleEnhancedObjectContainer.var.object.add("ioZ>UIHZXGHXYGY"); simpleEnhancedObjectContainer.var.object.add("XJIOUIhcgGuigscwvyv"); for (int i = 0; i < 1000; i++) { preloadedListContainer.var.listOfEnhancedObj.add(simpleEnhancedObjectContainer.var); } }, () -> { preloadedListContainer.var.listOfEnhancedObj.getLast(); }, () -> {}); testS("ObjectStrandeDbList: size() with 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrandeDbList<>(db); for (int i = 0; i < 1000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> { preloadedListContainer.var.list.size(); }, () -> {}); System.out.println("-------------------------------------------------------+-----------------------------------------------------------------"); System.out.println("Performance test finished."); deleteDb(); Files.deleteIfExists(rootDirectory); } private static void NtestS(String description, int times, RunnableWithIO beforeAction, RunnableWithIO action, RunnableWithIO afterAction) throws IOException, InterruptedException { } private static void testS(String description, int times, RunnableWithIO beforeAction, RunnableWithIO action, RunnableWithIO afterAction) throws IOException, InterruptedException { if (FAST_TESTS) { if (times >= 5) { times /= 5; } else if (times >= 2) { times /= 2; } } description = description + " time is"; int spacesCount = 40 - description.length(); int cutAt = 0; if (spacesCount < 0) { spacesCount = 40 - (description.length() - 40); cutAt = 40; } StringBuilder spaces = new StringBuilder(); for (int i = 0; i < spacesCount; i++) { spaces.append(' '); } double[] results = test(times, beforeAction, action, afterAction); if (cutAt > 0) { System.out.println(description.substring(0, cutAt) + " |"); } System.out.printf("%s:%s%s%s%n", description.substring(cutAt), spaces, format(results[0]) + " |", results.length > 1 ? (format(results[1]) + (results.length > 2 ? (format(results[2]) + (results.length > 3 ? (format(results[3]) + (results.length > 4 ? (format(results[4]) + (results.length > 5 ? format(results[5]) : "")) : "")) : "")) : "")) : ""); } private static String format(double result) { String spaces; if (result < 10) { spaces = " "; } else if (result < 100) { spaces = " "; } else if (result < 1000) { spaces = " "; } else { spaces = " "; } return spaces + String.format("%.2fms", result); } private static double[] test(int times, RunnableWithIO beforeAction, RunnableWithIO action, RunnableWithIO afterAction) throws IOException, InterruptedException { LongArrayList results = new LongArrayList(times); Thread.sleep(100); System.gc(); Thread.sleep(100); for (int i = 0; i < times; i++) { beforeAction.run(); long startTime = System.nanoTime(); action.run(); long elapsedTime = System.nanoTime() - startTime; afterAction.run(); results.add(elapsedTime); } double result1 = results.stream().limit(1).mapToLong(val -> val).average().orElse(0.0) / 1000000d; double result10 = results.stream().limit(10).mapToLong(val -> val).average().orElse(0.0) / 1000000d; double result100 = results.stream().limit(100).mapToLong(val -> val).average().orElse(0.0) / 1000000d; double result1000 = results.stream().limit(1000).mapToLong(val -> val).average().orElse(0.0) / 1000000d; double result10000 = results.stream().limit(10000).mapToLong(val -> val).average().orElse(0.0) / 1000000d; double resultMax = results.stream().mapToLong(val -> val).average().orElse(0.0) / 1000000d; if (times <= 1) { return new double[]{resultMax}; } else if (times <= 10) { return new double[]{resultMax, result1}; } else if (times <= 100) { return new double[]{resultMax, result1, result10}; } else if (times <= 1000) { return new double[]{resultMax, result1, result10, result100}; } else if (times <= 10000) { return new double[]{resultMax, result1, result10, result100, result1000}; } else { return new double[]{resultMax, result1, result10, result100, result1000, result10000}; } } public static void generateDb() throws IOException { dbDataFile = Files.createFile(rootDirectory.resolve("db_data.dat")); dbBlocksFile = Files.createFile(rootDirectory.resolve("db_blocks.dat")); dbReferencesFile = Files.createFile(rootDirectory.resolve("db_references.dat")); db = new Database(dbDataFile, dbBlocksFile, dbReferencesFile); } public static void deleteDb() throws IOException { db.close(); Files.deleteIfExists(dbDataFile); Files.deleteIfExists(dbBlocksFile); Files.deleteIfExists(dbReferencesFile); } public static void regenDb() throws IOException { deleteDb(); generateDb(); } public static class PreloadedListContainer extends EnhancedObject { @DbField(id = 0, type = DbDataType.ENHANCED_OBJECT) public ObjectStrandeDbList list; @DbField(id = 1, type = DbDataType.ENHANCED_OBJECT) public EnhancedObjectStrandeDbList listOfEnhancedObj; public PreloadedListContainer() { } public PreloadedListContainer(IDatabaseTools databaseTools) throws IOException { super(databaseTools); } } public static class DynamicListContainer extends EnhancedObject { public DynamicListContainer() { } public DynamicListContainer(IDatabaseTools databaseTools) throws IOException { super(databaseTools); } @DbPropertyGetter(id = 0, type = DbDataType.ENHANCED_OBJECT) public ObjectStrandeDbList getList() { return getProperty(); } @DbPropertySetter(id = 1, type = DbDataType.ENHANCED_OBJECT) public void setList(ObjectStrandeDbList list) { setProperty(list); } } public static class SimpleEnhancedObject extends EnhancedObject { public SimpleEnhancedObject() { } public SimpleEnhancedObject(IDatabaseTools databaseTools) throws IOException { super(databaseTools); } @DbField(id = 0, type = DbDataType.OBJECT) public ArrayList object; @DbPrimitiveField(id = 0, type = DbPrimitiveType.INTEGER) public int integerNumber; @DbPrimitiveField(id = 1, type = DbPrimitiveType.LONG) public long longNumber; } }