Original GRUB tends to reclaim 100% of the CPU time... And this allows a CPU hog to starve non-deadline tasks. To address this issue, allow the scheduler to reclaim only a specified fraction of CPU time, stored in the new "bw_ratio" field of the dl runqueue structure.
Unified · Split
| @@ -6759,6 +6759,16 @@ static int sched_dl_global_validate(void) · 6758 unmodified lines | |||
| 6759 | return ret; | 6759 | return ret; |
| 6760 | } | 6760 | } |
| 6761 | 6761 | ||
| 6762 | void init_dl_rq_bw_ratio(struct dl_rq *dl_rq) | ||
| 6763 | { | ||
| 6764 | if (global_rt_runtime() == RUNTIME_INF) { | ||
| 6765 | dl_rq->bw_ratio = 1 << RATIO_SHIFT; | ||
| 6766 | } else { | ||
| 6767 | dl_rq->bw_ratio = to_ratio(global_rt_runtime(), | ||
| 6768 | global_rt_period()) >> (BW_SHIFT - RATIO_SHIFT); | ||
| 6769 | } | ||
| 6770 | } | ||
| 6771 | |||
| 6762 | static void sched_dl_do_global(void) | 6772 | static void sched_dl_do_global(void) |
| 6763 | { | 6773 | { |
| 6764 | u64 new_bw = -1; | 6774 | u64 new_bw = -1; |
| @@ -6784,6 +6794,7 @@ static void sched_dl_do_global(void) · 19 unmodified lines | |||
| 6784 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); | 6794 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); |
| 6785 | 6795 | ||
| 6786 | rcu_read_unlock_sched(); | 6796 | rcu_read_unlock_sched(); |
| 6797 | init_dl_rq_bw_ratio(&cpu_rq(cpu)->dl); | ||
| 6787 | } | 6798 | } |
| 6788 | } | 6799 | } |
| 6789 | 6800 | ||
| @@ -268,6 +268,7 @@ void init_dl_rq(struct dl_rq *dl_rq) · 267 unmodified lines | |||
| 268 | #endif | 268 | #endif |
| 269 | 269 | ||
| 270 | dl_rq->running_bw = 0; | 270 | dl_rq->running_bw = 0; |
| 271 | init_dl_rq_bw_ratio(dl_rq); | ||
| 271 | } | 272 | } |
| 272 | 273 | ||
| 273 | #ifdef CONFIG_SMP | 274 | #ifdef CONFIG_SMP |
| @@ -924,11 +925,20 @@ extern bool sched_rt_bandwidth_account(struct rt_rq *rt_rq); · 650 unmodified lines | |||
| 924 | * Uact is the (per-runqueue) active utilization. | 925 | * Uact is the (per-runqueue) active utilization. |
| 925 | * Since rq->dl.running_bw contains Uact * 2^BW_SHIFT, the result | 926 | * Since rq->dl.running_bw contains Uact * 2^BW_SHIFT, the result |
| 926 | * has to be shifted right by BW_SHIFT. | 927 | * has to be shifted right by BW_SHIFT. |
| 928 | * To reclaim only a fraction Umax of the CPU time, the | ||
| 929 | * runtime accounting rule is modified as | ||
| 930 | * "dq = -Uact / Umax dt"; since rq->dl.bw_ratio contains | ||
| 931 | * 2^RATIO_SHIFT / Umax, delta is multiplied by bw_ratio and shifted | ||
| 932 | * right by RATIO_SHIFT. | ||
| 933 | * Since delta is a 64 bit variable, to have an overflow its value | ||
| 934 | * should be larger than 2^(64 - 20 - 8), which is more than 64 seconds. | ||
| 935 | * So, overflow is not an issue here. | ||
| 927 | */ | 936 | */ |
| 928 | u64 grub_reclaim(u64 delta, struct rq *rq) | 937 | u64 grub_reclaim(u64 delta, struct rq *rq) |
| 929 | { | 938 | { |
| 930 | delta *= rq->dl.running_bw; | 939 | delta *= rq->dl.running_bw; |
| 931 | delta >>= BW_SHIFT; | 940 | delta *= rq->dl.bw_ratio; |
| 941 | delta >>= BW_SHIFT + RATIO_SHIFT; | ||
| 932 | 942 | ||
| 933 | return delta; | 943 | return delta; |
| 934 | } | 944 | } |
| @@ -565,6 +565,12 @@ struct dl_rq { · 564 unmodified lines | |||
| 565 | * task blocks | 565 | * task blocks |
| 566 | */ | 566 | */ |
| 567 | u64 running_bw; | 567 | u64 running_bw; |
| 568 | |||
| 569 | /* | ||
| 570 | * Inverse of the fraction of CPU utilization that can be reclaimed | ||
| 571 | * by the GRUB algorithm. | ||
| 572 | */ | ||
| 573 | u64 bw_ratio; | ||
| 568 | }; | 574 | }; |
| 569 | 575 | ||
| 570 | #ifdef CONFIG_SMP | 576 | #ifdef CONFIG_SMP |
| @@ -1495,9 +1501,11 @@ extern struct dl_bandwidth def_dl_bandwidth; · 924 unmodified lines | |||
| 1495 | extern void init_dl_bandwidth(struct dl_bandwidth *dl_b, u64 period, u64 runtime); | 1501 | extern void init_dl_bandwidth(struct dl_bandwidth *dl_b, u64 period, u64 runtime); |
| 1496 | extern void init_dl_task_timer(struct sched_dl_entity *dl_se); | 1502 | extern void init_dl_task_timer(struct sched_dl_entity *dl_se); |
| 1497 | extern void init_dl_inactive_task_timer(struct sched_dl_entity *dl_se); | 1503 | extern void init_dl_inactive_task_timer(struct sched_dl_entity *dl_se); |
| 1504 | extern void init_dl_rq_bw_ratio(struct dl_rq *dl_rq); | ||
| 1498 | 1505 | ||
| 1499 | #define BW_SHIFT 20 | 1506 | #define BW_SHIFT 20 |
| 1500 | #define BW_UNIT (1 << BW_SHIFT) | 1507 | #define BW_UNIT (1 << BW_SHIFT) |
| 1508 | #define RATIO_SHIFT 8 | ||
| 1501 | unsigned long to_ratio(u64 period, u64 runtime); | 1509 | unsigned long to_ratio(u64 period, u64 runtime); |
| 1502 | 1510 | ||
| 1503 | extern void init_entity_runnable_average(struct sched_entity *se); | 1511 | extern void init_entity_runnable_average(struct sched_entity *se); |