Repository navigation
perf: faster graph export — bundle and impact facts, same answers - #1934
Open
swapnilpaliwal-sd wants to merge 2 commits into
Open
swapnilpaliwal-sd wants to merge 2 commits into
swapnilpaliwal-sd wants to merge 2 commits into
Conversation
) Bundle (raw relations + IR -> graph.sqlite): - the IR reader splits a quote-free line on tabs and keeps the character reader for lines a quote touches; rows the caller drops are skipped before they are split (call-site and expression passes) - keyed (WITHOUT ROWID) tables are loaded in key order (stable sort of a copy) - 16 KiB pages (AXIOM_BUNDLE_PAGE_SIZE overrides) - the c0 index only on ext relations the query layer reads (EXT_QUERIED); bundle-test fails when a script names one missing from it - AXIOM_BUNDLE_PROFILE=1 prints per-stage times Facts export (axiomcode-impact --warm): - const_values reads its whole-graph tables once, not once per const - gen_table finds each decorator's first declaration in one pass - Impact.code() copies runs of plain code whole - the route walk and stub_sites run once for both exports - config rows are filtered by a count of symbols rows instead of a join Every table row, every exported fact and every impact/path --json answer is byte-identical before and after on both measured projects. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
swapnilpaliwal-sd
requested review from
JaredHLZhang,
Whua689 and
suyashpaliwal26
as code owners
October 11, 2026 20:57
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.
Closes #1933.
Speeds up both graph exports without changing any answer: the bundle (raw relations + IR → graph.sqlite) and the impact facts export (
axiomcode-impact --warm). The branch also merges origin/dev, which the integration branch was behind by 25 commits.Before / after
Medians of interleaved runs (base, new, base, new). Each run is a full
axiomcode indexwithAXIOMCODE_REINDEX=1. "Facts ready" means the index has returned and every background warm-up has finished. The laptop had other load during the runs (1-minute load average 2-13).axiomcode indexwall--warm)Where the time went (profiled, base)
Bundle (6k-file project):
call_sites(510 k rows) took 5.6 s andmethods1.6 s.ext_config_affects_method, with 3.4 M rows; it is read, so it is kept.Facts export (6k-file project, 218 s):
const_valuesran the call_sites × call_edges join once for every const it was asked about: 45 runs, 22 M rows fetched, 82 s of SQL plus the Python that went with it.gen_tablescan walked every symbol once per decorator name.Impact.code()blanked comments and strings one character per loop iteration.stub_sitesand the route-registration walk each ran twice.ext_config_affects_method ⋈ symbolsjoin made 3.4 M index probes.What changed
Bundle
readRfc4180splits a line with no quote on tabs. A line with a quote, and any line a quoted field continues onto, still goes through the character reader, which defines the format. An optionalpickskips the split for rows the caller would drop; it is used by the call-site and expression passes.page_size = 16384before the first table.AXIOM_BUNDLE_PAGE_SIZEoverrides it. Query time did not change: the 20 measuredimpact/pathqueries took the same time on the new graph.EXT_QUERIEDincatalog.ts). On Java that is 12 of 39. Every manifest relation is still loaded as an ext table, so the documented schema is unchanged.bundle-test.shnow fails if a script under plugins/, hooks/ or bin/ names an ext relation that is missing from the list.AXIOM_BUNDLE_PROFILE=1prints the time of each stage to stderr.Facts export
ax_registration.const_value_tablesreads the join once for each_Handlersinstance. It also keeps one cached copy per open connection, soImpact._export's ownconst_valuescall reuses it.gen_tablefinds the first declaration of each decorator name in a single pass. The factory-base scan skips lines that do not contain the base name.Impact.code()copies a run of characters that cannot open a comment, string or regex in one step, and blanks a span with a single regex.registrations(…, with_own_lines=True)returns the route walk's own-line map as well, soroute_site_linesno longer runs separately.G.stub_sites()caches the stub set per connection for both exports.ext_config_affects_methodin scan order and repeat each row once per symbols row that names its method, which is what the old join returned.ckeyis computed once per key.Not changed (measured, left for a decision)
call_chain_edgehas a column the core table drops, andtype_use/field_accessturn-into NULL. Dropping them would save about 3.5 s and 280 MB on the 6k-file project.cache_sizeandthreadswere not kept. They did not help, and index builds were slower with them.Verification
.dumphash of every table, every row in storage order, and every core index matches base for both projects. The only differences are the ext c0 indexes, as intended, andrun.created_at.PYTHONHASHSEED=0; without a fixed seed, base itself writesgen_table.factsin a different order on each run).impact <t> --jsonfor 10 targets andpath <a> <b> --jsonfor 10 pairs on each project, base engine on a base-built graph against new engine on a new-built graph. All 40 stdout and stderr files are byte-identical.readRfc4180return identical rows on every IR file of both projects (up to 1.83 M rows each) and on 15 synthetic edge cases: CRLF, quoted newlines, doubled quotes, unterminated quotes, a quote mid-field, and a randomized 300 k-row file with fields that cross chunk boundaries.code(): old and new output is identical on 50,559 files, including Java files read as TS and Python. The two raise on the same files.tests/run.py --lang <l> --jobs 3): typescript 352/352, python 445/445, javascript 354/354 and csharp 319/319 pass. Java passes 372/374. The 2 failures are inlibrary-auto-discovers-imported-dependencies, which needs a decompiler that this machine lacks; base fails the same 2 checks.bundle-test.sh,csv-limit-test.shandempty-relation-test.shpass.tsc --noEmitis clean.