mirror of
https://github.com/pese-git/cherrypick.git
synced 2026-05-16 10:10:43 +00:00
feat(benchmark_di): add resolve phases, eager/lazy scenarios, and adapter parity
This commit is contained in:
@@ -31,184 +31,205 @@ class BenchmarkCliRunner {
|
||||
Future<void> run(List<String> args) async {
|
||||
final config = parseBenchmarkCli(args);
|
||||
final results = <Map<String, dynamic>>[];
|
||||
for (final bench in config.benchesToRun) {
|
||||
final scenario = toScenario(bench);
|
||||
final mode = toMode(bench);
|
||||
for (final c in config.chainCounts) {
|
||||
for (final d in config.nestDepths) {
|
||||
BenchmarkResult benchResult;
|
||||
if (config.di == 'getit') {
|
||||
final di = GetItAdapter();
|
||||
if (scenario == UniversalScenario.asyncChain) {
|
||||
final benchAsync = UniversalChainAsyncBenchmark<GetIt>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runAsync(
|
||||
benchmark: benchAsync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
);
|
||||
// DI implementations that do not support async scenarios
|
||||
const asyncUnsupported = {'kiwi', 'yx_scope'};
|
||||
for (final phase in config.phases) {
|
||||
for (final bench in config.benchesToRun) {
|
||||
final scenario = toScenario(bench);
|
||||
final mode = toMode(bench);
|
||||
if (asyncUnsupported.contains(config.di) &&
|
||||
scenario == UniversalScenario.asyncChain) {
|
||||
continue; // Skip async benchmarks for DI that does not support them
|
||||
}
|
||||
for (final c in config.chainCounts) {
|
||||
for (final d in config.nestDepths) {
|
||||
BenchmarkResult benchResult;
|
||||
if (config.di == 'getit') {
|
||||
final di = GetItAdapter();
|
||||
if (scenario == UniversalScenario.asyncChain) {
|
||||
final benchAsync = UniversalChainAsyncBenchmark<GetIt>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runAsync(
|
||||
benchmark: benchAsync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
phase: phase,
|
||||
);
|
||||
} else {
|
||||
final benchSync = UniversalChainBenchmark<GetIt>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
scenario: scenario,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runSync(
|
||||
benchmark: benchSync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
phase: phase,
|
||||
);
|
||||
}
|
||||
} else if (config.di == 'kiwi') {
|
||||
final di = KiwiAdapter();
|
||||
if (scenario == UniversalScenario.asyncChain) {
|
||||
final benchAsync = UniversalChainAsyncBenchmark<KiwiContainer>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runAsync(
|
||||
benchmark: benchAsync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
phase: phase,
|
||||
);
|
||||
} else {
|
||||
final benchSync = UniversalChainBenchmark<KiwiContainer>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
scenario: scenario,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runSync(
|
||||
benchmark: benchSync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
phase: phase,
|
||||
);
|
||||
}
|
||||
} else if (config.di == 'riverpod') {
|
||||
final di = RiverpodAdapter();
|
||||
if (scenario == UniversalScenario.asyncChain) {
|
||||
final benchAsync = UniversalChainAsyncBenchmark<
|
||||
Map<String, rp.ProviderBase<Object?>>>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runAsync(
|
||||
benchmark: benchAsync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
phase: phase,
|
||||
);
|
||||
} else {
|
||||
final benchSync = UniversalChainBenchmark<
|
||||
Map<String, rp.ProviderBase<Object?>>>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
scenario: scenario,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runSync(
|
||||
benchmark: benchSync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
phase: phase,
|
||||
);
|
||||
}
|
||||
} else if (config.di == 'yx_scope') {
|
||||
final di = YxScopeAdapter();
|
||||
if (scenario == UniversalScenario.asyncChain) {
|
||||
final benchAsync =
|
||||
UniversalChainAsyncBenchmark<UniversalYxScopeContainer>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runAsync(
|
||||
benchmark: benchAsync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
phase: phase,
|
||||
);
|
||||
} else {
|
||||
final benchSync =
|
||||
UniversalChainBenchmark<UniversalYxScopeContainer>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
scenario: scenario,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runSync(
|
||||
benchmark: benchSync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
phase: phase,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
final benchSync = UniversalChainBenchmark<GetIt>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
scenario: scenario,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runSync(
|
||||
benchmark: benchSync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
);
|
||||
}
|
||||
} else if (config.di == 'kiwi') {
|
||||
final di = KiwiAdapter();
|
||||
if (scenario == UniversalScenario.asyncChain) {
|
||||
// UnsupportedError будет выброшен адаптером, но если дойдёт — вызывать async benchmark
|
||||
final benchAsync = UniversalChainAsyncBenchmark<KiwiContainer>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runAsync(
|
||||
benchmark: benchAsync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
);
|
||||
} else {
|
||||
final benchSync = UniversalChainBenchmark<KiwiContainer>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
scenario: scenario,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runSync(
|
||||
benchmark: benchSync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
);
|
||||
}
|
||||
} else if (config.di == 'riverpod') {
|
||||
final di = RiverpodAdapter();
|
||||
if (scenario == UniversalScenario.asyncChain) {
|
||||
final benchAsync = UniversalChainAsyncBenchmark<
|
||||
Map<String, rp.ProviderBase<Object?>>>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runAsync(
|
||||
benchmark: benchAsync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
);
|
||||
} else {
|
||||
final benchSync = UniversalChainBenchmark<
|
||||
Map<String, rp.ProviderBase<Object?>>>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
scenario: scenario,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runSync(
|
||||
benchmark: benchSync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
);
|
||||
}
|
||||
} else if (config.di == 'yx_scope') {
|
||||
final di = YxScopeAdapter();
|
||||
if (scenario == UniversalScenario.asyncChain) {
|
||||
final benchAsync =
|
||||
UniversalChainAsyncBenchmark<UniversalYxScopeContainer>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runAsync(
|
||||
benchmark: benchAsync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
);
|
||||
} else {
|
||||
final benchSync =
|
||||
UniversalChainBenchmark<UniversalYxScopeContainer>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
scenario: scenario,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runSync(
|
||||
benchmark: benchSync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
final di = CherrypickDIAdapter();
|
||||
if (scenario == UniversalScenario.asyncChain) {
|
||||
final benchAsync = UniversalChainAsyncBenchmark<Scope>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runAsync(
|
||||
benchmark: benchAsync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
);
|
||||
} else {
|
||||
final benchSync = UniversalChainBenchmark<Scope>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
scenario: scenario,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runSync(
|
||||
benchmark: benchSync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
);
|
||||
final di = CherrypickDIAdapter();
|
||||
if (scenario == UniversalScenario.asyncChain) {
|
||||
final benchAsync = UniversalChainAsyncBenchmark<Scope>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runAsync(
|
||||
benchmark: benchAsync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
phase: phase,
|
||||
);
|
||||
} else {
|
||||
final benchSync = UniversalChainBenchmark<Scope>(
|
||||
di,
|
||||
chainCount: c,
|
||||
nestingDepth: d,
|
||||
mode: mode,
|
||||
scenario: scenario,
|
||||
);
|
||||
benchResult = await BenchmarkRunner.runSync(
|
||||
benchmark: benchSync,
|
||||
warmups: config.warmups,
|
||||
repeats: config.repeats,
|
||||
phase: phase,
|
||||
);
|
||||
}
|
||||
}
|
||||
final timings = benchResult.timings;
|
||||
if (timings.isEmpty) continue; // skip failed scenarios
|
||||
timings.sort();
|
||||
final count = timings.length;
|
||||
final mean = timings.reduce((a, b) => a + b) / count;
|
||||
final median = count.isOdd
|
||||
? timings[count ~/ 2]
|
||||
: (timings[count ~/ 2 - 1] + timings[count ~/ 2]) / 2;
|
||||
final minVal = timings.first;
|
||||
final maxVal = timings.last;
|
||||
final stddev = sqrt(timings
|
||||
.map((x) => pow(x - mean, 2))
|
||||
.reduce((a, b) => a + b) /
|
||||
count);
|
||||
results.add({
|
||||
'benchmark': 'Universal_$bench',
|
||||
'phase': phase.name,
|
||||
'chainCount': c,
|
||||
'nestingDepth': d,
|
||||
'mean_us': mean.toStringAsFixed(2),
|
||||
'median_us': median.toStringAsFixed(2),
|
||||
'stddev_us': stddev.toStringAsFixed(2),
|
||||
'min_us': minVal.toStringAsFixed(2),
|
||||
'max_us': maxVal.toStringAsFixed(2),
|
||||
'trials': timings.length,
|
||||
'timings_us': timings.map((t) => t.toStringAsFixed(2)).toList(),
|
||||
'memory_diff_kb': benchResult.memoryDiffKb,
|
||||
'delta_peak_kb': benchResult.deltaPeakKb,
|
||||
'peak_rss_kb': benchResult.peakRssKb,
|
||||
});
|
||||
}
|
||||
final timings = benchResult.timings;
|
||||
timings.sort();
|
||||
var mean = timings.reduce((a, b) => a + b) / timings.length;
|
||||
var median = timings[timings.length ~/ 2];
|
||||
var minVal = timings.first;
|
||||
var maxVal = timings.last;
|
||||
var stddev = timings.isEmpty
|
||||
? 0
|
||||
: sqrt(
|
||||
timings.map((x) => pow(x - mean, 2)).reduce((a, b) => a + b) /
|
||||
timings.length);
|
||||
results.add({
|
||||
'benchmark': 'Universal_$bench',
|
||||
'chainCount': c,
|
||||
'nestingDepth': d,
|
||||
'mean_us': mean.toStringAsFixed(2),
|
||||
'median_us': median.toStringAsFixed(2),
|
||||
'stddev_us': stddev.toStringAsFixed(2),
|
||||
'min_us': minVal.toStringAsFixed(2),
|
||||
'max_us': maxVal.toStringAsFixed(2),
|
||||
'trials': timings.length,
|
||||
'timings_us': timings.map((t) => t.toStringAsFixed(2)).toList(),
|
||||
'memory_diff_kb': benchResult.memoryDiffKb,
|
||||
'delta_peak_kb': benchResult.deltaPeakKb,
|
||||
'peak_rss_kb': benchResult.peakRssKb,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,18 @@ import 'package:benchmark_di/scenarios/universal_scenario.dart';
|
||||
|
||||
/// Enum describing all supported Universal DI benchmark types.
|
||||
enum UniversalBenchmark {
|
||||
/// Simple singleton registration benchmark
|
||||
/// Simple singleton registration benchmark (eager, where supported)
|
||||
registerSingleton,
|
||||
|
||||
/// Chain of singleton dependencies
|
||||
/// Simple lazy singleton registration benchmark
|
||||
registerLazySingleton,
|
||||
|
||||
/// Chain of eager singleton dependencies
|
||||
chainSingleton,
|
||||
|
||||
/// Chain of lazy singleton dependencies
|
||||
chainLazySingleton,
|
||||
|
||||
/// Chain using factories
|
||||
chainFactory,
|
||||
|
||||
@@ -25,12 +31,19 @@ enum UniversalBenchmark {
|
||||
override,
|
||||
}
|
||||
|
||||
enum ResolvePhase {
|
||||
firstResolve,
|
||||
steadyStateResolve,
|
||||
}
|
||||
|
||||
/// Maps [UniversalBenchmark] to the scenario enum for DI chains.
|
||||
UniversalScenario toScenario(UniversalBenchmark b) {
|
||||
switch (b) {
|
||||
case UniversalBenchmark.registerSingleton:
|
||||
case UniversalBenchmark.registerLazySingleton:
|
||||
return UniversalScenario.register;
|
||||
case UniversalBenchmark.chainSingleton:
|
||||
case UniversalBenchmark.chainLazySingleton:
|
||||
return UniversalScenario.chain;
|
||||
case UniversalBenchmark.chainFactory:
|
||||
return UniversalScenario.chain;
|
||||
@@ -43,21 +56,21 @@ UniversalScenario toScenario(UniversalBenchmark b) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps benchmark to registration mode (singleton/factory/async).
|
||||
/// Maps benchmark to registration mode (singleton/lazySingleton/factory/async).
|
||||
UniversalBindingMode toMode(UniversalBenchmark b) {
|
||||
switch (b) {
|
||||
case UniversalBenchmark.registerSingleton:
|
||||
return UniversalBindingMode.singletonStrategy;
|
||||
case UniversalBenchmark.chainSingleton:
|
||||
case UniversalBenchmark.named:
|
||||
case UniversalBenchmark.override:
|
||||
return UniversalBindingMode.singletonStrategy;
|
||||
case UniversalBenchmark.registerLazySingleton:
|
||||
case UniversalBenchmark.chainLazySingleton:
|
||||
return UniversalBindingMode.lazySingletonStrategy;
|
||||
case UniversalBenchmark.chainFactory:
|
||||
return UniversalBindingMode.factoryStrategy;
|
||||
case UniversalBenchmark.chainAsync:
|
||||
return UniversalBindingMode.asyncStrategy;
|
||||
case UniversalBenchmark.named:
|
||||
return UniversalBindingMode.singletonStrategy;
|
||||
case UniversalBenchmark.override:
|
||||
return UniversalBindingMode.singletonStrategy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +111,10 @@ class BenchmarkCliConfig {
|
||||
|
||||
/// Name of DI implementation ("cherrypick" or "getit")
|
||||
final String di;
|
||||
|
||||
/// Which resolve phase(s) to measure.
|
||||
final List<ResolvePhase> phases;
|
||||
|
||||
BenchmarkCliConfig({
|
||||
required this.benchesToRun,
|
||||
required this.chainCounts,
|
||||
@@ -106,6 +123,7 @@ class BenchmarkCliConfig {
|
||||
required this.warmups,
|
||||
required this.format,
|
||||
required this.di,
|
||||
required this.phases,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -119,6 +137,8 @@ BenchmarkCliConfig parseBenchmarkCli(List<String> args) {
|
||||
..addOption('repeat', abbr: 'r', defaultsTo: '2')
|
||||
..addOption('warmup', abbr: 'w', defaultsTo: '1')
|
||||
..addOption('format', abbr: 'f', defaultsTo: 'pretty')
|
||||
..addOption('resolvePhase',
|
||||
defaultsTo: 'all', help: 'Resolve phase: first, steady, or all')
|
||||
..addOption('di',
|
||||
defaultsTo: 'cherrypick',
|
||||
help: 'DI implementation: cherrypick, getit or riverpod')
|
||||
@@ -128,12 +148,39 @@ BenchmarkCliConfig parseBenchmarkCli(List<String> args) {
|
||||
print(parser.usage);
|
||||
exit(0);
|
||||
}
|
||||
final benchName = result['benchmark'] as String;
|
||||
final isAll = benchName == 'all';
|
||||
final benchNameInput = result['benchmark'] as String;
|
||||
final isAll = benchNameInput.trim() == 'all';
|
||||
final allBenches = UniversalBenchmark.values;
|
||||
|
||||
String normalizeBenchName(String name) {
|
||||
final n = name.trim().toLowerCase();
|
||||
return switch (n) {
|
||||
'register' || 'registersingleton' || 'registereager' => 'registerSingleton',
|
||||
'registerlazy' || 'registerlazysingleton' || 'registerlazysingle' => 'registerLazySingleton',
|
||||
'chain' || 'chainsingleton' || 'chaineager' => 'chainSingleton',
|
||||
'chainlazy' || 'chainlazysingleton' || 'lazysingleton' => 'chainLazySingleton',
|
||||
'chainfactory' || 'factory' => 'chainFactory',
|
||||
'async' || 'asyncchain' || 'chainasync' => 'chainAsync',
|
||||
'named' => 'named',
|
||||
'override' => 'override',
|
||||
_ => n,
|
||||
};
|
||||
}
|
||||
|
||||
final benchesToRun = isAll
|
||||
? allBenches
|
||||
: [parseEnum(benchName, allBenches, UniversalBenchmark.chainSingleton)];
|
||||
: benchNameInput
|
||||
.split(',')
|
||||
.map((n) => parseEnum(normalizeBenchName(n), allBenches,
|
||||
UniversalBenchmark.chainSingleton))
|
||||
.toSet()
|
||||
.toList();
|
||||
final phaseName = (result['resolvePhase'] as String).toLowerCase();
|
||||
final phases = switch (phaseName) {
|
||||
'first' => [ResolvePhase.firstResolve],
|
||||
'steady' => [ResolvePhase.steadyStateResolve],
|
||||
_ => ResolvePhase.values,
|
||||
};
|
||||
return BenchmarkCliConfig(
|
||||
benchesToRun: benchesToRun,
|
||||
chainCounts: parseIntList(result['chainCount'] as String),
|
||||
@@ -142,5 +189,6 @@ BenchmarkCliConfig parseBenchmarkCli(List<String> args) {
|
||||
warmups: int.tryParse(result['warmup'] as String? ?? "") ?? 1,
|
||||
format: result['format'] as String,
|
||||
di: result['di'] as String? ?? 'cherrypick',
|
||||
phases: phases,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ class CsvReport extends ReportGenerator {
|
||||
@override
|
||||
final List<String> keys = [
|
||||
'benchmark',
|
||||
'phase',
|
||||
'chainCount',
|
||||
'nestingDepth',
|
||||
'mean_us',
|
||||
|
||||
@@ -8,6 +8,7 @@ class MarkdownReport extends ReportGenerator {
|
||||
@override
|
||||
final List<String> keys = [
|
||||
'benchmark',
|
||||
'phase',
|
||||
'chainCount',
|
||||
'nestingDepth',
|
||||
'mean_us',
|
||||
@@ -24,7 +25,9 @@ class MarkdownReport extends ReportGenerator {
|
||||
/// Friendly display names for each benchmark type.
|
||||
static const nameMap = {
|
||||
'Universal_UniversalBenchmark.registerSingleton': 'RegisterSingleton',
|
||||
'Universal_UniversalBenchmark.registerLazySingleton': 'RegisterLazySingleton',
|
||||
'Universal_UniversalBenchmark.chainSingleton': 'ChainSingleton',
|
||||
'Universal_UniversalBenchmark.chainLazySingleton': 'ChainLazySingleton',
|
||||
'Universal_UniversalBenchmark.chainFactory': 'ChainFactory',
|
||||
'Universal_UniversalBenchmark.chainAsync': 'AsyncChain',
|
||||
'Universal_UniversalBenchmark.named': 'Named',
|
||||
@@ -36,6 +39,7 @@ class MarkdownReport extends ReportGenerator {
|
||||
String render(List<Map<String, dynamic>> rows) {
|
||||
final headers = [
|
||||
'Benchmark',
|
||||
'Phase',
|
||||
'Chain Count',
|
||||
'Depth',
|
||||
'Mean (us)',
|
||||
@@ -52,6 +56,7 @@ class MarkdownReport extends ReportGenerator {
|
||||
final readableName = nameMap[r['benchmark']] ?? r['benchmark'];
|
||||
return [
|
||||
readableName,
|
||||
r['phase'],
|
||||
r['chainCount'],
|
||||
r['nestingDepth'],
|
||||
r['mean_us'],
|
||||
@@ -82,6 +87,7 @@ class MarkdownReport extends ReportGenerator {
|
||||
final legend = '''
|
||||
> **Legend:**
|
||||
> `Benchmark` – Test name
|
||||
> `Phase` – `firstResolve` or `steadyStateResolve`
|
||||
> `Chain Count` – Number of independent chains
|
||||
> `Depth` – Depth of each chain
|
||||
> `Mean (us)` – Average time per run (microseconds)
|
||||
|
||||
@@ -8,6 +8,7 @@ class PrettyReport extends ReportGenerator {
|
||||
@override
|
||||
final List<String> keys = [
|
||||
'benchmark',
|
||||
'phase',
|
||||
'chainCount',
|
||||
'nestingDepth',
|
||||
'mean_us',
|
||||
@@ -24,7 +25,9 @@ class PrettyReport extends ReportGenerator {
|
||||
/// Mappings from internal benchmark IDs to display names.
|
||||
static const nameMap = {
|
||||
'Universal_UniversalBenchmark.registerSingleton': 'RegisterSingleton',
|
||||
'Universal_UniversalBenchmark.registerLazySingleton': 'RegisterLazySingleton',
|
||||
'Universal_UniversalBenchmark.chainSingleton': 'ChainSingleton',
|
||||
'Universal_UniversalBenchmark.chainLazySingleton': 'ChainLazySingleton',
|
||||
'Universal_UniversalBenchmark.chainFactory': 'ChainFactory',
|
||||
'Universal_UniversalBenchmark.chainAsync': 'AsyncChain',
|
||||
'Universal_UniversalBenchmark.named': 'Named',
|
||||
@@ -36,6 +39,7 @@ class PrettyReport extends ReportGenerator {
|
||||
String render(List<Map<String, dynamic>> rows) {
|
||||
final headers = [
|
||||
'Benchmark',
|
||||
'Phase',
|
||||
'Chain Count',
|
||||
'Depth',
|
||||
'Mean (us)',
|
||||
@@ -53,6 +57,7 @@ class PrettyReport extends ReportGenerator {
|
||||
final readableName = nameMap[r['benchmark']] ?? r['benchmark'];
|
||||
return [
|
||||
readableName,
|
||||
r['phase'],
|
||||
r['chainCount'],
|
||||
r['nestingDepth'],
|
||||
r['mean_us'],
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'package:benchmark_di/benchmarks/universal_chain_benchmark.dart';
|
||||
import 'package:benchmark_di/benchmarks/universal_chain_async_benchmark.dart';
|
||||
import 'package:benchmark_di/cli/parser.dart';
|
||||
|
||||
/// Holds the results for a single benchmark execution.
|
||||
class BenchmarkResult {
|
||||
@@ -50,17 +51,24 @@ class BenchmarkRunner {
|
||||
required UniversalChainBenchmark benchmark,
|
||||
required int warmups,
|
||||
required int repeats,
|
||||
required ResolvePhase phase,
|
||||
}) async {
|
||||
final timings = <num>[];
|
||||
final rssValues = <int>[];
|
||||
for (int i = 0; i < warmups; i++) {
|
||||
benchmark.setup();
|
||||
if (phase == ResolvePhase.steadyStateResolve) {
|
||||
benchmark.prewarm();
|
||||
}
|
||||
benchmark.run();
|
||||
benchmark.teardown();
|
||||
}
|
||||
final memBefore = ProcessInfo.currentRss;
|
||||
for (int i = 0; i < repeats; i++) {
|
||||
benchmark.setup();
|
||||
if (phase == ResolvePhase.steadyStateResolve) {
|
||||
benchmark.prewarm();
|
||||
}
|
||||
final sw = Stopwatch()..start();
|
||||
benchmark.run();
|
||||
sw.stop();
|
||||
@@ -78,17 +86,24 @@ class BenchmarkRunner {
|
||||
required UniversalChainAsyncBenchmark benchmark,
|
||||
required int warmups,
|
||||
required int repeats,
|
||||
required ResolvePhase phase,
|
||||
}) async {
|
||||
final timings = <num>[];
|
||||
final rssValues = <int>[];
|
||||
for (int i = 0; i < warmups; i++) {
|
||||
await benchmark.setup();
|
||||
if (phase == ResolvePhase.steadyStateResolve) {
|
||||
await benchmark.prewarm();
|
||||
}
|
||||
await benchmark.run();
|
||||
await benchmark.teardown();
|
||||
}
|
||||
final memBefore = ProcessInfo.currentRss;
|
||||
for (int i = 0; i < repeats; i++) {
|
||||
await benchmark.setup();
|
||||
if (phase == ResolvePhase.steadyStateResolve) {
|
||||
await benchmark.prewarm();
|
||||
}
|
||||
final sw = Stopwatch()..start();
|
||||
await benchmark.run();
|
||||
sw.stop();
|
||||
|
||||
Reference in New Issue
Block a user