Skip to content

perf: hot schedulers#4451

Open
grutt wants to merge 6 commits into
mainfrom
perf-hot-schedulers
Open

perf: hot schedulers#4451
grutt wants to merge 6 commits into
mainfrom
perf-hot-schedulers

Conversation

@grutt

@grutt grutt commented Jul 16, 2026

Copy link
Copy Markdown
Member

Description

Reworks the v1 scheduler so slot capacity lives in per-worker pools instead of being copied into each action, cutting assignment/replenish overhead on large worker sets. Also fixes unused-slot accounting so expiry cannot make selection skip valid capacity.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Refactor (non-breaking changes to code which doesn't change any behaviour)
  • Test changes (add, refactor, improve or change a test)

What's Changed

  • Own slots in slotPool keyed by worker + slot type; actions keep a thin worker-id index
  • Assign from pools with active() selection (do not hard-gate on unusedCount, which can drift on expiry)
  • Align pool refresh time with slot expiry on replenish; count only active slots into unused
  • Add shape / worker-scale scheduler benchmarks and cover unused-counter drift in unit tests

Checklist

Changes have been:

  • Tested (unit, integration, or manually with steps specified)
  • Linted and formatted
  • Documented (where applicable)
  • Added to CHANGELOG (where applicable) -- see Keep a Changelog

Testing

  • go test ./pkg/scheduling/v1/ -count=1

🤖 AI Disclosure
  • I acknowledge that an LLM was used in the creation of this Pull Request, in accordance with Hatchet's AI_POLICY.md.

  • Details: Used cursor throughout investigation and writing the pr

@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hatchet-docs Ready Ready Preview, Comment Jul 16, 2026 6:49pm

Request Review

@github-actions github-actions Bot added the engine Related to the core Hatchet engine label Jul 16, 2026
@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Benchmark results

goos: linux
goarch: amd64
pkg: github.com/hatchet-dev/hatchet/pkg/scheduling/v1
cpu: AMD Ryzen 9 7950X3D 16-Core Processor          
                                                                    │ /tmp/old.txt │            /tmp/new.txt             │
                                                                    │    sec/op    │    sec/op     vs base               │
RateLimiter-8                                                          47.52µ ± 6%   55.50µ ± 30%  +16.78% (p=0.002 n=6)
Scheduler_Replenish_DenseSharedActions-8                              14.236m ± 1%   5.556m ±  3%  -60.97% (p=0.002 n=6)
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_01-8                         5.405m ±  3%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_04-8                         6.937m ±  4%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_16-8                         16.65m ±  2%
Scheduler_InventoryShape_ReplenishMust/small_dense-8                                 48.43µ ± 10%
Scheduler_InventoryShape_ReplenishMust/dense_high_action_fanout-8                    8.716m ±  2%
Scheduler_InventoryShape_ReplenishMust/dense_high_slot_capacity-8                    7.970m ±  5%
Scheduler_InventoryShape_ReplenishMust/sparse_low_fanout-8                           1.114m ±  3%
Scheduler_InventoryShape_ReplenishMust/partitioned_20-8                              3.426m ±  2%
Scheduler_InventoryShape_ActiveCountScan/small_dense-8                               9.306µ ±  2%
Scheduler_InventoryShape_ActiveCountScan/dense_high_action_fanout-8                  4.010m ±  2%
Scheduler_InventoryShape_ActiveCountScan/dense_high_slot_capacity-8                  54.81µ ±  2%
Scheduler_InventoryShape_ActiveCountScan/sparse_low_fanout-8                         61.08µ ±  1%
Scheduler_InventoryShape_ActiveCountScan/partitioned_20-8                            992.7µ ±  3%
Scheduler_InventoryShape_TryAssignBatch/small_dense-8                                162.3µ ±  0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_action_fanout-8                   761.2µ ±  0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_slot_capacity-8                   14.04m ±  3%
Scheduler_InventoryShape_TryAssignBatch/sparse_low_fanout-8                          85.84µ ±  4%
Scheduler_InventoryShape_TryAssignBatch/partitioned_20-8                             214.0µ ±  0%
geomean                                                                822.5µ        793.4µ        -32.49%

                                                                    │ /tmp/old.txt  │             /tmp/new.txt              │
                                                                    │     B/op      │     B/op      vs base                 │
RateLimiter-8                                                          137.7Ki ± 0%   137.7Ki ± 0%        ~ (p=0.255 n=6)
Scheduler_Replenish_DenseSharedActions-8                              11.689Mi ± 0%   2.184Mi ± 0%  -81.31% (p=0.002 n=6)
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_01-8                          2.440Mi ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_04-8                          3.358Mi ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_16-8                          7.190Mi ± 0%
Scheduler_InventoryShape_ReplenishMust/small_dense-8                                  32.18Ki ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_action_fanout-8                     3.819Mi ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_slot_capacity-8                     7.837Mi ± 0%
Scheduler_InventoryShape_ReplenishMust/sparse_low_fanout-8                            1.005Mi ± 0%
Scheduler_InventoryShape_ReplenishMust/partitioned_20-8                               2.228Mi ± 0%
Scheduler_InventoryShape_ActiveCountScan/small_dense-8                                  0.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_action_fanout-8                     0.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_slot_capacity-8                     0.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/sparse_low_fanout-8                            0.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/partitioned_20-8                               0.000 ± 0%
Scheduler_InventoryShape_TryAssignBatch/small_dense-8                                 78.15Ki ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_action_fanout-8                    209.1Ki ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_slot_capacity-8                    169.9Ki ± 0%
Scheduler_InventoryShape_TryAssignBatch/sparse_low_fanout-8                           49.63Ki ± 0%
Scheduler_InventoryShape_TryAssignBatch/partitioned_20-8                              78.11Ki ± 0%
geomean                                                                1.254Mi                      -56.77%               ¹
¹ summaries must be >0 to compute geomean

                                                                    │ /tmp/old.txt │             /tmp/new.txt             │
                                                                    │  allocs/op   │  allocs/op   vs base                 │
RateLimiter-8                                                          1.022k ± 0%   1.022k ± 0%        ~ (p=1.000 n=6) ¹
Scheduler_Replenish_DenseSharedActions-8                              17.525k ± 0%   5.099k ± 0%  -70.90% (p=0.002 n=6)
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_01-8                         8.790k ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_04-8                         21.99k ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_16-8                         75.30k ± 0%
Scheduler_InventoryShape_ReplenishMust/small_dense-8                                  386.0 ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_action_fanout-8                    14.56k ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_slot_capacity-8                    112.6k ± 0%
Scheduler_InventoryShape_ReplenishMust/sparse_low_fanout-8                           10.40k ± 0%
Scheduler_InventoryShape_ReplenishMust/partitioned_20-8                              19.42k ± 0%
Scheduler_InventoryShape_ActiveCountScan/small_dense-8                                0.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_action_fanout-8                   0.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_slot_capacity-8                   0.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/sparse_low_fanout-8                          0.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/partitioned_20-8                             0.000 ± 0%
Scheduler_InventoryShape_TryAssignBatch/small_dense-8                                1.897k ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_action_fanout-8                   4.444k ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_slot_capacity-8                   2.958k ± 1%
Scheduler_InventoryShape_TryAssignBatch/sparse_low_fanout-8                          1.257k ± 0%
Scheduler_InventoryShape_TryAssignBatch/partitioned_20-8                             1.897k ± 0%
geomean                                                                4.232k                     -46.06%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                                                    │ /tmp/new.txt │
                                                                    │ action_rows  │
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_01-8           50.00k ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_04-8           50.00k ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_16-8           50.00k ± 0%
Scheduler_InventoryShape_ReplenishMust/small_dense-8                    200.0 ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_action_fanout-8      86.20k ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_slot_capacity-8      1.200k ± 0%
Scheduler_InventoryShape_ReplenishMust/sparse_low_fanout-8             1.000k ± 0%
Scheduler_InventoryShape_ReplenishMust/partitioned_20-8                20.00k ± 0%
Scheduler_InventoryShape_ActiveCountScan/small_dense-8                  200.0 ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_action_fanout-8    86.20k ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_slot_capacity-8    1.200k ± 0%
Scheduler_InventoryShape_ActiveCountScan/sparse_low_fanout-8           1.000k ± 0%
Scheduler_InventoryShape_ActiveCountScan/partitioned_20-8              20.00k ± 0%
Scheduler_InventoryShape_TryAssignBatch/small_dense-8                   200.0 ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_action_fanout-8     86.20k ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_slot_capacity-8     1.200k ± 0%
Scheduler_InventoryShape_TryAssignBatch/sparse_low_fanout-8            1.000k ± 0%
Scheduler_InventoryShape_TryAssignBatch/partitioned_20-8               20.00k ± 0%
geomean                                                                5.239k

                                                                    │ /tmp/new.txt │
                                                                    │   actions    │
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_01-8            500.0 ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_04-8            500.0 ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_16-8            500.0 ± 0%
Scheduler_InventoryShape_ReplenishMust/small_dense-8                    20.00 ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_action_fanout-8      1.724k ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_slot_capacity-8       30.00 ± 0%
Scheduler_InventoryShape_ReplenishMust/sparse_low_fanout-8             2.000k ± 0%
Scheduler_InventoryShape_ReplenishMust/partitioned_20-8                2.000k ± 0%
Scheduler_InventoryShape_ActiveCountScan/small_dense-8                  20.00 ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_action_fanout-8    1.724k ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_slot_capacity-8     30.00 ± 0%
Scheduler_InventoryShape_ActiveCountScan/sparse_low_fanout-8           2.000k ± 0%
Scheduler_InventoryShape_ActiveCountScan/partitioned_20-8              2.000k ± 0%
Scheduler_InventoryShape_TryAssignBatch/small_dense-8                   20.00 ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_action_fanout-8     1.724k ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_slot_capacity-8      30.00 ± 0%
Scheduler_InventoryShape_TryAssignBatch/sparse_low_fanout-8            2.000k ± 0%
Scheduler_InventoryShape_TryAssignBatch/partitioned_20-8               2.000k ± 0%
geomean                                                                 357.0

                                                                    │ /tmp/new.txt │
                                                                    │  slot_types  │
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_01-8            1.000 ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_04-8            4.000 ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_16-8            16.00 ± 0%
Scheduler_InventoryShape_ReplenishMust/small_dense-8                    1.000 ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_action_fanout-8       1.000 ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_slot_capacity-8       1.000 ± 0%
Scheduler_InventoryShape_ReplenishMust/sparse_low_fanout-8              1.000 ± 0%
Scheduler_InventoryShape_ReplenishMust/partitioned_20-8                 1.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/small_dense-8                  1.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_action_fanout-8     1.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_slot_capacity-8     1.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/sparse_low_fanout-8            1.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/partitioned_20-8               1.000 ± 0%
Scheduler_InventoryShape_TryAssignBatch/small_dense-8                   1.000 ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_action_fanout-8      1.000 ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_slot_capacity-8      1.000 ± 0%
Scheduler_InventoryShape_TryAssignBatch/sparse_low_fanout-8             1.000 ± 0%
Scheduler_InventoryShape_TryAssignBatch/partitioned_20-8                1.000 ± 0%
geomean                                                                 1.260

                                                                    │   /tmp/new.txt   │
                                                                    │ slots_per_worker │
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_01-8                20.00 ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_04-8                20.00 ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_16-8                20.00 ± 0%
Scheduler_InventoryShape_ReplenishMust/small_dense-8                        4.000 ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_action_fanout-8           20.00 ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_slot_capacity-8          1.400k ± 0%
Scheduler_InventoryShape_ReplenishMust/sparse_low_fanout-8                  20.00 ± 0%
Scheduler_InventoryShape_ReplenishMust/partitioned_20-8                     20.00 ± 0%
Scheduler_InventoryShape_ActiveCountScan/small_dense-8                      4.000 ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_action_fanout-8         20.00 ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_slot_capacity-8        1.400k ± 0%
Scheduler_InventoryShape_ActiveCountScan/sparse_low_fanout-8                20.00 ± 0%
Scheduler_InventoryShape_ActiveCountScan/partitioned_20-8                   20.00 ± 0%
Scheduler_InventoryShape_TryAssignBatch/small_dense-8                       4.000 ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_action_fanout-8          20.00 ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_slot_capacity-8         1.400k ± 0%
Scheduler_InventoryShape_TryAssignBatch/sparse_low_fanout-8                 20.00 ± 0%
Scheduler_InventoryShape_TryAssignBatch/partitioned_20-8                    20.00 ± 0%
geomean                                                                     31.05

                                                                    │ /tmp/new.txt │
                                                                    │ unique_slots │
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_01-8           2.000k ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_04-8           8.000k ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_16-8           32.00k ± 0%
Scheduler_InventoryShape_ReplenishMust/small_dense-8                    40.00 ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_action_fanout-8      1.000k ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_slot_capacity-8      56.00k ± 0%
Scheduler_InventoryShape_ReplenishMust/sparse_low_fanout-8             4.000k ± 0%
Scheduler_InventoryShape_ReplenishMust/partitioned_20-8                4.000k ± 0%
Scheduler_InventoryShape_ActiveCountScan/small_dense-8                  40.00 ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_action_fanout-8    1.000k ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_slot_capacity-8    56.00k ± 0%
Scheduler_InventoryShape_ActiveCountScan/sparse_low_fanout-8           4.000k ± 0%
Scheduler_InventoryShape_ActiveCountScan/partitioned_20-8              4.000k ± 0%
Scheduler_InventoryShape_TryAssignBatch/small_dense-8                   40.00 ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_action_fanout-8     1.000k ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_slot_capacity-8     56.00k ± 0%
Scheduler_InventoryShape_TryAssignBatch/sparse_low_fanout-8            4.000k ± 0%
Scheduler_InventoryShape_TryAssignBatch/partitioned_20-8               4.000k ± 0%
geomean                                                                2.568k

                                                                    │ /tmp/new.txt │
                                                                    │   workers    │
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_01-8            100.0 ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_04-8            100.0 ± 0%
Scheduler_InventoryShape_SlotTypeCardinality/slot_types_16-8            100.0 ± 0%
Scheduler_InventoryShape_ReplenishMust/small_dense-8                    10.00 ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_action_fanout-8       50.00 ± 0%
Scheduler_InventoryShape_ReplenishMust/dense_high_slot_capacity-8       40.00 ± 0%
Scheduler_InventoryShape_ReplenishMust/sparse_low_fanout-8              200.0 ± 0%
Scheduler_InventoryShape_ReplenishMust/partitioned_20-8                 200.0 ± 0%
Scheduler_InventoryShape_ActiveCountScan/small_dense-8                  10.00 ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_action_fanout-8     50.00 ± 0%
Scheduler_InventoryShape_ActiveCountScan/dense_high_slot_capacity-8     40.00 ± 0%
Scheduler_InventoryShape_ActiveCountScan/sparse_low_fanout-8            200.0 ± 0%
Scheduler_InventoryShape_ActiveCountScan/partitioned_20-8               200.0 ± 0%
Scheduler_InventoryShape_TryAssignBatch/small_dense-8                   10.00 ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_action_fanout-8      50.00 ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_slot_capacity-8      40.00 ± 0%
Scheduler_InventoryShape_TryAssignBatch/sparse_low_fanout-8             200.0 ± 0%
Scheduler_InventoryShape_TryAssignBatch/partitioned_20-8                200.0 ± 0%
geomean                                                                 65.64

                                                                   │ /tmp/new.txt │
                                                                   │  batch_size  │
Scheduler_InventoryShape_TryAssignBatch/small_dense-8                  64.00 ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_action_fanout-8     64.00 ± 0%
Scheduler_InventoryShape_TryAssignBatch/dense_high_slot_capacity-8     64.00 ± 0%
Scheduler_InventoryShape_TryAssignBatch/sparse_low_fanout-8            64.00 ± 0%
Scheduler_InventoryShape_TryAssignBatch/partitioned_20-8               64.00 ± 0%
geomean                                                                64.00

Compared against main (a3b2075)

f.uniqueSlots = refs
f.actionSlotRefs = refs
if f.uniqueSlots > 0 {
f.fanout = float64(f.actionSlotRefs) / float64(f.uniqueSlots)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this not trivially going to be 1.0 since we're dividing refs by itself?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol yes, artifact of the test written on main's code which would not have been 1.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do these tests fail on main?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are net new

@grutt grutt Jul 16, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wrote them before making any changes but they require changes on this branch which is bad

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I follow? I just ran these tests on main and they all passed, so I'm not convinced they're either 1) not flaky or 2) actually testing anything - I imagine these are supposed to be a regression test?

@grutt grutt changed the title Perf hot schedulers perf: hot schedulers Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

engine Related to the core Hatchet engine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants