Skip to content

Commit 2ef3d95

Browse files
authored
perf(l1,l2): use the new load test for the CI scripts (lambdaclass#2467)
Changes: - Flamegraph Watcher srcript now: - Uses the new load test. - Fails if any line fails (e.g. the load test binary panics). - CI: - The flamegraphs are now updated on push to main again. - Compilation and running is separated to delete the "while not compiled" polling. - Reth version is pinned so it does not rely on 2024 features and can be compiled again. - Load test: - `make` targets now run in release mode. - now waits until all transactions are included before exciting. There's a flag to set a timeout. - All ethrex_l2 references are deleted from CI and the watcher. Closes lambdaclass#2466
1 parent e8b7b23 commit 2ef3d95

File tree

5 files changed

+111
-76
lines changed

5 files changed

+111
-76
lines changed

.github/scripts/flamegraph_watcher.sh

100644100755
Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,28 @@
11
#!/bin/bash
2+
set -e
23

3-
# This script sends 171 * <iterations> transactions to a test account, per defined private key
4-
# then polls the account balance until the expected balance has been reached
5-
# and then kills the process. It also measures the elapsed time of the test and
6-
# outputs it to Github Action's outputs.
7-
iterations=3500
8-
value=1
9-
account=0x33c6b73432B3aeA0C1725E415CC40D04908B85fd
10-
end_val=$((171 * $iterations * $value))
4+
# This script runs a load test and then kills the node under test. The load test sends a
5+
# transaction from each rich account to a random one, so we can check their nonce to
6+
# determine that the load test finished.
7+
#
8+
# Usage:
9+
# ./flamegraph_watcher.sh
10+
# Requires a PROGRAM variable to be set (e.g. ethrex). This $PROGRAM will be killed when the
11+
# load test finishes. Must be run from the context of the repo root.
1112

12-
start_time=$(date +%s)
13-
ethrex_l2 test load --path /home/runner/work/ethrex/ethrex/test_data/private_keys.txt -i $iterations -v --value $value --to $account >/dev/null
13+
# TODO(#2486): Move this to a cached build outside.
14+
echo "Building load test"
15+
cargo build --release --manifest-path ./cmd/load_test/Cargo.toml
1416

15-
output=$(ethrex_l2 info -b -a $account --wei 2>&1)
16-
echo "balance: $output"
17-
while [[ $output -lt $end_val ]]; do
18-
sleep 2
19-
output=$(ethrex_l2 info -b -a $account --wei 2>&1)
20-
echo "balance: $output"
21-
done
17+
echo "Starting load test"
18+
start_time=$(date +%s)
19+
RUST_BACKTRACE=1 ./target/release/load_test -k ./test_data/private_keys.txt -t eth-transfers -N 1000 -n http://localhost:1729 -w 5 >/dev/null
2220
end_time=$(date +%s)
23-
elapsed=$((end_time - start_time))
2421

22+
elapsed=$((end_time - start_time))
2523
minutes=$((elapsed / 60))
2624
seconds=$((elapsed % 60))
27-
output=$(ethrex_l2 info -b -a $account --wei 2>&1)
28-
echo "Balance of $output reached in $minutes min $seconds s, killing process"
25+
echo "All load test transactions included in $minutes min $seconds s, killing node process."
2926

3027
echo killing "$PROGRAM"
3128
sudo pkill "$PROGRAM"

.github/workflows/main_flamegraph_report.yaml

Lines changed: 12 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ permissions:
66
id-token: write
77

88
on:
9-
# re-enable this when fixing the workflow
10-
# push:
11-
# branches: ["main"]
9+
push:
10+
branches: ["main"]
1211
workflow_dispatch:
1312

1413
env:
@@ -183,13 +182,6 @@ jobs:
183182
${{ env.HOME }}/.cargo/bin/inferno-*
184183
key: ${{ runner.os }}-extra-binaries
185184

186-
- name: Cache ethrex_l2
187-
id: cache-ethrex-l2
188-
uses: actions/cache@v4
189-
with:
190-
path: ${{ env.HOME }}/.cargo/bin/ethrex_l2
191-
key: ${{ runner.os }}-ethrex-l2-${{ hashFiles('cmd/ethrex_l2/Cargo.lock') }}
192-
193185
- name: Change perf settings
194186
run: |
195187
sudo sysctl kernel.perf_event_paranoid=-1
@@ -236,30 +228,18 @@ jobs:
236228
echo "$HOME/.cargo/bin/inferno-collapse-perf" already found
237229
fi
238230
239-
- name: Install ethrex_l2 cli
240-
run: |
241-
if [ -f "$HOME/.cargo/bin/ethrex_l2" ]; then
242-
echo "$HOME/.cargo/bin/ethrex_l2" already found
243-
else
244-
cargo install --force --path cmd/ethrex_l2
245-
fi
246-
ethrex_l2 config create default --default
247-
ethrex_l2 config set default
248-
249231
# By default ethrex uses revm as evm backend.
250232
- id: generate-flamegraph-ethrex
251233
name: Generate Flamegraph data for Ethrex
252234
shell: bash
253235
run: |
254236
rm -rf target/release/ethrex
237+
cargo build --release --bin ethrex --features dev
255238
CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -c "record -o perf.data -F997 --call-graph dwarf,16384 -g" \
256-
--bin ethrex --features dev -- --dev --network /home/runner/work/ethrex/ethrex/test_data/genesis-l2.json --http.port 1729 >/dev/null &
257-
while [ ! -x "./target/release/ethrex" ]; do
258-
echo "Waiting for ethrex binary to be ready..."
259-
sleep 2
260-
done
239+
--bin ethrex --release --features dev -- \
240+
--dev --network /home/runner/work/ethrex/ethrex/test_data/genesis-l2-ci.json --http.port 1729 >/dev/null &
261241
sleep 10
262-
echo "Compilation finished. Executing load test..."
242+
echo "Executing load test..."
263243
bash /home/runner/work/ethrex/ethrex/.github/scripts/flamegraph_watcher.sh &&
264244
echo "Load test finished"
265245
@@ -293,12 +273,13 @@ jobs:
293273
with:
294274
toolchain: ${{ env.RUST_RETH_VERSION }}
295275

276+
# We need a reth version that requires a rustc version <= 1.82.0
296277
- name: Checkout reth
297278
uses: actions/checkout@v4
298279
with:
299280
repository: paradigmxyz/reth
300281
path: "reth"
301-
ref: main
282+
ref: b2ead06d1d0804101de0d1eb3a070e08d8eab857
302283

303284
- name: Caching
304285
uses: Swatinem/rust-cache@v2
@@ -316,13 +297,6 @@ jobs:
316297
${{ env.HOME }}/.cargo/bin/inferno-*
317298
key: ${{ runner.os }}-extra-binaries
318299

319-
- name: Cache ethrex_l2
320-
id: cache-ethrex-l2
321-
uses: actions/cache@v4
322-
with:
323-
path: ${{ env.HOME }}/.cargo/bin/ethrex_l2
324-
key: ${{ runner.os }}-ethrex-l2-${{ hashFiles('cmd/ethrex_l2/Cargo.lock') }}
325-
326300
- name: Change perf settings
327301
run: |
328302
sudo sysctl kernel.perf_event_paranoid=-1
@@ -369,35 +343,22 @@ jobs:
369343
echo "$HOME/.cargo/bin/inferno-collapse-perf" already found
370344
fi
371345
372-
- name: Install ethrex_l2 cli
373-
run: |
374-
if [ -f "$HOME/.cargo/bin/ethrex_l2" ]; then
375-
echo "$HOME/.cargo/bin/ethrex_l2" already found
376-
else
377-
cargo install --force --path cmd/ethrex_l2
378-
fi
379-
ethrex_l2 config create default --default
380-
ethrex_l2 config set default
381-
382346
- id: generate-flamegraph-reth
383347
name: Build and test reth
384348
shell: bash
385349
# --dev.block-time 1000ms set to 1000ms to match ethrex block generation time
386350
run: |
387351
cd ./reth
388352
rm -rf target/profiling/reth
389-
CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -c "record -o perf.data -F997 --call-graph dwarf,16384 -g" \
390-
--bin reth --profile profiling -- node --chain /home/runner/work/ethrex/ethrex/test_data/genesis-load-test.json --dev \
353+
cargo build --bin reth --profile profiling
354+
CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -c "record -o perf.data -F997 --call-graph dwarf,16384 -g" --bin reth --profile profiling -- \
355+
node --chain /home/runner/work/ethrex/ethrex/test_data/genesis-l2-ci.json --dev \
391356
--dev.block-time 1000ms --http.port 1729 --txpool.max-pending-txns 100000000 --txpool.max-new-txns 1000000000 \
392357
--txpool.pending-max-count 100000000 --txpool.pending-max-size 10000000000 --txpool.basefee-max-count 100000000000 \
393358
--txpool.basefee-max-size 1000000000000 --txpool.queued-max-count 1000000000 >/dev/null &
394-
while [ ! -x "./target/profiling/reth" ]; do
395-
echo "Waiting for reth binary to be ready..."
396-
sleep 10
397-
done
398359
sleep 30
399360
echo "Executing load test..."
400-
bash /home/runner/work/ethrex/ethrex/.github/scripts/flamegraph_watcher.sh &&
361+
(cd /home/runner/work/ethrex/ethrex; ./.github/scripts/flamegraph_watcher.sh)
401362
echo "Load test finished"
402363
403364
- name: Generate SVG

Makefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,16 +161,16 @@ start-node-with-flamegraph: rm-test-db ## 🚀🔥 Starts an ethrex client used
161161
--datadir test_ethrex
162162

163163
load-test: ## 🚧 Runs a load-test. Run make start-node-with-flamegraph and in a new terminal make load-node
164-
cargo run --manifest-path ./cmd/load_test/Cargo.toml -- -k ./test_data/private_keys.txt -t eth-transfers
164+
cargo run --release --manifest-path ./cmd/load_test/Cargo.toml -- -k ./test_data/private_keys.txt -t eth-transfers
165165

166166
load-test-erc20:
167-
cargo run --manifest-path ./cmd/load_test/Cargo.toml -- -k ./test_data/private_keys.txt -t erc20
167+
cargo run --release --manifest-path ./cmd/load_test/Cargo.toml -- -k ./test_data/private_keys.txt -t erc20
168168

169169
load-test-fibonacci:
170-
cargo run --manifest-path ./cmd/load_test/Cargo.toml -- -k ./test_data/private_keys.txt -t fibonacci
170+
cargo run --release --manifest-path ./cmd/load_test/Cargo.toml -- -k ./test_data/private_keys.txt -t fibonacci
171171

172172
load-test-io:
173-
cargo run --manifest-path ./cmd/load_test/Cargo.toml -- -k ./test_data/private_keys.txt -t io-heavy
173+
cargo run --release --manifest-path ./cmd/load_test/Cargo.toml -- -k ./test_data/private_keys.txt -t io-heavy
174174

175175
rm-test-db: ## 🛑 Removes the DB used by the ethrex client used for testing
176176
sudo cargo run --release --bin ethrex -- removedb --force --datadir test_ethrex

cmd/load_test/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ Usage: load_test [OPTIONS] --pkeys <PKEYS>
1010
Options:
1111
-n, --node <NODE> URL of the node being tested. [default: http://localhost:8545]
1212
-k, --pkeys <PKEYS> Path to the file containing private keys.
13-
-t, --test-type <TEST_TYPE> Type of test to run. Can be eth_transfers or erc20. [default: erc20] [possible values: eth-transfers, erc20]
13+
-t, --test-type <TEST_TYPE> Type of test to run. Can be eth_transfers or erc20. [default: erc20] [possible values: eth-transfers, erc20, fibonacci, io-heavy]
1414
-N, --tx-amount <TX_AMOUNT> Number of transactions to send for each account. [default: 1000]
15+
-w, --wait <WAIT> Timeout to wait for all transactions to be included. If 0 is specified, wait indefinitely. [default: 0]
1516
-h, --help Print help
1617
```
1718

cmd/load_test/src/main.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ struct Cli {
5757
help = "Number of transactions to send for each account."
5858
)]
5959
tx_amount: u64,
60+
61+
// Amount of minutes to wait before exiting. If the value is 0, the program will wait indefinitely. If not present, the program will not wait for transactions to be included in blocks.
62+
#[arg(
63+
long,
64+
short = 'w',
65+
default_value_t = 0,
66+
help = "Timeout to wait for all transactions to be included. If 0 is specified, wait indefinitely."
67+
)]
68+
wait: u64,
6069
}
6170

6271
#[derive(ValueEnum, Clone, Debug)] // Derive ValueEnum for TestType
@@ -264,6 +273,49 @@ async fn load_test(
264273
Ok(())
265274
}
266275

276+
// Waits until the nonce of each account has reached the tx_amount.
277+
async fn wait_until_all_included(
278+
client: EthClient,
279+
wait: Option<Duration>,
280+
accounts: &[Account],
281+
tx_amount: u64,
282+
) -> Result<(), String> {
283+
let start_time = tokio::time::Instant::now();
284+
285+
for (pk, _) in accounts {
286+
let pk = *pk;
287+
let client = client.clone();
288+
let src = address_from_pub_key(pk);
289+
let encoded_src: String = src.encode_hex();
290+
loop {
291+
let elapsed = start_time.elapsed();
292+
let nonce = client.get_nonce(src, BlockByNumber::Latest).await.unwrap();
293+
if nonce >= tx_amount {
294+
println!(
295+
"All transactions sent from {} have been included in blocks. Nonce: {}",
296+
encoded_src, nonce
297+
);
298+
break;
299+
} else {
300+
println!(
301+
"Waiting for transactions to be included from {}. Nonce: {}. Needs: {}. Percentage: {:2}%. Elapsed time: {}s.",
302+
encoded_src, nonce, tx_amount, (nonce as f64 / tx_amount as f64) * 100.0, elapsed.as_secs()
303+
);
304+
}
305+
306+
if let Some(wait) = wait {
307+
if elapsed > wait {
308+
return Err("Timeout reached for transactions to be included".to_string());
309+
}
310+
}
311+
312+
sleep(Duration::from_secs(5)).await;
313+
}
314+
}
315+
316+
Ok(())
317+
}
318+
267319
fn parse_pk_file(path: &Path) -> eyre::Result<Vec<Account>> {
268320
let pkeys_content = fs::read_to_string(path).expect("Unable to read private keys file");
269321
let accounts: Vec<Account> = pkeys_content
@@ -335,6 +387,12 @@ async fn main() {
335387
}
336388
};
337389

390+
println!(
391+
"Starting load test with {} transactions per account",
392+
cli.tx_amount
393+
);
394+
let time_now = tokio::time::Instant::now();
395+
338396
load_test(
339397
cli.tx_amount,
340398
&accounts,
@@ -344,4 +402,22 @@ async fn main() {
344402
)
345403
.await
346404
.expect("Failed to load test");
405+
406+
let wait_time = if cli.wait > 0 {
407+
Some(Duration::from_secs(cli.wait * 60))
408+
} else {
409+
None
410+
};
411+
412+
println!("Waiting for all transactions to be included in blocks...");
413+
wait_until_all_included(client, wait_time, &accounts, cli.tx_amount)
414+
.await
415+
.unwrap();
416+
417+
let elapsed_time = time_now.elapsed();
418+
419+
println!(
420+
"Load test finished. Elapsed time: {} seconds",
421+
elapsed_time.as_secs()
422+
);
347423
}

0 commit comments

Comments
 (0)