Skip to content

fix(scheduler): enforce PodSet gang admission floor - #2096

Open
nvyutwu wants to merge 7 commits into
kai-scheduler:mainfrom
nvyutwu:fix/gang-admission-floor
Open

fix(scheduler): enforce PodSet gang admission floor#2096
nvyutwu wants to merge 7 commits into
kai-scheduler:mainfrom
nvyutwu:fix/gang-admission-floor

Conversation

@nvyutwu

@nvyutwu nvyutwu commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Description

GetTasksToAllocate documents that task collection respects minAvailable, but a PodSet below its admission floor currently returns every eligible task in the priority queue up to the remaining requirement. If a caller consumes that under-filled list, checkpoint/rollback is atomic only over the partial list.

This change makes the shared collector return no tasks until enough eligible tasks exist to satisfy the PodSet's remaining minAvailable requirement. Once the PodSet is admitted, existing elastic behavior is unchanged and continues to return at most one additional task.

The allocate action already filters jobs through IsReadyForScheduling. This patch preserves that guard and enforces the same invariant at the lower-level collection boundary used by other scheduler paths.

This is independent of and complementary to #2095, which fixes namespace collisions in PodGroup identity and membership.

Related Issues

N/A. Production investigation: https://reports-a3ad46.gitlab-master-pages.nvidia.com/reports/kai-clique-pinning-prd11/report.html

Checklist

  • Self-reviewed
  • Added/updated tests
  • Updated documentation (not needed; no API or configuration change)
  • Added a changelog fragment via make changelog

Breaking Changes

None.

Additional Notes

Pre-fix red test:

  • minAvailable=2, one pending task: returned 1, expected 0
  • minAvailable=4, three pending tasks: returned 3, expected 0
  • minAvailable=4, two allocated and one pending task: returned 1, expected 0 because two remaining members are required

Post-fix validation on linux/amd64:

  • go test ./pkg/scheduler/api/podgroup_info -count=1
  • go test ./pkg/scheduler/... -timeout 30m -count=1
  • go vet ./...
  • make lint-go (0 issues)
  • make build-go-amd SERVICE_NAME=scheduler

No physical GPU is required for these scheduler-state tests.

@nvyutwu
nvyutwu marked this pull request as ready for review August 23, 2026 04:10
@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown

Total coverage: 54.8% -> 54.8% (delta 0.00%)

Merging this branch will increase overall coverage

Impacted Packages Coverage Δ 🤖
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/podgroup_info 71.63% (+0.78%) 👍
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/podgroup_info/subgroup_info 86.00% (+0.58%) 👍
github.com/kai-scheduler/KAI-scheduler/test/e2e/suites/allocate/min_subgroups 0.00% (ø)

Coverage by file

Changed files (no unit tests)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/podgroup_info/allocation_info.go 82.24% (+2.46%) 107 (+13) 88 (+13) 19 👍
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/podgroup_info/job_info.go 61.09% (-0.09%) 257 (+2) 157 (+1) 100 (+1) 👎
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/podgroup_info/subgroup_info/subgroupset.go 93.44% (+0.99%) 61 (+8) 57 (+8) 4 👍

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files

  • github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/podgroup_info/allocation_info_test.go
  • github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/podgroup_info/job_info_test.go
  • github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/podgroup_info/subgroup_info/subgroupset_test.go
  • github.com/kai-scheduler/KAI-scheduler/test/e2e/suites/allocate/min_subgroups/min_subgroups_test.go

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown

📊 Performance Benchmark Results

Comparing PR (fix/gang-admission-floor) vs main branch — click to expand
goos: linux
goarch: amd64
pkg: github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions
cpu: AMD EPYC 7763 64-Core Processor                
                                    │ main-bench.txt │           pr-bench.txt            │
                                    │     sec/op     │   sec/op     vs base              │
AllocateAction_SmallCluster-4            108.0m ± 0%   108.4m ± 5%  +0.28% (p=0.009 n=6)
AllocateAction_MediumCluster-4           135.1m ± 0%   135.9m ± 1%  +0.61% (p=0.041 n=6)
AllocateAction_LargeCluster-4            200.2m ± 2%   198.0m ± 2%       ~ (p=0.240 n=6)
ReclaimAction_SmallCluster-4             103.5m ± 0%   103.4m ± 0%       ~ (p=0.310 n=6)
ReclaimAction_MediumCluster-4            106.6m ± 0%   106.7m ± 0%       ~ (p=0.818 n=6)
PreemptAction_SmallCluster-4             104.5m ± 0%   104.6m ± 0%       ~ (p=0.485 n=6)
PreemptAction_MediumCluster-4            115.7m ± 1%   115.4m ± 1%       ~ (p=1.000 n=6)
ConsolidationAction_SmallCluster-4       122.0m ± 1%   122.5m ± 1%       ~ (p=0.310 n=6)
ConsolidationAction_MediumCluster-4      264.6m ± 1%   266.6m ± 1%  +0.75% (p=0.026 n=6)
FullSchedulingCycle_SmallCluster-4       106.0m ± 0%   105.9m ± 0%  -0.10% (p=0.026 n=6)
FullSchedulingCycle_MediumCluster-4      120.2m ± 2%   120.1m ± 1%       ~ (p=0.818 n=6)
FullSchedulingCycle_LargeCluster-4       156.0m ± 1%   155.7m ± 1%       ~ (p=0.485 n=6)
ManyQueues_MediumCluster-4               138.6m ± 1%   138.3m ± 1%       ~ (p=0.818 n=6)
GangScheduling_MediumCluster-4           156.5m ± 1%   155.8m ± 1%       ~ (p=0.093 n=6)
geomean                                  133.0m        133.0m       -0.02%

                                    │ main-bench.txt │            pr-bench.txt            │
                                    │      B/op      │     B/op      vs base              │
AllocateAction_SmallCluster-4           2.103Mi ± 1%   2.145Mi ± 1%  +2.02% (p=0.002 n=6)
AllocateAction_MediumCluster-4          10.03Mi ± 0%   10.18Mi ± 0%  +1.51% (p=0.002 n=6)
AllocateAction_LargeCluster-4           31.57Mi ± 0%   31.94Mi ± 0%  +1.19% (p=0.002 n=6)
ReclaimAction_SmallCluster-4            971.1Ki ± 0%   969.1Ki ± 1%       ~ (p=0.180 n=6)
ReclaimAction_MediumCluster-4           3.164Mi ± 0%   3.158Mi ± 0%  -0.19% (p=0.041 n=6)
PreemptAction_SmallCluster-4            1.367Mi ± 0%   1.395Mi ± 1%  +2.02% (p=0.002 n=6)
PreemptAction_MediumCluster-4           6.028Mi ± 0%   6.143Mi ± 0%  +1.92% (p=0.002 n=6)
ConsolidationAction_SmallCluster-4      8.226Mi ± 0%   8.305Mi ± 0%  +0.96% (p=0.002 n=6)
ConsolidationAction_MediumCluster-4     67.85Mi ± 0%   68.15Mi ± 0%  +0.44% (p=0.002 n=6)
FullSchedulingCycle_SmallCluster-4      1.429Mi ± 0%   1.452Mi ± 1%  +1.62% (p=0.002 n=6)
FullSchedulingCycle_MediumCluster-4     6.232Mi ± 0%   6.304Mi ± 0%  +1.15% (p=0.002 n=6)
FullSchedulingCycle_LargeCluster-4      18.59Mi ± 0%   18.76Mi ± 0%  +0.97% (p=0.002 n=6)
ManyQueues_MediumCluster-4              13.25Mi ± 0%   13.41Mi ± 0%  +1.15% (p=0.002 n=6)
GangScheduling_MediumCluster-4          15.57Mi ± 0%   15.66Mi ± 0%  +0.57% (p=0.002 n=6)
geomean                                 6.625Mi        6.696Mi       +1.08%

                                    │ main-bench.txt │           pr-bench.txt            │
                                    │   allocs/op    │  allocs/op   vs base              │
AllocateAction_SmallCluster-4            30.99k ± 0%   31.54k ± 0%  +1.78% (p=0.002 n=6)
AllocateAction_MediumCluster-4           243.8k ± 0%   246.0k ± 0%  +0.90% (p=0.002 n=6)
AllocateAction_LargeCluster-4            1.002M ± 0%   1.008M ± 0%  +0.55% (p=0.002 n=6)
ReclaimAction_SmallCluster-4             8.687k ± 0%   8.686k ± 0%       ~ (p=0.665 n=6)
ReclaimAction_MediumCluster-4            27.12k ± 0%   27.12k ± 0%  +0.01% (p=0.041 n=6)
PreemptAction_SmallCluster-4             14.89k ± 0%   15.09k ± 0%  +1.35% (p=0.002 n=6)
PreemptAction_MediumCluster-4            53.79k ± 0%   54.59k ± 0%  +1.49% (p=0.002 n=6)
ConsolidationAction_SmallCluster-4       109.3k ± 0%   109.8k ± 0%  +0.47% (p=0.002 n=6)
ConsolidationAction_MediumCluster-4      1.019M ± 0%   1.021M ± 0%  +0.20% (p=0.002 n=6)
FullSchedulingCycle_SmallCluster-4       19.26k ± 0%   19.53k ± 0%  +1.41% (p=0.002 n=6)
FullSchedulingCycle_MediumCluster-4      134.8k ± 0%   135.9k ± 0%  +0.82% (p=0.002 n=6)
FullSchedulingCycle_LargeCluster-4       533.9k ± 0%   536.6k ± 0%  +0.52% (p=0.002 n=6)
ManyQueues_MediumCluster-4               272.0k ± 0%   274.2k ± 0%  +0.81% (p=0.002 n=6)
GangScheduling_MediumCluster-4           451.4k ± 0%   452.6k ± 0%  +0.29% (p=0.002 n=6)
geomean                                  107.4k        108.2k       +0.75%

pkg: github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions/integration_tests/reclaim
                                                          │ main-bench.txt │             pr-bench.txt             │
                                                          │     sec/op     │    sec/op      vs base               │
ReclaimLargeJobs_10Node-4                                     138.0m ±  0%    137.1m ±  1%   -0.69% (p=0.015 n=6)
ReclaimLargeJobs_50Node-4                                     332.0m ±  4%    318.1m ±  1%   -4.20% (p=0.002 n=6)
ReclaimLargeJobs_100Node-4                                    667.4m ±  2%    663.0m ±  4%        ~ (p=0.818 n=6)
ReclaimLargeJobs_200Node-4                                     1.647 ±  1%     1.616 ±  1%   -1.86% (p=0.009 n=6)
ReclaimLargeJobs_500Node-4                                     7.460 ±  1%     7.345 ±  2%   -1.55% (p=0.041 n=6)
ReclaimLargeJobs_1000Node-4                                    32.44 ±  1%     34.52 ±  6%   +6.41% (p=0.041 n=6)
ReclaimManySingleGPUJobsFullCycle_10Node-4                    159.2m ±  1%    160.4m ±  1%   +0.76% (p=0.041 n=6)
ReclaimManySingleGPUJobsFullCycle_50Node-4                    993.8m ±  1%   1018.5m ±  2%   +2.48% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_100Node-4                    3.429 ±  2%     3.750 ±  5%   +9.36% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_200Node-4                    13.63 ±  1%     18.62 ±  4%  +36.61% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_500Node-4                    102.3 ±  7%     110.4 ± 32%   +7.96% (p=0.015 n=6)
ReclaimManySingleGPUJobsFullCycleWithMinRuntime_500Node-4      103.4 ± 20%     100.0 ± 16%        ~ (p=0.180 n=6)
geomean                                                        3.150           3.270         +3.80%

                                                          │ main-bench.txt │            pr-bench.txt            │
                                                          │      B/op      │     B/op      vs base              │
ReclaimLargeJobs_10Node-4                                     17.26Mi ± 1%   17.36Mi ± 1%  +0.60% (p=0.026 n=6)
ReclaimLargeJobs_50Node-4                                     92.13Mi ± 0%   92.40Mi ± 0%  +0.29% (p=0.002 n=6)
ReclaimLargeJobs_100Node-4                                    204.6Mi ± 0%   205.2Mi ± 0%  +0.30% (p=0.002 n=6)
ReclaimLargeJobs_200Node-4                                    487.1Mi ± 0%   488.0Mi ± 0%  +0.19% (p=0.002 n=6)
ReclaimLargeJobs_500Node-4                                    1.700Gi ± 0%   1.702Gi ± 0%  +0.13% (p=0.002 n=6)
ReclaimLargeJobs_1000Node-4                                   5.145Gi ± 0%   5.149Gi ± 0%  +0.08% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_10Node-4                    14.90Mi ± 0%   15.15Mi ± 0%  +1.72% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_50Node-4                    145.5Mi ± 0%   146.8Mi ± 0%  +0.93% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_100Node-4                   471.6Mi ± 0%   474.2Mi ± 0%  +0.56% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_200Node-4                   1.631Gi ± 0%   1.637Gi ± 0%  +0.32% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_500Node-4                   10.35Gi ± 0%   10.36Gi ± 0%  +0.13% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycleWithMinRuntime_500Node-4     10.35Gi ± 0%   10.36Gi ± 0%  +0.12% (p=0.002 n=6)
geomean                                                       505.5Mi        507.8Mi       +0.45%

                                                          │ main-bench.txt │           pr-bench.txt            │
                                                          │   allocs/op    │  allocs/op   vs base              │
ReclaimLargeJobs_10Node-4                                      241.4k ± 0%   242.2k ± 0%  +0.36% (p=0.002 n=6)
ReclaimLargeJobs_50Node-4                                      1.478M ± 0%   1.482M ± 0%  +0.22% (p=0.002 n=6)
ReclaimLargeJobs_100Node-4                                     3.735M ± 0%   3.741M ± 0%  +0.17% (p=0.002 n=6)
ReclaimLargeJobs_200Node-4                                     10.51M ± 0%   10.52M ± 0%  +0.12% (p=0.002 n=6)
ReclaimLargeJobs_500Node-4                                     45.54M ± 0%   45.57M ± 0%  +0.06% (p=0.002 n=6)
ReclaimLargeJobs_1000Node-4                                    159.4M ± 0%   159.5M ± 0%  +0.04% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_10Node-4                     278.3k ± 0%   280.5k ± 0%  +0.78% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_50Node-4                     3.733M ± 0%   3.744M ± 0%  +0.29% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_100Node-4                    13.32M ± 0%   13.34M ± 0%  +0.16% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_200Node-4                    50.03M ± 0%   50.08M ± 0%  +0.09% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_500Node-4                    300.5M ± 0%   300.6M ± 0%  +0.04% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycleWithMinRuntime_500Node-4      300.5M ± 0%   300.6M ± 0%  +0.04% (p=0.002 n=6)
geomean                                                        11.67M        11.69M       +0.20%

                                                          │ main-bench.txt │              pr-bench.txt              │
                                                          │ full_cycles/op │ full_cycles/op  vs base                │
ReclaimManySingleGPUJobsFullCycle_10Node-4                      1.000 ± 0%       1.000 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimManySingleGPUJobsFullCycle_50Node-4                      1.000 ± 0%       1.000 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimManySingleGPUJobsFullCycle_100Node-4                     1.000 ± 0%       1.000 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimManySingleGPUJobsFullCycle_200Node-4                     1.000 ± 0%       1.000 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimManySingleGPUJobsFullCycle_500Node-4                     1.000 ± 0%       1.000 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimManySingleGPUJobsFullCycleWithMinRuntime_500Node-4       1.000 ± 0%       1.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                                         1.000            1.000       +0.00%
¹ all samples are equal

                                            │          main-bench.txt           │                     pr-bench.txt                     │
                                            │ fit_error_tasks_after_allocate/op │ fit_error_tasks_after_allocate/op  vs base           │
ReclaimManySingleGPUJobsFullCycle_500Node-4                         4.000k ± 0%                         4.000k ± 0%  ~ (p=1.000 n=6) ¹
¹ all samples are equal

                                            │          main-bench.txt           │                    pr-bench.txt                    │
                                            │ heap_live_after_allocate_bytes/op │ heap_live_after_allocate_bytes/op  vs base         │
ReclaimManySingleGPUJobsFullCycle_500Node-4                        41.55M ± 76%                        43.98M ± 72%  ~ (p=0.180 n=6)

                                            │         main-bench.txt         │                  pr-bench.txt                   │
                                            │ heap_live_after_cycle_bytes/op │ heap_live_after_cycle_bytes/op  vs base         │
ReclaimManySingleGPUJobsFullCycle_500Node-4                     56.14M ± 56%                     58.58M ± 54%  ~ (p=0.180 n=6)

pkg: github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions/preempt
                                  │ main-bench.txt │         pr-bench.txt         │
                                  │     sec/op     │   sec/op     vs base         │
OrderedVictimsQueueConstruction-4      765.2µ ± 6%   767.8µ ± 7%  ~ (p=0.240 n=6)

                                  │ main-bench.txt │          pr-bench.txt           │
                                  │      B/op      │     B/op      vs base           │
OrderedVictimsQueueConstruction-4     114.9Ki ± 0%   114.9Ki ± 0%  ~ (p=1.000 n=6) ¹
¹ all samples are equal

                                  │ main-bench.txt │          pr-bench.txt          │
                                  │   allocs/op    │  allocs/op   vs base           │
OrderedVictimsQueueConstruction-4      4.033k ± 0%   4.033k ± 0%  ~ (p=1.000 n=6) ¹
¹ all samples are equal

pkg: github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions/reclaim
                                                         │ main-bench.txt │           pr-bench.txt            │
                                                         │     sec/op     │   sec/op     vs base              │
ReclaimUnschedulableDistributedJob_10Node-4                   148.5m ± 2%   147.8m ± 2%       ~ (p=0.240 n=6)
ReclaimUnschedulableDistributedJob_50Node-4                    3.587 ± 2%    3.616 ± 1%  +0.83% (p=0.026 n=6)
ReclaimUnschedulableDistributedJob_100Node-4                   17.18 ± 2%    16.98 ± 3%       ~ (p=0.394 n=6)
ReclaimUnschedulableDistributedJob_AntiAffinity100Node-4       16.02 ± 4%    15.89 ± 3%       ~ (p=0.485 n=6)
ReclaimWithMissingPVCJobs-4                                   2.624m ± 8%   2.559m ± 8%       ~ (p=0.699 n=6)
geomean                                                       826.2m        819.2m       -0.85%

                                                         │ main-bench.txt │             pr-bench.txt             │
                                                         │      B/op      │     B/op       vs base               │
ReclaimUnschedulableDistributedJob_10Node-4                  20.95Mi ± 3%    21.04Mi ± 3%        ~ (p=0.132 n=6)
ReclaimUnschedulableDistributedJob_50Node-4                  1.154Gi ± 0%    1.165Gi ± 0%   +0.92% (p=0.002 n=6)
ReclaimUnschedulableDistributedJob_100Node-4                 5.560Gi ± 0%    5.603Gi ± 0%   +0.77% (p=0.002 n=6)
ReclaimUnschedulableDistributedJob_AntiAffinity100Node-4     5.159Gi ± 0%    5.192Gi ± 0%   +0.64% (p=0.002 n=6)
ReclaimWithMissingPVCJobs-4                                  9.039Ki ± 2%   11.055Ki ± 2%  +22.30% (p=0.002 n=6)
geomean                                                      91.95Mi         96.26Mi        +4.68%

                                                         │ main-bench.txt │           pr-bench.txt            │
                                                         │   allocs/op    │  allocs/op   vs base              │
ReclaimUnschedulableDistributedJob_10Node-4                   305.2k ± 3%   306.3k ± 3%  +0.35% (p=0.041 n=6)
ReclaimUnschedulableDistributedJob_50Node-4                   27.76M ± 0%   27.84M ± 0%  +0.29% (p=0.002 n=6)
ReclaimUnschedulableDistributedJob_100Node-4                  169.0M ± 0%   169.4M ± 0%  +0.19% (p=0.002 n=6)
ReclaimUnschedulableDistributedJob_AntiAffinity100Node-4      146.8M ± 0%   147.1M ± 0%  +0.18% (p=0.002 n=6)
ReclaimWithMissingPVCJobs-4                                    170.0 ± 1%    182.0 ± 1%  +7.06% (p=0.002 n=6)
geomean                                                       2.045M        2.077M       +1.58%

                                                         │ main-bench.txt │             pr-bench.txt             │
                                                         │  duplicate/op  │ duplicate/op  vs base                │
ReclaimUnschedulableDistributedJob_10Node-4                  0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimUnschedulableDistributedJob_50Node-4                  366.0 ± 0%       366.0 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimUnschedulableDistributedJob_100Node-4                1.020k ± 0%      1.020k ± 0%       ~ (p=1.000 n=6) ¹
ReclaimUnschedulableDistributedJob_AntiAffinity100Node-4    1.020k ± 0%      1.020k ± 0%       ~ (p=1.000 n=6) ¹
geomean                                                                 ²                 +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                                         │ main-bench.txt │             pr-bench.txt             │
                                                         │  simulated/op  │ simulated/op  vs base                │
ReclaimUnschedulableDistributedJob_10Node-4                    18.00 ± 0%     18.00 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimUnschedulableDistributedJob_50Node-4                    178.0 ± 0%     178.0 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimUnschedulableDistributedJob_100Node-4                   378.0 ± 0%     378.0 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimUnschedulableDistributedJob_AntiAffinity100Node-4       378.0 ± 0%     378.0 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                                        146.3          146.3       +0.00%
¹ all samples are equal

Legend

  • 📉 Negative delta = Performance improvement (faster)
  • 📈 Positive delta = Performance regression (slower)
  • p-value < 0.05 indicates statistically significant change
Raw benchmark data

PR branch:

goos: linux
goarch: amd64
pkg: github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions
cpu: AMD EPYC 7763 64-Core Processor                
BenchmarkAllocateAction_SmallCluster-4         	       9	 113572228 ns/op	 2262354 B/op	   31557 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108475222 ns/op	 2245264 B/op	   31544 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108150523 ns/op	 2243492 B/op	   31534 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108407061 ns/op	 2247227 B/op	   31540 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108176745 ns/op	 2254148 B/op	   31535 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108296667 ns/op	 2252128 B/op	   31537 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 136043488 ns/op	10668982 B/op	  245965 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 134957274 ns/op	10671224 B/op	  245985 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 136666788 ns/op	10672887 B/op	  245975 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 135510090 ns/op	10671374 B/op	  245947 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 135904826 ns/op	10671078 B/op	  245989 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 135991280 ns/op	10670895 B/op	  245978 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 198331461 ns/op	33514176 B/op	 1007652 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 197816866 ns/op	33503804 B/op	 1007640 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 198167478 ns/op	33489906 B/op	 1007631 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 194252184 ns/op	33491566 B/op	 1007715 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 199148676 ns/op	33492272 B/op	 1007673 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 197237736 ns/op	33489672 B/op	 1007680 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103326950 ns/op	  992242 B/op	    8685 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103141754 ns/op	  996135 B/op	    8688 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103425266 ns/op	  993560 B/op	    8689 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103523129 ns/op	  992439 B/op	    8686 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103052676 ns/op	  985476 B/op	    8686 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103593846 ns/op	  988973 B/op	    8686 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 107070735 ns/op	 3319598 B/op	   27120 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106871593 ns/op	 3311064 B/op	   27120 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106878400 ns/op	 3310760 B/op	   27119 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106540706 ns/op	 3311160 B/op	   27120 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106391121 ns/op	 3310776 B/op	   27118 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106348382 ns/op	 3314680 B/op	   27120 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104502523 ns/op	 1462767 B/op	   15093 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104499746 ns/op	 1466397 B/op	   15095 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104795869 ns/op	 1462528 B/op	   15093 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104395612 ns/op	 1462367 B/op	   15092 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104842604 ns/op	 1462887 B/op	   15093 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104644257 ns/op	 1473236 B/op	   15095 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 115130541 ns/op	 6442457 B/op	   54595 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 114441059 ns/op	 6441803 B/op	   54592 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 115689219 ns/op	 6437794 B/op	   54592 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 116684486 ns/op	 6441629 B/op	   54591 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 117064935 ns/op	 6442208 B/op	   54595 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 114974774 ns/op	 6442009 B/op	   54593 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 122876925 ns/op	 8709149 B/op	  109811 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 123511380 ns/op	 8707428 B/op	  109793 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 122578522 ns/op	 8705902 B/op	  109786 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 122395333 ns/op	 8717095 B/op	  109744 allocs/op

Main branch:

goos: linux
goarch: amd64
pkg: github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions
cpu: AMD EPYC 7763 64-Core Processor                
BenchmarkAllocateAction_SmallCluster-4         	      10	 108020218 ns/op	 2218093 B/op	   31004 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 107995969 ns/op	 2204788 B/op	   30982 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108106404 ns/op	 2205396 B/op	   30996 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108077418 ns/op	 2203428 B/op	   30990 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 107948464 ns/op	 2203072 B/op	   30986 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108182269 ns/op	 2208254 B/op	   30977 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 135328812 ns/op	10529328 B/op	  243792 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 134863128 ns/op	10511532 B/op	  243791 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 135579799 ns/op	10514460 B/op	  243796 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 135075218 ns/op	10512185 B/op	  243789 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 134863866 ns/op	10510929 B/op	  243776 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 135182386 ns/op	10513657 B/op	  243809 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 201558231 ns/op	33094916 B/op	 1002174 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       5	 200948440 ns/op	33103553 B/op	 1002159 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 199504554 ns/op	33098474 B/op	 1002170 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 196525646 ns/op	33097593 B/op	 1002162 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 201807432 ns/op	33098277 B/op	 1002173 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 195511343 ns/op	33100994 B/op	 1002193 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103312089 ns/op	  993948 B/op	    8686 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103532156 ns/op	  990500 B/op	    8686 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103360666 ns/op	  994751 B/op	    8689 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103668202 ns/op	  994520 B/op	    8687 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103567777 ns/op	  994314 B/op	    8687 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103430852 ns/op	  995634 B/op	    8686 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106844253 ns/op	 3317300 B/op	   27117 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106583145 ns/op	 3317532 B/op	   27118 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106578258 ns/op	 3320836 B/op	   27119 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106686639 ns/op	 3317357 B/op	   27119 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106502842 ns/op	 3316948 B/op	   27118 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106537366 ns/op	 3317032 B/op	   27118 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104418674 ns/op	 1428919 B/op	   14891 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104549655 ns/op	 1431807 B/op	   14891 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104327014 ns/op	 1435951 B/op	   14895 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104708492 ns/op	 1431760 B/op	   14891 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104470836 ns/op	 1438333 B/op	   14892 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104695755 ns/op	 1436047 B/op	   14895 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 115225998 ns/op	 6320548 B/op	   53793 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 114935605 ns/op	 6320365 B/op	   53793 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 116240897 ns/op	 6320314 B/op	   53793 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 116244245 ns/op	 6320390 B/op	   53793 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 115010959 ns/op	 6320288 B/op	   53792 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 116644151 ns/op	 6315993 B/op	   53791 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 122631963 ns/op	 8627671 B/op	  109281 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 122025456 ns/op	 8625568 B/op	  109275 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 121951415 ns/op	 8624642 B/op	  109266 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 121321864 ns/op	 8625185 B/op	  109271 allocs/op

nvyutwu and others added 2 commits August 26, 2026 09:45
Signed-off-by: Yuting Wu (DLAlgo) <yutwu@nvidia.com>
Signed-off-by: itsomri <omric@nvidia.com>
@nvyutwu
nvyutwu force-pushed the fix/gang-admission-floor branch from 882b963 to 41e7f92 Compare August 26, 2026 16:45
itsomri
itsomri previously approved these changes Aug 27, 2026
gshaibi
gshaibi previously approved these changes Aug 27, 2026
@gshaibi
gshaibi dismissed their stale review August 27, 2026 14:06

I need to think about it a bit further, will re-review later today

Comment thread pkg/scheduler/api/podgroup_info/allocation_info.go Outdated
return getTasksFromQueue(taskPriorityQueue, maxNumOfTasksToAllocate)
numTasksToAllocate := getNumTasksToAllocate(ps, isRealAllocation)
if ps.GetNumActiveAllocatedTasks() < int(ps.GetMinAvailable()) && taskPriorityQueue.Len() < numTasksToAllocate {
return nil

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What happens when the child picked in the gang phase can't form? It returns nil now but still takes a top-K slot, so with root minSubGroup=1 and subgroups a (minMember=2, 1 pod), b (minMember=1, 1 pod), the podgroup collects zero tasks every cycle and b never schedules, right?
Should the gang phase skip it and try the next child, like the elastic loop does?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Also, this function is also consumed in preempt/consolidate for virtual preemption where we in-memory evict pods and then try to re-allocate them.
Now, a workload with running pods < minMember (due to completed pod for example, temporary state) will be in-memory evicted, and its pods will not be re-allocated since we don't return these pods here, right?

@nvyutwu nvyutwu Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catches. Fixed in 8efeb01: the gang phase now counts only children that return tasks and continues to the next prioritized child, so an underfilled child a no longer starves ready child b. The admission-floor guard now applies only to real allocation; virtual preempt/consolidate paths continue returning the available virtual tasks even when the workload is temporarily below minMember. Added regression tests for both cases; the full scheduler test suite and go vet pass.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks. Should we make PodGroup.IsStale also minSubGroup aware so workload with a not-ready (now skipped) subgroup won't be evicted?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in a88773d. PodGroupInfo.IsStale now evaluates gang satisfaction through the subgroup tree: each SubGroupSet applies its minSubGroup threshold recursively, while leaf PodSets continue to apply minMember. Added a regression test covering one satisfied running subgroup plus an optional unready subgroup.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@nvyutwu do you think of other areas where this might cause issues? podgroup/queue status reporting? anything else?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Traced this end to end. PodGroup stale evaluation is now minSubGroup-aware. Queue/resource accounting must keep partial estimates, so it now uses an explicit PartialTaskAllocation mode. The actual pending paths in preempt, reclaim, and consolidation use SimulatedTaskAllocation, which enforces the subgroup floor before JobSolver; internal solver prefixes remain partial, and victim restoration uses VictimReallocation. Added mode-routing, admission-floor, ready-sibling, and cache-isolation tests in 8889e79.

@gshaibi
gshaibi dismissed their stale review August 28, 2026 14:37

requested changes by mistake, meant to comment

Signed-off-by: Yuting Wu (DLAlgo) <yutwu@nvidia.com>
Signed-off-by: Yuting Wu (DLAlgo) <yutwu@nvidia.com>
Signed-off-by: Yuting Wu (DLAlgo) <yutwu@nvidia.com>
Signed-off-by: Yuting Wu (DLAlgo) <yutwu@nvidia.com>
if !podSet.IsGangSatisfied() {
return false
root := pgi.RootSubGroupSet
if root == nil {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In what case does this happen?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There is no supported production case. Constructors and clones always initialize RootSubGroupSet. I removed the synthesized fallback; nil now fails closed, consistent with IsReadyForScheduling.

activeAllocatedCount *int
aliveTasksRequestedGPUs *float64
allPodsMap *pod_info.PodsMap
tasksToAllocateByMode map[bool][]*pod_info.PodInfo

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What does "by mode" mean?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The bool meant real versus virtual, but virtual was overloaded. In 8889e79 it is replaced by TaskAllocationMode: RealTaskAllocation, SimulatedTaskAllocation, PartialTaskAllocation, and VictimReallocation. The cache is partitioned by admission semantics so partial accounting cannot contaminate simulated admission.

Signed-off-by: Yuting Wu (DLAlgo) <yutwu@nvidia.com>
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.

5 participants