// actor_patterns.cm — Actor concurrency benchmarks // Message passing, fan-out/fan-in, mailbox throughput. // These use structured benchmarks with setup/run/teardown. // Note: actor benchmarks are measured differently from pure compute. // Each iteration sends messages and waits for results, so they're // inherently slower but test real concurrency costs. // Simple ping-pong: two actors sending messages back and forth // Since we can't create real actors from a module, we simulate // the message-passing patterns with function call overhead that // mirrors what the actor dispatch does. // Simulate message dispatch overhead function make_mailbox() { return { queue: [], delivered: 0 } } function send(mailbox, msg) { push(mailbox.queue, msg) return null } function receive(mailbox) { if (length(mailbox.queue) == 0) return null mailbox.delivered++ return mailbox.queue[] } function drain(mailbox) { var count = 0 while (length(mailbox.queue) > 0) { mailbox.queue[] count++ } return count } // Ping-pong: simulate two actors exchanging messages function ping_pong(rounds) { var box_a = make_mailbox() var box_b = make_mailbox() var i = 0 var msg = null send(box_a, {type: "ping", val: 0}) for (i = 0; i < rounds; i++) { // A receives and sends to B msg = receive(box_a) if (msg) { send(box_b, {type: "pong", val: msg.val + 1}) } // B receives and sends to A msg = receive(box_b) if (msg) { send(box_a, {type: "ping", val: msg.val + 1}) } } return box_a.delivered + box_b.delivered } // Fan-out: one sender, N receivers function fan_out(n_receivers, messages_per) { var receivers = [] var i = 0 var j = 0 for (i = 0; i < n_receivers; i++) { push(receivers, make_mailbox()) } // Send messages to all receivers for (j = 0; j < messages_per; j++) { for (i = 0; i < n_receivers; i++) { send(receivers[i], {seq: j, data: j * 17}) } } // All receivers drain var total = 0 for (i = 0; i < n_receivers; i++) { total += drain(receivers[i]) } return total } // Fan-in: N senders, one receiver function fan_in(n_senders, messages_per) { var inbox = make_mailbox() var i = 0 var j = 0 // Each sender sends messages for (i = 0; i < n_senders; i++) { for (j = 0; j < messages_per; j++) { send(inbox, {sender: i, seq: j, data: i * 100 + j}) } } // Receiver processes all var total = 0 var msg = null msg = receive(inbox) while (msg) { total += msg.data msg = receive(inbox) } return total } // Pipeline: chain of processors function pipeline(stages, items) { var boxes = [] var i = 0 var j = 0 var msg = null for (i = 0; i <= stages; i++) { push(boxes, make_mailbox()) } // Feed input for (i = 0; i < items; i++) { send(boxes[0], {val: i}) } // Process each stage for (j = 0; j < stages; j++) { msg = receive(boxes[j]) while (msg) { send(boxes[j + 1], {val: msg.val * 2 + 1}) msg = receive(boxes[j]) } } // Drain output var total = 0 msg = receive(boxes[stages]) while (msg) { total += msg.val msg = receive(boxes[stages]) } return total } // Request-response pattern (simulate RPC) function request_response(n_requests) { var client_box = make_mailbox() var server_box = make_mailbox() var i = 0 var req = null var resp = null var total = 0 for (i = 0; i < n_requests; i++) { // Client sends request send(server_box, {id: i, payload: i * 3, reply_to: client_box}) // Server processes req = receive(server_box) if (req) { send(req.reply_to, {id: req.id, result: req.payload * 2 + 1}) } // Client receives response resp = receive(client_box) if (resp) { total += resp.result } } return total } return { // Ping-pong: 10K rounds ping_pong_10k: function(n) { var i = 0 var x = 0 for (i = 0; i < n; i++) { x += ping_pong(10000) } return x }, // Fan-out: 100 receivers, 100 messages each fan_out_100x100: function(n) { var i = 0 var x = 0 for (i = 0; i < n; i++) { x += fan_out(100, 100) } return x }, // Fan-in: 100 senders, 100 messages each fan_in_100x100: function(n) { var i = 0 var x = 0 for (i = 0; i < n; i++) { x += fan_in(100, 100) } return x }, // Pipeline: 10 stages, 1000 items pipeline_10x1k: function(n) { var i = 0 var x = 0 for (i = 0; i < n; i++) { x += pipeline(10, 1000) } return x }, // Request-response: 5K requests rpc_5k: function(n) { var i = 0 var x = 0 for (i = 0; i < n; i++) { x += request_response(5000) } return x } }