Skip to content

perf(planner): the snow bake runs its chunks on every core and keeps its tiles on disk - #2734

Merged
timohueser merged 2 commits into
developfrom
claude/snow-all-cores
Oct 18, 2026
Merged

timohueser merged 2 commits into
developfrom
claude/snow-all-cores

Conversation

@timohueser

@timohueser timohueser commented Oct 18, 2026 •

Copy link
Copy Markdown
Owner

Summary

tools/planner_snow.py bakes each zoom-9 chunk in a worker process, one per core. Before, it used 4 threads.

  • No copies. The workers fork from the bake, so they read the planes of the sources without a copy.
  • Tiles on disk. The tiles of each chunk go to a spill file beside the output as the chunk ends.
  • Same bytes. The archive takes the tiles in tile order, so its bytes do not depend on which chunk ends first. The layer revision does not change.
  • Less memory. The 4 GiB dict of gzip tiles that the step held until the end is gone. A chunk body for the parent zooms comes back from its tile in the spill file.
  • S3 limit. The command line keeps 4 workers when it reads HR-WSI from CDSE S3, which allows 4 connections per user.

Why

On the DACH bake of 2026-10-17 (runs/2026-10-17-071235), planner/snow ran alone for 8.7 h:

Estimate, not measured on DACH. About 60 CPU-s per chunk remain after #2730.

This is finding 4 of the bake system review.

Memory note

Each worker holds the planes of one chunk: about 0.5 GB for HR-WSI at 20 m. That is an estimate from the chunk size. On 12 cores, a worker peak of 0.5 GB means 6 GB in all.

The receipt shows ru_maxrss: the peak of the largest process, not the sum of the processes. The engine review (finding 1) proposes per-step processes. A cgroup memory.peak would count the sum.

Tests

  • Byte check. Old (develop) and new code baked the same synthetic HR-WSI + MODIS input across the corner of four zoom-9 chunks. The archives have the same SHA-256:
    • 21 tiles: 9269efeb…
    • 67 tiles: bbe6e18a…
  • Peak memory on the 67-tile case. The parent went from 197 MiB to 80 MiB; each worker peaks at 109 MiB.
  • tools/tests suite, as CI runs it (--group dev --group planner-snow --group planner-sun): 331 tests OK. There are no fork warnings.
  • test_the_bake_reads_one_zoom_9_chunk_and_stores_to_the_max_zoom now counts reads through a file, because a chunk reads in a worker process.

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

Public docs: no change.

Review round

An adversarial review confirmed that old and new give the same bytes on four more synthetic inputs. It also found the issues below; all are fixed in cacf667.

  • The parent kept every chunk's tiles in RAM. The list of futures held them until the bake returned. The list is gone, and as_completed lets go of each future. On the inputs above, the parent now peaks at 69 to 77 MiB, against 183 to 201 MiB on develop.
  • Workers outlived the bake. They survived a SIGKILL of the bake, such as an out-of-memory kill, and kept their memory. Each worker now sets PR_SET_PDEATHSIG. I killed a running bake with SIGKILL and both of its workers ended.
  • The worker count ignored limits. The default now follows the cores that the process can use (sched_getaffinity) and is at most one worker per GB of free memory. A worker holds about 0.6 GB for nine seasons.
  • Fork is not safe on macOS. Outside Linux the chunks now bake in threads.

The receipt still records the peak of the largest process, not the sum of the workers. That is finding 1 of the review: the session "Run every obc data step in its own process" works on it.

Requirements: none

🤖 Generated with Claude Code

…its tiles on disk

The snow step baked its zoom-9 chunks in four threads. Most of their work holds
the Python interpreter lock, so the DACH bake of 2026-10-17 ran at 1.49 CPU
seconds per second for 8.7 hours: one chunk each 81 s, 374 chunks.

Each chunk now bakes in a worker process, one per core. The workers fork from
the bake, so they read the planes of the sources without a copy. The tiles of a
chunk go to a file beside the output, and the archive takes them in tile order,
so the bytes do not depend on which chunk ends first. The tiles no longer wait
in a dict: the step held 4 GiB of them in RAM until the end. The command line
keeps four workers when it reads HR-WSI from CDSE S3, which allows four
connections per user.

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: 5415b1e3-d6fb-4f79-bc70-d640eb2371af
  • 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.

…e machine

Review fixes:
- The finished futures held every chunk's tiles until the bake returned: the
  list of futures is gone, and `as_completed` lets go of each.
- A worker ends when the bake process ends, also on SIGKILL (PR_SET_PDEATHSIG);
  before, idle workers outlived an out-of-memory kill and kept their memory.
- The default worker count follows the cores that the process can use and is at
  most one per GB of free memory: a worker holds about 0.6 GB.
- Outside Linux the chunks bake in threads, because a fork is not safe on macOS.

On the synthetic inputs of the pull request the bytes are the same as on develop,
and the parent peaks at 69 to 77 MiB instead of 183 to 201 MiB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@timohueser
timohueser enabled auto-merge October 18, 2026 17:47
@timohueser
timohueser merged commit adb370f into develop Oct 18, 2026
26 checks passed
@timohueser
timohueser deleted the claude/snow-all-cores branch October 18, 2026 17:48
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