Skip to content

Performance: trim Overpass query, add CPU-usage control, and opt-in pipelined tile merge#1125

Open
TonyD365 wants to merge 10 commits into
louis-e:mainfrom
TonyD365:main
Open

Performance: trim Overpass query, add CPU-usage control, and opt-in pipelined tile merge#1125
TonyD365 wants to merge 10 commits into
louis-e:mainfrom
TonyD365:main

Conversation

@TonyD365

Copy link
Copy Markdown
Contributor

Summary

Three independent improvements aimed at generating large areas faster, plus a small
follow-up fix. Only the Overpass query change affects default output; the new generation
feature is opt-in and defaults off.

1. Overpass: drop the unfiltered way; selector

The query included a bare way; that pulled every way in the bbox (and all their
nodes), regardless of tags. The renderer only dispatches ways with recognised tags
(building / highway / landuse / …), which already have explicit selectors, and multipolygon
member ways are still fetched via way(r.relsinbbox). The bare selector only added data
that gets discarded — a major source of oversized responses, timeouts, and the resulting
multi-server retry cascade on large areas.

  • Follow-up: added an explicit nwr["area:aeroway"] selector, because the renderer handles
    area:aeroway (airport aprons / taxiway polygons), which previously rode in only via the
    bare way;.

2. CPU-usage control

Generation now runs in a dedicated rayon pool sized to a new setting (cpu_percent,
default 90%, range 10–100). A scoped pool is used because rayon's global pool can only
be built once per process, so this is the only way the setting can take effect per-run
without a restart. Exposed as a GUI "CPU Usage" slider and a --cpu-percent flag;
RAYON_NUM_THREADS still overrides. Lets users push past the previously hard-coded 90% cap.

3. Opt-in pipelined tile merge

Phase 2 (merging each tile into the shared editor) is sequential, so worker cores sit idle
during merges. Behind an opt-in toggle, batch N's merge now overlaps batch N+1's placement
via rayon::join. Merge order is unchanged (in-order, batch by batch), so output is
bit-exact vs. the default path. Enabled via a GUI "Faster merge" toggle, a --pipeline-merge
flag, or the ARNIS_PIPELINE_MERGE env var; default off.

Testing

  • CI green: cargo build --all-targets --all-features --release, clippy (-D warnings),
    and unit tests all pass.
  • On a large metropolitan-area generation at 1:1 scale (~80×60 km, ~9,900 tiles), enabling
    the pipeline lowered the in-app ETA from ~9h39m to ~6h58m at the same progress point
    (~28% faster). This is an observation, not a controlled benchmark — output equivalence
    can be verified with ARNIS_BLOCK_HASH=1 (the per-region content hash should match
    between the default and pipelined runs).

Notes

  • The three changes are logically independent; happy to split into separate PRs if preferred.

claude added 8 commits June 24, 2026 20:54
The Overpass query included a bare 'way;' selector that pulled every way in
the bounding box (plus all their nodes), regardless of tags. Arnis only
renders ways carrying recognized tags (building, highway, landuse, etc.),
which are already covered by the explicit selectors above, and multipolygon
member ways are still fetched via way(r.relsinbbox). The bare selector only
added data that gets discarded — for large areas (e.g. the GTA) this was a
major source of oversized responses, server-side timeouts, and the resulting
multi-server retry cascade.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpmryD9UzEfMqj3yCq8Zoo
Removing the unfiltered 'way;' selector exposed one real gap: the renderer
dispatches ways carrying 'area:aeroway' (airport aprons / taxiway polygons),
but the query only selected plain 'aeroway'. Those area-only features were
previously pulled solely via the bare 'way;', so they would have vanished.
Add an explicit nwr["area:aeroway"] selector to keep them while retaining
the download-size win.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpmryD9UzEfMqj3yCq8Zoo
Generation now runs inside a dedicated rayon thread pool sized to a new
'CPU usage' setting (args.cpu_percent, default 90%, range 10-100). A scoped
pool is used because rayon's global pool can only be built once per process
(already built at startup), so this is the only way the setting can take
effect per-run without an app restart. RAYON_NUM_THREADS still overrides.

Exposed in the GUI settings as a 'CPU Usage' slider (10-100%, persisted to
localStorage), wired through the gui_start_generation command. Lets users
with spare cores push generation to 100% of cores instead of the previous
hard-coded 90% cap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpmryD9UzEfMqj3yCq8Zoo
Phase 2 (merging each tile's WorldToModify into the shared editor) is
sequential, so during merges all worker cores sit idle — a ~20-30% Amdahl
tail on large eviction-active worlds.

Refactor the placement and merge halves of the tile loop into reusable
closures (place_batch is a pure function of immutable inputs; merge_batch is
the sole writer of the editor + eviction bookkeeping). Behind the opt-in
ARNIS_PIPELINE_MERGE env flag, overlap batch N's serial merge with batch
N+1's parallel placement via rayon::join. Merge order is unchanged
(in-order, batch by batch), so output is bit-exact vs. the default path.

Default behaviour is untouched (flag off = original serial place-then-merge).
Validate the flagged path locally with --benchmark and ARNIS_BLOCK_HASH
(the per-region content hash must match the unflagged run).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpmryD9UzEfMqj3yCq8Zoo
Apply rustfmt to the place_batch/merge_batch closures and silence the
expected clippy::type_complexity on the merge_batch tile-result parameter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpmryD9UzEfMqj3yCq8Zoo
Expose the pipelined merge (previously ARNIS_PIPELINE_MERGE env only) as a
GUI settings toggle so users don't have to launch from a terminal. Adds
args.pipeline_merge (+ --pipeline-merge CLI flag); generation enables the
pipeline when the toggle is on OR the env var is set. The toggle is persisted
to localStorage so the choice sticks across launches. Default off.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpmryD9UzEfMqj3yCq8Zoo
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpmryD9UzEfMqj3yCq8Zoo
Place the two performance controls above all settings sections (no category)
so they're the first thing in the settings panel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpmryD9UzEfMqj3yCq8Zoo
@TonyD365

Copy link
Copy Markdown
Contributor Author

@louis-e
Note: the failing "benchmark" check is the known fork-PR limitation —
the benchmark runs fine, but posting its result as a PR comment needs a
write-scoped token, which fork PRs don't get ("Resource not accessible by
integration"). Nothing actionable on my end; the CI Build checks pass.
Please merge the PR.

TonyD365 added 2 commits June 27, 2026 11:12
Updated the PR benchmark workflow to save benchmark results to files and upload them as artifacts.
This workflow triggers on completion of the 'PR Benchmark' workflow, downloads benchmark results, and comments on the pull request with the results.
@TonyD365

TonyD365 commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@louis-e

1 similar comment
@TonyD365

Copy link
Copy Markdown
Contributor Author

@louis-e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants