@feltdb/core 0.4.11 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands.js +5 -2
- package/dist/cli/index.js +1 -1
- package/dist/create/cli.js +16 -1
- package/dist/create/create.js +30 -16
- package/dist/create/docker-compose-generator.js +48 -9
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/Cargo.lock +2238 -0
- package/dist/create/server-source/Cargo.toml +7 -0
- package/dist/create/server-source/crates/feltdb/Cargo.lock +175 -0
- package/dist/create/server-source/crates/feltdb/Cargo.toml +79 -0
- package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +370 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +589 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +259 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +446 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +272 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +378 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +414 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +486 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +273 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +587 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +513 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +395 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +469 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +409 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +627 -0
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +383 -0
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +298 -0
- package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +1698 -0
- package/dist/create/server-source/crates/feltdb/src/acquisition.rs +286 -0
- package/dist/create/server-source/crates/feltdb/src/admission.rs +192 -0
- package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +566 -0
- package/dist/create/server-source/crates/feltdb/src/analytics.rs +475 -0
- package/dist/create/server-source/crates/feltdb/src/application.rs +2244 -0
- package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +1070 -0
- package/dist/create/server-source/crates/feltdb/src/authorization.rs +1030 -0
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +266 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +8 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +482 -0
- package/dist/create/server-source/crates/feltdb/src/capability.rs +903 -0
- package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +261 -0
- package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +78 -0
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +2214 -0
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +194 -0
- package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +427 -0
- package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +453 -0
- package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +465 -0
- package/dist/create/server-source/crates/feltdb/src/convergence.rs +618 -0
- package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +380 -0
- package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +362 -0
- package/dist/create/server-source/crates/feltdb/src/cron.rs +294 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +474 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +1003 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +536 -0
- package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +364 -0
- package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +235 -0
- package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +207 -0
- package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +316 -0
- package/dist/create/server-source/crates/feltdb/src/execution.rs +426 -0
- package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +219 -0
- package/dist/create/server-source/crates/feltdb/src/indexing.rs +779 -0
- package/dist/create/server-source/crates/feltdb/src/lib.rs +2838 -0
- package/dist/create/server-source/crates/feltdb/src/materialization.rs +184 -0
- package/dist/create/server-source/crates/feltdb/src/metrics.rs +267 -0
- package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +311 -0
- package/dist/create/server-source/crates/feltdb/src/observability.rs +366 -0
- package/dist/create/server-source/crates/feltdb/src/operation.rs +251 -0
- package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +438 -0
- package/dist/create/server-source/crates/feltdb/src/operation_log.rs +344 -0
- package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +166 -0
- package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +261 -0
- package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +560 -0
- package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +3226 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +201 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +263 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +484 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +216 -0
- package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +281 -0
- package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +323 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +573 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +404 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +381 -0
- package/dist/create/server-source/crates/feltdb/src/phase_1c_three_node.rs +523 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +334 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +306 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +355 -0
- package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +395 -0
- package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +346 -0
- package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +430 -0
- package/dist/create/server-source/crates/feltdb/src/production_api.rs +400 -0
- package/dist/create/server-source/crates/feltdb/src/provenance.rs +207 -0
- package/dist/create/server-source/crates/feltdb/src/query_performance.rs +217 -0
- package/dist/create/server-source/crates/feltdb/src/references.rs +404 -0
- package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +401 -0
- package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +160 -0
- package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +132 -0
- package/dist/create/server-source/crates/feltdb/src/routing.rs +409 -0
- package/dist/create/server-source/crates/feltdb/src/sharding.rs +523 -0
- package/dist/create/server-source/crates/feltdb/src/state_contract.rs +3118 -0
- package/dist/create/server-source/crates/feltdb/src/state_hash.rs +291 -0
- package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +376 -0
- package/dist/create/server-source/crates/feltdb/src/storage.rs +267 -0
- package/dist/create/server-source/crates/feltdb/src/submission.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/sync.rs +483 -0
- package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +822 -0
- package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +366 -0
- package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +473 -0
- package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +949 -0
- package/dist/create/server-source/crates/feltdb/src/transactions.rs +646 -0
- package/dist/create/server-source/crates/feltdb/src/trigger.rs +390 -0
- package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +928 -0
- package/dist/create/server-source/crates/feltdb/src/workflow.rs +713 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +510 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +354 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +594 -0
- package/dist/create/server-source/crates/feltdb/src/workload.rs +1310 -0
- package/dist/create/server-source/crates/feltdb-server/Cargo.toml +23 -0
- package/dist/create/server-source/crates/feltdb-server/README.md +79 -0
- package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +73 -0
- package/dist/create/server-source/crates/feltdb-server/src/application_contract.rs +425 -0
- package/dist/create/server-source/crates/feltdb-server/src/artifacts.rs +449 -0
- package/dist/create/server-source/crates/feltdb-server/src/audit.rs +59 -0
- package/dist/create/server-source/crates/feltdb-server/src/auth.rs +308 -0
- package/dist/create/server-source/crates/feltdb-server/src/authorization.rs +228 -0
- package/dist/create/server-source/crates/feltdb-server/src/backup.rs +416 -0
- package/dist/create/server-source/crates/feltdb-server/src/causal.rs +218 -0
- package/dist/create/server-source/crates/feltdb-server/src/certification.rs +223 -0
- package/dist/create/server-source/crates/feltdb-server/src/clock.rs +132 -0
- package/dist/create/server-source/crates/feltdb-server/src/cluster.rs +165 -0
- package/dist/create/server-source/crates/feltdb-server/src/connections.rs +1044 -0
- package/dist/create/server-source/crates/feltdb-server/src/content.rs +111 -0
- package/dist/create/server-source/crates/feltdb-server/src/identity.rs +250 -0
- package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +78 -0
- package/dist/create/server-source/crates/feltdb-server/src/key_provider.rs +247 -0
- package/dist/create/server-source/crates/feltdb-server/src/leases.rs +123 -0
- package/dist/create/server-source/crates/feltdb-server/src/lib.rs +25 -0
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +8715 -0
- package/dist/create/server-source/crates/feltdb-server/src/metrics.rs +97 -0
- package/dist/create/server-source/crates/feltdb-server/src/portable_bundle.rs +350 -0
- package/dist/create/server-source/crates/feltdb-server/src/principals.rs +510 -0
- package/dist/create/server-source/crates/feltdb-server/src/providers.rs +269 -0
- package/dist/create/server-source/crates/feltdb-server/src/releases.rs +2563 -0
- package/dist/create/server-source/crates/feltdb-server/src/sessions.rs +156 -0
- package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +1097 -0
- package/dist/create/server-source/crates/feltdb-server/src/versions.rs +264 -0
- package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +31 -0
- package/dist/create/server-source/crates/feltdb-wasm/src/lib.rs +1086 -0
- package/dist/create/server-source/crates/feltdb-wasm/test.db +0 -0
- package/dist/flowspec.d.ts +2 -0
- package/dist/flowspec.d.ts.map +1 -1
- package/dist/flowspec.js +28 -4
- package/dist/state-contract.d.ts +7 -1
- package/dist/state-contract.d.ts.map +1 -1
- package/dist/studio/components/ApplicationDesigner.d.ts.map +1 -1
- package/dist/studio/components/index.js +1 -1
- package/dist/studio/{components-q43NSTTH.js → components-bHTARBin.js} +160 -89
- package/dist/studio/index.js +31 -28
- package/dist/studio-app/assets/{index-DZpBoVMp.js → index-BqKquLuU.js} +8 -8
- package/dist/studio-app/index.html +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
/// Phase 7.1.2: Optimization Benchmark & Regression Gate
|
|
2
|
+
///
|
|
3
|
+
/// Proves three things independently:
|
|
4
|
+
/// 1. The optimized release path is materially faster
|
|
5
|
+
/// 2. The speedup comes from reducing candidate examination (causal evidence)
|
|
6
|
+
/// 3. The optimization doesn't create a new bottleneck elsewhere
|
|
7
|
+
///
|
|
8
|
+
/// Key principle: Don't declare victory from a microbenchmark.
|
|
9
|
+
/// Systematically measure: latency, examination counts, memory, concurrency.
|
|
10
|
+
|
|
11
|
+
use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId};
|
|
12
|
+
use feltdb::causal_dependency_barrier::CausalDependencyBarrier;
|
|
13
|
+
use feltdb::convergence::VectorClock;
|
|
14
|
+
|
|
15
|
+
/// Benchmark workload configuration
|
|
16
|
+
#[derive(Clone, Debug)]
|
|
17
|
+
struct BenchmarkWorkload {
|
|
18
|
+
pending_size: usize, // 10, 100, 1K, 10K, 100K
|
|
19
|
+
frontier_advances: usize, // 1, 10
|
|
20
|
+
release_selectivity: f64, // Fraction of operations that will be released
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// Metrics collected during a benchmark run
|
|
24
|
+
#[derive(Clone, Default, Debug)]
|
|
25
|
+
struct ReleaseMetrics {
|
|
26
|
+
// Reference implementation
|
|
27
|
+
ref_pending_examined: u64,
|
|
28
|
+
ref_operations_released: u64,
|
|
29
|
+
ref_readiness_checks: u64,
|
|
30
|
+
ref_latency_ns: u64,
|
|
31
|
+
|
|
32
|
+
// Optimized implementation
|
|
33
|
+
opt_candidates_discovered: u64,
|
|
34
|
+
opt_candidates_examined: u64,
|
|
35
|
+
opt_operations_released: u64,
|
|
36
|
+
opt_readiness_checks: u64,
|
|
37
|
+
opt_latency_ns: u64,
|
|
38
|
+
|
|
39
|
+
// Index maintenance
|
|
40
|
+
opt_index_entries: u64,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
impl ReleaseMetrics {
|
|
44
|
+
/// Calculate candidate reduction percentage
|
|
45
|
+
fn candidate_reduction_pct(&self) -> f64 {
|
|
46
|
+
if self.ref_pending_examined == 0 {
|
|
47
|
+
0.0
|
|
48
|
+
} else {
|
|
49
|
+
(1.0 - (self.opt_candidates_examined as f64 / self.ref_pending_examined as f64))
|
|
50
|
+
* 100.0
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/// Calculate speedup ratio
|
|
55
|
+
fn speedup_ratio(&self) -> f64 {
|
|
56
|
+
if self.opt_latency_ns == 0 {
|
|
57
|
+
0.0
|
|
58
|
+
} else {
|
|
59
|
+
self.ref_latency_ns as f64 / self.opt_latency_ns as f64
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// Generate a benchmark workload with reproducible randomness
|
|
65
|
+
fn generate_workload(workload: &BenchmarkWorkload, seed: u64) -> (Vec<(String, VectorClock)>, Vec<VectorClock>) {
|
|
66
|
+
use std::collections::hash_map::DefaultHasher;
|
|
67
|
+
use std::hash::{Hash, Hasher};
|
|
68
|
+
|
|
69
|
+
let mut hasher = DefaultHasher::new();
|
|
70
|
+
seed.hash(&mut hasher);
|
|
71
|
+
let mut rng_seed = hasher.finish();
|
|
72
|
+
|
|
73
|
+
fn next_rng(seed: &mut u64) -> u64 {
|
|
74
|
+
*seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
|
|
75
|
+
*seed
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Generate pending operations
|
|
79
|
+
let mut operations = Vec::new();
|
|
80
|
+
let node_count = 5; // Fixed for consistency
|
|
81
|
+
|
|
82
|
+
for i in 0..workload.pending_size {
|
|
83
|
+
let mut required = VectorClock::new();
|
|
84
|
+
// Create dependency that will be satisfied based on selectivity
|
|
85
|
+
let release_threshold = (workload.pending_size as f64 * workload.release_selectivity) as usize;
|
|
86
|
+
let ts = if i < release_threshold {
|
|
87
|
+
10 // Will be released when frontier advances to 10
|
|
88
|
+
} else {
|
|
89
|
+
100 // Will remain pending
|
|
90
|
+
};
|
|
91
|
+
required.clocks.insert(format!("node_0"), ts);
|
|
92
|
+
operations.push((format!("op_{}", i), required));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Generate frontier advances
|
|
96
|
+
let mut advances = Vec::new();
|
|
97
|
+
for _ in 0..workload.frontier_advances {
|
|
98
|
+
let mut frontier = VectorClock::new();
|
|
99
|
+
frontier.clocks.insert("node_0".to_string(), 10);
|
|
100
|
+
advances.push(frontier);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
(operations, advances)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/// Run reference implementation benchmark
|
|
107
|
+
fn benchmark_reference_release(
|
|
108
|
+
workload: &BenchmarkWorkload,
|
|
109
|
+
operations: &[(String, VectorClock)],
|
|
110
|
+
advances: &[VectorClock],
|
|
111
|
+
) -> ReleaseMetrics {
|
|
112
|
+
let mut barrier = CausalDependencyBarrier::new();
|
|
113
|
+
let mut metrics = ReleaseMetrics::default();
|
|
114
|
+
|
|
115
|
+
// Load operations
|
|
116
|
+
for (op_id, required) in operations {
|
|
117
|
+
barrier.receive_operation(op_id.clone(), required.clone());
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Execute advances and measure
|
|
121
|
+
for advance in advances {
|
|
122
|
+
barrier.clear_metrics();
|
|
123
|
+
{
|
|
124
|
+
let current = barrier.get_frontier().clone();
|
|
125
|
+
barrier.get_prev_frontier_mut().clone_from(¤t);
|
|
126
|
+
}
|
|
127
|
+
barrier.get_frontier_mut().merge(advance);
|
|
128
|
+
|
|
129
|
+
let start = std::time::Instant::now();
|
|
130
|
+
let _released = barrier.check_unblocked_operations_full_scan();
|
|
131
|
+
metrics.ref_latency_ns += start.elapsed().as_nanos() as u64;
|
|
132
|
+
|
|
133
|
+
metrics.ref_pending_examined += barrier.get_metrics().pending_entries_examined;
|
|
134
|
+
metrics.ref_operations_released += barrier.get_metrics().operations_released;
|
|
135
|
+
metrics.ref_readiness_checks += barrier.get_metrics().frontier_checks;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
metrics
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/// Run optimized implementation benchmark
|
|
142
|
+
fn benchmark_optimized_release(
|
|
143
|
+
workload: &BenchmarkWorkload,
|
|
144
|
+
operations: &[(String, VectorClock)],
|
|
145
|
+
advances: &[VectorClock],
|
|
146
|
+
) -> ReleaseMetrics {
|
|
147
|
+
let mut barrier = CausalDependencyBarrier::new();
|
|
148
|
+
let mut metrics = ReleaseMetrics::default();
|
|
149
|
+
|
|
150
|
+
// Load operations
|
|
151
|
+
for (op_id, required) in operations {
|
|
152
|
+
barrier.receive_operation(op_id.clone(), required.clone());
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Execute advances and measure
|
|
156
|
+
for advance in advances {
|
|
157
|
+
barrier.clear_metrics();
|
|
158
|
+
{
|
|
159
|
+
let current = barrier.get_frontier().clone();
|
|
160
|
+
barrier.get_prev_frontier_mut().clone_from(¤t);
|
|
161
|
+
}
|
|
162
|
+
barrier.get_frontier_mut().merge(advance);
|
|
163
|
+
|
|
164
|
+
let start = std::time::Instant::now();
|
|
165
|
+
let _released = barrier.check_unblocked_operations_indexed();
|
|
166
|
+
metrics.opt_latency_ns += start.elapsed().as_nanos() as u64;
|
|
167
|
+
|
|
168
|
+
let barrier_metrics = barrier.get_metrics();
|
|
169
|
+
metrics.opt_candidates_examined += barrier_metrics.pending_entries_examined;
|
|
170
|
+
metrics.opt_operations_released += barrier_metrics.operations_released;
|
|
171
|
+
metrics.opt_readiness_checks += barrier_metrics.frontier_checks;
|
|
172
|
+
|
|
173
|
+
// Track index size
|
|
174
|
+
metrics.opt_index_entries = barrier.get_dependency_index().waiters.len() as u64;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
metrics
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/// Phase 7.1.2 Stage 1: Single-threaded Optimization Benchmark
|
|
181
|
+
fn benchmark_optimization_matrix(c: &mut Criterion) {
|
|
182
|
+
let mut group = c.benchmark_group("phase_7_1_2_optimization");
|
|
183
|
+
group.sample_size(10); // Fewer samples for larger workloads
|
|
184
|
+
|
|
185
|
+
// Primary matrix: pending × advances × selectivity
|
|
186
|
+
let pending_sizes = vec![10, 100, 1_000, 10_000];
|
|
187
|
+
let advance_counts = vec![1, 10];
|
|
188
|
+
let selectivities = vec![0.10]; // Start with 10% release
|
|
189
|
+
|
|
190
|
+
println!("\n=== Phase 7.1.2: Optimization Matrix Metrics ===");
|
|
191
|
+
println!("{:<8} {:<10} {:<10} {:<15} {:<15} {:<12} {:<12}",
|
|
192
|
+
"Pending", "Advances", "Selectivity", "Ref (µs)", "Opt (µs)", "Speedup", "Candidate %");
|
|
193
|
+
|
|
194
|
+
for pending in &pending_sizes {
|
|
195
|
+
for advances in &advance_counts {
|
|
196
|
+
for selectivity in &selectivities {
|
|
197
|
+
let workload = BenchmarkWorkload {
|
|
198
|
+
pending_size: *pending,
|
|
199
|
+
frontier_advances: *advances,
|
|
200
|
+
release_selectivity: *selectivity,
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
let (ops, advs) = generate_workload(&workload, 42);
|
|
204
|
+
let ref_metrics = benchmark_reference_release(&workload, &ops, &advs);
|
|
205
|
+
let opt_metrics = benchmark_optimized_release(&workload, &ops, &advs);
|
|
206
|
+
|
|
207
|
+
let ref_us = ref_metrics.ref_latency_ns as f64 / 1000.0;
|
|
208
|
+
let opt_us = opt_metrics.opt_latency_ns as f64 / 1000.0;
|
|
209
|
+
let speedup = ref_metrics.ref_latency_ns as f64 / opt_metrics.opt_latency_ns as f64;
|
|
210
|
+
let candidate_reduction = opt_metrics.candidate_reduction_pct();
|
|
211
|
+
|
|
212
|
+
println!("{:<8} {:<10} {:<10.0}% {:<15.1} {:<15.1} {:<12.2}x {:<12.1}%",
|
|
213
|
+
pending, advances, selectivity * 100.0, ref_us, opt_us, speedup, candidate_reduction);
|
|
214
|
+
|
|
215
|
+
let bench_name = format!("pending_{}_advances_{}_sel_{:.0}pct",
|
|
216
|
+
pending, advances, selectivity * 100.0);
|
|
217
|
+
|
|
218
|
+
group.bench_with_input(
|
|
219
|
+
BenchmarkId::new("reference", &bench_name),
|
|
220
|
+
&workload,
|
|
221
|
+
|b, w| {
|
|
222
|
+
let (ops, advs) = generate_workload(w, 42);
|
|
223
|
+
b.iter(|| {
|
|
224
|
+
benchmark_reference_release(black_box(w), black_box(&ops), black_box(&advs))
|
|
225
|
+
});
|
|
226
|
+
},
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
group.bench_with_input(
|
|
230
|
+
BenchmarkId::new("optimized", &bench_name),
|
|
231
|
+
&workload,
|
|
232
|
+
|b, w| {
|
|
233
|
+
let (ops, advs) = generate_workload(w, 42);
|
|
234
|
+
b.iter(|| {
|
|
235
|
+
benchmark_optimized_release(black_box(w), black_box(&ops), black_box(&advs))
|
|
236
|
+
});
|
|
237
|
+
},
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
group.finish();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/// Phase 7.1.2 Stage 2: Release Selectivity Variation
|
|
247
|
+
fn benchmark_selectivity_variation(c: &mut Criterion) {
|
|
248
|
+
let mut group = c.benchmark_group("phase_7_1_2_selectivity");
|
|
249
|
+
group.sample_size(10);
|
|
250
|
+
|
|
251
|
+
// Fixed pending size, vary selectivity
|
|
252
|
+
let pending_size = 1_000;
|
|
253
|
+
let selectivities = vec![0.0, 0.01, 0.10, 0.25, 0.50, 0.75, 1.0];
|
|
254
|
+
|
|
255
|
+
println!("\n=== Phase 7.1.2: Selectivity Variation Metrics ===");
|
|
256
|
+
println!("{:<12} {:<15} {:<15} {:<12} {:<12}",
|
|
257
|
+
"Selectivity", "Ref (µs)", "Opt (µs)", "Speedup", "Candidate %");
|
|
258
|
+
|
|
259
|
+
for selectivity in selectivities {
|
|
260
|
+
let workload = BenchmarkWorkload {
|
|
261
|
+
pending_size,
|
|
262
|
+
frontier_advances: 1,
|
|
263
|
+
release_selectivity: selectivity,
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
let (ops, advs) = generate_workload(&workload, 42);
|
|
267
|
+
let ref_metrics = benchmark_reference_release(&workload, &ops, &advs);
|
|
268
|
+
let opt_metrics = benchmark_optimized_release(&workload, &ops, &advs);
|
|
269
|
+
|
|
270
|
+
let ref_us = ref_metrics.ref_latency_ns as f64 / 1000.0;
|
|
271
|
+
let opt_us = opt_metrics.opt_latency_ns as f64 / 1000.0;
|
|
272
|
+
let speedup = if opt_metrics.opt_latency_ns > 0 {
|
|
273
|
+
ref_metrics.ref_latency_ns as f64 / opt_metrics.opt_latency_ns as f64
|
|
274
|
+
} else {
|
|
275
|
+
0.0
|
|
276
|
+
};
|
|
277
|
+
let candidate_reduction = opt_metrics.candidate_reduction_pct();
|
|
278
|
+
|
|
279
|
+
println!("{:<12.0}% {:<15.1} {:<15.1} {:<12.2}x {:<12.1}%",
|
|
280
|
+
selectivity * 100.0, ref_us, opt_us, speedup, candidate_reduction);
|
|
281
|
+
|
|
282
|
+
let bench_name = format!("pending_1000_sel_{:.0}pct", selectivity * 100.0);
|
|
283
|
+
|
|
284
|
+
group.bench_with_input(
|
|
285
|
+
BenchmarkId::new("reference", &bench_name),
|
|
286
|
+
&workload,
|
|
287
|
+
|b, w| {
|
|
288
|
+
let (ops, advs) = generate_workload(w, 42);
|
|
289
|
+
b.iter(|| {
|
|
290
|
+
benchmark_reference_release(black_box(w), black_box(&ops), black_box(&advs))
|
|
291
|
+
});
|
|
292
|
+
},
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
group.bench_with_input(
|
|
296
|
+
BenchmarkId::new("optimized", &bench_name),
|
|
297
|
+
&workload,
|
|
298
|
+
|b, w| {
|
|
299
|
+
let (ops, advs) = generate_workload(w, 42);
|
|
300
|
+
b.iter(|| {
|
|
301
|
+
benchmark_optimized_release(black_box(w), black_box(&ops), black_box(&advs))
|
|
302
|
+
});
|
|
303
|
+
},
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
group.finish();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/// Phase 7.1.2 Stage 3: Pathological Scaling Case
|
|
311
|
+
/// Previous evidence: 100 pending × 10 advances = 1000 examinations vs 100-200 candidates
|
|
312
|
+
/// Now scale it to see the curve
|
|
313
|
+
fn benchmark_pathological_scaling(c: &mut Criterion) {
|
|
314
|
+
let mut group = c.benchmark_group("phase_7_1_2_pathological_scaling");
|
|
315
|
+
group.sample_size(10); // Criterion requires minimum 10 samples
|
|
316
|
+
|
|
317
|
+
let pending_sizes = vec![100, 1_000, 10_000];
|
|
318
|
+
let advance_count = 10;
|
|
319
|
+
let selectivity = 0.10; // 10% of pending operations become ready each advance
|
|
320
|
+
|
|
321
|
+
println!("\n=== Phase 7.1.2: Pathological Scaling (10 advances) ===");
|
|
322
|
+
println!("{:<10} {:<15} {:<15} {:<12} {:<12}",
|
|
323
|
+
"Pending", "Ref (µs)", "Opt (µs)", "Speedup", "Candidate %");
|
|
324
|
+
|
|
325
|
+
for pending in &pending_sizes {
|
|
326
|
+
let workload = BenchmarkWorkload {
|
|
327
|
+
pending_size: *pending,
|
|
328
|
+
frontier_advances: advance_count,
|
|
329
|
+
release_selectivity: selectivity,
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
let (ops, advs) = generate_workload(&workload, 42);
|
|
333
|
+
let ref_metrics = benchmark_reference_release(&workload, &ops, &advs);
|
|
334
|
+
let opt_metrics = benchmark_optimized_release(&workload, &ops, &advs);
|
|
335
|
+
|
|
336
|
+
let ref_us = ref_metrics.ref_latency_ns as f64 / 1000.0;
|
|
337
|
+
let opt_us = opt_metrics.opt_latency_ns as f64 / 1000.0;
|
|
338
|
+
let speedup = if opt_metrics.opt_latency_ns > 0 {
|
|
339
|
+
ref_metrics.ref_latency_ns as f64 / opt_metrics.opt_latency_ns as f64
|
|
340
|
+
} else {
|
|
341
|
+
0.0
|
|
342
|
+
};
|
|
343
|
+
let candidate_reduction = opt_metrics.candidate_reduction_pct();
|
|
344
|
+
|
|
345
|
+
println!("{:<10} {:<15.1} {:<15.1} {:<12.2}x {:<12.1}%",
|
|
346
|
+
pending, ref_us, opt_us, speedup, candidate_reduction);
|
|
347
|
+
|
|
348
|
+
let bench_name = format!("pending_{}_advances_{}", pending, advance_count);
|
|
349
|
+
|
|
350
|
+
group.bench_with_input(
|
|
351
|
+
BenchmarkId::new("reference", &bench_name),
|
|
352
|
+
&workload,
|
|
353
|
+
|b, w| {
|
|
354
|
+
let (ops, advs) = generate_workload(w, 42);
|
|
355
|
+
b.iter(|| {
|
|
356
|
+
benchmark_reference_release(black_box(w), black_box(&ops), black_box(&advs))
|
|
357
|
+
});
|
|
358
|
+
},
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
group.bench_with_input(
|
|
362
|
+
BenchmarkId::new("optimized", &bench_name),
|
|
363
|
+
&workload,
|
|
364
|
+
|b, w| {
|
|
365
|
+
let (ops, advs) = generate_workload(w, 42);
|
|
366
|
+
b.iter(|| {
|
|
367
|
+
benchmark_optimized_release(black_box(w), black_box(&ops), black_box(&advs))
|
|
368
|
+
});
|
|
369
|
+
},
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
group.finish();
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
criterion_group!(
|
|
377
|
+
benches,
|
|
378
|
+
benchmark_optimization_matrix,
|
|
379
|
+
benchmark_selectivity_variation,
|
|
380
|
+
benchmark_pathological_scaling,
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
criterion_main!(benches);
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/// Phase 7.1.3: Crossover Analysis & Dispatch Economics
|
|
2
|
+
///
|
|
3
|
+
/// Determines where full_scan vs indexed dispatch should switch.
|
|
4
|
+
///
|
|
5
|
+
/// Measures across the full workload matrix:
|
|
6
|
+
/// - Pending size: 32, 64, 128, 256, 512, 1K, 10K
|
|
7
|
+
/// - Release selectivity: 0%, 1%, 10%, 25%, 50%, 75%, 100%
|
|
8
|
+
/// - Frontier advances: 1, 10, 100
|
|
9
|
+
///
|
|
10
|
+
/// Output: CSV table suitable for crossover curve analysis
|
|
11
|
+
|
|
12
|
+
use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId};
|
|
13
|
+
use feltdb::causal_dependency_barrier::CausalDependencyBarrier;
|
|
14
|
+
use feltdb::convergence::VectorClock;
|
|
15
|
+
use std::fs::File;
|
|
16
|
+
use std::io::Write;
|
|
17
|
+
|
|
18
|
+
/// Full workload configuration
|
|
19
|
+
#[derive(Clone, Debug)]
|
|
20
|
+
struct CrossoverWorkload {
|
|
21
|
+
pending_size: usize,
|
|
22
|
+
frontier_advances: usize,
|
|
23
|
+
release_selectivity: f64,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// Complete measurement record
|
|
27
|
+
#[derive(Clone, Debug)]
|
|
28
|
+
struct CrossoverMetrics {
|
|
29
|
+
// Scenario
|
|
30
|
+
pending: usize,
|
|
31
|
+
advances: usize,
|
|
32
|
+
selectivity: f64,
|
|
33
|
+
|
|
34
|
+
// Full scan path
|
|
35
|
+
fs_latency_ns: u64,
|
|
36
|
+
fs_entries_examined: u64,
|
|
37
|
+
fs_ops_released: u64,
|
|
38
|
+
|
|
39
|
+
// Indexed path
|
|
40
|
+
ix_latency_ns: u64,
|
|
41
|
+
ix_candidates_discovered: u64,
|
|
42
|
+
ix_candidates_examined: u64,
|
|
43
|
+
ix_ops_released: u64,
|
|
44
|
+
ix_index_entries: u64,
|
|
45
|
+
|
|
46
|
+
// Derived
|
|
47
|
+
speedup: f64,
|
|
48
|
+
winner: char, // 'F' for full_scan, 'I' for indexed
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
impl CrossoverMetrics {
|
|
52
|
+
fn to_csv(&self) -> String {
|
|
53
|
+
format!(
|
|
54
|
+
"{},{},{},{},{},{},{},{},{},{},{},{},{},{}",
|
|
55
|
+
self.pending,
|
|
56
|
+
self.advances,
|
|
57
|
+
self.selectivity * 100.0,
|
|
58
|
+
self.fs_latency_ns,
|
|
59
|
+
self.fs_entries_examined,
|
|
60
|
+
self.fs_ops_released,
|
|
61
|
+
self.ix_latency_ns,
|
|
62
|
+
self.ix_candidates_discovered,
|
|
63
|
+
self.ix_candidates_examined,
|
|
64
|
+
self.ix_ops_released,
|
|
65
|
+
self.ix_index_entries,
|
|
66
|
+
self.speedup,
|
|
67
|
+
self.winner,
|
|
68
|
+
if self.winner == 'I' { "INDEXED" } else { "FULL_SCAN" }
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/// Generate reproducible workload
|
|
74
|
+
fn generate_workload(
|
|
75
|
+
workload: &CrossoverWorkload,
|
|
76
|
+
seed: u64,
|
|
77
|
+
) -> (Vec<(String, VectorClock)>, Vec<VectorClock>) {
|
|
78
|
+
use std::collections::hash_map::DefaultHasher;
|
|
79
|
+
use std::hash::{Hash, Hasher};
|
|
80
|
+
|
|
81
|
+
let mut hasher = DefaultHasher::new();
|
|
82
|
+
seed.hash(&mut hasher);
|
|
83
|
+
let _rng_seed = hasher.finish();
|
|
84
|
+
|
|
85
|
+
// Generate pending operations
|
|
86
|
+
let mut operations = Vec::new();
|
|
87
|
+
for i in 0..workload.pending_size {
|
|
88
|
+
let mut required = VectorClock::new();
|
|
89
|
+
let release_threshold = (workload.pending_size as f64 * workload.release_selectivity) as usize;
|
|
90
|
+
let ts = if i < release_threshold {
|
|
91
|
+
10 // Will be released when frontier advances to 10
|
|
92
|
+
} else {
|
|
93
|
+
100 // Will remain pending
|
|
94
|
+
};
|
|
95
|
+
required.clocks.insert(format!("node_0"), ts);
|
|
96
|
+
operations.push((format!("op_{}", i), required));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Generate frontier advances
|
|
100
|
+
let mut advances = Vec::new();
|
|
101
|
+
for _ in 0..workload.frontier_advances {
|
|
102
|
+
let mut frontier = VectorClock::new();
|
|
103
|
+
frontier.clocks.insert("node_0".to_string(), 10);
|
|
104
|
+
advances.push(frontier);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
(operations, advances)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/// Measure full_scan path
|
|
111
|
+
fn measure_full_scan(
|
|
112
|
+
workload: &CrossoverWorkload,
|
|
113
|
+
operations: &[(String, VectorClock)],
|
|
114
|
+
advances: &[VectorClock],
|
|
115
|
+
) -> (u64, u64, u64) {
|
|
116
|
+
let mut barrier = CausalDependencyBarrier::new();
|
|
117
|
+
let mut latency_ns = 0u64;
|
|
118
|
+
let mut entries_examined = 0u64;
|
|
119
|
+
let mut ops_released = 0u64;
|
|
120
|
+
|
|
121
|
+
// Load operations
|
|
122
|
+
for (op_id, required) in operations {
|
|
123
|
+
barrier.receive_operation(op_id.clone(), required.clone());
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Execute advances and measure
|
|
127
|
+
for advance in advances {
|
|
128
|
+
barrier.clear_metrics();
|
|
129
|
+
{
|
|
130
|
+
let current = barrier.get_frontier().clone();
|
|
131
|
+
barrier.get_prev_frontier_mut().clone_from(¤t);
|
|
132
|
+
}
|
|
133
|
+
barrier.get_frontier_mut().merge(advance);
|
|
134
|
+
|
|
135
|
+
let start = std::time::Instant::now();
|
|
136
|
+
let _released = barrier.check_unblocked_operations_full_scan();
|
|
137
|
+
latency_ns += start.elapsed().as_nanos() as u64;
|
|
138
|
+
|
|
139
|
+
let metrics = barrier.get_metrics();
|
|
140
|
+
entries_examined += metrics.pending_entries_examined;
|
|
141
|
+
ops_released += metrics.operations_released;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
(latency_ns, entries_examined, ops_released)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/// Measure indexed path
|
|
148
|
+
fn measure_indexed(
|
|
149
|
+
workload: &CrossoverWorkload,
|
|
150
|
+
operations: &[(String, VectorClock)],
|
|
151
|
+
advances: &[VectorClock],
|
|
152
|
+
) -> (u64, u64, u64, u64, u64) {
|
|
153
|
+
let mut barrier = CausalDependencyBarrier::new();
|
|
154
|
+
let mut latency_ns = 0u64;
|
|
155
|
+
let mut candidates_discovered = 0u64;
|
|
156
|
+
let mut candidates_examined = 0u64;
|
|
157
|
+
let mut ops_released = 0u64;
|
|
158
|
+
|
|
159
|
+
// Load operations
|
|
160
|
+
for (op_id, required) in operations {
|
|
161
|
+
barrier.receive_operation(op_id.clone(), required.clone());
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Execute advances and measure
|
|
165
|
+
for advance in advances {
|
|
166
|
+
barrier.clear_metrics();
|
|
167
|
+
{
|
|
168
|
+
let current = barrier.get_frontier().clone();
|
|
169
|
+
barrier.get_prev_frontier_mut().clone_from(¤t);
|
|
170
|
+
}
|
|
171
|
+
barrier.get_frontier_mut().merge(advance);
|
|
172
|
+
|
|
173
|
+
// Track candidates before
|
|
174
|
+
let index_before = barrier.get_dependency_index().waiters.len() as u64;
|
|
175
|
+
|
|
176
|
+
let start = std::time::Instant::now();
|
|
177
|
+
let _released = barrier.check_unblocked_operations_indexed();
|
|
178
|
+
latency_ns += start.elapsed().as_nanos() as u64;
|
|
179
|
+
|
|
180
|
+
let metrics = barrier.get_metrics();
|
|
181
|
+
candidates_examined += metrics.pending_entries_examined;
|
|
182
|
+
ops_released += metrics.operations_released;
|
|
183
|
+
|
|
184
|
+
// Track index entries
|
|
185
|
+
candidates_discovered = barrier.get_dependency_index().waiters.len() as u64;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
(latency_ns, candidates_discovered, candidates_examined, ops_released, candidates_discovered)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/// Phase 7.1.3: Crossover Matrix Benchmark
|
|
192
|
+
fn benchmark_crossover_matrix(c: &mut Criterion) {
|
|
193
|
+
let mut group = c.benchmark_group("phase_7_1_3_crossover");
|
|
194
|
+
group.sample_size(10);
|
|
195
|
+
|
|
196
|
+
// Expanded matrix for crossover analysis
|
|
197
|
+
let pending_sizes = vec![32, 64, 128, 256, 512, 1_000, 10_000];
|
|
198
|
+
let selectivities = vec![0.0, 0.01, 0.10, 0.25, 0.50, 0.75, 1.0];
|
|
199
|
+
let advance_counts = vec![1, 10];
|
|
200
|
+
|
|
201
|
+
let mut results = Vec::new();
|
|
202
|
+
|
|
203
|
+
println!("\n=== Phase 7.1.3: Crossover Analysis ===");
|
|
204
|
+
println!("{:>7} {:>3} {:>5} {:>10} {:>12} {:>12} {:>7}",
|
|
205
|
+
"Pending", "Adv", "Sel%", "FS (µs)", "IX (µs)", "Speedup", "Winner");
|
|
206
|
+
|
|
207
|
+
for pending in &pending_sizes {
|
|
208
|
+
for advances in &advance_counts {
|
|
209
|
+
for selectivity in &selectivities {
|
|
210
|
+
let workload = CrossoverWorkload {
|
|
211
|
+
pending_size: *pending,
|
|
212
|
+
frontier_advances: *advances,
|
|
213
|
+
release_selectivity: *selectivity,
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
let (ops, advs) = generate_workload(&workload, 42);
|
|
217
|
+
|
|
218
|
+
// Measure both paths
|
|
219
|
+
let (fs_latency, fs_examined, fs_released) = measure_full_scan(&workload, &ops, &advs);
|
|
220
|
+
let (ix_latency, ix_discovered, ix_examined, ix_released, ix_entries) =
|
|
221
|
+
measure_indexed(&workload, &ops, &advs);
|
|
222
|
+
|
|
223
|
+
let speedup = if ix_latency > 0 {
|
|
224
|
+
fs_latency as f64 / ix_latency as f64
|
|
225
|
+
} else {
|
|
226
|
+
0.0
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
let winner = if ix_latency < fs_latency { 'I' } else { 'F' };
|
|
230
|
+
|
|
231
|
+
let fs_us = fs_latency as f64 / 1000.0;
|
|
232
|
+
let ix_us = ix_latency as f64 / 1000.0;
|
|
233
|
+
|
|
234
|
+
println!("{:>7} {:>3} {:>5.0} {:>10.1} {:>12.1} {:>12.2}x {}",
|
|
235
|
+
pending, advances, selectivity * 100.0, fs_us, ix_us, speedup,
|
|
236
|
+
if winner == 'I' { "INDEXED" } else { "FULL_SCAN" });
|
|
237
|
+
|
|
238
|
+
let metrics = CrossoverMetrics {
|
|
239
|
+
pending: *pending,
|
|
240
|
+
advances: *advances,
|
|
241
|
+
selectivity: *selectivity,
|
|
242
|
+
fs_latency_ns: fs_latency,
|
|
243
|
+
fs_entries_examined: fs_examined,
|
|
244
|
+
fs_ops_released: fs_released,
|
|
245
|
+
ix_latency_ns: ix_latency,
|
|
246
|
+
ix_candidates_discovered: ix_discovered,
|
|
247
|
+
ix_candidates_examined: ix_examined,
|
|
248
|
+
ix_ops_released: ix_released,
|
|
249
|
+
ix_index_entries: ix_entries,
|
|
250
|
+
speedup,
|
|
251
|
+
winner,
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
results.push(metrics);
|
|
255
|
+
|
|
256
|
+
// Criterion benchmarks for regression gates
|
|
257
|
+
let bench_name = format!("pending_{}_adv_{}_sel_{:.0}pct",
|
|
258
|
+
pending, advances, selectivity * 100.0);
|
|
259
|
+
|
|
260
|
+
group.bench_with_input(
|
|
261
|
+
BenchmarkId::new("full_scan", &bench_name),
|
|
262
|
+
&workload,
|
|
263
|
+
|b, w| {
|
|
264
|
+
let (ops, advs) = generate_workload(w, 42);
|
|
265
|
+
b.iter(|| measure_full_scan(black_box(w), black_box(&ops), black_box(&advs)));
|
|
266
|
+
},
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
group.bench_with_input(
|
|
270
|
+
BenchmarkId::new("indexed", &bench_name),
|
|
271
|
+
&workload,
|
|
272
|
+
|b, w| {
|
|
273
|
+
let (ops, advs) = generate_workload(w, 42);
|
|
274
|
+
b.iter(|| measure_indexed(black_box(w), black_box(&ops), black_box(&advs)));
|
|
275
|
+
},
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
group.finish();
|
|
282
|
+
|
|
283
|
+
// Write results to CSV for analysis
|
|
284
|
+
if let Ok(mut file) = File::create("target/phase_7_1_3_crossover.csv") {
|
|
285
|
+
let _ = writeln!(file,
|
|
286
|
+
"pending,advances,selectivity_pct,fs_latency_ns,fs_entries_examined,fs_ops_released,\
|
|
287
|
+
ix_latency_ns,ix_candidates_discovered,ix_candidates_examined,ix_ops_released,\
|
|
288
|
+
ix_index_entries,speedup,winner,winner_name");
|
|
289
|
+
for result in &results {
|
|
290
|
+
let _ = writeln!(file, "{}", result.to_csv());
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
println!("\nCrossover analysis written to target/phase_7_1_3_crossover.csv");
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
criterion_group!(benches, benchmark_crossover_matrix);
|
|
298
|
+
criterion_main!(benches);
|