@@ -5,31 +5,63 @@ use std::sync::Arc;
55use std:: time:: Duration ;
66use tokio:: sync:: RwLock ;
77use tokio:: runtime:: Runtime ;
8+ use std:: sync:: OnceLock ;
89
9- /// Setup test server for benchmarking
10- async fn setup_benchmark_server ( ) -> Result < ( tokio:: task:: JoinHandle < ( ) > , u16 ) , Box < dyn std:: error:: Error + Send + Sync > > {
10+ static BENCHMARK_SERVER : OnceLock < ( u16 , Arc < RwLock < ServerState > > ) > = OnceLock :: new ( ) ;
11+
12+ /// Setup shared test server for all benchmarks to reduce overhead
13+ async fn setup_shared_benchmark_server ( ) -> Result < ( tokio:: task:: JoinHandle < ( ) > , u16 ) , Box < dyn std:: error:: Error + Send + Sync > > {
1114 // Use a fixed port for benchmarks to avoid conflicts
1215 let port = 9001 ;
1316
14- // Load configuration
15- let config = Config :: load ( ) . map_err ( |e| format ! ( "Failed to load config: {e}" ) ) ?;
17+ // Load configuration with mock settings for faster startup
18+ let mut config = Config :: load ( ) . map_err ( |e| format ! ( "Failed to load config: {e}" ) ) ?;
19+ // Override with localhost for faster responses (avoiding external network calls)
20+ config. rpc_url = "http://localhost:8899" . to_string ( ) ; // Mock local RPC for benchmarks
21+ config. timeouts . http_request_seconds = 1 ; // Reduce timeouts for benchmarks
1622
1723 // Create server state
1824 let server_state = ServerState :: new ( config) ;
1925 let state = Arc :: new ( RwLock :: new ( server_state) ) ;
2026
2127 // Start HTTP server with MCP API
22- let handle = start_mcp_server_task ( port, state) ;
28+ let handle = start_mcp_server_task ( port, state. clone ( ) ) ;
29+
30+ // Store shared server state
31+ BENCHMARK_SERVER . set ( ( port, state) ) . ok ( ) ;
2332
2433 // Give server time to start
25- tokio:: time:: sleep ( Duration :: from_millis ( 200 ) ) . await ;
34+ tokio:: time:: sleep ( Duration :: from_millis ( 100 ) ) . await ; // Reduced startup time
2635
2736 Ok ( ( handle, port) )
2837}
2938
30- /// Helper function to make HTTP requests for benchmarking
39+ /// Get or initialize the shared benchmark server
40+ fn get_benchmark_server_port ( ) -> u16 {
41+ if let Some ( ( port, _) ) = BENCHMARK_SERVER . get ( ) {
42+ * port
43+ } else {
44+ // Initialize server if not already done
45+ let rt = Runtime :: new ( ) . unwrap ( ) ;
46+ let ( _handle, port) = rt. block_on ( async {
47+ setup_shared_benchmark_server ( ) . await . expect ( "Failed to setup shared server" )
48+ } ) ;
49+ port
50+ }
51+ }
52+
53+ /// Helper function to make HTTP requests for benchmarking (with connection reuse)
3154async fn make_benchmark_request ( request : Value , port : u16 ) -> Result < Value , Box < dyn std:: error:: Error + Send + Sync > > {
32- let client = reqwest:: Client :: new ( ) ;
55+ static CLIENT : OnceLock < reqwest:: Client > = OnceLock :: new ( ) ;
56+
57+ let client = CLIENT . get_or_init ( || {
58+ reqwest:: Client :: builder ( )
59+ . timeout ( Duration :: from_secs ( 5 ) ) // Shorter timeout for benchmarks
60+ . pool_idle_timeout ( Duration :: from_secs ( 30 ) ) // Connection reuse
61+ . build ( )
62+ . unwrap ( )
63+ } ) ;
64+
3365 let response = client
3466 . post ( format ! ( "http://localhost:{port}/api/mcp" ) )
3567 . header ( "Content-Type" , "application/json" )
@@ -44,11 +76,7 @@ async fn make_benchmark_request(request: Value, port: u16) -> Result<Value, Box<
4476/// Benchmark MCP protocol initialization
4577fn bench_mcp_initialization ( c : & mut Criterion ) {
4678 let rt = Runtime :: new ( ) . unwrap ( ) ;
47-
48- // Setup server once for all benchmark iterations
49- let ( _handle, port) = rt. block_on ( async {
50- setup_benchmark_server ( ) . await . expect ( "Failed to setup server" )
51- } ) ;
79+ let port = get_benchmark_server_port ( ) ;
5280
5381 let initialize_request = json ! ( {
5482 "jsonrpc" : "2.0" ,
@@ -69,15 +97,12 @@ fn bench_mcp_initialization(c: &mut Criterion) {
6997 } ) ;
7098}
7199
72- /// Benchmark tools list retrieval
100+ /// Benchmark tools list retrieval
73101fn bench_tools_list ( c : & mut Criterion ) {
74102 let rt = Runtime :: new ( ) . unwrap ( ) ;
103+ let port = get_benchmark_server_port ( ) ;
75104
76- let ( _handle, port) = rt. block_on ( async {
77- setup_benchmark_server ( ) . await . expect ( "Failed to setup server" )
78- } ) ;
79-
80- // Initialize first
105+ // Initialize first (one time setup)
81106 let initialize_request = json ! ( {
82107 "jsonrpc" : "2.0" ,
83108 "id" : 1 ,
@@ -107,15 +132,12 @@ fn bench_tools_list(c: &mut Criterion) {
107132 } ) ;
108133}
109134
110- /// Benchmark different RPC tool calls
135+ /// Benchmark different RPC tool calls (reduced scope for performance)
111136fn bench_rpc_tool_calls ( c : & mut Criterion ) {
112137 let rt = Runtime :: new ( ) . unwrap ( ) ;
138+ let port = get_benchmark_server_port ( ) ;
113139
114- let ( _handle, port) = rt. block_on ( async {
115- setup_benchmark_server ( ) . await . expect ( "Failed to setup server" )
116- } ) ;
117-
118- // Initialize first
140+ // Initialize first (one time setup)
119141 let initialize_request = json ! ( {
120142 "jsonrpc" : "2.0" ,
121143 "id" : 1 ,
@@ -133,12 +155,10 @@ fn bench_rpc_tool_calls(c: &mut Criterion) {
133155
134156 let mut group = c. benchmark_group ( "rpc_tool_calls" ) ;
135157
136- // Benchmark simple methods
158+ // Benchmark only fast methods that don't require external network calls
137159 let simple_methods = vec ! [
138- ( "getHealth" , json!( { } ) ) ,
139- ( "getVersion" , json!( { } ) ) ,
140- ( "getGenesisHash" , json!( { } ) ) ,
141- ( "minimumLedgerSlot" , json!( { } ) ) ,
160+ ( "getVersion" , json!( { } ) ) , // Fast local method
161+ ( "getSlot" , json!( { } ) ) , // Local cached data
142162 ] ;
143163
144164 for ( method_name, params) in simple_methods {
@@ -160,44 +180,15 @@ fn bench_rpc_tool_calls(c: &mut Criterion) {
160180 } ) ;
161181 }
162182
163- // Benchmark methods with parameters
164- let param_methods = vec ! [
165- ( "getBalance" , json!( { "pubkey" : "11111111111111111111111111111112" } ) ) ,
166- ( "getAccountInfo" , json!( { "pubkey" : "11111111111111111111111111111112" } ) ) ,
167- ( "getSlot" , json!( "{}" ) ) ,
168- ] ;
169-
170- for ( method_name, params) in param_methods {
171- let request = json ! ( {
172- "jsonrpc" : "2.0" ,
173- "id" : 3 ,
174- "method" : "tools/call" ,
175- "params" : {
176- "name" : method_name,
177- "arguments" : params
178- }
179- } ) ;
180-
181- group. bench_with_input ( BenchmarkId :: new ( "with_params" , method_name) , & request, |b, req| {
182- b. to_async ( & rt) . iter ( || async {
183- let result = make_benchmark_request ( black_box ( req. clone ( ) ) , port) . await ;
184- black_box ( result)
185- } )
186- } ) ;
187- }
188-
189183 group. finish ( ) ;
190184}
191185
192- /// Benchmark concurrent requests
186+ /// Benchmark concurrent requests (reduced concurrency for faster benchmarks)
193187fn bench_concurrent_requests ( c : & mut Criterion ) {
194188 let rt = Runtime :: new ( ) . unwrap ( ) ;
189+ let port = get_benchmark_server_port ( ) ;
195190
196- let ( _handle, port) = rt. block_on ( async {
197- setup_benchmark_server ( ) . await . expect ( "Failed to setup server" )
198- } ) ;
199-
200- // Initialize first
191+ // Initialize first (one time setup)
201192 let initialize_request = json ! ( {
202193 "jsonrpc" : "2.0" ,
203194 "id" : 1 ,
@@ -215,15 +206,16 @@ fn bench_concurrent_requests(c: &mut Criterion) {
215206
216207 let mut group = c. benchmark_group ( "concurrent_requests" ) ;
217208
218- for concurrency in [ 1 , 5 , 10 , 20 ] . iter ( ) {
219- group. bench_with_input ( BenchmarkId :: new ( "getHealth" , concurrency) , concurrency, |b, & concurrency| {
209+ // Test smaller concurrency levels for faster benchmarks
210+ for concurrency in [ 1 , 5 , 10 ] . iter ( ) {
211+ group. bench_with_input ( BenchmarkId :: new ( "getVersion" , concurrency) , concurrency, |b, & concurrency| {
220212 b. to_async ( & rt) . iter ( || async {
221213 let request = json ! ( {
222214 "jsonrpc" : "2.0" ,
223215 "id" : 1 ,
224216 "method" : "tools/call" ,
225217 "params" : {
226- "name" : "getHealth" ,
218+ "name" : "getVersion" , // Use faster method
227219 "arguments" : { }
228220 }
229221 } ) ;
@@ -249,14 +241,19 @@ fn bench_concurrent_requests(c: &mut Criterion) {
249241/// Benchmark health endpoint
250242fn bench_health_endpoint ( c : & mut Criterion ) {
251243 let rt = Runtime :: new ( ) . unwrap ( ) ;
252-
253- let ( _handle, port) = rt. block_on ( async {
254- setup_benchmark_server ( ) . await . expect ( "Failed to setup server" )
244+ let port = get_benchmark_server_port ( ) ;
245+
246+ static CLIENT : OnceLock < reqwest:: Client > = OnceLock :: new ( ) ;
247+ let client = CLIENT . get_or_init ( || {
248+ reqwest:: Client :: builder ( )
249+ . timeout ( Duration :: from_secs ( 5 ) )
250+ . pool_idle_timeout ( Duration :: from_secs ( 30 ) )
251+ . build ( )
252+ . unwrap ( )
255253 } ) ;
256254
257255 c. bench_function ( "health_endpoint" , |b| {
258256 b. to_async ( & rt) . iter ( || async {
259- let client = reqwest:: Client :: new ( ) ;
260257 let response = client
261258 . get ( format ! ( "http://localhost:{port}/health" ) )
262259 . send ( )
@@ -270,14 +267,19 @@ fn bench_health_endpoint(c: &mut Criterion) {
270267/// Benchmark metrics endpoint
271268fn bench_metrics_endpoint ( c : & mut Criterion ) {
272269 let rt = Runtime :: new ( ) . unwrap ( ) ;
273-
274- let ( _handle, port) = rt. block_on ( async {
275- setup_benchmark_server ( ) . await . expect ( "Failed to setup server" )
270+ let port = get_benchmark_server_port ( ) ;
271+
272+ static CLIENT : OnceLock < reqwest:: Client > = OnceLock :: new ( ) ;
273+ let client = CLIENT . get_or_init ( || {
274+ reqwest:: Client :: builder ( )
275+ . timeout ( Duration :: from_secs ( 5 ) )
276+ . pool_idle_timeout ( Duration :: from_secs ( 30 ) )
277+ . build ( )
278+ . unwrap ( )
276279 } ) ;
277280
278281 c. bench_function ( "metrics_endpoint" , |b| {
279282 b. to_async ( & rt) . iter ( || async {
280- let client = reqwest:: Client :: new ( ) ;
281283 let response = client
282284 . get ( format ! ( "http://localhost:{port}/metrics" ) )
283285 . send ( )
0 commit comments