Skip to content

Commit 7a02fe4

Browse files
authored
chore(ci): add a heaptrack job (#265)
* chore(ci): add a `heaptrack` job * chore(e2e): switch the client from JS to rust * chore(e2e): fix heaptrack file upload * chore(e2e): fix upload-artifact version * chore(e2e): `kill` the server after 60s * chore(e2e/bench): custom bench workflow with optional trigger
1 parent 3ab5cd7 commit 7a02fe4

File tree

8 files changed

+171
-2
lines changed

8 files changed

+171
-2
lines changed

.github/workflows/bench.yml

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Bench
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
heaptrack:
7+
description: 'Run heaptrack memory benchmark'
8+
required: true
9+
default: false
10+
type: boolean
11+
12+
jobs:
13+
heaptrack:
14+
if: ${{ github.event.inputs.heaptrack == 'true' }}
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: dtolnay/rust-toolchain@master
19+
with:
20+
toolchain: stable
21+
- uses: actions/cache@v4
22+
with:
23+
path: |
24+
~/.cargo/bin/
25+
~/.cargo/registry/index/
26+
~/.cargo/registry/cache/
27+
~/.cargo/git/db/
28+
target/
29+
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-heaptrack
30+
- name: Install heaptrack
31+
run: sudo apt-get install -y heaptrack
32+
- name: Build server && client
33+
run: cargo build -r -p heaptrack && cargo build -r -p heaptrack --bin heaptrack-client
34+
- name: Run memory benchmark
35+
run: heaptrack target/release/heaptrack > server.txt & ./target/release/heaptrack-client > client.txt
36+
- name: Server output
37+
if: always()
38+
run: cat server.txt
39+
- name: Client output
40+
if: always()
41+
run: cat client.txt
42+
- name: Publish memory benchmark
43+
uses: actions/upload-artifact@v4
44+
with:
45+
name: heaptrack-${{ github.head_ref }}.${{ github.sha }}
46+
path: heaptrack.heaptrack.*

.github/workflows/github-ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -251,4 +251,4 @@ jobs:
251251
run: cat server.txt
252252
- name: Client output
253253
if: always()
254-
run: cat client.txt
254+
run: cat client.txt

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
target
22
Cargo.lock
33
.env
4-
.vscode
4+
.vscode
5+
*.gz

e2e/heaptrack/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.gz
2+
client/node_modules
3+
memory_usage.svg

e2e/heaptrack/Cargo.toml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[package]
2+
name = "heaptrack"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
socketioxide = { path = "../../socketioxide" }
10+
hyper = { workspace = true, features = ["server", "http1", "http2"] }
11+
hyper-util = { workspace = true, features = ["tokio"] }
12+
tokio = { workspace = true, features = ["rt-multi-thread", "macros", "signal"] }
13+
rust_socketio = { version = "0.4.2", features = ["async"] }
14+
serde_json = "1.0.68"
15+
rand = "0.8.4"
16+
17+
[[bin]]
18+
name = "heaptrack-client"
19+
path = "src/client.rs"

e2e/heaptrack/README.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Memory usage benchmark
2+
## Based on the official implementation : https://socket.io/docs/v4/memory-usage/
3+
4+
The goal of this program is to benchmark the memory usage of the socket.io server under different conditions.
5+
The server can be configured to generated its own reports with the `custom-report` feature flag.
6+
7+
The best way is still to run the program with (heaptrack)[https://github.com/KDE/heaptrack] and analyze the results with the `heaptrack_gui` tool.

e2e/heaptrack/src/client.rs

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use std::{pin::Pin, time::Duration};
2+
3+
use rust_socketio::{
4+
asynchronous::{Client, ClientBuilder},
5+
Payload,
6+
};
7+
8+
const PING_INTERVAL: Duration = Duration::from_millis(1000);
9+
const POLLING_PERCENTAGE: f32 = 0.05;
10+
const MAX_CLIENT: usize = 200;
11+
12+
fn cb(_: Payload, socket: Client) -> Pin<Box<dyn std::future::Future<Output = ()> + Send>> {
13+
Box::pin(async move {
14+
tokio::spawn(async move {
15+
let mut inter = tokio::time::interval(PING_INTERVAL);
16+
loop {
17+
inter.tick().await;
18+
let _ = socket.emit("ping", serde_json::Value::Null).await;
19+
let _ = socket
20+
.emit("ping", (0..u8::MAX).into_iter().collect::<Vec<u8>>())
21+
.await;
22+
}
23+
});
24+
})
25+
}
26+
#[tokio::main]
27+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
28+
tokio::spawn(async move {
29+
for _ in 0..MAX_CLIENT {
30+
let random: f32 = rand::random();
31+
let transport_type = if POLLING_PERCENTAGE > random {
32+
rust_socketio::TransportType::Polling
33+
} else {
34+
rust_socketio::TransportType::WebsocketUpgrade
35+
};
36+
// get a socket that is connected to the admin namespace
37+
ClientBuilder::new("http://localhost:3000/")
38+
.transport_type(transport_type)
39+
.namespace("/")
40+
.on("open", cb)
41+
.on("error", |err, _| {
42+
Box::pin(async move { eprintln!("Error: {:#?}", err) })
43+
})
44+
.connect()
45+
.await
46+
.expect("Connection failed");
47+
}
48+
});
49+
tokio::time::sleep(Duration::from_secs(60)).await;
50+
51+
Ok(())
52+
}

e2e/heaptrack/src/main.rs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use hyper::server::conn::http1;
2+
use hyper_util::rt::TokioIo;
3+
use socketioxide::{extract::SocketRef, SocketIo};
4+
use std::{net::SocketAddr, time::Duration};
5+
use tokio::net::TcpListener;
6+
7+
fn on_connect(socket: SocketRef) {
8+
socket.on("ping", |s: SocketRef| {
9+
s.emit("pong", ()).ok();
10+
});
11+
}
12+
13+
#[tokio::main]
14+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
15+
let (svc, io) = SocketIo::new_svc();
16+
17+
io.ns("/", on_connect);
18+
19+
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
20+
let listener = TcpListener::bind(addr).await?;
21+
22+
tokio::spawn(async move {
23+
tokio::time::sleep(Duration::from_secs(60)).await;
24+
std::process::exit(0);
25+
});
26+
27+
loop {
28+
let (stream, _) = listener.accept().await?;
29+
30+
let io = TokioIo::new(stream);
31+
let svc = svc.clone();
32+
33+
tokio::task::spawn(async move {
34+
http1::Builder::new()
35+
.serve_connection(io, svc)
36+
.with_upgrades()
37+
.await
38+
.ok()
39+
});
40+
}
41+
}

0 commit comments

Comments
 (0)