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 int DIVISOR; private static Path rootDirectory; private static Path dbDataFile; private static Path dbReferencesFile; private static DatabaseJava db; private static boolean tempDirectory; private static final int BASE_WIDTH = 35; private static final int SPACE_WIDTH = BASE_WIDTH + 35; private static String spaces = ""; private static String bars = ""; private static boolean doFillTests; private static boolean doLoadTests; private static boolean doQueryTests; private static boolean doInstantiationTests; static { for (int i = 0; i < SPACE_WIDTH; i++) { spaces += " "; bars += "-"; } } /** * * @param args args[0] = true for fast tests * @throws IOException * @throws InterruptedException */ public static void main(String[] args) throws IOException, InterruptedException { DIVISOR = args.length > 0 ? Integer.parseInt(args[0]) : 1; if (args.length >= 2) { doQueryTests = args[1].contains("query"); doFillTests = args[1].contains("fill"); doLoadTests = args[1].contains("load"); doInstantiationTests = args[1].contains("new"); if (args[1].contains("all")) { doQueryTests = true; doFillTests = true; doLoadTests = true; doInstantiationTests = true; } } if (args.length >= 3) { rootDirectory = Paths.get(args[2]); if (Files.notExists(rootDirectory)) { Files.createDirectory(rootDirectory); } tempDirectory = false; } else { rootDirectory = Files.createTempDirectory("performance-tests"); tempDirectory = true; } generateDb(); System.out.println("Performance test started."); System.out.println(bars + "---------------+-----------------------------------------------------------------"); System.out.println("Test name" + spaces.substring(0, spaces.length() - 5) + "Total Time | Time at 1 Time at 10 Time at 100 Time at 1K Time at 10K"); System.out.println(bars + "---------------+-----------------------------------------------------------------"); if (doInstantiationTests) { 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); if (doInstantiationTests) { testS("ObjectStrangeDbList creation", 1000, () -> { regenDb(); preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new); }, () -> preloadedListContainer.var.list = new ObjectStrangeDbList<>(db), () -> {}); } if (doFillTests) { 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); } }, () -> {}); } if (doLoadTests) { 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(); }, () -> {}); } if (doQueryTests) { 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(bars + "---------------+-----------------------------------------------------------------"); 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 (times >= 5 * DIVISOR) { times /= 5 * DIVISOR; } else if (times >= 2 * DIVISOR) { times /= 2 * DIVISOR; } description = description + " time is"; int spacesCount = SPACE_WIDTH - description.length(); int cutAt = 0; if (spacesCount < 0) { spacesCount = SPACE_WIDTH - (description.length() - SPACE_WIDTH); cutAt = SPACE_WIDTH; } 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"); dbReferencesFile = rootDirectory.resolve("db_references.dat"); deleteDbFolders(); Files.createFile(dbDataFile); Files.createFile(dbReferencesFile); db = new DatabaseJava(dbDataFile, 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(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; } }