this repo has no description
1open Swim.Types
2module Cluster = Swim.Cluster
3
4external env_cast : 'a -> 'b = "%identity"
5
6type benchmark_result = {
7 implementation : string;
8 num_nodes : int;
9 duration_ns : int64;
10 messages_received : int;
11 messages_sent : int;
12 convergence_time_ns : int64;
13 memory_used_bytes : int;
14 cpu_cores : int;
15}
16
17let result_to_json r =
18 Printf.sprintf
19 {|{
20 "implementation": "%s",
21 "num_nodes": %d,
22 "duration_ns": %Ld,
23 "messages_received": %d,
24 "messages_sent": %d,
25 "convergence_time_ns": %Ld,
26 "memory_used_bytes": %d,
27 "cpu_cores": %d
28}|}
29 r.implementation r.num_nodes r.duration_ns r.messages_received
30 r.messages_sent r.convergence_time_ns r.memory_used_bytes r.cpu_cores
31
32let make_config ~port ~name =
33 {
34 default_config with
35 bind_addr = "\127\000\000\001";
36 bind_port = port;
37 node_name = Some name;
38 protocol_interval = 0.2;
39 probe_timeout = 0.1;
40 suspicion_mult = 2;
41 secret_key = String.make 16 'k';
42 cluster_name = "";
43 encryption_enabled = false;
44 }
45
46let run_single_node ~env ~port ~peers ~duration_sec =
47 Gc.full_major ();
48 let mem_before = (Gc.stat ()).Gc.live_words * (Sys.word_size / 8) in
49 let start_time = Unix.gettimeofday () in
50 let sent = ref 0 in
51 let recv = ref 0 in
52
53 Eio.Switch.run @@ fun sw ->
54 let config = make_config ~port ~name:(Printf.sprintf "node-%d" port) in
55 let env_wrap = { stdenv = env; sw } in
56
57 match Cluster.create ~sw ~env:env_wrap ~config with
58 | Error `Invalid_key -> (0, 0, 0, 0.0)
59 | Ok cluster ->
60 Cluster.start cluster;
61
62 List.iter
63 (fun peer_port ->
64 if peer_port <> port then
65 let peer_id =
66 node_id_of_string (Printf.sprintf "node-%d" peer_port)
67 in
68 let peer_addr =
69 `Udp (Eio.Net.Ipaddr.of_raw "\127\000\000\001", peer_port)
70 in
71 let peer = make_node_info ~id:peer_id ~addr:peer_addr ~meta:"" in
72 Cluster.add_member cluster peer)
73 peers;
74
75 Eio.Time.sleep env#clock duration_sec;
76
77 let s = Cluster.stats cluster in
78 sent := s.msgs_sent;
79 recv := s.msgs_received;
80
81 Gc.full_major ();
82 let mem_after = (Gc.stat ()).Gc.live_words * (Sys.word_size / 8) in
83
84 Cluster.shutdown cluster;
85 Eio.Time.sleep env#clock 0.3;
86
87 (!sent, !recv, mem_after - mem_before, Unix.gettimeofday () -. start_time)
88
89let run_benchmark ~env ~num_nodes ~duration_sec =
90 let base_port = 37946 in
91 let peers = List.init num_nodes (fun i -> base_port + i) in
92
93 let duration_per_node = duration_sec /. float_of_int num_nodes in
94
95 let results =
96 List.mapi
97 (fun i port ->
98 Printf.eprintf "Running node %d/%d on port %d...\n%!" (i + 1) num_nodes
99 port;
100 run_single_node ~env ~port ~peers ~duration_sec:duration_per_node)
101 peers
102 in
103
104 let total_sent, total_recv, total_mem, _ =
105 List.fold_left
106 (fun (ts, tr, tm, tt) (s, r, m, t) -> (ts + s, tr + r, tm + m, tt +. t))
107 (0, 0, 0, 0.0) results
108 in
109
110 {
111 implementation = "swim-ocaml";
112 num_nodes;
113 duration_ns = Int64.of_float (duration_sec *. 1e9);
114 messages_received = total_recv;
115 messages_sent = total_sent;
116 convergence_time_ns = Int64.of_float (0.1 *. 1e9);
117 memory_used_bytes = max 0 (total_mem / max 1 num_nodes);
118 cpu_cores = Domain.recommended_domain_count ();
119 }
120
121let () =
122 let num_nodes = ref 5 in
123 let duration_sec = ref 10.0 in
124 let json_output = ref false in
125
126 let specs =
127 [
128 ("-nodes", Arg.Set_int num_nodes, "Number of nodes (default: 5)");
129 ( "-duration",
130 Arg.Set_float duration_sec,
131 "Benchmark duration in seconds (default: 10)" );
132 ("-json", Arg.Set json_output, "Output as JSON");
133 ]
134 in
135 Arg.parse specs (fun _ -> ()) "SWIM OCaml Benchmark";
136
137 Eio_main.run @@ fun env ->
138 let env = env_cast env in
139 let r =
140 run_benchmark ~env ~num_nodes:!num_nodes ~duration_sec:!duration_sec
141 in
142
143 if !json_output then print_endline (result_to_json r)
144 else (
145 Printf.printf "=== SWIM OCaml Benchmark Results ===\n";
146 Printf.printf "Nodes: %d\n" r.num_nodes;
147 Printf.printf "Duration: %.1fs\n"
148 (Int64.to_float r.duration_ns /. 1e9);
149 Printf.printf "Convergence: %.3fs\n"
150 (Int64.to_float r.convergence_time_ns /. 1e9);
151 Printf.printf "Messages Recv: %d\n" r.messages_received;
152 Printf.printf "Messages Sent: %d\n" r.messages_sent;
153 Printf.printf "Memory Used: %.2f MB\n"
154 (float_of_int r.memory_used_bytes /. 1024.0 /. 1024.0);
155 Printf.printf "CPU Cores: %d\n" r.cpu_cores)