Repository navigation
rs-upstream-sweep-3: markdown-it-py upstream perf PR + lane report - #77
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
rs-upstream-sweep-3 report — markdown-it-py upstream PR
Target: executablebooks/markdown-it-py @
6f58654.Fork: John-Cusack/markdown-it-py,
branch
rs-upstream-perf.Status: UPSTREAM PR OPENED — executablebooks/markdown-it-py#449
(open,
draft: no, verified viagh-axi pr view).1. Target selection (registry re-verified, not cached)
Prod PyPI re-queried per lane (sweep-1 lesson). Prod-live
-rustset2026-10-14: crc-rust 0.1.0, strsimpy-rust 0.2.1, python-dateutil-rust
2.9.0, markdown-it-py-rust 4.2.0, packaging-rust 26.4.0,
charset-normalizer-rust 3.5.1. TestPyPI-only (404 on prod PyPI):
pyyaml-rust, pyparsing-rust, python-multipart-rust, pygments-rust.
Exclusions hold (pyyaml PR yaml/pyyaml#976 open; charset
saturated/killed; packaging no-gain PR74; dateutil PR
dateutil/dateutil#1609 open). Highest-download prod-live original not
yet reviewed: markdown-it-py (427M dl/mo; KEEP #5). Hot units:
parser_block.py,parser_inline.py,emphasis.py; our side measured2.36x render-16KB / 0.20x bulk-280KB (Rust mirror; bulk loss is
per-token GIL crossings — not shippable upstream, see ADR-040).
2. Upstream process (followed to the letter)
Upstream HEAD
6f58654(master). Read before changing anything:docs/contributing.md(+EBP guide): pytest, tox matrix, ruff +black via pre-commit, type annotations + docstrings required. No PR
template (issue templates only). CHANGELOG has an
Unreleasedsection with per-PR entries (added post-open with the PR number).
tests.yml): pre-commit, pytest on 3.10–3.13 + pypy-3.10,CommonMark spec freshness check, coverage, mdit-py-plugins downstream
tests,
bench-coreartifact;benchmark.ymltracks package means.mdurl).fixed quadratic
text_join; #383 CLI fix). A 2022 mypyc suggestion(#198) was never adopted. The maintainer-owned Rust path lives
outside this repo (
markdown-it-pyrs, indocs/performance.md+compareextra) — so a vendored native core here would duplicate it.Acceptable shape: pure-Python only (ADR-040).
3. Baseline (their commands, before any change)
venv, editable install of upstream HEAD +
testing,linkifyextras(CI installs
.[testing,linkify]): 1031 passed, 1 skipped —matches the board exactly. Baseline green before any change. Frozen
workload for proof: mirror
bench/corpora (16.7KB mixed doc, 280KBbulk doc) + render differential oracle (
diff_oracle.py: 2 corpora +30 edge docs × default/commonmark/zero presets).
4. Profiling
cProfile over the frozen workload (per 16.7KB render, ~7ms real):
StateBlock.__init__line-marker precompute ~1.1ms (~15%) — aper-character Python loop (
enumerate+isStrSpacecall per char)over the whole source on every render. Rest is genuine port-faithful
parsing (block/inline rule dispatch tracked against the JS port in
port.yaml) — out of bounds. Killed without building:srcproperty→ plain attr (microbenched: 12ns/access × 5.5K/render ≈ 1% — API churn
not worth it),
LOGGER.debugguards (0.25ms/render ≈ 3.5% — 10-filechurn maintainers would reject),
Tokendouble-dict alloc (≈1%).5. The change — 1.20x, per-line marker precompute
markdown_it/rules_block/state_block.py+29/-29: build the identicalmarkers once per line —
str.findlocates each\nat C speed, onlyleading whitespace scanned, same space/tab counting body (same
isStrSpacepredicate, same tab-stop expansion).Memory (tracemalloc peak):
1200469 Bboth sides, every run —neutral (same lists, same lengths).
Correctness: fork suite 1031 passed + 1 skipped (counts identical to
base); render oracle 0 divergences; ruff + black clean.
6. Proof (public-materials-only repro in the PR body)
Self-contained script (stdlib + installed
markdown-it-py, seed-fixedsynthetic doc — no internal corpora) pasted verbatim in the PR body;
numbers above are that script's own output. No tokens, no internal
paths in the PR.
7. Fork diff
markdown_it/rules_block/state_block.py+29/-29 (per-line markerloop + NOTE comment).
CHANGELOG.md+1 (Unreleasedentry with PR link, 👌 marker perhouse style). No Rust, no packaging change.
8. Checklist deltas (new lessons; standing list unchanged otherwise)
measure peak memory in a separate run. Tracemalloc inflates Python
dispatch cost ~2–3x, and unevenly: under tracing, base looked 2.4x
slower than the patch (33ms vs 14ms); without tracing the real gap
is 1.2x (7.6ms vs 5.7ms medians). A combined harness would have
overstated the claim in the PR body. Memory peaks are unaffected,
so split the axes.