Repository navigation
Closed
Labels
agent:triagedbenchsocket-patch scan benchmark suitesocket-patch scan benchmark suiteenhancementNew feature or requestNew feature or requestpm:poetryPoetryPoetrypriority:p1
Description
[agent] Bench: poetry has been flagged slow in 3 consecutive benchmark runs (2026-10-02, 10-03, 10-04). Its hosted scan costs about 4.5x the median ms per package across all package managers.
| run | poetry/hosted median |
ms/pkg | x median ms/pkg | poetry/rescan median |
|---|---|---|---|---|
| 2026-10-02 | 187.6 ms | 0.469 | 3.7x | 170.3 ms |
| 2026-10-03 | 221.4 ms | 0.554 | 4.3x | 224.4 ms |
| 2026-10-04 | 201.6 ms | 0.504 | 4.5x | 175.1 ms |
Fixture: 400 packages, 12 patched, poetry.lock 2.1, in-project .venv. For comparison, pip/hosted (1000 packages, 25 patched) takes 81.8 ms (0.082 ms/pkg) on the same runner.
Hot spot (callgrind, poetry/hosted, 2026-10-04)
patch::redirect::poetry::rewrite_poetry→utils::poetry_lock::rewrite_poetry_lock_in: 77% of all instructions.toml_edit::Document::parse: 45.5%DocumentMutDisplay (re-serialize): 18.2%
rewrite_poetryloops over the patched deps and callsrewrite_poetry_lock_inonce per dep.PoetryLockParsereuses a parse only whiledoc.raw() == text. Each rewrite mutates the doc and re-serializes it to new text, so the next dep misses the cache and re-parses the whole lock. Cost is O(patches × lock size): 12 full parses and 12 full serializations ofpoetry.lockhere.- Possible fix: plan every dep against one parsed
DocumentMut, apply all mutations, then serialize once. Per-depedits()fragments could come from the original text plus the final document. - Secondary:
vex::discover::pypi_locks::extract(10.4%) parses the lock again for VEX.
Runner
4 vCPU, Intel(R) Xeon(R) Processor @ 2.10GHz (cloud sandbox), main 045d7ec7. Absolute timings vary from runner to runner; the ratio to the cross-PM median is the signal.
Repro
CARGO_PROFILE_PERF_INHERITS=release CARGO_PROFILE_PERF_LTO=thin CARGO_PROFILE_PERF_STRIP=none \
cargo build --locked --profile perf -p socket-patch-cli -p socket-patch-bench
target/perf/socket-patch-bench run --bin target/perf/socket-patch -f '^poetry/' -v
# profile: serve the fixture, then prefix the printed command's binary with
# valgrind --tool=callgrind
target/perf/socket-patch-bench serve poetry/hosted --bin target/perf/socket-patchTracked in the ledger of #575 (standing slow-systems list). This is a standing slowness report, not a regression: the cost has been flat since the suite started.
Generated by Claude Code
Metadata
Metadata
Assignees
Labels
agent:triagedbenchsocket-patch scan benchmark suitesocket-patch scan benchmark suiteenhancementNew feature or requestNew feature or requestpm:poetryPoetryPoetrypriority:p1
Activity
mikolalysenko commentedon Oct 4, 2026
[agent] Shares root cause with #762:
rewrite_poetry_lock_inandrewrite_pdm_lock_ineach mutate, re-serialize and re-parse the whole lock once per patched dep (the*LockParsecache only saves the input parse), so hosted cost is O(patches × lock size). Will be fixed together. Both engines are being merged into one shared fragment-splice engine in open PR #703, so the batching fix should land on top of that.Generated by Claude Code
mikolalysenko commentedon Oct 5, 2026
[agent] Claiming this issue (with #762; shared root cause: the shared Poetry/PDM fragment-splice engine renders and re-parses the whole lock once per patched dep). Branch: agent/fix-python-lock-batch-rewrite. Claim-ID: 2026-10-05T18:20:49Z-728c05
Generated by Claude Code
mikolalysenko commentedon Oct 5, 2026
[agent] Draft PR: #877
Generated by Claude Code
Test that a Poetry/PDM lock renders once per scan
Rewrite each Poetry/PDM lock in one pass