Skip to content

IPC Libraries

Some binary size numbers for existing network based solutions for IPC.

Note: A network based solution is needed for R3 because we need to communicate between a Wine client and the Linux host in some cases.

Also a portable solution for those esoteric platforms, so ideally raw work over libc.

Build Script

Build command for the solutions is

RUSTFLAGS="-C panic=abort -C lto=fat -C embed-bitcode=yes" cargo +nightly bloat -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort --target x86_64-unknown-linux-gnu --profile profile

And the following Cargo.toml

# Profile Build
[profile.profile]
inherits = "release"
debug = true
codegen-units = 1
lto = true
strip = false  # No stripping!!

# Optimized Release Build
[profile.release]
codegen-units = 1
lto = true
strip = true  # Automatically strip symbols from the binary.
panic = "abort"

With an example specified, if available.

Use most slim example that talks client and server. Use -C linker-plugin-lto when applicable.

ZeroMQ (libzmq Rust Bindings)

A simple client-server has 500kB of code when built with minimum size settings.

Automatic disqualification.

Also the cross-platform aspect is uncertain, for esoteric platforms without a guaranteed libc.

zmq.rs

Same as the native version above, builds to 1MiB by default, but could potentially been brought down easily to 300-400KB by removing regex, and some other minor things.

nanomsg-rs

Builds with around 154KB of code. Mostly native C code.

Requires setting 'bundled' feature.

Portability with esoteric platforms is uncertain.

rust_tcp_ipc

This is an ancient code base, so needed some fixing, as the built-in example was commented out and out of date.

Once the example is fixed, we get the following for both client and server:

ile  .text    Size Crate
2.0%  41.8% 37.8KiB std
2.0%  40.6% 36.7KiB core
0.6%  12.5% 11.3KiB [Unknown]
0.1%   2.5%  2.2KiB alloc
0.1%   1.2%  1.1KiB rust_tcp_ipc
4.8% 100.0% 90.4KiB .text section size, the file size is 1.8MiB
0.6%  12.5% 11.3KiB    [Unknown] main
0.2%   4.8%  4.4KiB         core core::ops::function::FnOnce::call_once{vtable.shim}
0.2%   4.7%  4.2KiB         core <&T as core::fmt::Debug>::fmt
0.2%   4.3%  3.9KiB          std std::sync::mpmc::Sender<T>::send
0.2%   3.5%  3.2KiB         core core::ops::function::FnOnce::call_once{vtable.shim}
0.2%   3.4%  3.1KiB          std std::sync::mpmc::Sender<T>::send
0.2%   3.2%  2.9KiB          std std::sync::mpmc::Sender<T>::send
0.1%   2.9%  2.6KiB          std <str as std::net::socket_addr::ToSocketAddrs>::to_socket_addrs
0.1%   2.6%  2.3KiB         core <str as core::fmt::Debug>::fmt
0.1%   2.6%  2.3KiB         core <&T as core::fmt::Display>::fmt
0.1%   2.0%  1.8KiB         core core::ptr::drop_in_place<std::sync::mpsc::Receiver<reasonable_example::examp...
0.1%   1.9%  1.7KiB         core core::fmt::Formatter::pad
0.1%   1.9%  1.7KiB         core core::ptr::drop_in_place<std::sync::mpsc::Receiver<()>>
0.1%   1.9%  1.7KiB          std std::sync::mpmc::list::Channel<T>::read
0.1%   1.7%  1.5KiB          std std::sync::mpmc::zero::Channel<T>::send::{closure}
0.1%   1.6%  1.5KiB          std std::sync::mpmc::Receiver<T>::try_recv
0.1%   1.6%  1.5KiB          std std::sync::mpmc::zero::Channel<T>::send::{closure}
0.1%   1.6%  1.4KiB          std std::sync::mpmc::zero::Channel<T>::send::{closure}
0.1%   1.5%  1.3KiB         std? <std::sys_common::net::LookupHost as core::convert::TryFrom<(&str,u16)>>::tr...
0.1%   1.4%  1.3KiB          std <std::io::stdio::StdoutLock as std::io::Write>::write_all
0.1%   1.2%  1.1KiB rust_tcp_ipc rust_tcp_ipc::protocol_buffer::ProtocolBuffer<P>::process_new_buffer
0.1%   1.2%  1.0KiB          std std::sys::sync::once::futex::Once::call
0.1%   1.1%    999B         core <core::net::socket_addr::SocketAddr as core::fmt::Debug>::fmt
0.0%   1.0%    960B          std std::sync::mpmc::array::Channel<T>::send::{closure}
0.0%   1.0%    944B          std std::sync::mpmc::list::Channel<T>::recv::{closure}
0.0%   1.0%    925B         core core::net::parser::Parser::read_ipv4_addr
0.0%   1.0%    891B          std std::sync::mpmc::list::Channel<T>::start_recv
0.0%   0.9%    815B         core <core::str::pattern::CharSearcher as core::str::pattern::Searcher>::next_match
0.0%   0.8%    733B         core core::fmt::Formatter::pad_integral
0.0%   0.8%    720B          std std::sync::mpmc::zero::Channel<T>::disconnect
0.0%   0.8%    706B          std std::io::stdio::_print
0.0%   0.7%    624B          std std::sync::mpmc::waker::SyncWaker::notify
0.0%   0.6%    600B         core <core::fmt::builders::PadAdapter as core::fmt::Write>::write_str
0.0%   0.6%    591B          std std::io::buffered::bufwriter::BufWriter<W>::write_all_cold
0.0%   0.6%    566B         core core::ptr::drop_in_place<rust_tcp_ipc::tcp_ipc::TcpIpc<reasonable_example::e...
0.0%   0.6%    566B         core <&T as core::fmt::Debug>::fmt
0.0%   0.6%    543B          std std::sync::mpmc::list::Channel<T>::recv
0.0%   0.6%    530B         core core::fmt::write
0.0%   0.5%    508B         core core::net::parser::Parser::read_number
0.0%   0.5%    499B         core core::str::converts::from_utf8
0.0%   0.5%    494B         core core::fmt::num::<impl core::fmt::Debug for i32>::fmt
0.0%   0.5%    484B         core core::net::parser::Parser::read_ipv6_addr::read_groups
0.0%   0.5%    460B          std std::thread::park_timeout
0.0%   0.5%    445B          std std::sync::mpmc::waker::SyncWaker::disconnect
0.0%   0.5%    437B         core core::ptr::drop_in_place<std::sync::mpsc::Sender<reasonable_example::example...
0.0%   0.5%    433B         core core::ptr::drop_in_place<std::sync::mpsc::Sender<()>>
0.0%   0.5%    431B          std std::sys::pal::unix::stack_overflow::imp::make_handler
0.0%   0.5%    427B         core <core::str::lossy::Utf8Chunks as core::iter::traits::iterator::Iterator>::next
0.0%   0.5%    420B         core <&T as core::fmt::Debug>::fmt
0.0%   0.4%    407B          std std::sys::pal::unix::thread_local_dtor::register_dtor
0.0%   0.4%    386B          std std::sys::pal::unix::thread::Thread::new
0.0%   0.4%    384B          std std::sys::sync::once::futex::Once::call
0.0%   0.4%    369B          std std::sys::pal::common::small_c_string::run_with_cstr_allocating
0.0%   0.4%    366B          std std::sys::pal::unix::stack_overflow::imp::signal_handler
0.0%   0.4%    362B         core <core::net::ip_addr::Ipv4Addr as core::fmt::Display>::fmt
0.0%   0.4%    360B          std std::sys::sync::once::futex::Once::call
0.0%   0.4%    357B        alloc alloc::raw_vec::finish_grow
0.0%   0.4%    355B         core <&T as core::fmt::Debug>::fmt
0.0%   0.4%    354B         core <&T as core::fmt::Debug>::fmt
0.0%   0.4%    336B          std std::sys::sync::rwlock::futex::RwLock::read_contended
0.0%   0.4%    328B         core core::fmt::builders::DebugTuple::field
0.0%   0.3%    322B         core core::fmt::Write::write_char
0.0%   0.3%    307B          std std::thread::park
0.0%   0.3%    292B       alloc? <alloc::string::String as core::fmt::Write>::write_char
0.0%   0.3%    264B          std std::env::_var_os
0.0%   0.3%    264B         std? <std::io::Write::write_fmt::Adapter<T> as core::fmt::Write>::write_str
0.0%   0.3%    262B         core core::fmt::Write::write_char
0.0%   0.3%    262B         core core::fmt::num::imp::<impl core::fmt::Display for u32>::fmt
0.0%   0.3%    260B         core <core::result::Result<T,E> as core::fmt::Debug>::fmt
0.0%   0.3%    259B        alloc alloc::sync::Arc<T,A>::drop_slow
0.0%   0.3%    249B         core core::fmt::Write::write_char
0.0%   0.3%    249B         core core::fmt::Write::write_char
0.0%   0.3%    249B         core core::fmt::Write::write_char
0.0%   0.3%    249B         core core::fmt::Write::write_char
0.0%   0.3%    247B          std std::sys::sync::mutex::futex::Mutex::lock_contended
0.0%   0.3%    239B         core <&T as core::fmt::Debug>::fmt
0.0%   0.3%    238B          std std::sync::mpmc::context::Context::new
0.0%   0.2%    228B         core core::fmt::num::imp::<impl core::fmt::Display for u16>::fmt
0.0%   0.2%    217B          std std::io::error::Error::kind
0.0%   0.2%    215B         core core::fmt::Write::write_char
0.0%   0.2%    210B          std std::sys::sync::rwlock::futex::RwLock::wake_writer_or_readers
0.0%   0.2%    189B          std std::sys_common::thread_local_key::StaticKey::lazy_init
0.0%   0.2%    188B          std std::sys_common::thread_local_dtor::register_dtor_fallback::run_dtors
0.0%   0.2%    185B          std std::sys::pal::unix::time::Timespec::sub_timespec
0.0%   0.2%    170B        alloc alloc::raw_vec::RawVec<T,A>::grow_one
0.0%   0.2%    168B          std std::sys::pal::unix::thread::Thread::new::thread_start
0.0%   0.2%    168B          std std::thread::set_current
0.0%   0.2%    166B         core core::ptr::drop_in_place<core::result::Result<(reasonable_example::example_p...
0.0%   0.2%    163B          std std::sys::pal::unix::weak::DlsymWeak<F>::initialize
0.0%   0.2%    163B         core core::ptr::drop_in_place<std::sync::mpmc::waker::Waker>
0.0%   0.2%    158B          std std::io::error::Error::new
0.0%   0.2%    155B        alloc alloc::raw_vec::RawVec<T,A>::grow_one
0.0%   0.2%    150B          std std::io::error::Error::new
0.0%   0.2%    150B          std std::io::error::Error::new
0.0%   0.2%    149B        alloc alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle
0.0%   0.2%    147B          std std::io::Write::write_fmt
0.0%   0.1%    137B         core core::fmt::num::imp::<impl core::fmt::Display for u8>::fmt
0.0%   0.1%    137B        alloc alloc::raw_vec::RawVec<T,A>::grow_one
0.0%   0.1%    134B         std? <std::io::Write::write_fmt::Adapter<T> as core::fmt::Write>::write_str
0.0%   0.1%    134B        alloc alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle
0.1%   3.1%  2.8KiB              And 55 smaller methods. Use -n N to show more.
4.8% 100.0% 90.4KiB              .text section size, the file size is 1.8MiB

Getting good. Most of this is just monomorphisation and formatting, something like this can easily be stripped down, maybe down to even 20KiB.

The underlying network library mio is very portable and binds directly to libc.

message.io

File  .text     Size             Crate Name
0.4%  11.5%  13.9KiB              core core::ops::function::FnOnce::call_once{vtable.shim}
0.4%  10.6%  12.8KiB         [Unknown] main
0.1%   2.5%   3.1KiB        message_io <message_io::network::driver::Driver<R,L> as message_io::network::driver::EventProcessor>::process
0.1%   2.2%   2.6KiB         multicast multicast::main::{closure}
0.1%   2.1%   2.5KiB             alloc alloc::collections::btree::remove::<impl alloc::collections::btree::node::Handle<alloc::collections::btr...
0.1%   1.9%   2.3KiB        message_io <message_io::network::driver::Driver<R,L> as message_io::network::driver::ActionController>::listen_with
0.1%   1.9%   2.3KiB             alloc <<alloc::boxed::Box<dyn core::error::Error+core::marker::Send+core::marker::Sync> as core::convert::From...
0.1%   1.8%   2.2KiB         hashbrown hashbrown::raw::RawTable<T,A>::reserve_rehash
0.1%   1.6%   2.0KiB        message_io <message_io::network::driver::Driver<R,L> as message_io::network::driver::ActionController>::connect_with
0.1%   1.5%   1.9KiB        message_io <message_io::network::driver::Driver<R,L> as message_io::network::driver::EventProcessor>::process
0.1%   1.4%   1.7KiB              core core::fmt::Formatter::pad
0.1%   1.4%   1.7KiB crossbeam_channel crossbeam_channel::select::run_select::{closure}
0.1%   1.4%   1.7KiB        message_io <message_io::network::driver::Driver<R,L> as message_io::network::driver::ActionController>::listen_with
0.1%   1.4%   1.6KiB              core core::ptr::drop_in_place<crossbeam_channel::channel::Receiver<std::time::Instant>>
0.1%   1.3%   1.6KiB        message_io message_io::network::transport::Transport::mount_adapter
0.1%   1.3%   1.6KiB              core core::ptr::drop_in_place<message_io::events::EventReceiver<()>>
0.0%   1.3%   1.5KiB crossbeam_channel crossbeam_channel::flavors::list::Channel<T>::read
0.0%   1.2%   1.5KiB crossbeam_channel <crossbeam_channel::channel::Receiver<T> as crossbeam_channel::select::SelectHandle>::register
0.0%   1.2%   1.5KiB crossbeam_channel <crossbeam_channel::channel::Receiver<T> as crossbeam_channel::select::SelectHandle>::register
0.0%   1.2%   1.5KiB              core core::ops::function::FnOnce::call_once{vtable.shim}
1.8%  47.8%  57.9KiB                   And 184 smaller methods. Use -n N to show more.
3.8% 100.0% 121.2KiB                   .text section size, the file size is 3.1MiB

The multicast example, with TCP (minor code edits required).

A bit too heavy, but this would be great for adding multiplayer to a game inside a mod.

Conclusion

Reloaded's IPC requirements are extremely minimal

But everything is way too overkill, either in functionality or in binary size.

Build your own TCP based IPC, with mio. It's the most portable and the smallest. We're talking extremely barebones, single thread per client, small stack