From 134fc5207a52a02ddd16eb9cf6ee2c9ee54b1735 Mon Sep 17 00:00:00 2001 From: Sergey Penkovsky Date: Wed, 6 Aug 2025 23:15:28 +0300 Subject: [PATCH] Add English documentation comments to all benchmark_cherrypick source files (adapters, scenarios, CLI, reporters, runner) --- .../lib/cli/benchmark_cli.dart | 6 +++++ benchmark_cherrypick/lib/cli/parser.dart | 20 +++++++++++++++ .../lib/cli/report/csv_report.dart | 3 +++ .../lib/cli/report/json_report.dart | 3 +++ .../lib/cli/report/markdown_report.dart | 9 ++++++- .../lib/cli/report/pretty_report.dart | 6 +++++ .../lib/cli/report/report_generator.dart | 5 ++++ benchmark_cherrypick/lib/cli/runner.dart | 11 ++++++++ .../lib/di_adapters/cherrypick_adapter.dart | 7 ++++++ .../lib/di_adapters/di_adapter.dart | 13 ++++++++++ .../lib/scenarios/universal_chain_module.dart | 25 +++++++++++++++++++ .../lib/scenarios/universal_service.dart | 7 ++++++ 12 files changed, 114 insertions(+), 1 deletion(-) diff --git a/benchmark_cherrypick/lib/cli/benchmark_cli.dart b/benchmark_cherrypick/lib/cli/benchmark_cli.dart index 9b155d8..61ca734 100644 --- a/benchmark_cherrypick/lib/cli/benchmark_cli.dart +++ b/benchmark_cherrypick/lib/cli/benchmark_cli.dart @@ -12,7 +12,13 @@ import 'package:benchmark_cherrypick/benchmarks/universal_chain_benchmark.dart'; import 'package:benchmark_cherrypick/benchmarks/universal_chain_async_benchmark.dart'; import 'package:benchmark_cherrypick/di_adapters/cherrypick_adapter.dart'; +/// Command-line interface (CLI) runner for benchmarks. +/// +/// Parses CLI arguments, orchestrates benchmarks for different +/// scenarios and configurations, collects results, and generates reports +/// in the desired output format. class BenchmarkCliRunner { + /// Runs benchmarks based on CLI [args], configuring different test scenarios. Future run(List args) async { final config = parseBenchmarkCli(args); final results = >[]; diff --git a/benchmark_cherrypick/lib/cli/parser.dart b/benchmark_cherrypick/lib/cli/parser.dart index 3d8450b..11ad208 100644 --- a/benchmark_cherrypick/lib/cli/parser.dart +++ b/benchmark_cherrypick/lib/cli/parser.dart @@ -3,15 +3,23 @@ import 'dart:io'; import 'package:args/args.dart'; import 'package:benchmark_cherrypick/scenarios/universal_chain_module.dart'; +/// Enum describing all supported Universal DI benchmark types. enum UniversalBenchmark { + /// Simple singleton registration benchmark registerSingleton, + /// Chain of singleton dependencies chainSingleton, + /// Chain using factories chainFactory, + /// Async chain resolution chainAsync, + /// Named registration benchmark named, + /// Override/child-scope benchmark override, } +/// Maps [UniversalBenchmark] to the scenario enum for DI chains. UniversalScenario toScenario(UniversalBenchmark b) { switch (b) { case UniversalBenchmark.registerSingleton: @@ -29,6 +37,7 @@ UniversalScenario toScenario(UniversalBenchmark b) { } } +/// Maps benchmark to registration mode (singleton/factory/async). UniversalBindingMode toMode(UniversalBenchmark b) { switch (b) { case UniversalBenchmark.registerSingleton: @@ -46,6 +55,7 @@ UniversalBindingMode toMode(UniversalBenchmark b) { } } +/// Utility to parse a string into its corresponding enum value [T]. T parseEnum(String value, List values, T defaultValue) { return values.firstWhere( (v) => v.toString().split('.').last.toLowerCase() == value.toLowerCase(), @@ -53,15 +63,23 @@ T parseEnum(String value, List values, T defaultValue) { ); } +/// Parses comma-separated integer list from [s]. List parseIntList(String s) => s.split(',').map((e) => int.tryParse(e.trim()) ?? 0).where((x) => x > 0).toList(); +/// CLI config describing what and how to benchmark. class BenchmarkCliConfig { + /// Benchmarks enabled to run (scenarios). final List benchesToRun; + /// List of chain counts (parallel, per test). final List chainCounts; + /// List of nesting depths (max chain length, per test). final List nestDepths; + /// How many times to repeat each trial. final int repeats; + /// How many times to warm-up before measuring. final int warmups; + /// Output report format. final String format; BenchmarkCliConfig({ required this.benchesToRun, @@ -73,6 +91,8 @@ class BenchmarkCliConfig { }); } +/// Parses CLI arguments [args] into a [BenchmarkCliConfig]. +/// Supports --benchmark, --chainCount, --nestingDepth, etc. BenchmarkCliConfig parseBenchmarkCli(List args) { final parser = ArgParser() ..addOption('benchmark', abbr: 'b', defaultsTo: 'chainSingleton') diff --git a/benchmark_cherrypick/lib/cli/report/csv_report.dart b/benchmark_cherrypick/lib/cli/report/csv_report.dart index 03e2449..6379889 100644 --- a/benchmark_cherrypick/lib/cli/report/csv_report.dart +++ b/benchmark_cherrypick/lib/cli/report/csv_report.dart @@ -1,11 +1,14 @@ import 'report_generator.dart'; +/// Generates a CSV-formatted report for benchmark results. class CsvReport extends ReportGenerator { + /// List of all keys/columns to include in the CSV output. @override final List keys = [ 'benchmark','chainCount','nestingDepth','mean_us','median_us','stddev_us', 'min_us','max_us','trials','timings_us','memory_diff_kb','delta_peak_kb','peak_rss_kb' ]; + /// Renders rows as a CSV table string. @override String render(List> rows) { final header = keys.join(','); diff --git a/benchmark_cherrypick/lib/cli/report/json_report.dart b/benchmark_cherrypick/lib/cli/report/json_report.dart index a21d662..fb75d67 100644 --- a/benchmark_cherrypick/lib/cli/report/json_report.dart +++ b/benchmark_cherrypick/lib/cli/report/json_report.dart @@ -1,8 +1,11 @@ import 'report_generator.dart'; +/// Generates a JSON-formatted report for benchmark results. class JsonReport extends ReportGenerator { + /// No specific keys; outputs all fields in raw map. @override List get keys => []; + /// Renders all result rows as a pretty-printed JSON array. @override String render(List> rows) { return '[\n${rows.map((r) => ' $r').join(',\n')}\n]'; diff --git a/benchmark_cherrypick/lib/cli/report/markdown_report.dart b/benchmark_cherrypick/lib/cli/report/markdown_report.dart index 5e58f66..cf97ecc 100644 --- a/benchmark_cherrypick/lib/cli/report/markdown_report.dart +++ b/benchmark_cherrypick/lib/cli/report/markdown_report.dart @@ -1,11 +1,17 @@ import 'report_generator.dart'; +/// Generates a Markdown-formatted report for benchmark results. +/// +/// Displays result rows as a visually clear Markdown table including a legend for all metrics. class MarkdownReport extends ReportGenerator { + /// List of columns (keys) to show in the Markdown table. @override final List keys = [ 'benchmark','chainCount','nestingDepth','mean_us','median_us','stddev_us', 'min_us','max_us','trials','memory_diff_kb','delta_peak_kb','peak_rss_kb' ]; + + /// Friendly display names for each benchmark type. static const nameMap = { 'Universal_UniversalBenchmark.registerSingleton':'RegisterSingleton', 'Universal_UniversalBenchmark.chainSingleton':'ChainSingleton', @@ -15,6 +21,7 @@ class MarkdownReport extends ReportGenerator { 'Universal_UniversalBenchmark.override':'Override', }; + /// Renders all results as a formatted Markdown table with aligned columns and a legend. @override String render(List> rows) { final headers = [ @@ -38,7 +45,7 @@ class MarkdownReport extends ReportGenerator { ].map((cell) => cell.toString()).toList(); }).toList(); - // Вычислить ширину каждой колонки + // Calculate column width for pretty alignment final all = [headers] + dataRows; final widths = List.generate(headers.length, (i) { return all.map((row) => row[i].length).reduce((a, b) => a > b ? a : b); diff --git a/benchmark_cherrypick/lib/cli/report/pretty_report.dart b/benchmark_cherrypick/lib/cli/report/pretty_report.dart index 70d80a7..36688ef 100644 --- a/benchmark_cherrypick/lib/cli/report/pretty_report.dart +++ b/benchmark_cherrypick/lib/cli/report/pretty_report.dart @@ -1,12 +1,17 @@ import 'report_generator.dart'; +/// Generates a human-readable, tab-delimited report for benchmark results. +/// +/// Used for terminal and log output; shows each result as a single line with labeled headers. class PrettyReport extends ReportGenerator { + /// List of columns to output in the pretty report. @override final List keys = [ 'benchmark','chainCount','nestingDepth','mean_us','median_us','stddev_us', 'min_us','max_us','trials','memory_diff_kb','delta_peak_kb','peak_rss_kb' ]; + /// Mappings from internal benchmark IDs to display names. static const nameMap = { 'Universal_UniversalBenchmark.registerSingleton': 'RegisterSingleton', 'Universal_UniversalBenchmark.chainSingleton': 'ChainSingleton', @@ -16,6 +21,7 @@ class PrettyReport extends ReportGenerator { 'Universal_UniversalBenchmark.override': 'Override', }; + /// Renders the results as a header + tab-separated value table. @override String render(List> rows) { final headers = [ diff --git a/benchmark_cherrypick/lib/cli/report/report_generator.dart b/benchmark_cherrypick/lib/cli/report/report_generator.dart index c46645d..59a1e98 100644 --- a/benchmark_cherrypick/lib/cli/report/report_generator.dart +++ b/benchmark_cherrypick/lib/cli/report/report_generator.dart @@ -1,4 +1,9 @@ +/// Abstract base for generating benchmark result reports in different formats. +/// +/// Subclasses implement [render] to output results, and [keys] to define columns (if any). abstract class ReportGenerator { + /// Renders the given [results] as a formatted string (table, markdown, csv, etc). String render(List> results); + /// List of output columns/keys included in the export (or [] for auto/all). List get keys; } \ No newline at end of file diff --git a/benchmark_cherrypick/lib/cli/runner.dart b/benchmark_cherrypick/lib/cli/runner.dart index b2ea3e1..5687dba 100644 --- a/benchmark_cherrypick/lib/cli/runner.dart +++ b/benchmark_cherrypick/lib/cli/runner.dart @@ -3,10 +3,15 @@ import 'dart:math'; import 'package:benchmark_cherrypick/benchmarks/universal_chain_benchmark.dart'; import 'package:benchmark_cherrypick/benchmarks/universal_chain_async_benchmark.dart'; +/// Holds the results for a single benchmark execution. class BenchmarkResult { + /// List of timings for each run (in microseconds). final List timings; + /// Difference in memory (RSS, in KB) after running. final int memoryDiffKb; + /// Difference between peak RSS and initial RSS (in KB). final int deltaPeakKb; + /// Peak RSS memory observed (in KB). final int peakRssKb; BenchmarkResult({ required this.timings, @@ -14,6 +19,7 @@ class BenchmarkResult { required this.deltaPeakKb, required this.peakRssKb, }); + /// Computes a BenchmarkResult instance from run timings and memory data. factory BenchmarkResult.collect({ required List timings, required List rssValues, @@ -32,7 +38,10 @@ class BenchmarkResult { } } +/// Static methods to execute and time benchmarks for DI containers. class BenchmarkRunner { + /// Runs a synchronous benchmark ([UniversalChainBenchmark]) for a given number of [warmups] and [repeats]. + /// Collects execution time and observed memory. static Future runSync({ required UniversalChainBenchmark benchmark, required int warmups, @@ -58,6 +67,8 @@ class BenchmarkRunner { return BenchmarkResult.collect(timings: timings, rssValues: rssValues, memBefore: memBefore); } + /// Runs an asynchronous benchmark ([UniversalChainAsyncBenchmark]) for a given number of [warmups] and [repeats]. + /// Collects execution time and observed memory. static Future runAsync({ required UniversalChainAsyncBenchmark benchmark, required int warmups, diff --git a/benchmark_cherrypick/lib/di_adapters/cherrypick_adapter.dart b/benchmark_cherrypick/lib/di_adapters/cherrypick_adapter.dart index e9489ec..55bcdfd 100644 --- a/benchmark_cherrypick/lib/di_adapters/cherrypick_adapter.dart +++ b/benchmark_cherrypick/lib/di_adapters/cherrypick_adapter.dart @@ -1,6 +1,11 @@ import 'package:cherrypick/cherrypick.dart'; import 'di_adapter.dart'; +/// DIAdapter implementation for the CherryPick DI library. +/// +/// Wraps a CherryPick [Scope] and provides methods +/// to setup modules, resolve dependencies, teardown, +/// and open nested sub-scopes for benchmarking. class CherrypickDIAdapter implements DIAdapter { Scope? _scope; @@ -37,6 +42,8 @@ class CherrypickDIAdapter implements DIAdapter { } } +/// Internal adapter for a CherryPick sub-scope. +/// Used for simulating child/override DI scopes in benchmarks. class _CherrypickSubScopeAdapter extends CherrypickDIAdapter { final Scope _subScope; _CherrypickSubScopeAdapter(this._subScope); diff --git a/benchmark_cherrypick/lib/di_adapters/di_adapter.dart b/benchmark_cherrypick/lib/di_adapters/di_adapter.dart index de818e3..6a134eb 100644 --- a/benchmark_cherrypick/lib/di_adapters/di_adapter.dart +++ b/benchmark_cherrypick/lib/di_adapters/di_adapter.dart @@ -1,9 +1,22 @@ import 'package:cherrypick/cherrypick.dart'; +/// Abstraction for Dependency Injection (DI) Adapter. +/// +/// Provides a uniform interface to setup, resolve, and teardown DI containers/modules +/// and open sub-scopes to benchmark them under different libraries. abstract class DIAdapter { + /// Installs the provided modules into the DI container. void setupModules(List modules); + + /// Resolves an instance of type [T] by optional [named] tag. T resolve({String? named}); + + /// Asynchronously resolves an instance of type [T] by optional [named] tag. Future resolveAsync({String? named}); + + /// Tears down or disposes of the DI container. void teardown(); + + /// Opens a child DI sub-scope, useful for override/child-scope benchmarks. DIAdapter openSubScope(String name); } diff --git a/benchmark_cherrypick/lib/scenarios/universal_chain_module.dart b/benchmark_cherrypick/lib/scenarios/universal_chain_module.dart index dd89644..c006581 100644 --- a/benchmark_cherrypick/lib/scenarios/universal_chain_module.dart +++ b/benchmark_cherrypick/lib/scenarios/universal_chain_module.dart @@ -1,26 +1,47 @@ import 'package:cherrypick/cherrypick.dart'; import 'universal_service.dart'; +/// Enum to represent the DI registration/binding mode. enum UniversalBindingMode { + /// Singleton/provider binding. singletonStrategy, + + /// Factory-based binding. factoryStrategy, + + /// Async-based binding. asyncStrategy, } +/// Enum to represent which scenario is constructed for the benchmark. enum UniversalScenario { + /// Single registration. register, + /// Chain of dependencies. chain, + /// Named registrations. named, + /// Child-scope override scenario. override, + /// Asynchronous chain scenario. asyncChain, } +/// Test module that generates a chain of service bindings for benchmarking. +/// +/// Configurable by chain count, nesting depth, binding mode, and scenario +/// to support various DI performance tests (singleton, factory, async, etc). class UniversalChainModule extends Module { + /// Number of chains to create. final int chainCount; + /// Depth of each chain. final int nestingDepth; + /// How modules are registered (factory/singleton/async). final UniversalBindingMode bindingMode; + /// Which di scenario to generate (chained, named, etc). final UniversalScenario scenario; + /// Constructs a configured test DI module for the benchmarks. UniversalChainModule({ required this.chainCount, required this.nestingDepth, @@ -31,6 +52,7 @@ class UniversalChainModule extends Module { @override void builder(Scope currentScope) { if (scenario == UniversalScenario.asyncChain) { + // Generate async chain with singleton async bindings. for (var chainIndex = 0; chainIndex < chainCount; chainIndex++) { for (var levelIndex = 0; levelIndex < nestingDepth; levelIndex++) { final chain = chainIndex + 1; @@ -56,15 +78,18 @@ class UniversalChainModule extends Module { switch (scenario) { case UniversalScenario.register: + // Simple singleton registration. bind() .toProvide(() => UniversalServiceImpl(value: 'reg', dependency: null)) .singleton(); break; case UniversalScenario.named: + // Named factory registration for two distinct objects. bind().toProvide(() => UniversalServiceImpl(value: 'impl1')).withName('impl1'); bind().toProvide(() => UniversalServiceImpl(value: 'impl2')).withName('impl2'); break; case UniversalScenario.chain: + // Chain of nested services, with dependency on previous level by name. for (var chainIndex = 0; chainIndex < chainCount; chainIndex++) { for (var levelIndex = 0; levelIndex < nestingDepth; levelIndex++) { final chain = chainIndex + 1; diff --git a/benchmark_cherrypick/lib/scenarios/universal_service.dart b/benchmark_cherrypick/lib/scenarios/universal_service.dart index f6ff736..910201f 100644 --- a/benchmark_cherrypick/lib/scenarios/universal_service.dart +++ b/benchmark_cherrypick/lib/scenarios/universal_service.dart @@ -1,10 +1,17 @@ +/// Base interface for any universal service in the benchmarks. +/// +/// Represents an object in the dependency chain with an identifiable value +/// and (optionally) a dependency on a previous service in the chain. abstract class UniversalService { + /// String ID for this service instance (e.g. chain/level info). final String value; + /// Optional reference to dependency service in the chain. final UniversalService? dependency; UniversalService({required this.value, this.dependency}); } +/// Default implementation for [UniversalService] used in service chains. class UniversalServiceImpl extends UniversalService { UniversalServiceImpl({required super.value, super.dependency}); } \ No newline at end of file