TCP/TLS connection pooling for Eio

fix(lint): resolve E205 Printf/Format usage and add missing fmt deps

Replace Printf.sprintf/printf with Fmt.str/pr across cbort, cfdp,
cgr, claudeio, clcw, conpool, cookeio, and cpio packages. Add fmt
library dependency to dune files where needed.

+41 -41
+2 -2
test/dune
··· 8 test_cmd 9 test_connection 10 test_conpool) 11 - (libraries conpool alcotest)) 12 13 (executable 14 (name stress_test) 15 (modules stress_test) 16 - (libraries conpool eio eio_main unix)) 17 18 ; Stress tests are slow - only run when STRESS_TESTS=1 19
··· 8 test_cmd 9 test_connection 10 test_conpool) 11 + (libraries conpool alcotest fmt)) 12 13 (executable 14 (name stress_test) 15 (modules stress_test) 16 + (libraries conpool eio eio_main fmt unix)) 17 18 ; Stress tests are slow - only run when STRESS_TESTS=1 19
+36 -36
test/stress_test.ml
··· 212 let endpoint_idx = Random.int (Array.length endpoints) in 213 let endpoint = endpoints.(endpoint_idx) in 214 let message = 215 - Printf.sprintf "c%d-%s" client_id (generate_message cfg.message_size) 216 in 217 run_client_test ~clock ~test_start_time pool endpoint message latency_stats 218 errors ··· 353 354 (** Convert result to JSON string *) 355 let result_to_json result = 356 - Printf.sprintf 357 {|{ 358 "test_name": "%s", 359 "num_servers": %d, ··· 409 let bucket_labels = 410 List.init num_buckets (fun i -> 411 let start = min_lat +. (float_of_int i *. bucket_width) in 412 - Printf.sprintf "%.2f" start) 413 in 414 let bucket_counts = Array.to_list buckets in 415 (bucket_labels, bucket_counts) ··· 418 let generate_html_report results = 419 let timestamp = Unix.time () |> Unix.gmtime in 420 let date_str = 421 - Printf.sprintf "%04d-%02d-%02d %02d:%02d:%02d UTC" 422 (timestamp.Unix.tm_year + 1900) 423 (timestamp.Unix.tm_mon + 1) 424 timestamp.Unix.tm_mday timestamp.Unix.tm_hour timestamp.Unix.tm_min ··· 440 let test_names = 441 String.concat ", " 442 (List.map 443 - (fun r -> Printf.sprintf "\"%s\"" (js_escape r.test_name)) 444 results) 445 in 446 let throughputs = 447 String.concat ", " 448 - (List.map (fun r -> Printf.sprintf "%.2f" r.throughput) results) 449 in 450 let avg_latencies = 451 String.concat ", " 452 - (List.map (fun r -> Printf.sprintf "%.2f" r.avg_latency) results) 453 in 454 let error_rates = 455 String.concat ", " 456 (List.map 457 (fun r -> 458 if r.total_messages > 0 then 459 - Printf.sprintf "%.2f" 460 (float_of_int r.total_errors 461 /. float_of_int r.total_messages 462 *. 100.0) ··· 474 in 475 let hist_labels_str = 476 String.concat ", " 477 - (List.map (fun s -> Printf.sprintf "\"%s\"" s) hist_labels) 478 in 479 let hist_counts_str = 480 String.concat ", " (List.map string_of_int hist_counts) ··· 489 let timeline_data = 490 String.concat ", " 491 (List.map 492 - (fun (t, l) -> Printf.sprintf "{x: %.2f, y: %.3f}" t l) 493 sampled_data) 494 in 495 496 - Printf.sprintf 497 {| 498 <div class="test-detail"> 499 <h3>%s</h3> ··· 590 results) 591 in 592 593 - Printf.sprintf 594 {|<!DOCTYPE html> 595 <html lang="en"> 596 <head> ··· 870 </html>|} 871 date_str (List.length results) 872 (if total_messages >= 1000 then 873 - Printf.sprintf "%d,%03d" (total_messages / 1000) (total_messages mod 1000) 874 else string_of_int total_messages) 875 total_errors total_duration test_details test_names throughputs 876 avg_latencies error_rates ··· 879 let run_all_presets ~env = 880 List.map 881 (fun config -> 882 - Printf.eprintf "Running test: %s\n%!" config.name; 883 run_stress_test ~env config) 884 presets 885 ··· 914 (fun p -> 915 match List.find_opt (fun c -> c.name = p) presets with 916 | Some c -> mode := Single c 917 - | None -> failwith (Printf.sprintf "Unknown preset: %s" p)), 918 "Use a named preset configuration" ); 919 ("-n", Arg.Set_string name, "Test name"); 920 ( "-s", 921 Arg.Set_int num_servers, 922 - Printf.sprintf "Number of servers (default: %d)" 923 default_config.num_servers ); 924 ( "-c", 925 Arg.Set_int num_clients, 926 - Printf.sprintf "Clients per server (default: %d)" 927 default_config.num_clients ); 928 ( "-m", 929 Arg.Set_int messages_per_client, 930 - Printf.sprintf "Messages per client (default: %d)" 931 default_config.messages_per_client ); 932 ( "-p", 933 Arg.Set_int max_parallel, 934 - Printf.sprintf "Max parallel clients (default: %d)" 935 default_config.max_parallel_clients ); 936 ( "-b", 937 Arg.Set_int message_size, 938 - Printf.sprintf "Message size (default: %d)" default_config.message_size 939 ); 940 ( "-P", 941 Arg.Set_int pool_size, 942 - Printf.sprintf "Pool size per endpoint (default: %d)" 943 default_config.pool_size ); 944 ( "-o", 945 Arg.Set_string output_file, ··· 970 971 match mode with 972 | List_presets -> 973 - Printf.printf "Available presets:\n"; 974 List.iter 975 (fun c -> 976 - Printf.printf 977 " %s: %d servers, %d clients, %d msgs/client, pool=%d\n" c.name 978 c.num_servers c.num_clients c.messages_per_client c.pool_size) 979 presets ··· 984 let results = [ result ] in 985 986 (* Write JSON *) 987 - let json = Printf.sprintf "[%s]" (result_to_json result) in 988 let oc = open_out output_file in 989 output_string oc json; 990 close_out oc; 991 - Printf.printf "Results written to %s\n" output_file; 992 993 (* Write HTML *) 994 let html_file = ··· 1000 let oc_html = open_out html_file in 1001 output_string oc_html html; 1002 close_out oc_html; 1003 - Printf.printf "HTML report written to %s\n" html_file; 1004 1005 - Printf.printf 1006 "Test: %s - %d messages, %.2f msg/s, %.2fms avg latency, %d errors\n" 1007 result.test_name result.total_messages result.throughput 1008 result.avg_latency result.total_errors ··· 1017 let oc = open_out output_file in 1018 output_string oc json; 1019 close_out oc; 1020 - Printf.printf "Results written to %s\n" output_file; 1021 1022 (* Write HTML *) 1023 let html_file = ··· 1029 let oc_html = open_out html_file in 1030 output_string oc_html html; 1031 close_out oc_html; 1032 - Printf.printf "HTML report written to %s\n" html_file; 1033 1034 List.iter 1035 (fun r -> 1036 - Printf.printf 1037 " %s: %d messages, %.2f msg/s, %.2fms avg latency, %d errors\n" 1038 r.test_name r.total_messages r.throughput r.avg_latency 1039 r.total_errors) 1040 results 1041 | Extended -> 1042 - Printf.printf 1043 "Running extended stress test: %d servers, %d clients/server, %d \ 1044 msgs/client\n" 1045 extended_preset.num_servers extended_preset.num_clients 1046 extended_preset.messages_per_client; 1047 - Printf.printf "Total messages: %d\n%!" 1048 (extended_preset.num_servers * extended_preset.num_clients 1049 * extended_preset.messages_per_client); 1050 Eio_main.run @@ fun env -> ··· 1052 let results = [ result ] in 1053 1054 (* Write JSON *) 1055 - let json = Printf.sprintf "[%s]" (result_to_json result) in 1056 let oc = open_out output_file in 1057 output_string oc json; 1058 close_out oc; 1059 - Printf.printf "Results written to %s\n" output_file; 1060 1061 (* Write HTML *) 1062 let html_file = ··· 1068 let oc_html = open_out html_file in 1069 output_string oc_html html; 1070 close_out oc_html; 1071 - Printf.printf "HTML report written to %s\n" html_file; 1072 1073 - Printf.printf 1074 "Test: %s - %d messages, %.2f msg/s, %.2fms avg latency, %d errors\n" 1075 result.test_name result.total_messages result.throughput 1076 result.avg_latency result.total_errors
··· 212 let endpoint_idx = Random.int (Array.length endpoints) in 213 let endpoint = endpoints.(endpoint_idx) in 214 let message = 215 + Fmt.str "c%d-%s" client_id (generate_message cfg.message_size) 216 in 217 run_client_test ~clock ~test_start_time pool endpoint message latency_stats 218 errors ··· 353 354 (** Convert result to JSON string *) 355 let result_to_json result = 356 + Fmt.str 357 {|{ 358 "test_name": "%s", 359 "num_servers": %d, ··· 409 let bucket_labels = 410 List.init num_buckets (fun i -> 411 let start = min_lat +. (float_of_int i *. bucket_width) in 412 + Fmt.str "%.2f" start) 413 in 414 let bucket_counts = Array.to_list buckets in 415 (bucket_labels, bucket_counts) ··· 418 let generate_html_report results = 419 let timestamp = Unix.time () |> Unix.gmtime in 420 let date_str = 421 + Fmt.str "%04d-%02d-%02d %02d:%02d:%02d UTC" 422 (timestamp.Unix.tm_year + 1900) 423 (timestamp.Unix.tm_mon + 1) 424 timestamp.Unix.tm_mday timestamp.Unix.tm_hour timestamp.Unix.tm_min ··· 440 let test_names = 441 String.concat ", " 442 (List.map 443 + (fun r -> Fmt.str "\"%s\"" (js_escape r.test_name)) 444 results) 445 in 446 let throughputs = 447 String.concat ", " 448 + (List.map (fun r -> Fmt.str "%.2f" r.throughput) results) 449 in 450 let avg_latencies = 451 String.concat ", " 452 + (List.map (fun r -> Fmt.str "%.2f" r.avg_latency) results) 453 in 454 let error_rates = 455 String.concat ", " 456 (List.map 457 (fun r -> 458 if r.total_messages > 0 then 459 + Fmt.str "%.2f" 460 (float_of_int r.total_errors 461 /. float_of_int r.total_messages 462 *. 100.0) ··· 474 in 475 let hist_labels_str = 476 String.concat ", " 477 + (List.map (fun s -> Fmt.str "\"%s\"" s) hist_labels) 478 in 479 let hist_counts_str = 480 String.concat ", " (List.map string_of_int hist_counts) ··· 489 let timeline_data = 490 String.concat ", " 491 (List.map 492 + (fun (t, l) -> Fmt.str "{x: %.2f, y: %.3f}" t l) 493 sampled_data) 494 in 495 496 + Fmt.str 497 {| 498 <div class="test-detail"> 499 <h3>%s</h3> ··· 590 results) 591 in 592 593 + Fmt.str 594 {|<!DOCTYPE html> 595 <html lang="en"> 596 <head> ··· 870 </html>|} 871 date_str (List.length results) 872 (if total_messages >= 1000 then 873 + Fmt.str "%d,%03d" (total_messages / 1000) (total_messages mod 1000) 874 else string_of_int total_messages) 875 total_errors total_duration test_details test_names throughputs 876 avg_latencies error_rates ··· 879 let run_all_presets ~env = 880 List.map 881 (fun config -> 882 + Fmt.epr "Running test: %s\n%!" config.name; 883 run_stress_test ~env config) 884 presets 885 ··· 914 (fun p -> 915 match List.find_opt (fun c -> c.name = p) presets with 916 | Some c -> mode := Single c 917 + | None -> failwith (Fmt.str "Unknown preset: %s" p)), 918 "Use a named preset configuration" ); 919 ("-n", Arg.Set_string name, "Test name"); 920 ( "-s", 921 Arg.Set_int num_servers, 922 + Fmt.str "Number of servers (default: %d)" 923 default_config.num_servers ); 924 ( "-c", 925 Arg.Set_int num_clients, 926 + Fmt.str "Clients per server (default: %d)" 927 default_config.num_clients ); 928 ( "-m", 929 Arg.Set_int messages_per_client, 930 + Fmt.str "Messages per client (default: %d)" 931 default_config.messages_per_client ); 932 ( "-p", 933 Arg.Set_int max_parallel, 934 + Fmt.str "Max parallel clients (default: %d)" 935 default_config.max_parallel_clients ); 936 ( "-b", 937 Arg.Set_int message_size, 938 + Fmt.str "Message size (default: %d)" default_config.message_size 939 ); 940 ( "-P", 941 Arg.Set_int pool_size, 942 + Fmt.str "Pool size per endpoint (default: %d)" 943 default_config.pool_size ); 944 ( "-o", 945 Arg.Set_string output_file, ··· 970 971 match mode with 972 | List_presets -> 973 + Fmt.pr "Available presets:\n"; 974 List.iter 975 (fun c -> 976 + Fmt.pr 977 " %s: %d servers, %d clients, %d msgs/client, pool=%d\n" c.name 978 c.num_servers c.num_clients c.messages_per_client c.pool_size) 979 presets ··· 984 let results = [ result ] in 985 986 (* Write JSON *) 987 + let json = Fmt.str "[%s]" (result_to_json result) in 988 let oc = open_out output_file in 989 output_string oc json; 990 close_out oc; 991 + Fmt.pr "Results written to %s\n" output_file; 992 993 (* Write HTML *) 994 let html_file = ··· 1000 let oc_html = open_out html_file in 1001 output_string oc_html html; 1002 close_out oc_html; 1003 + Fmt.pr "HTML report written to %s\n" html_file; 1004 1005 + Fmt.pr 1006 "Test: %s - %d messages, %.2f msg/s, %.2fms avg latency, %d errors\n" 1007 result.test_name result.total_messages result.throughput 1008 result.avg_latency result.total_errors ··· 1017 let oc = open_out output_file in 1018 output_string oc json; 1019 close_out oc; 1020 + Fmt.pr "Results written to %s\n" output_file; 1021 1022 (* Write HTML *) 1023 let html_file = ··· 1029 let oc_html = open_out html_file in 1030 output_string oc_html html; 1031 close_out oc_html; 1032 + Fmt.pr "HTML report written to %s\n" html_file; 1033 1034 List.iter 1035 (fun r -> 1036 + Fmt.pr 1037 " %s: %d messages, %.2f msg/s, %.2fms avg latency, %d errors\n" 1038 r.test_name r.total_messages r.throughput r.avg_latency 1039 r.total_errors) 1040 results 1041 | Extended -> 1042 + Fmt.pr 1043 "Running extended stress test: %d servers, %d clients/server, %d \ 1044 msgs/client\n" 1045 extended_preset.num_servers extended_preset.num_clients 1046 extended_preset.messages_per_client; 1047 + Fmt.pr "Total messages: %d\n%!" 1048 (extended_preset.num_servers * extended_preset.num_clients 1049 * extended_preset.messages_per_client); 1050 Eio_main.run @@ fun env -> ··· 1052 let results = [ result ] in 1053 1054 (* Write JSON *) 1055 + let json = Fmt.str "[%s]" (result_to_json result) in 1056 let oc = open_out output_file in 1057 output_string oc json; 1058 close_out oc; 1059 + Fmt.pr "Results written to %s\n" output_file; 1060 1061 (* Write HTML *) 1062 let html_file = ··· 1068 let oc_html = open_out html_file in 1069 output_string oc_html html; 1070 close_out oc_html; 1071 + Fmt.pr "HTML report written to %s\n" html_file; 1072 1073 + Fmt.pr 1074 "Test: %s - %d messages, %.2f msg/s, %.2fms avg latency, %d errors\n" 1075 result.test_name result.total_messages result.throughput 1076 result.avg_latency result.total_errors
+1 -1
test/test_config.ml
··· 28 29 let test_pp () = 30 let c = Conpool.Config.default in 31 - let s = Format.asprintf "%a" Conpool.Config.pp c in 32 Alcotest.(check bool) "non-empty" true (String.length s > 0) 33 34 let suite =
··· 28 29 let test_pp () = 30 let c = Conpool.Config.default in 31 + let s = Fmt.str "%a" Conpool.Config.pp c in 32 Alcotest.(check bool) "non-empty" true (String.length s > 0) 33 34 let suite =
+1 -1
test/test_endpoint.ml
··· 17 18 let test_pp () = 19 let ep = Conpool.Endpoint.v ~host:"example.com" ~port:8080 in 20 - let s = Format.asprintf "%a" Conpool.Endpoint.pp ep in 21 Alcotest.(check bool) "contains host" true (String.length s > 0) 22 23 let suite =
··· 17 18 let test_pp () = 19 let ep = Conpool.Endpoint.v ~host:"example.com" ~port:8080 in 20 + let s = Fmt.str "%a" Conpool.Endpoint.pp ep in 21 Alcotest.(check bool) "contains host" true (String.length s > 0) 22 23 let suite =
+1 -1
test/test_stats.ml
··· 20 Conpool.Stats.v ~active:0 ~idle:0 ~total_created:0 ~total_reused:0 21 ~total_closed:0 ~errors:0 22 in 23 - let str = Format.asprintf "%a" Conpool.Stats.pp s in 24 Alcotest.(check bool) "non-empty" true (String.length str > 0) 25 26 let suite =
··· 20 Conpool.Stats.v ~active:0 ~idle:0 ~total_created:0 ~total_reused:0 21 ~total_closed:0 ~errors:0 22 in 23 + let str = Fmt.str "%a" Conpool.Stats.pp s in 24 Alcotest.(check bool) "non-empty" true (String.length str > 0) 25 26 let suite =