<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Systems Programming on Yarang's Tech Lair</title><link>https://blog.agentthread.dev/tags/systems-programming/</link><description>Recent content in Systems Programming on Yarang's Tech Lair</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sun, 31 May 2026 09:01:25 +0900</lastBuildDate><atom:link href="https://blog.agentthread.dev/tags/systems-programming/index.xml" rel="self" type="application/rss+xml"/><item><title>High-Performance IPC Channel Optimization for ZeroClaw Agents: Rust Zero-Copy Strategy</title><link>https://blog.agentthread.dev/post/high-performance-ipc-channel-optimization-for-zeroclaw-agents-rust-zero-copy-strategy/</link><pubDate>Sun, 31 May 2026 09:01:25 +0900</pubDate><guid>https://blog.agentthread.dev/post/high-performance-ipc-channel-optimization-for-zeroclaw-agents-rust-zero-copy-strategy/</guid><description>&lt;h2 id="bottlenecks-in-multi-agent-systems"&gt;Bottlenecks in Multi-Agent Systems
&lt;/h2&gt;&lt;p&gt;While developing the &lt;a class="link" href="https://github.com" target="_blank" rel="noopener"
 &gt;ZeroClaw&lt;/a&gt; multi-agent runtime, the biggest performance bottleneck has unequivocally been &amp;lsquo;inter-agent communication&amp;rsquo;. In our designed architecture, multiple dedicated agents (Workers) communicate with the main Hub to distribute tasks.&lt;/p&gt;
&lt;p&gt;The initial design used simple JSON serialization and standard streams. However, as throughput increased, memory copying and serialization overhead began to pose problems. Specifically, latency was detected when relaying token streams of large models like LLMs in real-time, or when transferring large volumes of logs to file system agents.&lt;/p&gt;
&lt;p&gt;This post introduces how we significantly improved inter-agent communication performance by leveraging Rust&amp;rsquo;s powerful features to implement &lt;strong&gt;Zero-Copy&lt;/strong&gt; and &lt;strong&gt;Shared Memory&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="problem-diagnosis-serialization-and-copy-overhead"&gt;Problem Diagnosis: Serialization and Copy Overhead
&lt;/h2&gt;&lt;p&gt;The existing communication method followed this flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Data Generation&lt;/strong&gt;: Agent A creates a data struct.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Serialization&lt;/strong&gt;: Converts to JSON using &lt;code&gt;serde_json::to_string&lt;/code&gt;, etc. (consumes CPU resources).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transmission&lt;/strong&gt;: Sends byte streams via IPC channels (sockets, etc.).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reception and Parsing&lt;/strong&gt;: Agent B receives bytes and parses them using &lt;code&gt;serde_json::from_str&lt;/code&gt; (consumes CPU resources).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In this process, data is copied at least three times between memory spaces. The cost of data on the heap being moved to the stack or buffer reallocations, due to Rust&amp;rsquo;s safety guarantees, was non-negligible.&lt;/p&gt;
&lt;h2 id="solution-rust-based-zero-copy-ipc-design"&gt;Solution: Rust-based Zero-Copy IPC Design
&lt;/h2&gt;&lt;p&gt;We introduced &lt;strong&gt;&lt;code&gt;serde&lt;/code&gt;&amp;rsquo;s &lt;code&gt;zero_copy&lt;/code&gt; feature and the &lt;code&gt;bytes::Bytes&lt;/code&gt; crate&lt;/strong&gt; into ZeroClaw&amp;rsquo;s communication layer to eliminate unnecessary copies.&lt;/p&gt;
&lt;h3 id="1-buffer-management-using-bytes-and-arc"&gt;1. Buffer Management using &lt;code&gt;Bytes&lt;/code&gt; and &lt;code&gt;Arc&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;Rust&amp;rsquo;s &lt;code&gt;bytes::Bytes&lt;/code&gt; is based on &lt;code&gt;Arc&lt;/code&gt; (Atomic Reference Counting). When transferring data ownership, it copies only the pointer and metadata, not the data itself. This allows multiple agents to safely reference data in the same memory region.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; bytes::{Bytes, BytesMut, BufMut};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Serialize, Deserialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Message struct to be transmitted between agents
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Deserialize, Serialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; id: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; payload: &lt;span style="color:#a6e22e"&gt;Bytes&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// Stores raw data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; AgentMessage {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Directly wraps Bytes read from the network or file
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from_bytes&lt;/span&gt;(id: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;, data: &lt;span style="color:#a6e22e"&gt;Bytes&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;Self&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Self { id, payload: &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-shared-memory-ipc-ipc-channel-implementation"&gt;2. Shared Memory IPC (IPC Channel) Implementation
&lt;/h3&gt;&lt;p&gt;Beyond simple byte transmission, for high performance, we can also consider using OS-level shared memory. Rust&amp;rsquo;s ecosystem provides the &lt;code&gt;shared_memory&lt;/code&gt; crate for this. However, here we will apply a method to maintain Zero-Copy over the more general &lt;strong&gt;&lt;code&gt;tokio::sync::mpsc&lt;/code&gt; channel&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::sync::mpsc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::sync::Arc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Agent A (Sender)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;producer_task&lt;/span&gt;(tx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Sender&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; large_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vec!&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;u8&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// Example: 8KB data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Convert to BytesMut, then freeze to create immutable Bytes (wrapped in Arc)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; shared_bytes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BytesMut::from(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;large_data[&lt;span style="color:#f92672"&gt;..&lt;/span&gt;]).freeze();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; msg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentMessage::from_bytes(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, shared_bytes);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// When sending via tx, only the pointer within msg.payload (Bytes) is copied.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// The actual 8KB data is not copied (Zero-Copy).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx.send(msg).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;.unwrap();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Agent B (Receiver)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;consumer_task&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; rx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(msg) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; rx.recv().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Here, msg.payload is a reference pointing to the original data.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Received message ID: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, Payload Len: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, msg.id, msg.payload.len());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Can be directly written to disk or sent over the network without further processing.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// save_to_disk(msg.payload).await;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The core of this code is that even when &lt;code&gt;Bytes&lt;/code&gt; transfers ownership, it internally shares the heap data via &lt;code&gt;Arc&lt;/code&gt;. This means that when &lt;code&gt;tx.send()&lt;/code&gt; is called, the 8KB array is not copied; instead, the &lt;code&gt;Arc&lt;/code&gt;&amp;rsquo;s count is incremented, and only the pointer is passed.&lt;/p&gt;
&lt;h2 id="performance-comparison-and-measurement"&gt;Performance Comparison and Measurement
&lt;/h2&gt;&lt;p&gt;To compare before and after improvements, we conducted benchmarks using Criterion.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Environment&lt;/strong&gt;: Apple M1 Pro, 16GB RAM&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: Transmitting 1MB of payload 10,000 times&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;Category&lt;/th&gt;
					&lt;th style="text-align: center"&gt;Before Improvement (Vec&lt;u8&gt; Clone)&lt;/th&gt;
					&lt;th style="text-align: center"&gt;After Improvement (Bytes Zero-Copy)&lt;/th&gt;
					&lt;th style="text-align: center"&gt;Performance Improvement&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;Time Taken&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: center"&gt;2,450ms&lt;/td&gt;
					&lt;td style="text-align: center"&gt;320ms&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;strong&gt;Approx. 7.6x&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;Memory Usage&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Peak 2.1GB&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Stable 150MB&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;strong&gt;Approx. 14x Reduction&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;As the data size increases (e.g., for LLM context transfer), the effect of Zero-Copy becomes maximized. The original method caused CPU spikes due to allocation/deallocation, while the improved version showed stable resource usage.&lt;/p&gt;
&lt;h2 id="conclusion-completing-zeroclaws-high-performance-architecture"&gt;Conclusion: Completing ZeroClaw&amp;rsquo;s High-Performance Architecture
&lt;/h2&gt;&lt;p&gt;The Zero-Copy strategy, utilizing Rust&amp;rsquo;s ownership system with &lt;code&gt;Bytes&lt;/code&gt; and &lt;code&gt;Arc&lt;/code&gt;, is essential for multi-agent runtimes like &lt;strong&gt;ZeroClaw&lt;/strong&gt;. Beyond simply being &amp;lsquo;fast&amp;rsquo;, it allows for more efficient use of server resources, enabling the execution of more agents concurrently.&lt;/p&gt;
&lt;p&gt;In the future, the &lt;a class="link" href="https://github.com" target="_blank" rel="noopener"
 &gt;ZeroClaw&lt;/a&gt; project plans to further abstract this IPC layer and develop a macro that automatically generates optimized communication code simply by using &lt;code&gt;#[derive(AgentMessage)]&lt;/code&gt;, without the user needing to know the internal Rust implementation.&lt;/p&gt;
&lt;p&gt;We hope this experience is helpful for those building high-performance Rust servers, and we recommend applying it to your projects, with actual code examples provided.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Reference Code Repository&lt;/strong&gt;: &lt;a class="link" href="https://github.com" target="_blank" rel="noopener"
 &gt;ZeroClaw GitHub Repository&lt;/a&gt;
&lt;strong&gt;Related Post&lt;/strong&gt;: &lt;a class="link" href="https://blog.agentthread.dev/posts/zeroclaw-intro" &gt;Introducing ZeroClaw - A High-Performance Rust Agent Runtime&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item></channel></rss>