| @@ -2634,7 +2634,7 @@ static int balance_one(struct rq *rq, struct task_struct *prev) · 2633 unmodified lines |
| 2634 | | 2634 | |
| 2635 | lockdep_assert_rq_held(rq); | 2635 | lockdep_assert_rq_held(rq); |
| 2636 | rq->scx.flags |= SCX_RQ_IN_BALANCE; | 2636 | rq->scx.flags |= SCX_RQ_IN_BALANCE; |
| 2637 | rq->scx.flags &= ~SCX_RQ_BAL_KEEP; | 2637 | rq->scx.flags &= ~(SCX_RQ_BAL_PENDING | SCX_RQ_BAL_KEEP); |
| 2638 | | 2638 | |
| 2639 | if (static_branch_unlikely(&scx_ops_cpu_preempt) && | 2639 | if (static_branch_unlikely(&scx_ops_cpu_preempt) && |
| 2640 | unlikely(rq->scx.cpu_released)) { | 2640 | unlikely(rq->scx.cpu_released)) { |
| @@ -2948,12 +2948,11 @@ static struct task_struct *pick_task_scx(struct rq *rq) · 307 unmodified lines |
| 2948 | { | 2948 | { |
| 2949 | struct task_struct *prev = rq->curr; | 2949 | struct task_struct *prev = rq->curr; |
| 2950 | struct task_struct *p; | 2950 | struct task_struct *p; |
| | 2951 | bool prev_on_scx = prev->sched_class == &ext_sched_class; |
| | 2952 | bool keep_prev = rq->scx.flags & SCX_RQ_BAL_KEEP; |
| | 2953 | bool kick_idle = false; |
| 2951 | | 2954 | |
| 2952 | /* | 2955 | /* |
| 2953 | * If balance_scx() is telling us to keep running @prev, replenish slice | | |
| 2954 | * if necessary and keep running @prev. Otherwise, pop the first one | | |
| 2955 | * from the local DSQ. | | |
| 2956 | * | | |
| 2957 | * WORKAROUND: | 2956 | * WORKAROUND: |
| 2958 | * | 2957 | * |
| 2959 | * %SCX_RQ_BAL_KEEP should be set iff $prev is on SCX as it must just | 2958 | * %SCX_RQ_BAL_KEEP should be set iff $prev is on SCX as it must just |
| @@ -2962,22 +2961,41 @@ static struct task_struct *pick_task_scx(struct rq *rq) · 2 unmodified lines |
| 2962 | * which then ends up calling pick_task_scx() without preceding | 2961 | * which then ends up calling pick_task_scx() without preceding |
| 2963 | * balance_scx(). | 2962 | * balance_scx(). |
| 2964 | * | 2963 | * |
| 2965 | * For now, ignore cases where $prev is not on SCX. This isn't great and | 2964 | * Keep running @prev if possible and avoid stalling from entering idle |
| 2966 | * can theoretically lead to stalls. However, for switch_all cases, this | 2965 | * without balancing. |
| 2967 | * happens only while a BPF scheduler is being loaded or unloaded, and, | | |
| 2968 | * for partial cases, fair will likely keep triggering this CPU. | | |
| 2969 | * | 2966 | * |
| 2970 | * Once fair is fixed, restore WARN_ON_ONCE(). | 2967 | * Once fair is fixed, remove the workaround and trigger WARN_ON_ONCE() |
| | 2968 | * if pick_task_scx() is called without preceding balance_scx(). |
| 2971 | */ | 2969 | */ |
| 2972 | if ((rq->scx.flags & SCX_RQ_BAL_KEEP) && | 2970 | if (unlikely(rq->scx.flags & SCX_RQ_BAL_PENDING)) { |
| 2973 | prev->sched_class == &ext_sched_class) { | 2971 | if (prev_on_scx) { |
| | 2972 | keep_prev = true; |
| | 2973 | } else { |
| | 2974 | keep_prev = false; |
| | 2975 | kick_idle = true; |
| | 2976 | } |
| | 2977 | } else if (unlikely(keep_prev && !prev_on_scx)) { |
| | 2978 | /* only allowed during transitions */ |
| | 2979 | WARN_ON_ONCE(scx_ops_enable_state() == SCX_OPS_ENABLED); |
| | 2980 | keep_prev = false; |
| | 2981 | } |
| | 2982 | |
| | 2983 | /* |
| | 2984 | * If balance_scx() is telling us to keep running @prev, replenish slice |
| | 2985 | * if necessary and keep running @prev. Otherwise, pop the first one |
| | 2986 | * from the local DSQ. |
| | 2987 | */ |
| | 2988 | if (keep_prev) { |
| 2974 | p = prev; | 2989 | p = prev; |
| 2975 | if (!p->scx.slice) | 2990 | if (!p->scx.slice) |
| 2976 | p->scx.slice = SCX_SLICE_DFL; | 2991 | p->scx.slice = SCX_SLICE_DFL; |
| 2977 | } else { | 2992 | } else { |
| 2978 | p = first_local_task(rq); | 2993 | p = first_local_task(rq); |
| 2979 | if (!p) | 2994 | if (!p) { |
| | 2995 | if (kick_idle) |
| | 2996 | scx_bpf_kick_cpu(cpu_of(rq), SCX_KICK_IDLE); |
| 2980 | return NULL; | 2997 | return NULL; |
| | 2998 | } |
| 2981 | | 2999 | |
| 2982 | if (unlikely(!p->scx.slice)) { | 3000 | if (unlikely(!p->scx.slice)) { |
| 2983 | if (!scx_rq_bypassing(rq) && !scx_warned_zero_slice) { | 3001 | if (!scx_rq_bypassing(rq) && !scx_warned_zero_slice) { |