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"
 name = "loopback"
 required-features = ["log", "socket-tcp"]
 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]]
 [[example]]
-name = "stress"
+name = "benchmark"
 required-features = ["std", "phy-tap_interface", "socket-tcp"]
 required-features = ["std", "phy-tap_interface", "socket-tcp"]
 
 
 [profile.release]
 [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],
 _smoltcp_ does not need heap allocation *at all*, is [extensively documented][docs],
 and compiles on stable Rust 1.20 and later.
 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/
 [docs]: https://docs.rs/smoltcp/
 
 
 ## Features
 ## 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`),
 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.
 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
 ## Bare-metal usage examples
 
 
 Examples that use no services from the host OS are necessarily less illustrative than 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::SocketSet;
 use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
 use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
 
 
-const AMOUNT: usize = 10_000_000;
+const AMOUNT: usize = 1_000_000_000;
 
 
 enum Client { Reader, Writer }
 enum Client { Reader, Writer }
 
 
 fn client(kind: Client) {
 fn client(kind: Client) {
     let port = match kind { Client::Reader => 1234, Client::Writer => 1235 };
     let port = match kind { Client::Reader => 1234, Client::Writer => 1235 };
     let mut stream = TcpStream::connect(("192.168.69.1", port)).unwrap();
     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;
     let mut processed = 0;
     while processed < AMOUNT {
     while processed < AMOUNT {
@@ -47,7 +49,15 @@ fn client(kind: Client) {
             Err(err) => panic!("cannot process: {}", err)
             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);
     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");
     }
     }
 }
 }