weichen lai created YUNIKORN-3445:
-------------------------------------

             Summary: [Core] SortAllocationsBasedOnAsk prioritizes originator 
and opted-out pods for preemption instead of protecting them
                 Key: YUNIKORN-3445
                 URL: https://issues.apache.org/jira/browse/YUNIKORN-3445
             Project: Apache YuniKorn
          Issue Type: Bug
          Components: core - scheduler
    Affects Versions: 1.9.0
            Reporter: weichen lai
            Assignee: weichen lai


h3. Overview

In {{pkg/scheduler/objects/preemption_utilities.go}}, 
{{SortAllocationsBasedOnAsk()}} and {{scoreAllocationBasedOnAsk()}} determine 
victim ordering during preemption.

Under the current implementation, allocations with {{!allowPreemptSelf}} 
(opted-out) or {{isOriginator}} (driver/manager) receive higher-order score 
bits ({{scoreNoPreempt}} = {{1 << 34}}, {{scoreOriginator}} = {{1 << 33}}):

{code:go}func scoreAllocationBasedOnAsk(allocation *Allocation, ask 
*resources.Resource) uint64 {
        var score uint64 = 0
        if allocation.IsOriginator() {
                score |= scoreOriginator // 1 << 33
        }
        if !allocation.IsAllowPreemptSelf() {
                score |= scoreNoPreempt  // 1 << 34
        }
        score += allocation.GetAllocatedResource().TypeMatching(ask)
        return score
}
{code}

Because {{SortAllocationsBasedOnAsk()}} orders allocations in descending order 
({{scoreLeft > scoreRight}}), opted-out and originator allocations receive 
higher scores and are placed at the beginning of the candidate slice rather 
than at the end.
h2. 

h3. Comparison with Design Documentation

This ordering conflicts with documented design specifications:
* **Preemption Law #1 (preemption policies are strong suggestions, not 
guarantees):** Opting out of preemption and originator status are intended as a 
last resort when no other suitable allocations can be preempted.
* **Quota Preemption Design Document:** The specification states that 
non-originators and pods with {{allowPreemption: true}} should receive higher 
scores to prioritize regular allocations for preemption over originators and 
opted-out pods.
h2. 

h3. Test Verification

The following test demonstrates the ordering in 
{{pkg/scheduler/objects/preemption_utilities_test.go}}:

{code:go}func TestSortAllocationsBasedOnAsk_PreemptionOrdering(t *testing.T) {
        node := NewNode(&si.NodeInfo{
                NodeID: "node1",
                SchedulableResource: &si.Resource{
                        Resources: map[string]*si.Quantity{"first": {Value: 
100}},
                },
        })
        res := 
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 10})
        total := 
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 100})
        ask := 
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 10})

        regularPod := createAllocation("regularPod", "app1", node.NodeID, true, 
false, 10, false, res)
        originatorPod := createAllocation("originatorPod", "app1", node.NodeID, 
true, true, 10, false, res)
        optedOutPod := createAllocation("optedOutPod", "app1", node.NodeID, 
false, false, 10, false, res)

        allocations := []*Allocation{regularPod, originatorPod, optedOutPod}
        SortAllocationsBasedOnAsk(allocations, total, ask)

        // Current ordering:
        // allocations[0]: optedOutPod
        // allocations[1]: originatorPod
        // allocations[2]: regularPod
        //
        // Expected ordering per design: regularPod should be placed at index 0
        assert.Equal(t, allocations[0].GetAllocationKey(), "regularPod",
                "Expected regularPod at index 0, but got: %s", 
allocations[0].GetAllocationKey())
}
{code}

*Output:*
{code}=== RUN   TestSortAllocationsBasedOnAsk_PreemptionOrdering
    preemption_utilities_test.go:320: Expected regularPod at index 0, but got: 
optedOutPod
--- FAIL: TestSortAllocationsBasedOnAsk_PreemptionOrdering (0.00s)
{code}
h2. 

h3. Impact

During Quota Preemption, reducing a queue's quota results in originator and 
opted-out allocations being preempted before standard worker allocations.
h2. 

h3. Proposed Solution

In {{pkg/scheduler/objects/preemption_utilities.go}}, assign the higher-order 
score bits to unprotected allocations ({{allowPreemptSelf == true}} and 
{{!isOriginator}}):

{code:go}const (
        scoreAllowPreempt  uint64 = 1 << 34
        scoreNonOriginator uint64 = 1 << 33
)

func scoreAllocationBasedOnAsk(allocation *Allocation, ask *resources.Resource) 
uint64 {
        var score uint64 = 0
        if !allocation.IsOriginator() {
                score |= scoreNonOriginator
        }
        if allocation.IsAllowPreemptSelf() {
                score |= scoreAllowPreempt
        }
        score += allocation.GetAllocatedResource().TypeMatching(ask)
        return score
}
{code}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to