@@ -21,12 +21,10 @@ import (
2121 "fmt"
2222 "sort"
2323 "sync/atomic"
24- "time"
2524
2625 "github.com/go-logr/logr"
2726 corev1 "k8s.io/api/core/v1"
2827 "k8s.io/apimachinery/pkg/api/meta"
29- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3028 "k8s.io/apimachinery/pkg/util/sets"
3129 "k8s.io/client-go/tools/record"
3230 "k8s.io/client-go/util/workqueue"
@@ -43,6 +41,7 @@ import (
4341 "sigs.k8s.io/kueue/pkg/resources"
4442 "sigs.k8s.io/kueue/pkg/scheduler/flavorassigner"
4543 "sigs.k8s.io/kueue/pkg/scheduler/preemption/classical"
44+ preemptioncommon "sigs.k8s.io/kueue/pkg/scheduler/preemption/common"
4645 "sigs.k8s.io/kueue/pkg/scheduler/preemption/fairsharing"
4746 "sigs.k8s.io/kueue/pkg/util/priority"
4847 "sigs.k8s.io/kueue/pkg/util/routine"
@@ -208,7 +207,7 @@ func (p *Preemptor) classicalPreemptions(preemptionCtx *preemptionCtx) []*Target
208207 Requests : preemptionCtx .workloadUsage .Quota ,
209208 WorkloadOrdering : p .workloadOrdering ,
210209 }
211- candidatesGenerator := classical .NewCandidateIterator (hierarchicalReclaimCtx , preemptionCtx .frsNeedPreemption , preemptionCtx .snapshot , p .clock , CandidatesOrdering )
210+ candidatesGenerator := classical .NewCandidateIterator (hierarchicalReclaimCtx , preemptionCtx .frsNeedPreemption , preemptionCtx .snapshot , p .clock , preemptioncommon . CandidatesOrdering )
212211 var attemptPossibleOpts []preemptionAttemptOpts
213212 borrowWithinCohortForbidden , _ := classical .IsBorrowingWithinCohortForbidden (preemptionCtx .preemptorCQ )
214213 // We have three types of candidates:
@@ -299,7 +298,8 @@ func parseStrategies(s []config.PreemptionStrategy) []fairsharing.Strategy {
299298// and returns (fits, targets, retryCandidates) retryCandidates may be
300299// used if rule S2-b is configured.
301300func runFirstFsStrategy (preemptionCtx * preemptionCtx , candidates []* workload.Info , strategy fairsharing.Strategy ) (bool , []* Target , []* workload.Info ) {
302- ordering := fairsharing .MakeClusterQueueOrdering (preemptionCtx .preemptorCQ , candidates )
301+ ordering := fairsharing .MakeClusterQueueOrdering (preemptionCtx .preemptorCQ , candidates , preemptionCtx .log )
302+
303303 var targets []* Target
304304 var retryCandidates []* workload.Info
305305 for candCQ := range ordering .Iter () {
@@ -344,7 +344,7 @@ func runFirstFsStrategy(preemptionCtx *preemptionCtx, candidates []*workload.Inf
344344// runSecondFsStrategy implements Fair Sharing Rule S2-b. It returns
345345// (fits, targets).
346346func runSecondFsStrategy (retryCandidates []* workload.Info , preemptionCtx * preemptionCtx , targets []* Target ) (bool , []* Target ) {
347- ordering := fairsharing .MakeClusterQueueOrdering (preemptionCtx .preemptorCQ , retryCandidates )
347+ ordering := fairsharing .MakeClusterQueueOrdering (preemptionCtx .preemptorCQ , retryCandidates , preemptionCtx . log )
348348 for candCQ := range ordering .Iter () {
349349 preemptorNewShare , targetOldShare := candCQ .ComputeShares ()
350350 // Due to API validation, we can only reach here if the second strategy is LessThanInitialShare,
@@ -373,7 +373,7 @@ func (p *Preemptor) fairPreemptions(preemptionCtx *preemptionCtx, strategies []f
373373 if len (candidates ) == 0 {
374374 return nil
375375 }
376- sort .Slice (candidates , CandidatesOrdering (candidates , preemptionCtx .preemptorCQ .Name , p .clock .Now ()))
376+ sort .Slice (candidates , preemptioncommon . CandidatesOrdering (candidates , preemptionCtx .preemptorCQ .Name , p .clock .Now ()))
377377 if logV := preemptionCtx .log .V (5 ); logV .Enabled () {
378378 logV .Info ("Simulating fair preemption" , "candidates" , workload .References (candidates ), "resourcesRequiringPreemption" , preemptionCtx .frsNeedPreemption .UnsortedList (), "preemptingWorkload" , klog .KObj (preemptionCtx .preemptor .Obj ))
379379 }
@@ -504,47 +504,3 @@ func queueUnderNominalInResourcesNeedingPreemption(preemptionCtx *preemptionCtx)
504504 }
505505 return true
506506}
507-
508- // candidatesOrdering criteria:
509- // 0. Workloads already marked for preemption first.
510- // 1. Workloads from other ClusterQueues in the cohort before the ones in the
511- // same ClusterQueue as the preemptor.
512- // 2. Workloads with lower priority first.
513- // 3. Workloads admitted more recently first.
514- func CandidatesOrdering (candidates []* workload.Info , cq kueue.ClusterQueueReference , now time.Time ) func (int , int ) bool {
515- return func (i , j int ) bool {
516- a := candidates [i ]
517- b := candidates [j ]
518- aEvicted := meta .IsStatusConditionTrue (a .Obj .Status .Conditions , kueue .WorkloadEvicted )
519- bEvicted := meta .IsStatusConditionTrue (b .Obj .Status .Conditions , kueue .WorkloadEvicted )
520- if aEvicted != bEvicted {
521- return aEvicted
522- }
523- aInCQ := a .ClusterQueue == cq
524- bInCQ := b .ClusterQueue == cq
525- if aInCQ != bInCQ {
526- return ! aInCQ
527- }
528- pa := priority .Priority (a .Obj )
529- pb := priority .Priority (b .Obj )
530- if pa != pb {
531- return pa < pb
532- }
533- timeA := quotaReservationTime (a .Obj , now )
534- timeB := quotaReservationTime (b .Obj , now )
535- if ! timeA .Equal (timeB ) {
536- return timeA .After (timeB )
537- }
538- // Arbitrary comparison for deterministic sorting.
539- return a .Obj .UID < b .Obj .UID
540- }
541- }
542-
543- func quotaReservationTime (wl * kueue.Workload , now time.Time ) time.Time {
544- cond := meta .FindStatusCondition (wl .Status .Conditions , kueue .WorkloadQuotaReserved )
545- if cond == nil || cond .Status != metav1 .ConditionTrue {
546- // The condition wasn't populated yet, use the current time.
547- return now
548- }
549- return cond .LastTransitionTime .Time
550- }
0 commit comments