/** * implexus-perf - Performance benchmarking tool for Implexus * * This tool runs performance benchmarks against different DBM backends * to compare their performance characteristics. * * @version 0.1 * @since 0.1 */ namespace Implexus.Tools.Perf { public class BenchmarkConfig : Object { public int iterations { get; set; default = 100; } public int quick_iterations { get { return iterations / 10; } } public int heavy_iterations { get { return iterations / 5; } } public int test_doc_count { get { return iterations; } } } public static int main(string[] args) { string? connection_string = null; var config = new BenchmarkConfig(); for (int i = 1; i < args.length; i++) { string arg = args[i]; if (arg == "--help" || arg == "-h") { print_usage(); return 0; } else if ((arg == "--iterations" || arg == "-i") && i + 1 < args.length) { i++; int iter = int.parse(args[i]); if (iter <= 0) { stderr.printf("Error: Invalid iterations value: %s\n", args[i]); return 1; } config.iterations = iter; } else if (arg.has_prefix("--iterations=")) { string iter_str = arg.substring(12); int iter = int.parse(iter_str); if (iter <= 0) { stderr.printf("Error: Invalid iterations value: %s\n", iter_str); return 1; } config.iterations = iter; } else if (!arg.has_prefix("-")) { connection_string = arg; } else { stderr.printf("Error: Unknown option: %s\n", arg); print_usage(); return 1; } } if (connection_string == null) { stderr.printf("Error: No connection string provided\n"); print_usage(); return 1; } var loop = new MainLoop(); int result = 0; Error? error = null; run_benchmarks.begin(connection_string, config, (obj, res) => { try { result = run_benchmarks.end(res); } catch (Error e) { error = e; result = 1; } loop.quit(); }); loop.run(); if (error != null) { stderr.printf("Error: %s\n", ((!)error).message); } return result; } private static async int run_benchmarks(string connection_string, BenchmarkConfig config) throws Error { var cs = new Engine.ConnectionString(connection_string); var engine = cs.create_engine(); print("Implexus Performance Benchmark\n"); print("==============================\n"); print("Connection: %s\n", connection_string); print("Iterations: %d (quick: %d, heavy: %d)\n\n", config.iterations, config.quick_iterations, config.heavy_iterations); var cleanup_tracker = new CleanupTracker(); var benchmarks = new Benchmark[] { new ContainerBenchmark(engine, config), new CategoryBenchmark(engine, config), new CatalogueBenchmark(engine, config), new DocumentBenchmark(engine, config), new IndexBenchmark(engine, config), new PostIndexDocumentBenchmark(engine, config) }; foreach (var benchmark in benchmarks) { benchmark.set_cleanup_tracker(cleanup_tracker); } var results = new Results(); foreach (var benchmark in benchmarks) { print("Running %s benchmarks...\n", benchmark.name); benchmark.run(results); } results.print_summary(); print("\nPerforming final cleanup...\n"); yield perform_final_cleanup_async(engine, cleanup_tracker); return 0; } private static async void perform_final_cleanup_async(Core.Engine engine, CleanupTracker tracker) { int deleted_count = 0; int error_count = 0; // 1. Delete documents first print(" Cleaning up documents...\n"); foreach (unowned string path_str in tracker.get_documents()) { try { var path = new Core.EntityPath(path_str); var entity = yield engine.get_entity_or_null_async(path); if (entity != null) { yield ((!) entity).delete_async(); deleted_count++; } } catch (Error e) { error_count++; } } // 2. Delete indexes print(" Cleaning up indexes...\n"); foreach (unowned string path_str in tracker.get_indices()) { try { var path = new Core.EntityPath(path_str); var entity = yield engine.get_entity_or_null_async(path); if (entity != null) { yield ((!) entity).delete_async(); deleted_count++; } } catch (Error e) { error_count++; } } // 3. Delete catalogues print(" Cleaning up catalogues...\n"); foreach (unowned string path_str in tracker.get_catalogues()) { try { var path = new Core.EntityPath(path_str); var entity = yield engine.get_entity_or_null_async(path); if (entity != null) { yield ((!) entity).delete_async(); deleted_count++; } } catch (Error e) { error_count++; } } // 4. Delete categories print(" Cleaning up categories...\n"); foreach (unowned string path_str in tracker.get_categories()) { try { var path = new Core.EntityPath(path_str); var entity = yield engine.get_entity_or_null_async(path); if (entity != null) { yield ((!) entity).delete_async(); deleted_count++; } } catch (Error e) { error_count++; } } // 5. Delete containers (in reverse order) print(" Cleaning up containers...\n"); foreach (unowned string path_str in tracker.get_containers_reversed()) { try { var path = new Core.EntityPath(path_str); var entity = yield engine.get_entity_or_null_async(path); if (entity != null) { yield ((!) entity).delete_async(); deleted_count++; } } catch (Error e) { error_count++; } } print("Final cleanup complete: %d entities deleted, %d errors\n", deleted_count, error_count); } private static void print_usage() { print("Usage: implexus-perf [options] \n"); print("\n"); print("Options:\n"); print(" -i, --iterations=N Number of iterations for benchmarks (default: 100)\n"); print(" -h, --help Show this help message\n"); print("\n"); print("Connection string formats:\n"); print(" Embedded: lmdb:///path/to/db\n"); print(" gdbm:///path/to/db\n"); print(" filesystem:///path/to/db\n"); print(" Remote: implexus://host:port\n"); print("\n"); print("Examples:\n"); print(" implexus-perf lmdb:///tmp/benchmark-db\n"); print(" implexus-perf -i 500 gdbm:///tmp/benchmark-db\n"); } }