From 6528c1977d30b5de9e6d187356cf1782633a37bc Mon Sep 17 00:00:00 2001
From: Konrad Zemek <konrad.zemek@gmail.com>
Date: Fri, 14 Jun 2019 19:40:27 +0200
Subject: [PATCH] Add benchmark results to README.

---
 README.md     |  24 ++++++++++++++++++++++++
 benchmark.png | Bin 0 -> 17823 bytes
 2 files changed, 24 insertions(+)
 create mode 100644 benchmark.png

diff --git a/README.md b/README.md
index e14eee9..11e1700 100644
--- a/README.md
+++ b/README.md
@@ -76,3 +76,27 @@ Example invocation:
 ```shell
 sudo ./go-mmproxy -l 0.0.0.0:25577 -4 127.0.0.1:25578 -6 [::1]:25578 --allowed-subnets ./path-prefixes.txt
 ```
+
+## Benchmark
+
+### Setup
+
+The benchmark was ran on Dell XPS 9570 with Intel Core i9-8950HK CPU @ 2.90GHz (12 logical cores). The upstream service to which proxy sent traffic was mocked by [bpf-echo](https://github.com/path-network/bpf-echo) server.
+Traffic was generated by [tcpkali](https://github.com/satori-com/tcpkali) v1.1.1 .
+
+The following command was used for load generation in all cases (50 connections, 10s runtime, send PROXYv1 header for each connection, use `PING\r\n` as TCP message):
+
+```
+tcpkali -c 50 -T 10s -e1 'PROXY TCP4 127.0.0.1 127.0.0.1 \{connection.uid} 25578\r\n' -m 'PING\r\n' 127.0.0.1:1122
+```
+
+### Results
+
+|                         | ⇅ Mbps    | ↓ Mbps    | ↑ Mbps    | ↓ pkt/s   | ↑ pkt/s   |
+| ----------------------- | --------- | --------- | --------- | --------- | --------- |
+| cloudflare/mmproxy      | 1524.454  | 756.385   | 768.069   | 70365.9   | 65921.9   |
+| go-mmproxy GOMAXPROCS=1 | 7418.312  | 2858.794  | 4559.518  | 262062.7  | 391334.6  |
+| go-mmproxy              | 45483.233 | 16142.348 | 29340.885 | 1477889.6 | 2518271.5 |
+| no proxy                | 52640.116 | 22561.129 | 30078.987 | 2065805.4 | 2581621.3 |
+
+![result barchart](benchmark.png)
diff --git a/benchmark.png b/benchmark.png
new file mode 100644
index 0000000000000000000000000000000000000000..389c0f2d8c9e46e39328ab44b86351e6cca9d0e5
GIT binary patch
literal 17823
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

literal 0
HcmV?d00001

-- 
GitLab