| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- /**
- * Results - Results aggregation and output for benchmarks
- *
- * Collects benchmark results and provides formatted output
- * for comparing performance across different operations.
- *
- * @version 0.1
- * @since 0.1
- */
- namespace Implexus.Tools.Perf {
- /**
- * Collects and displays benchmark results.
- *
- * Results are organized by benchmark name (e.g., "Container", "Document")
- * and can be output as a formatted summary table.
- */
- public class Results : Object {
-
- /**
- * Internal storage for benchmark results.
- * Maps benchmark name to list of operation results.
- */
- private Invercargill.DataStructures.Dictionary<string, Invercargill.DataStructures.Vector<BenchmarkResults>> _results;
-
- /**
- * Creates a new Results instance.
- */
- public Results() {
- _results = new Invercargill.DataStructures.Dictionary<string, Invercargill.DataStructures.Vector<BenchmarkResults>>();
- }
-
- /**
- * Adds a benchmark result.
- *
- * @param benchmark The benchmark name (e.g., "Container")
- * @param result The benchmark result to add
- */
- public void add(string benchmark, BenchmarkResults result) {
- if (!_results.has(benchmark)) {
- _results.set(benchmark, new Invercargill.DataStructures.Vector<BenchmarkResults>());
- }
- _results.get(benchmark).add(result);
- }
-
- /**
- * Gets all results for a specific benchmark.
- *
- * @param benchmark The benchmark name
- * @return An enumerable of results, or empty if not found
- */
- public Invercargill.Enumerable<BenchmarkResults> get_results(string benchmark) {
- if (!_results.has(benchmark)) {
- return new Invercargill.DataStructures.Vector<BenchmarkResults>().as_enumerable();
- }
- return _results.get(benchmark).as_enumerable();
- }
-
- /**
- * Gets all benchmark names.
- *
- * @return An enumerable of benchmark names
- */
- public Invercargill.Enumerable<string> get_benchmark_names() {
- var names = new Invercargill.DataStructures.Vector<string>();
- foreach (var key in _results.keys) {
- names.add(key);
- }
- return names.as_enumerable();
- }
-
- /**
- * Prints a formatted summary of all benchmark results.
- */
- public void print_summary() {
- print("\n");
- print("================================================================================\n");
- print(" IMPLEXUS PERFORMANCE RESULTS \n");
- print("================================================================================\n");
- print("\n");
-
- // Track overall statistics
- int total_operations = 0;
- double total_time = 0;
-
- foreach (var benchmark_name in _results.keys) {
- var results_vec = _results.get(benchmark_name);
-
- print("=== %s ===\n", benchmark_name);
-
- // Check if any results are batch operations
- bool has_batch = false;
- foreach (var result in results_vec) {
- if (result.batch_size > 0) {
- has_batch = true;
- break;
- }
- }
-
- if (has_batch) {
- // Extended format for batch operations
- print("%-30s %8s %10s %12s %12s %12s\n",
- "Operation", "Iters", "Batch", "Total(ms)", "Avg(ms)", "Items/sec");
- print("--------------------------------------------------------------------------------------------------------\n");
-
- foreach (var result in results_vec) {
- if (result.batch_size > 0) {
- // Batch operation - show batch details
- print("%-30s %8d %10d %12.2f %12.4f %12.2f\n",
- result.operation,
- result.iterations,
- result.batch_size,
- result.total_time_ms,
- result.avg_item_time_ms,
- result.items_per_second);
- } else {
- // Non-batch operation
- print("%-30s %8d %10s %12.2f %12.4f %12.2f\n",
- result.operation,
- result.iterations,
- "-",
- result.total_time_ms,
- result.avg_time_ms,
- result.ops_per_second);
- }
-
- total_operations += result.total_items;
- total_time += result.total_time_ms;
- }
- } else {
- // Standard format
- print("%-30s %10s %12s %15s\n", "Operation", "Iterations", "Avg (ms)", "Ops/sec");
- print("--------------------------------------------------------------------------------\n");
-
- foreach (var result in results_vec) {
- print("%-30s %10d %12.4f %15.2f\n",
- result.operation,
- result.iterations,
- result.avg_time_ms,
- result.ops_per_second);
-
- total_operations += result.iterations;
- total_time += result.total_time_ms;
- }
- }
- print("\n");
- }
-
- // Print overall summary
- print("================================================================================\n");
- print(" SUMMARY \n");
- print("================================================================================\n");
- print("Total operations: %d\n", total_operations);
- print("Total time: %.2f ms\n", total_time);
- print("Overall throughput: %.2f ops/sec\n", total_time > 0 ? (total_operations / total_time) * 1000 : 0);
- print("================================================================================\n");
- }
-
- /**
- * Exports results as JSON for comparison or storage.
- *
- * @return A JSON string representation of the results
- */
- public string to_json() {
- var sb = new StringBuilder();
- sb.append("{\n");
-
- bool first_benchmark = true;
- foreach (var benchmark_name in _results.keys) {
- var results_vec = _results.get(benchmark_name);
-
- if (!first_benchmark) {
- sb.append(",\n");
- }
- first_benchmark = false;
-
- sb.append(" \"%s\": [\n".printf(escape_json_string(benchmark_name)));
-
- bool first_result = true;
- foreach (var result in results_vec) {
- if (!first_result) {
- sb.append(",\n");
- }
- first_result = false;
-
- sb.append(" {\n");
- sb.append(" \"operation\": \"%s\",\n".printf(escape_json_string(result.operation)));
- sb.append(" \"iterations\": %d,\n".printf(result.iterations));
- if (result.batch_size > 0) {
- sb.append(" \"batch_size\": %d,\n".printf(result.batch_size));
- sb.append(" \"total_items\": %d,\n".printf(result.total_items));
- }
- sb.append(" \"total_time_ms\": %.4f,\n".printf(result.total_time_ms));
- sb.append(" \"avg_time_ms\": %.4f,\n".printf(result.avg_time_ms));
- if (result.batch_size > 0) {
- sb.append(" \"avg_item_time_ms\": %.4f,\n".printf(result.avg_item_time_ms));
- sb.append(" \"items_per_second\": %.2f\n".printf(result.items_per_second));
- } else {
- sb.append(" \"ops_per_second\": %.2f\n".printf(result.ops_per_second));
- }
- sb.append(" }");
- }
-
- sb.append("\n ]");
- }
-
- sb.append("\n}\n");
- return sb.str;
- }
-
- /**
- * Exports results to a file.
- *
- * @param path The file path to write to
- * @param format The output format ("text" or "json")
- * @throws Error if writing fails
- */
- public void export(string path, string format = "text") throws Error {
- string content;
- if (format == "json") {
- content = to_json();
- } else {
- content = format_as_text();
- }
-
- FileUtils.set_contents(path, content);
- }
-
- /**
- * Formats results as plain text suitable for file output.
- *
- * @return A formatted text string
- */
- private string format_as_text() {
- var sb = new StringBuilder();
-
- sb.append("Implexus Performance Benchmark Results\n");
- sb.append("======================================\n");
- sb.append("Generated: %s\n\n".printf(new DateTime.now_utc().format("%Y-%m-%d %H:%M:%S UTC")));
-
- foreach (var benchmark_name in _results.keys) {
- var results_vec = _results.get(benchmark_name);
-
- sb.append("[%s]\n".printf(benchmark_name));
-
- foreach (var result in results_vec) {
- sb.append(" %s: %d iterations, %.4f ms avg, %.2f ops/sec\n".printf(
- result.operation,
- result.iterations,
- result.avg_time_ms,
- result.ops_per_second
- ));
- }
- sb.append("\n");
- }
-
- return sb.str;
- }
-
- /**
- * Escapes a string for JSON output.
- *
- * @param s The string to escape
- * @return The escaped string
- */
- private string escape_json_string(string s) {
- return s.replace("\\", "\\\\")
- .replace("\"", "\\\"")
- .replace("\n", "\\n")
- .replace("\r", "\\r")
- .replace("\t", "\\t");
- }
-
- /**
- * Calculates summary statistics for a benchmark.
- *
- * @param benchmark The benchmark name
- * @return A SummaryStats object with total_ops, total_time_ms, and avg_ops_per_sec
- */
- public SummaryStats? get_summary_stats(string benchmark) {
- if (!_results.has(benchmark)) {
- return null;
- }
-
- int total_ops = 0;
- double total_time = 0;
-
- foreach (var result in _results.get(benchmark)) {
- total_ops += result.iterations;
- total_time += result.total_time_ms;
- }
-
- double avg_ops = total_time > 0 ? (total_ops / total_time) * 1000 : 0;
-
- return new SummaryStats(total_ops, total_time, avg_ops);
- }
- }
- /**
- * Holds summary statistics for a benchmark.
- */
- public class SummaryStats : Object {
- /**
- * Total number of operations performed.
- */
- public int total_ops { get; private set; }
-
- /**
- * Total time in milliseconds.
- */
- public double total_time_ms { get; private set; }
-
- /**
- * Average operations per second.
- */
- public double avg_ops_per_sec { get; private set; }
-
- /**
- * Creates a new SummaryStats instance.
- */
- public SummaryStats(int total_ops, double total_time_ms, double avg_ops_per_sec) {
- this.total_ops = total_ops;
- this.total_time_ms = total_time_ms;
- this.avg_ops_per_sec = avg_ops_per_sec;
- }
- }
- }
|