Skip to content

perf(planner): the sun bake reads the terrain grid in place and traces bands of tiles on every core - #2742

Merged
timohueser merged 4 commits into
developfrom
claude/planner-sun-all-cores
Oct 18, 2026
Merged

timohueser merged 4 commits into
developfrom
claude/planner-sun-all-cores

Conversation

@timohueser

@timohueser timohueser commented Oct 18, 2026 •

Copy link
Copy Markdown
Owner

Summary

planner/sun now reads the terrain grid archives in place, holds the heights of one band of tile rows at a time, and runs every tile pass on a thread per core. Before, it wrote a merged copy of the terrain, memory-mapped every zoom-12 pixel of the coverage, and traced on 2 threads.

  • Grid archives in place. terrain_grid hashes each grid archive once (on threads) and gives the bake a Tiles reader. A tile comes from the archive of its zoom-11 tile. Before, materialize hashed each object twice and the step wrote all tiles again into a temporary terrain.pmtiles. A grid archive must be stored as it is (identity), which pack_file always does for .pmtiles.
  • Tile placement. terrain_grid reads the directories of each grid archive and refuses a tile that is not in the archive of its zoom-11 tile, as the rebuild did.
  • Bands with a halo. The horizons trace in bands of 16 zoom-12 tile rows. load_arrays holds, at every level, the rows of the band and the rows that a ray of distance_m from it reaches. The halo comes from the pixel size at the band edge farther from the equator, plus 2 pixels for the bilinear corners and the rounding. A height outside the arrays is unknown, as before outside the coverage, so the halo must reach every row that a ray reaches.
  • Every core. The trace runs on a thread per core that the process may use (step_pool.cores, from sched_getaffinity): trace_tile is nogil. The index tiles of each zoom, the overview tiles of each zoom, and the tile decodes of a band also run on the threads: WebP decode and numpy release the interpreter lock. The terrain cache of the index bake holds 25 tiles per thread, because each index tile in flight reads 25 terrain tiles.
  • Same bytes. Each pool returns its tiles in the old order, so the writer takes the same tiles in the same order.
  • Command line. planner_sun.py --terrain reads its one archive through the same Tiles reader.
  • Shared module. tools/step_pool.py is the same file as in perf(planner): the climate bake runs its spatial chunks on every core #2741 (climate), which also moves the snow pool into it. Here the sun step uses only cores(). The suites.toml trigger line is the same in both PRs.
  • Spec. planner-sun-tiles.md and the planner/sun row of obc-data.md say that the step reads the tiles from the grid archives. It no longer reconstructs an archive.

Why

The DACH run of 2026-10-17 (runs/2026-10-17-071235) did not reach planner/sun. These figures come from the code and the DACH terrain layer:

  • load_arrays wrote a 13.4 GB memory map: 25,521 zoom-12 tiles of coverage, 141 tiles wide.
  • terrain_grid hashed 5.37 GB of grid archives twice and wrote them again as one archive.
  • The trace ran on 2 threads, and the index and overview passes on one.

Estimates, not measured on DACH.

  • Memory: a band of 16 rows plus a halo of 5.4 rows on each side at 55.4° N is about 28 rows × 141 tiles: 2.1 GB, against 13.4 GB.
  • The halo rows decode again in the next band: about 1.7 decodes per zoom-12 tile, at 5.3 ms each (measured on DACH terrain tiles), on all threads.
  • Trace: 0.74 s of CPU per zoom-12 tile on one thread for the Grimsel case below. For about 22,000 tiles in the DACH bounds, that is about 4.5 CPU-h: about 2.3 h on 2 threads, and about 25 min on 12 cores.

This is the sun part of the bake system review.

Tests

Byte check. I cut the tiles of a coverage box at zooms 0 to 12 from the DACH terrain.mbtiles in the store, and gridded them with planner_grid_maps.step. The develop code and this code ran planner_sun.step on the same grid. BAND=1 and BAND=2 make several bands with partial windows.

Coverage Bounds distance_m Develop This code SHA-256
8.0,46.25,9.1,46.95 (Grimsel) 8.45,46.55,8.65,46.65 30000 14.3 s 6.2 s (BAND=16), 6.2 s (BAND=1) 9aef8173…
9.5,46.6,10.6,47.3 (Engadin) 9.9,46.8,10.2,47.1 15000 19.3 s 8.6 s (BAND=16), 9.7 s (BAND=2) a25c80e1…
  • This code ran with 4 threads. After the review fixes, the Grimsel case gives 9aef8173… again, with all cores.
  • The command line path (bake of one PMTiles archive, Grimsel) gives the same SHA-256 in both: 35707f75….
  • Band test. test_bands_of_one_tile_row_trace_what_one_band_traces bakes bowl terrain, where every ray reads heights to its full distance (10 km, more than one tile row), with bands of one tile row and with one band. The archives must be the same. With a halo of 2 pixels, the test fails.
  • The step test again checks that the grid archives hold no other tile, and that a tile in another archive stops the step with "Terrain tile belongs to another grid archive". Its tamper case still fails with "Checksum mismatch".
  • tools/tests suite, as CI runs it (--group dev --group planner-snow --group planner-sun): 332 tests OK. obc suites check: OK.

Not run: a real sun bake, because the machine runs other work.

Public docs: no change. The spec change is its own docs(spec): commit.

Requirements: none

🤖 Generated with Claude Code

timohueser and others added 2 commits October 18, 2026 20:02
…and traces bands of tiles on every core

`terrain_grid` hashes each grid archive once and gives the bake a `Tiles` reader over the
archives, so the step no longer writes a merged copy of the terrain. A tile comes from the
archive of its zoom-11 tile. The command line reads one archive through the same reader.

The horizons trace in bands of 16 zoom-12 tile rows on a thread per core. A band holds the
heights of every level that a ray from it reaches: its rows, and a halo of the rows within
`distance_m` at the band edge farther from the equator. This replaces the memory map of every
zoom-12 pixel of the coverage. The index tiles and the overview tiles of each zoom also run on
the threads. Every pool keeps the old tile order, so the archive bytes do not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ives

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1c39640f-282e-42e6-bba0-fac9b4008170
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

timohueser and others added 2 commits October 18, 2026 21:05
…hreads to its cores, and tests its bands

- `terrain_grid` reads the directories of each grid archive and refuses a tile that is not in
  the archive of its zoom-11 tile, as the rebuild did: `Tiles.get` looks only there.
- The thread pools use the cores that the process may use (`step_pool.cores`). The terrain
  cache of the index bake holds the 25 tiles of each index tile in flight.
- A test bakes bowl terrain, where every ray reads heights to its full distance, with bands of
  one tile row and with one band, and compares the archives. A halo of 2 pixels fails it.
- The step test again checks that the grid archives hold no other tile, and that a tile in
  another archive stops the step.

`tools/step_pool.py` is the same file as in #2741.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@timohueser
timohueser merged commit 88d8e6e into develop Oct 18, 2026
30 checks passed
@timohueser
timohueser deleted the claude/planner-sun-all-cores branch October 18, 2026 19:20
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.

1 participant