lean_ctx/core/context_kernel/
perf_benchmark.rs1#[cfg(test)]
2mod tests {
3 use std::sync::MutexGuard;
4 use std::time::{Duration, Instant};
5
6 use crate::core::context_kernel::{
7 adaptive_bridge, adaptive_hook, ctx_read_dedup, evidence_hook, evidence_wiring, health,
8 kernel_config, list_tools_opt, response_evidence, startup, token_envelope::TokenEnvelope,
9 };
10 use crate::tools::{search_hook, search_kernel};
11
12 fn timing_enforced() -> bool {
17 std::env::var("LEAN_CTX_PERF_GATE").as_deref() == Ok("1")
18 }
19
20 fn isolated() -> MutexGuard<'static, ()> {
21 let guard = kernel_config::KERNEL_TEST_LOCK
22 .lock()
23 .unwrap_or_else(std::sync::PoisonError::into_inner);
24 kernel_config::reset_features();
25 crate::core::context_kernel::dedup_wiring::reset_dedup();
26 crate::core::context_kernel::schema_wiring::reset_schema_state();
27 crate::core::context_kernel::envelope_wiring::reset_evidence();
28 crate::core::context_kernel::proxy_bridge::reset_state();
29 crate::core::context_kernel::mcp_bridge::reset_mcp_state();
30 evidence_wiring::reset();
31 adaptive_bridge::reset();
32 search_kernel::reset();
33 crate::core::context_kernel::usage_normalizer::reset_usage();
34 crate::core::context_kernel::receipt_chain::reset_chain();
35 response_evidence::reset();
36 search_hook::reset();
37 adaptive_hook::reset();
38 startup::reset();
39 ctx_read_dedup::reset();
40 list_tools_opt::reset();
41 guard
42 }
43
44 #[test]
45 fn dedup_throughput() {
46 let _guard = isolated();
47 let started = Instant::now();
48 for index in 0..1_000 {
49 let content = format!("unique content {index}");
50 assert!(ctx_read_dedup::try_dedup("bench.rs", &content).is_none());
51 }
52 assert!(!timing_enforced() || started.elapsed() < Duration::from_millis(500));
53 }
54
55 #[test]
56 fn evidence_throughput() {
57 let _guard = isolated();
58 let started = Instant::now();
59 for _ in 0..10_000 {
60 evidence_hook::record_tool_call("ctx_read", 100, 25);
61 }
62 assert!(!timing_enforced() || started.elapsed() < Duration::from_millis(200));
63 assert_eq!(evidence_hook::evidence_report().tool_calls, 10_000);
64 }
65
66 #[test]
67 fn health_latency() {
68 let _guard = isolated();
69 let started = Instant::now();
70 for _ in 0..100 {
71 std::hint::black_box(health::kernel_health());
72 }
73 assert!(!timing_enforced() || started.elapsed() < Duration::from_millis(50));
74 }
75
76 #[test]
77 fn search_dedup_scales() {
78 let _guard = isolated();
79 let started = Instant::now();
80 for index in 0..500 {
81 search_kernel::record_search(&format!("query-{index}"), 5, 100);
82 }
83 for index in 0..100 {
84 search_kernel::record_search(&format!("query-{index}"), 5, 100);
85 }
86 let summary = search_kernel::search_summary();
87 assert!(!timing_enforced() || started.elapsed() < Duration::from_millis(200));
88 assert_eq!(summary.total_searches, 600);
89 assert_eq!(summary.unique_queries, 500);
90 assert_eq!(summary.repeated_queries, 100);
91 }
92
93 #[test]
94 fn envelope_creation_speed() {
95 let _guard = isolated();
96 let started = Instant::now();
97 let mut token_total = 0;
98 for index in 0..5_000 {
99 let envelope = TokenEnvelope {
100 model: "benchmark-model".to_owned(),
101 input_tokens: index,
102 output_tokens: 10,
103 cache_read_tokens: 5,
104 ..TokenEnvelope::default()
105 };
106 token_total += std::hint::black_box(envelope).input_tokens;
107 }
108 assert!(!timing_enforced() || started.elapsed() < Duration::from_millis(50));
109 assert_eq!(token_total, 12_497_500);
110 }
111
112 #[test]
113 fn concurrent_evidence_safe() {
114 let _guard = isolated();
115 let threads: Vec<_> = (0..4)
116 .map(|_| {
117 std::thread::spawn(|| {
118 for _ in 0..1_000 {
119 evidence_hook::record_tool_call("ctx_shell", 20, 10);
120 }
121 })
122 })
123 .collect();
124 for thread in threads {
125 thread.join().expect("evidence worker panicked");
126 }
127 assert_eq!(evidence_hook::evidence_report().tool_calls, 4_000);
128 }
129
130 #[test]
131 fn schema_opt_throughput() {
132 let _guard = isolated();
133 let tools: Vec<_> = (0..20)
134 .map(|index| {
135 (
136 format!("tool-{index}"),
137 "Read files and return complete file contents with metadata".to_owned(),
138 0_usize,
139 )
140 })
141 .collect();
142 let started = Instant::now();
143 for _ in 0..100 {
144 std::hint::black_box(list_tools_opt::optimize_descriptions(
145 tools.clone(),
146 "cursor",
147 ));
148 }
149 assert!(!timing_enforced() || started.elapsed() < Duration::from_millis(500));
150 }
151}