Skip to content

kll: reduce allocations in ItemsSketch - #78

Merged
freakyzoidberg merged 1 commit into
apache:mainfrom
tsenart:master
Dec 30, 2025
Merged

freakyzoidberg merged 1 commit into
apache:mainfrom
tsenart:master

Conversation

@tsenart

@tsenart tsenart commented Dec 29, 2025

Copy link
Copy Markdown
Contributor

The ItemsSketch.Update method and its compression helpers were
allocating unnecessarily, causing significant GC pressure in
high-throughput scenarios.

Three changes:

  1. Store minItem/maxItem by value instead of pointer. The previous
    implementation used *C pointers and assigned &item on each update,
    causing the item parameter to escape to heap. Now we store values
    directly and use a hasMinMax bool to track initialization state.

  2. In compressWhileUpdatingSketch, work on s.items directly instead
    of calling GetTotalItemsArray() which copies the entire items slice.
    All operations (sort, halve, merge, shift) modify the array in
    place, so the copy was unnecessary.

  3. In addEmptyTopLevelToCompletelyFullSketch, use s.levels and
    s.items directly
    instead of getLevelsArray() and GetTotalItemsArray().
    The copies were only used to read current state before growing.

Benchmarks

On a 500k item workload:

Metric Before After Delta
time/op (KeyFuncNone) 89ms 34ms -62%
time/op (KeyFuncZorder) 251ms 187ms -26%
alloc/op (KeyFuncNone) 472MB 4.4MB -99%
alloc/op (KeyFuncZorder) 611MB 143MB -77%
allocs/op (KeyFuncNone) 518,979 210 -99.96%
allocs/op (KeyFuncZorder) 1,019,840 501,097 -51%

All existing tests pass.

The ItemsSketch.Update method and its compression helpers were
allocating unnecessarily, causing significant GC pressure in
high-throughput scenarios.

Three changes:

1. Store minItem/maxItem by value instead of pointer. The previous
   implementation used *C pointers and assigned &item on each update,
   causing the item parameter to escape to heap. Now we store values
   directly and use a hasMinMax bool to track initialization state.

2. In compressWhileUpdatingSketch, work on s.items directly instead
   of calling GetTotalItemsArray which copies the entire items slice.
   All operations (sort, halve, merge, shift) modify the array in
   place, so the copy was unnecessary.

3. In addEmptyTopLevelToCompletelyFullSketch, use s.levels and
   s.items directly instead of getLevelsArray and GetTotalItemsArray.
   The copies were only used to read current state before growing.

Benchmarks on a 500k item workload show:

    name                  old time/op    new time/op    delta
    Sketch/KeyFuncNone      89ms           34ms          -62%
    Sketch/KeyFuncZorder   251ms          187ms          -26%

    name                  old alloc/op   new alloc/op   delta
    Sketch/KeyFuncNone     472MB          4.4MB         -99%
    Sketch/KeyFuncZorder   611MB          143MB         -77%

    name                  old allocs/op  new allocs/op  delta
    Sketch/KeyFuncNone     518979         210           -99.96%
    Sketch/KeyFuncZorder   1019840        501097        -51%
@freakyzoidberg

Copy link
Copy Markdown
Member

Nice catch - Thanks !

@freakyzoidberg
freakyzoidberg merged commit b6a455b into apache:main Dec 30, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants