feat(perf): migrate python perf image config from test-plans #808#37
Conversation
(cherry picked from commit 285b6d3b7d3e4004e19975ae4426a07b27dd7d5f)
|
Hi @seetadev, this was the same on the old test-plans I checked the failing run and pulled the artifacts/logs for Result summary
Passing cases
Failing cases
Direct failure reason
So this is a genuine test-execution failure (timeouts + one QUIC runtime error), not an artifact upload/workflow issue. |
It sounds like that is incorrect. We shouldn't fail if an impl is super slow and it times out. However 300s is 5 minutes...any idea what is taking so long? I'm ok with doubling this but if that's not long enough I think py-libp2p needs some optimization work. |
|
|
@acul71 the issues are deep in python. I ran the perf test with Here is the (tcp, tls, yamux) log file: So you can see that with 1 MB transfers it completes all 10 iterations and then times out anyway. Something else is going on other than just being slow. |
…n-perf Made-with: Cursor # Conflicts: # perf/images.yaml
I've just discovered that increasing the # Larger default window reduces flow-control churn on high-throughput links.
DEFAULT_WINDOW_SIZE = 16 * 1024 * 1024But I discovered that number with testing, I don't know what the full implications are of this mod. For I'm going to review the About |
Pin perf Python tests to the intended py-libp2p snapshot and avoid docker compose project/container name collisions between reruns by using a per-test-pass project suffix. Made-with: Cursor
|
Why this change was needed:
What the fix does:
Result:
|
|
In CI/CD this test is failing for timeout python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Connected to listener
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Upload 1/10: 0.43 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Upload 2/10: 0.43 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Upload 3/10: 0.43 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Upload 4/10: 0.43 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Upload 5/10: 0.43 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Upload 6/10: 0.43 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Upload 7/10: 0.43 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Upload 8/10: 0.43 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Upload 9/10: 0.43 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Upload 10/10: 0.43 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Download 1/10: 0.49 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Download 2/10: 0.50 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Download 3/10: 0.49 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Download 4/10: 0.49 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__4a514541_dialer | Download 5/10: 0.50 Gbps
Gracefully stopping... (press Ctrl+C again to force)in my linux-box works (faster hardware I think) python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Connected to listener
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Upload 1/10: 1.05 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Upload 2/10: 1.10 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Upload 3/10: 1.07 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Upload 4/10: 1.04 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Upload 5/10: 1.06 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Upload 6/10: 0.99 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Upload 7/10: 0.91 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Upload 8/10: 0.99 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Upload 9/10: 1.01 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Upload 10/10: 1.07 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Download 1/10: 1.23 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Download 2/10: 1.23 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Download 3/10: 1.26 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Download 4/10: 1.22 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Download 5/10: 1.28 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Download 6/10: 1.23 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Download 7/10: 1.21 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Download 8/10: 1.28 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Download 9/10: 1.23 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Download 10/10: 1.25 Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | Latency iterations done
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | upload:
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | iterations: 10
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | min: 0.91
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | q1: 1.00
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | median: 1.05
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | q3: 1.07
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | max: 1.10
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | outliers: []
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | samples: [0.91, 0.99, 0.99, 1.01, 1.04, 1.05, 1.06, 1.07, 1.07, 1.1]
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | unit: Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | download:
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | iterations: 10
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | min: 1.21
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | q1: 1.23
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | median: 1.23
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | q3: 1.26
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | max: 1.28
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | outliers: []
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | samples: [1.21, 1.22, 1.23, 1.23, 1.23, 1.23, 1.25, 1.26, 1.28, 1.28]
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | unit: Gbps
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | latency:
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | iterations: 100
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | min: 1.310
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | q1: 1.804
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | median: 2.266
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | q3: 2.831
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | max: 4.360
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | outliers: [4.952]
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | samples: [1.31, 1.322, 1.34, 1.345, 1.365, 1.377, 1.378, 1.393, 1.468, 1.481, 1.514, 1.567, 1.625, 1.635, 1.635, 1.652, 1.653, 1.669, 1.697, 1.739, 1.739, 1.757, 1.77, 1.775, 1.782, 1.811, 1.831, 1.855, 1.873, 1.904, 1.923, 1.936, 1.937, 1.956, 1.96, 2.005, 2.005, 2.006, 2.062, 2.178, 2.189, 2.191, 2.217, 2.221, 2.229, 2.235, 2.249, 2.252, 2.262, 2.265, 2.268, 2.282, 2.283, 2.297, 2.322, 2.326, 2.346, 2.36, 2.366, 2.384, 2.4, 2.477, 2.486, 2.487, 2.51, 2.519, 2.549, 2.577, 2.578, 2.587, 2.66, 2.746, 2.759, 2.762, 2.83, 2.833, 2.847, 2.908, 2.952, 2.958, 2.996, 3.083, 3.099, 3.12, 3.121, 3.143, 3.212, 3.221, 3.247, 3.319, 3.402, 3.421, 3.66, 3.669, 3.735, 3.959, 4.103, 4.187, 4.36, 4.952]
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer | unit: ms
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer exited with code 0
Compose Stopping Aborting on container exit...
Container python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer Stopping
Container python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer Stopped
Container python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_listener Stopping
Container python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_listener Stopped
python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_listener exited with code 143
[2026-03-07 04:40:13] INFO: ✓ Test complete
Container python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer Stopping
Container python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer Stopped
Container python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer Removing
Container python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_dialer Removed
Container python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_listener Stopping
Container python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_listener Stopped
Container python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_listener Removing
Container python-v0_x_x_python-v0_x__ws__tls__mplex__216ffd9a_listener Removed |
|
@acul71 it seems like you and @sumanjeet0012 are trying to do the same thing. @sumanjeet0012 has this PR: #52 I think you two should combine efforts. |
Co-authored-by: Cursor <cursoragent@cursor.com>
Compare perf implementation definitions as normalized JSON so comment-only edits do not mark unrelated implementations as changed, while keeping the local Python example in place in perf/images.yaml. Co-authored-by: Cursor <cursoragent@cursor.com>
Update the pinned py-libp2p perf source to the lighter-image commit so CI builds the smaller Python perf Docker image. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@seetadev @sumanjeet0012 |
@acul71 : Definitely, will help you in this effort. This is fantastic. Thank you so much for fixing the yamux issues. |
Expose PERF_TEST_TIMEOUT_SECS via --timeout so slow stacks can run longer than the default 300s cap. Forward PY_YAMUX_* tuning env vars into python-v0.x containers only, bump the py-libp2p perf image commit, and clarify timeout vs legacy --duration in the README. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@seetadev @dhuseby @sumanjeet0012 CI failure: runner disk / Docker buildkit (not Python perf)The perf workflow failed during Docker image build, before any tests ran. Failed run: https://github.com/libp2p/unified-testing/actions/runs/27034698883 Root cause (from logs): Sequence:
This is infra / CI scope, not a regression in the Python perf harness changes on this branch. Suggested fixes (maintainers / CI)
Local validationPython self-tests were run locally on this branch (8/8 stacks passing in Happy to add a small |
- Merge origin/master into migrate/pr808-python-perf - Pin python-v0.x to py-libp2p abb5b34d (QUIC fix #1346) - Preserve eth-p2p-z and nim in perf images alias - DRY PY_YAMUX env injection in run-single-test.sh - Wire --timeout and PY_YAMUX_* into perf PR CI - Skip baseline builds on impl-only perf PRs Co-authored-by: Cursor <cursoragent@cursor.com>
Document known py-libp2p perf flakes so PR CI (~failing ignore) runs the stable noise stacks while tls/mplex issues are tracked upstream. Co-authored-by: Cursor <cursoragent@cursor.com>
Pin py-libp2p to 34d7bcda (fix/tls-libp2p-extension-verify) and remove python TLS entries from ~failing. Validated locally: 8/8 python×python perf stacks pass with --force-image-rebuild. Related: libp2p/py-libp2p#1367 libp2p/py-libp2p#1368 Co-authored-by: Cursor <cursoragent@cursor.com>
Validation update — python×python perf (8/8 pass)Local (
|
| Stack | Upload (median) | Download (median) | Latency (median) |
|---|---|---|---|
| tcp, noise, yamux | 0.45 Gbps | 0.44 Gbps | 6.7 ms |
| tcp, noise, mplex | 0.82 Gbps | 0.83 Gbps | 5.2 ms |
| tcp, tls, yamux | 0.39 Gbps | 0.39 Gbps | 6.3 ms |
| tcp, tls, mplex | 0.50 Gbps | 0.50 Gbps | 4.7 ms |
| ws, noise, yamux | 0.21 Gbps | 0.23 Gbps | 8.5 ms |
| ws, noise, mplex | 0.31 Gbps | 0.37 Gbps | 6.0 ms |
| ws, tls, yamux | 0.19 Gbps | 0.22 Gbps | 8.5 ms |
| ws, tls, mplex | 0.29 Gbps | 0.34 Gbps | 5.6 ms |
All four TLS stacks pass without TLSV1_ALERT_UNKNOWN_CA after unmasking from ~failing.
CI (run #28865769767)
- Result: 8/8 pass (
perf-007bc62b-122302-07-07-2026) - Wall time: 1h 14m (self-hosted runner, single worker, cold image build)
- Per-test harness timeout: 900s (python-specific CI override)
Per-test wall times on CI (well above the 300s default — only tcp,noise,mplex finished under 300s):
| # | Stack | ~Duration |
|---|---|---|
| 1 | tcp, noise, yamux | 404s |
| 2 | tcp, noise, mplex | 218s |
| 3 | tcp, tls, yamux | 448s |
| 4 | tcp, tls, mplex | 356s |
| 5 | ws, noise, yamux | 793s |
| 6 | ws, noise, mplex | 519s |
| 7 | ws, tls, yamux | 852s |
| 8 | ws, tls, mplex | 564s |
Throughput on CI matches local (same ballpark; WS stacks slower than TCP as expected).
Timeout design
- Harness default: 300s (
PERF_TEST_TIMEOUT_SECSinperf/run.sh) - CI: 900s when changed impls include
python, 300s otherwise (.github/workflows/perf-pr.ymlresolve step) - Local docs:
perf/README.mddocuments--timeout(default 300, example 900 for slow stacks)
Follow-up
- QUIC (
quic-v1) for python perf is still excluded from the matrix — will be addressed in a follow-up PR once py-libp2p QUIC interop is ready for perf.
Related
- py-libp2p TLS fix: libp2p/py-libp2p#1368 (CI green, including Windows)
- Issue: libp2p/py-libp2p#1367
|
@acul71 : This is a great piece of work, nice job migrating the Python perf configuration while also improving the overall test harness. I especially like the attention to CI reliability with the Python-specific timeout handling, compose project isolation, and skipping unnecessary baseline builds for impl-only PRs. The extensive investigation into the Yamux performance issues and the follow-up fixes in py-libp2p show a thorough debugging process, and it's great to see the final validation with all 8/8 Python perf stacks passing locally and in CI. The changes are well documented, the rationale behind the timeout adjustments is clear, and the remaining QUIC work is appropriately scoped as follow-up. LGTM! Thanks for driving this migration forward and for sticking with the debugging until the Python perf suite was green. @sumanjeet0012 : Can you please check the self hosted runners. We see two CI/CD tests being skipped. @acul71 and @sumanjeet0012 : Lets ensure that all tests are CI/CD tests passing. |
Thanks @seetadev The two skipped run-tests jobs are Transport Interop (PR) and Hole Punch Interop (PR) — not perf. This PR only changes perf/ (and related harness/CI wiring), so detect-changed-impls correctly sets should-run-tests=false for transport and hole-punch. Those workflows still run resolve-parameters, but skip the heavy test matrix when no impls in their scope changed. The perf workflow ran to completion: 8/8 python×python stacks passed (run #28865769767). |
|
@acul71 : Awesome, this is fantastic to hear. Appreciate your efforts. This is indeed an important milestone on perf module. This PR is indeed ready for final review + merge :) Very happy to see all the interop tests passing. CCing @PoulavBhowmick03, who works on key Ethereum consensus clients including Lighthouse and has played a key role in so many awesome rust@Ethereum initiatives. Had a discussion with him in details yesterday. We will utilize this as a base and extend this to discover performance measurements in rust-libp2p and understand the landscape of lean Ethereum consensus clients vs. regular Ethereum consensus clients in rust. Also, CCing @johannamoran and @mishmosh. Keeping them in sync with this update. |
Summary
libp2p/test-plans#808intolibp2p/unified-testing.python-v0.xto perf (perf/images.yaml) pinned to py-libp2p@abb5b34d (QUIC fix #1346).--timeout,PY_YAMUX_*injection for python containers.PY_YAMUX_*defaults, skip baseline builds on impl-only PRs.Context
Test plan
--test-select "~python".CI notes
~baselinesto avoid heavy Quinn rebuilds on self-hosted runners.--timeout 900andPY_YAMUX_DISABLE_HYSTERESIS=1/PY_YAMUX_ASSUME_RTT_MS=1.