fix(scheduler): enforce PodSet gang admission floor - #2096
Conversation
|
Total coverage: 54.8% -> 54.8% (delta 0.00%) Merging this branch will increase overall coverage
Coverage by fileChanged files (no unit tests)
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
|
📊 Performance Benchmark ResultsComparing PR (
|
Signed-off-by: Yuting Wu (DLAlgo) <yutwu@nvidia.com>
Signed-off-by: itsomri <omric@nvidia.com>
882b963 to
41e7f92
Compare
I need to think about it a bit further, will re-review later today
| return getTasksFromQueue(taskPriorityQueue, maxNumOfTasksToAllocate) | ||
| numTasksToAllocate := getNumTasksToAllocate(ps, isRealAllocation) | ||
| if ps.GetNumActiveAllocatedTasks() < int(ps.GetMinAvailable()) && taskPriorityQueue.Len() < numTasksToAllocate { | ||
| return nil |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Thanks. Should we make PodGroup.IsStale also minSubGroup aware so workload with a not-ready (now skipped) subgroup won't be evicted?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
@nvyutwu do you think of other areas where this might cause issues? podgroup/queue status reporting? anything else?
There was a problem hiding this comment.
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.
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 { |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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>
Description
GetTasksToAllocatedocuments that task collection respectsminAvailable, 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
minAvailablerequirement. 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
make changelogBreaking Changes
None.
Additional Notes
Pre-fix red test:
minAvailable=2, one pending task: returned 1, expected 0minAvailable=4, three pending tasks: returned 3, expected 0minAvailable=4, two allocated and one pending task: returned 1, expected 0 because two remaining members are requiredPost-fix validation on linux/amd64:
go test ./pkg/scheduler/api/podgroup_info -count=1go test ./pkg/scheduler/... -timeout 30m -count=1go vet ./...make lint-go(0 issues)make build-go-amd SERVICE_NAME=schedulerNo physical GPU is required for these scheduler-state tests.