package it.cavallium.strangedb.tests; import it.cavallium.strangedb.functionalinterfaces.RunnableWithIO; import it.cavallium.strangedb.java.annotations.*; import it.cavallium.strangedb.java.database.DatabaseJava; import it.cavallium.strangedb.java.objects.lists.EnhancedObjectStrangeDbList; import it.cavallium.strangedb.java.objects.lists.ListQuery; import it.cavallium.strangedb.java.objects.lists.ObjectStrangeDbList; import it.cavallium.strangedb.java.objects.lists.ValuePointer; import it.cavallium.strangedb.java.objects.lists.operations.ContainsIgnoreCase; import it.cavallium.strangedb.tests.query.*; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.cavallium.strangedb.java.objects.EnhancedObject; import it.cavallium.strangedb.java.database.IDatabaseTools; import it.cavallium.strangedb.VariableWrapper; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Random; 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 DatabaseJava db; private static boolean tempDirectory; /** * * @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) { } tempDirectory = false; } else { rootDirectory = Files.createTempDirectory("performance-tests"); tempDirectory = true; } 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("DatabaseCore creation", 300, Performance::deleteDb, Performance::generateDb, () -> {}); testS("DatabaseCore root creation", 300, Performance::regenDb, () -> db.loadRoot(PreloadedListContainer::new), () -> {}); final VariableWrapper preloadedListContainer = new VariableWrapper<>(null); final VariableWrapper simpleEnhancedObjectContainer = new VariableWrapper<>(null); testS("ObjectStrangeDbList creation", 3000, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new); }, () -> preloadedListContainer.var.list = new ObjectStrangeDbList<>(db), () -> {}); testS("ObjectStrangeDbList: Filling with 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrangeDbList<>(db); }, () -> { for (int i = 0; i < 1000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> {}); testS("ObjectStrangeDbList: Filling with 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new); preloadedListContainer.var.listOfEnhancedObj = new EnhancedObjectStrangeDbList<>(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("ObjectStrangeDbList: Filling with 10000 items", 10, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrangeDbList<>(db); }, () -> { for (int i = 0; i < 10000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> {}); testS("ObjectStrangeDbList: Filling with 100000 items", 1, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrangeDbList<>(db); }, () -> { for (int i = 0; i < 100000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> {}); testS("ObjectStrangeDbList: Loading 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrangeDbList<>(db); for (int i = 0; i < 1000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> { preloadedListContainer.var.list.forEachParallelUnsorted((i) -> {}); }, () -> {}); testS("ObjectStrangeDbList: Loading with 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new); preloadedListContainer.var.listOfEnhancedObj = new EnhancedObjectStrangeDbList<>(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.forEachParallelUnsorted((i) -> {}); }, () -> {}); testS("ObjectStrangeDbList: Loading 10000 items", 10, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrangeDbList<>(db); for (int i = 0; i < 10000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> { preloadedListContainer.var.list.forEachParallelUnsorted((i) -> {}); }, () -> {}); testS("ObjectStrangeDbList: getLast() with 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrangeDbList<>(db); for (int i = 0; i < 1000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> { preloadedListContainer.var.list.getLast(); }, () -> {}); testS("ObjectStrangeDbList: getLast() with 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new); preloadedListContainer.var.listOfEnhancedObj = new EnhancedObjectStrangeDbList<>(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("ObjectStrangeDbList: size() with 1000 items", 100, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new); preloadedListContainer.var.list = new ObjectStrangeDbList<>(db); for (int i = 0; i < 1000; i++) { preloadedListContainer.var.list.add(1000); } }, () -> { preloadedListContainer.var.list.size(); }, () -> {}); for (int items = 1000; items <= 100000; items *= 10) { final int itemsF = items; testS("ListQuery: query with " + items + " items", 100 / (items / 1000), () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new); preloadedListContainer.var.listOfMessages = new EnhancedObjectStrangeDbList<>(db); Random random = new Random(); for (int i = 0; i < itemsF; i++) { EMessageContent content; if (random.nextBoolean()) { List stringList = new ArrayList<>(); for (int j = 0; j < 10; j++) { stringList.add("[entity]"); } byte[] stringBytes = new byte[200]; random.nextBytes(stringBytes); content = new EMessageText(db, new EFormattedText(db, new String(stringBytes, StandardCharsets.UTF_8) + (random.nextBoolean() ? "not found" : " text to find!"), stringList.toArray(new String[0]))); } else { content = new EMessageOtherContent(db, "EMPTY ABCDEFG"); } EMessage message = new EMessage(db, content); preloadedListContainer.var.listOfMessages.add(message); } }, () -> { ListQuery query = ListQuery.create( ValuePointer.ofField(EMessage.class, "content").field(EMessageText.class, "text").field(EFormattedText.class, "text"), ContainsIgnoreCase.containsValue("text to find")); ArrayList results = preloadedListContainer.var.listOfMessages.query(query).asList(); }, () -> {}); } System.out.println("-------------------------------------------------------+-----------------------------------------------------------------"); System.out.println("Performance test finished."); deleteDb(); if (tempDirectory) { 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 = rootDirectory.resolve("db_data.dat"); dbBlocksFile = rootDirectory.resolve("db_blocks.dat"); dbReferencesFile = rootDirectory.resolve("db_references.dat"); deleteDbFolders(); Files.createFile(dbDataFile); Files.createFile(dbBlocksFile); Files.createFile(dbReferencesFile); db = new DatabaseJava(dbDataFile, dbBlocksFile, dbReferencesFile); int i = 0; db.registerClass(SimpleEnhancedObject.class, i++); db.registerClass(PreloadedListContainer.class, i++); db.registerClass(DynamicListContainer.class, i++); db.registerClass(EMessage.class, i++); db.registerClass(EMessageContent.class, i++); db.registerClass(EMessageText.class, i++); db.registerClass(EMessageOtherContent.class, i++); db.registerClass(EFormattedText.class, i++); } public static void deleteDb() throws IOException { db.close(); deleteDbFolders(); } public static void deleteDbFolders() throws IOException { 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 ObjectStrangeDbList list; @DbField(id = 1, type = DbDataType.ENHANCED_OBJECT) public EnhancedObjectStrangeDbList listOfEnhancedObj; @DbField(id = 2, type = DbDataType.ENHANCED_OBJECT) public EnhancedObjectStrangeDbList listOfMessages; 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); } @DbProperty(id = 0, type = DbDataType.ENHANCED_OBJECT) @DbPropertyGetter() public ObjectStrangeDbList getList() { return getProperty(); } @DbProperty(id = 1, type = DbDataType.ENHANCED_OBJECT) @DbPropertySetter() public void setList(ObjectStrangeDbList 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; } }