Browse Source

Convert the stress.rs example into a simple benchmark.

There are no more bugs exposed by stress.rs as far as I can tell,
so let's make it do something more useful.
whitequark 7 years ago
parent
commit
ba1d5ed576
3 changed files with 41 additions and 7 deletions
  1. 1 3
      Cargo.toml
  2. 26 0
      README.md
  3. 14 4
      examples/benchmark.rs

+ 1 - 3
Cargo.toml

@@ -69,10 +69,8 @@ required-features = ["std", "phy-tap_interface", "socket-tcp", "socket-udp"]
 name = "loopback"
 required-features = ["log", "socket-tcp"]
 
-# This is really a test, but it requires root privileges for setup (the tap interface)
-# so it is built as an example.
 [[example]]
-name = "stress"
+name = "benchmark"
 required-features = ["std", "phy-tap_interface", "socket-tcp"]
 
 [profile.release]

+ 26 - 0
README.md

@@ -8,6 +8,9 @@ at cost of performance degradation.
 _smoltcp_ does not need heap allocation *at all*, is [extensively documented][docs],
 and compiles on stable Rust 1.20 and later.
 
+_smoltcp_ achieves [~Gbps of throughput](#examplesbenchmarkrs) when tested against
+the Linux TCP stack in loopback mode.
+
 [docs]: https://docs.rs/smoltcp/
 
 ## Features
@@ -295,6 +298,29 @@ cargo run --example client -- tap0 ADDRESS PORT
 It connects to the given address (not a hostname) and port (e.g. `socat stdio tcp4-listen:1234`),
 and will respond with reversed chunks of the input indefinitely.
 
+### examples/benchmark.rs
+
+_examples/benchmark.rs_ implements a simple throughput benchmark.
+
+Read its [source code](/examples/benchmark.rs), then run it as:
+
+```sh
+cargo run --release --example benchmark -- tap0 [reader|writer]
+```
+
+It establishes a connection to itself from a different thread and reads or writes a large amount
+of data in one direction.
+
+A typical result (achieved on a Intel Core i7-7500U CPU and a Linux 4.9.65 x86_64 kernel running
+on a Dell XPS 13 9360 laptop) is as follows:
+
+```
+$ cargo run -q --release --example benchmark tap0 reader
+throughput: 2.219 Gbps
+$ cargo run -q --release --example benchmark tap0 writer
+throughput: 4.519 Gbps
+```
+
 ## Bare-metal usage examples
 
 Examples that use no services from the host OS are necessarily less illustrative than examples

+ 14 - 4
examples/stress.rs → examples/benchmark.rs

@@ -22,14 +22,16 @@ use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
 use smoltcp::socket::SocketSet;
 use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
 
-const AMOUNT: usize = 10_000_000;
+const AMOUNT: usize = 1_000_000_000;
 
 enum Client { Reader, Writer }
 
 fn client(kind: Client) {
     let port = match kind { Client::Reader => 1234, Client::Writer => 1235 };
     let mut stream = TcpStream::connect(("192.168.69.1", port)).unwrap();
-    let mut buffer = vec![0; 64];
+    let mut buffer = vec![0; 1_000_000];
+
+    let start = Instant::now();
 
     let mut processed = 0;
     while processed < AMOUNT {
@@ -47,7 +49,15 @@ fn client(kind: Client) {
             Err(err) => panic!("cannot process: {}", err)
         }
     }
-    println!("client done");
+
+    let end = Instant::now();
+
+    let elapsed = end - start;
+    let elapsed = elapsed.as_secs() as f64
+                + elapsed.subsec_nanos() as f64 * 1e-9;
+
+    println!("throughput: {:.3} Gbps", AMOUNT as f64 / elapsed / 0.125e9);
+
     CLIENT_DONE.store(true, Ordering::SeqCst);
 }
 
@@ -139,6 +149,6 @@ fn main() {
             }
         }
 
-        phy_wait(fd, iface.poll_delay(&sockets, timestamp)).expect("wait error");
+        phy_wait(fd, iface.poll_delay(&sockets, timestamp).or(Some(1000))).expect("wait error");
     }
 }