Skip to content

DDIR: sort arrange ingest by (key, val, time) at once, and concatenate by ranges - #1064

Merged
frankmcsherry merged 2 commits into
TimelyDataflow:master-nextfrom
frankmcsherry:ddir-sort-consolidate
Oct 31, 2026
Merged

frankmcsherry merged 2 commits into
TimelyDataflow:master-nextfrom
frankmcsherry:ddir-sort-consolidate

Conversation

@frankmcsherry

Copy link
Copy Markdown
Member

The arrange ingest stage (the chunker's flush) now sorts by (key, val, time) in one corgi sort and consolidates by the sort's run labels, and it concatenates its input blocks a range at a time. Two commits, both in interactive/src/runtime/chunk.rs (+106 −46).

  1. Ingest.
    • Concatenation: each input block goes to gather_lanes as a one-row list holding the whole block, so corgi copies ranges, instead of a block number and offset per row.
    • Times in the sort: the time lanes join the one sort as trailing integer fields. Lanes constant within the flush are dropped, and the rest are packed into one u64 where their spreads fit (in practice always).
    • Consolidation: the sort's run labels number (key, val, time) classes, so consolidation is one pass summing diffs over equal labels. The per-run Rust time sort and its comparisons are gone.
  2. advance and settle: CorgiChunk::concat uses the same block copy.

Output is identical: the sort is stable, so each class's representative row and the order its diffs are summed in are unchanged.

Measured on one worker, three alternating trials, answers byte-identical:

Change
SCC initial computation (LiveJournal 250k) −13.1% CPU (3.70 → 3.22 s)
Reachability initial computation −14.2%
LDBC SF1 one-off replay −4.0%
Churn ticks, commit 1 / commit 2 unchanged / −1.1% SCC, −1.6% reachability
Ingest stage alone, captured flushes SCC 21.5 → 14.5 ns/row, LDBC 39.8 → 34.3

Peak memory also falls (SCC −2.4%, reachability −14.3%).

  • Not taken: consolidating by hash before sorting, in the manner of scatter, was emulated with the pinned corgi. It was 2–4× slower, even on a flush keeping 4.6% of its rows.
  • What remains of the stage: mostly corgi's sort itself.
  • Overlap with DDIR: chunk times and diffs in adaptive columns #1059: both rewrite sort_consolidate. DDIR: chunk times and diffs in adaptive columns #1059 adds a fast path for flushes whose times are all equal, which this PR's dropping of constant lanes covers. Whichever merges second needs time_words rewritten against the other's ColTimes.

Checks: cargo test -p differential-dataflow -p differential-dogs3 -p interactive -p ddir-server (485 passed) and the 1,000-case release difftest.

Implemented and measured by a Claude subagent.

🤖 Generated with Claude Code

https://claude.ai/code/session_019XsakwFGwtESwZ1gSYwG4o

frankmcsherry and others added 2 commits October 31, 2026 15:36
… run labels

The chunker's flush concatenated its input blocks through a per-row block
number and offset, sorted by (key, val), and then walked every (key, val) run:
it copied the run, sorted it by time with a Rust comparison sort, and compared
neighbouring times to consolidate. Two changes remove those passes.

- Concatenation copies each block a range at a time. Each block goes to
  corgi's `gather_lanes` as a one-row list holding the whole block, so corgi
  copies ranges at every level it can (leaves, products, lists, references
  into one arena) and falls back to row positions only for sums, as before.
  No per-row index is built.
- The time is part of the one corgi sort. The time lanes become trailing
  integer fields: lanes constant within the flush are dropped, the rest are
  taken as offsets from their least value and packed into one u64 wherever
  their spreads fit (in practice always), each word offset by 2^63 so that
  corgi's signed order is the lanes' unsigned order. The sort's run labels
  then number (key, val, time) classes, and consolidation is one pass that
  sums diffs within runs of equal labels, with no comparisons, into vectors
  sized from the number of runs.

Output is identical: the sort is stable, so each class's representative row
and the order its diffs are summed in are unchanged.

On captured flush inputs the stage goes from 21.5 to 14.5 ns per input row
on SCC and from 39.8 to 34.3 on LDBC. End to end, one worker, three
alternating trials: SCC initial computation
-13.1% CPU, reachability initial -14.2%, churn ticks unchanged, LDBC SF1
one-off replay -4.0%; answers identical.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XsakwFGwtESwZ1gSYwG4o
`CorgiChunk::concat`, which `advance` and `settle` use to join a run of
chunks, built a block number and an offset for every row and copied the key
and value columns row by row through them. It now uses `concat_blocks`, which
the ingest stage already uses: each chunk's columns are copied as one range.

End to end, one worker, three alternating trials: instructions fall in every
phase (SCC -1.6%, reachability churn -2.0%, LDBC -0.3%); CPU SCC churn -1.1%,
reachability churn -1.6%, LDBC -0.3%; answers identical.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XsakwFGwtESwZ1gSYwG4o
@frankmcsherry
frankmcsherry merged commit a6b7922 into TimelyDataflow:master-next Oct 31, 2026
7 checks passed
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