main.vala 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /**
  2. * implexus-perf - Performance benchmarking tool for Implexus
  3. *
  4. * This tool runs performance benchmarks against different DBM backends
  5. * to compare their performance characteristics.
  6. *
  7. * @version 0.1
  8. * @since 0.1
  9. */
  10. namespace Implexus.Tools.Perf {
  11. public class BenchmarkConfig : Object {
  12. public int iterations { get; set; default = 100; }
  13. public int quick_iterations { get { return iterations / 10; } }
  14. public int heavy_iterations { get { return iterations / 5; } }
  15. public int test_doc_count { get { return iterations; } }
  16. }
  17. public static int main(string[] args) {
  18. string? connection_string = null;
  19. var config = new BenchmarkConfig();
  20. for (int i = 1; i < args.length; i++) {
  21. string arg = args[i];
  22. if (arg == "--help" || arg == "-h") {
  23. print_usage();
  24. return 0;
  25. } else if ((arg == "--iterations" || arg == "-i") && i + 1 < args.length) {
  26. i++;
  27. int iter = int.parse(args[i]);
  28. if (iter <= 0) {
  29. stderr.printf("Error: Invalid iterations value: %s\n", args[i]);
  30. return 1;
  31. }
  32. config.iterations = iter;
  33. } else if (arg.has_prefix("--iterations=")) {
  34. string iter_str = arg.substring(12);
  35. int iter = int.parse(iter_str);
  36. if (iter <= 0) {
  37. stderr.printf("Error: Invalid iterations value: %s\n", iter_str);
  38. return 1;
  39. }
  40. config.iterations = iter;
  41. } else if (!arg.has_prefix("-")) {
  42. connection_string = arg;
  43. } else {
  44. stderr.printf("Error: Unknown option: %s\n", arg);
  45. print_usage();
  46. return 1;
  47. }
  48. }
  49. if (connection_string == null) {
  50. stderr.printf("Error: No connection string provided\n");
  51. print_usage();
  52. return 1;
  53. }
  54. var loop = new MainLoop();
  55. int result = 0;
  56. Error? error = null;
  57. run_benchmarks.begin(connection_string, config, (obj, res) => {
  58. try {
  59. result = run_benchmarks.end(res);
  60. } catch (Error e) {
  61. error = e;
  62. result = 1;
  63. }
  64. loop.quit();
  65. });
  66. loop.run();
  67. if (error != null) {
  68. stderr.printf("Error: %s\n", ((!)error).message);
  69. }
  70. return result;
  71. }
  72. private static async int run_benchmarks(string connection_string, BenchmarkConfig config) throws Error {
  73. var cs = new Engine.ConnectionString(connection_string);
  74. var engine = cs.create_engine();
  75. print("Implexus Performance Benchmark\n");
  76. print("==============================\n");
  77. print("Connection: %s\n", connection_string);
  78. print("Iterations: %d (quick: %d, heavy: %d)\n\n",
  79. config.iterations, config.quick_iterations, config.heavy_iterations);
  80. var cleanup_tracker = new CleanupTracker();
  81. var benchmarks = new Benchmark[] {
  82. new ContainerBenchmark(engine, config),
  83. new CategoryBenchmark(engine, config),
  84. new CatalogueBenchmark(engine, config),
  85. new DocumentBenchmark(engine, config),
  86. new IndexBenchmark(engine, config),
  87. new PostIndexDocumentBenchmark(engine, config)
  88. };
  89. foreach (var benchmark in benchmarks) {
  90. benchmark.set_cleanup_tracker(cleanup_tracker);
  91. }
  92. var results = new Results();
  93. foreach (var benchmark in benchmarks) {
  94. print("Running %s benchmarks...\n", benchmark.name);
  95. benchmark.run(results);
  96. }
  97. results.print_summary();
  98. print("\nPerforming final cleanup...\n");
  99. yield perform_final_cleanup_async(engine, cleanup_tracker);
  100. return 0;
  101. }
  102. private static async void perform_final_cleanup_async(Core.Engine engine, CleanupTracker tracker) {
  103. int deleted_count = 0;
  104. int error_count = 0;
  105. // 1. Delete documents first
  106. print(" Cleaning up documents...\n");
  107. foreach (unowned string path_str in tracker.get_documents()) {
  108. try {
  109. var path = new Core.EntityPath(path_str);
  110. var entity = yield engine.get_entity_or_null_async(path);
  111. if (entity != null) {
  112. yield ((!) entity).delete_async();
  113. deleted_count++;
  114. }
  115. } catch (Error e) {
  116. error_count++;
  117. }
  118. }
  119. // 2. Delete indexes
  120. print(" Cleaning up indexes...\n");
  121. foreach (unowned string path_str in tracker.get_indices()) {
  122. try {
  123. var path = new Core.EntityPath(path_str);
  124. var entity = yield engine.get_entity_or_null_async(path);
  125. if (entity != null) {
  126. yield ((!) entity).delete_async();
  127. deleted_count++;
  128. }
  129. } catch (Error e) {
  130. error_count++;
  131. }
  132. }
  133. // 3. Delete catalogues
  134. print(" Cleaning up catalogues...\n");
  135. foreach (unowned string path_str in tracker.get_catalogues()) {
  136. try {
  137. var path = new Core.EntityPath(path_str);
  138. var entity = yield engine.get_entity_or_null_async(path);
  139. if (entity != null) {
  140. yield ((!) entity).delete_async();
  141. deleted_count++;
  142. }
  143. } catch (Error e) {
  144. error_count++;
  145. }
  146. }
  147. // 4. Delete categories
  148. print(" Cleaning up categories...\n");
  149. foreach (unowned string path_str in tracker.get_categories()) {
  150. try {
  151. var path = new Core.EntityPath(path_str);
  152. var entity = yield engine.get_entity_or_null_async(path);
  153. if (entity != null) {
  154. yield ((!) entity).delete_async();
  155. deleted_count++;
  156. }
  157. } catch (Error e) {
  158. error_count++;
  159. }
  160. }
  161. // 5. Delete containers (in reverse order)
  162. print(" Cleaning up containers...\n");
  163. foreach (unowned string path_str in tracker.get_containers_reversed()) {
  164. try {
  165. var path = new Core.EntityPath(path_str);
  166. var entity = yield engine.get_entity_or_null_async(path);
  167. if (entity != null) {
  168. yield ((!) entity).delete_async();
  169. deleted_count++;
  170. }
  171. } catch (Error e) {
  172. error_count++;
  173. }
  174. }
  175. print("Final cleanup complete: %d entities deleted, %d errors\n", deleted_count, error_count);
  176. }
  177. private static void print_usage() {
  178. print("Usage: implexus-perf [options] <connection-string>\n");
  179. print("\n");
  180. print("Options:\n");
  181. print(" -i, --iterations=N Number of iterations for benchmarks (default: 100)\n");
  182. print(" -h, --help Show this help message\n");
  183. print("\n");
  184. print("Connection string formats:\n");
  185. print(" Embedded: lmdb:///path/to/db\n");
  186. print(" gdbm:///path/to/db\n");
  187. print(" filesystem:///path/to/db\n");
  188. print(" Remote: implexus://host:port\n");
  189. print("\n");
  190. print("Examples:\n");
  191. print(" implexus-perf lmdb:///tmp/benchmark-db\n");
  192. print(" implexus-perf -i 500 gdbm:///tmp/benchmark-db\n");
  193. }
  194. }