sched: SCHED_DEADLINE v5
Subsystems (25)
cover sched: SCHED_DEADLINE v5
Hello everyone,
This is the take 5 for the SCHED_DEADLINE patchset.
The patchset introduces a new deadline based real-time task scheduling policy --called SCHED_DEADLINE-- with bandwidth isolation (aka "resource reservation") capabilities. It supports global/clustered multiprocessor scheduling through dynamic task migrations.
From the previous releases[1]:
- comments and fixes coming from the reviews we got have been considered and mostly applied; still awaiting:
* Steven Rostedt's "take into account the RT tasks" when migrating DL tasks; the DL push/pull mechanism will probably see major changes (RT tasks accounting included) on which we are currently working;
* Peter Zijlstra's "gcc work-around"; based on a not yet mainline accepted patch;
* Peter Zijlstra's "unify the use of nr_cpus_allowed" suggestion was addressed too; however this changes too are based on a not yet merged patch.
- this release is on top of tip/master (as of today), so the actual news is the rebase on v3.4 :-); anyway, -rt guys can find -rt branches on the repo (more info below);
- first two patches are Peter Zijlstra's math128; later patches are a use-case for them.
Still missing/incomplete:
- (c)group based bandwidth management, and maybe scheduling;
- bandwidth inheritance (to replace deadline/priority inheritance);
- access control for non-root users (and related security concerns to address).
The development is taking place at:
https://github.com/jlelli/sched-deadline
The repo has been cleaned-up, main branches are now:
- mainline-dl: tracking tip/master (raw commits);
- linux-rt-dl: tracking -rt releases;
- linux-stable-rt-dl: tracking Rostedt's 3.2-stable-rt branch[2];
- sched-dl-V5: this patchset on top of tip/master.
Check the repositories frequently if you're interested, and feel free to e-mail me for any issue you run into.
Test application:
https://github.com/gbagnoli/rt-app
Development mailing list: linux-dl; you can subscribe from here:
http://feanor.sssup.it/mailman/listinfo/linux-dl
or via e-mail (send a message to [email protected] with just the word `help' as subject or in the body to receive info).
There is also a parallel branch maintained by Insop Song (from Ericsson)
(https://github.com/insop/sched-deadline2). Ericsson is in fact evaluating the use of SCHED_DEADLINE for CPE (Customer Premise Equipment) devices in order to reserve CPU bandwidth to processes.
The code was being jointly developed by ReTiS Lab (http://retis.sssup.it)
and Evidence S.r.l (http://www.evidence.eu.com) in the context of the ACTORS EU-funded project (http://www.actors-project.eu). It is now also supported by the S(o)OS EU-funded project (http://www.soos-project.eu/).
It has also some users, both in academic and applied research. We got positive feedbacks from Ericsson (see above), Wind River, Porto (ISEP), Trento, Lund and Malardalen universities.
As usual, any kind of feedback is welcome and appreciated.
Thanks in advice and regards,
- Juri
[1] http://lwn.net/Articles/376502, http://lwn.net/Articles/353797,
http://lwn.net/Articles/412410, http://lwn.net/Articles/490944
[2] http://www.kernel.org/pub/linux/kernel/projects/rt/3.2/README
Dario Faggioli (9):
sched: add sched_class->task_dead.
sched: add extended scheduling interface.
sched: SCHED_DEADLINE structures & implementation.
sched: SCHED_DEADLINE avg_update accounting.
sched: add schedstats for -deadline tasks.
sched: add latency tracing for -deadline tasks.
sched: drafted deadline inheritance logic.
sched: add bandwidth management for sched_dl.
sched: add sched_dl documentation.
Peter Zijlstra (3):
math128: Introduce various 128bit primitives math128, x86_64: Implement {mul,add}_u128 in 64bit asm
rtmutex: turn the plist into an rb-tree.
Juri Lelli (2):
sched: SCHED_DEADLINE SMP-related data structures & logic.
sched: speed up -dl pushes with a push-heap.
Harald Gustafsson (1):
sched: add period support for -deadline tasks.
Documentation/scheduler/sched-deadline.txt | 164 +++ arch/alpha/include/asm/Kbuild | 1 + arch/arm/include/asm/Kbuild | 1 + arch/arm/include/asm/unistd.h | 3 + arch/arm/kernel/calls.S | 3 + arch/avr32/include/asm/Kbuild | 1 + arch/blackfin/include/asm/Kbuild | 1 + arch/c6x/include/asm/Kbuild | 1 + arch/cris/include/asm/Kbuild | 1 + arch/frv/include/asm/Kbuild | 1 + arch/h8300/include/asm/Kbuild | 1 + arch/hexagon/include/asm/Kbuild | 1 + arch/ia64/include/asm/Kbuild | 1 + arch/m32r/include/asm/Kbuild | 1 + arch/m68k/include/asm/Kbuild | 1 + arch/microblaze/include/asm/Kbuild | 1 + arch/mips/include/asm/Kbuild | 1 + arch/mn10300/include/asm/Kbuild | 1 + arch/openrisc/include/asm/Kbuild | 1 + arch/parisc/include/asm/Kbuild | 1 + arch/powerpc/include/asm/Kbuild | 1 + arch/s390/include/asm/Kbuild | 1 + arch/score/include/asm/Kbuild | 1 + arch/sh/include/asm/Kbuild | 1 + arch/sparc/include/asm/Kbuild | 1 + arch/tile/include/asm/Kbuild | 1 + arch/um/include/asm/Kbuild | 1 + arch/unicore32/include/asm/Kbuild | 1 + arch/x86/include/asm/math128.h | 39 + arch/x86/syscalls/syscall_32.tbl | 3 + arch/x86/syscalls/syscall_64.tbl | 3 + arch/xtensa/include/asm/Kbuild | 1 + include/asm-generic/math128.h | 4 + include/linux/init_task.h | 10 + include/linux/math128.h | 180 +++ include/linux/rtmutex.h | 18 +- include/linux/sched.h | 155 ++- include/linux/syscalls.h | 7 + kernel/fork.c | 8 +- kernel/hrtimer.c | 2 +- kernel/rtmutex-debug.c | 10 +- kernel/rtmutex.c | 161 ++- kernel/rtmutex_common.h | 22 +- kernel/sched/Makefile | 4 +- kernel/sched/core.c | 689 +++++++++++- kernel/sched/cpudl.c | 208 ++++ kernel/sched/cpudl.h | 33 + kernel/sched/debug.c | 46 + kernel/sched/dl.c | 1646 ++++++++++++++++++++++++++++ kernel/sched/rt.c | 2 +- kernel/sched/sched.h | 143 +++ kernel/sched/stop_task.c | 2 +- kernel/sysctl.c | 14 + kernel/trace/trace_sched_wakeup.c | 44 +- kernel/trace/trace_selftest.c | 30 +- lib/Makefile | 2 +- lib/math128.c | 40 + 57 files changed, 3586 insertions(+), 135 deletions(-)
PATCH 1/15 math128: Introduce various 128bit primitives
From: Peter Zijlstra <[email protected]>
Grow rudimentary u128 support without relying on gcc/libgcc.
--- arch/alpha/include/asm/Kbuild | 1 + arch/arm/include/asm/Kbuild | 1 + arch/avr32/include/asm/Kbuild | 1 + arch/blackfin/include/asm/Kbuild | 1 + arch/c6x/include/asm/Kbuild | 1 + arch/cris/include/asm/Kbuild | 1 + arch/frv/include/asm/Kbuild | 1 + arch/h8300/include/asm/Kbuild | 1 + arch/hexagon/include/asm/Kbuild | 1 + arch/ia64/include/asm/Kbuild | 1 + arch/m32r/include/asm/Kbuild | 1 + arch/m68k/include/asm/Kbuild | 1 + arch/microblaze/include/asm/Kbuild | 1 + arch/mips/include/asm/Kbuild | 1 + arch/mn10300/include/asm/Kbuild | 1 + arch/openrisc/include/asm/Kbuild | 1 + arch/parisc/include/asm/Kbuild | 1 + arch/powerpc/include/asm/Kbuild | 1 + arch/s390/include/asm/Kbuild | 1 + arch/score/include/asm/Kbuild | 1 + arch/sh/include/asm/Kbuild | 1 + arch/sparc/include/asm/Kbuild | 1 + arch/tile/include/asm/Kbuild | 1 + arch/um/include/asm/Kbuild | 1 + arch/unicore32/include/asm/Kbuild | 1 + arch/x86/include/asm/Kbuild | 1 + arch/xtensa/include/asm/Kbuild | 1 + include/asm-generic/math128.h | 4 + include/linux/math128.h | 180 ++++++++++++++++++++++++++++++++++++ lib/Makefile | 2 +- lib/math128.c | 40 ++++++++ 31 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 include/asm-generic/math128.h create mode 100644 include/linux/math128.h create mode 100644 lib/math128.c
arch/alpha/include/asm/Kbuild +1 -0
@@ -8,3 +8,4 @@ header-y += pal.h header-y += reg.h header-y += regdef.h header-y += sysinfo.h +generic-y += math128.h
arch/arm/include/asm/Kbuild +1 -0
@@ -18,3 +18,4 @@ generic-y += resource.h generic-y += sections.h generic-y += siginfo.h generic-y += sizes.h +generic-y += math128.h
arch/avr32/include/asm/Kbuild +1 -0
@@ -1,3 +1,4 @@ include include/asm-generic/Kbuild.asm header-y += cachectl.h +generic-y += math128.h
arch/blackfin/include/asm/Kbuild +1 -0
@@ -47,3 +47,4 @@ generic-y += xor.h header-y += bfin_sport.h header-y += cachectl.h header-y += fixed_code.h +generic-y += math128.h
arch/c6x/include/asm/Kbuild +1 -0
@@ -51,3 +51,4 @@ generic-y += types.h generic-y += ucontext.h generic-y += user.h generic-y += vga.h +generic-y += math128.h
arch/cris/include/asm/Kbuild +1 -0
@@ -8,3 +8,4 @@ header-y += etraxgpio.h header-y += rs485.h header-y += rtc.h header-y += sync_serial.h +generic-y += math128.h
arch/frv/include/asm/Kbuild +1 -0
@@ -2,3 +2,4 @@ include include/asm-generic/Kbuild.asm header-y += registers.h header-y += termios.h +generic-y += math128.h
arch/h8300/include/asm/Kbuild +1 -0
@@ -1 +1,2 @@ include include/asm-generic/Kbuild.asm +generic-y += math128.h
arch/hexagon/include/asm/Kbuild +1 -0
@@ -56,3 +56,4 @@ generic-y += types.h generic-y += ucontext.h generic-y += unaligned.h generic-y += xor.h +generic-y += math128.h
arch/ia64/include/asm/Kbuild +1 -0
@@ -12,3 +12,4 @@ header-y += ptrace_offsets.h header-y += rse.h header-y += ucontext.h header-y += ustack.h +generic-y += math128.h
arch/m32r/include/asm/Kbuild +1 -0
@@ -1 +1,2 @@ include include/asm-generic/Kbuild.asm +generic-y += math128.h
arch/m68k/include/asm/Kbuild +1 -0
@@ -1,2 +1,3 @@ include include/asm-generic/Kbuild.asm header-y += cachectl.h +generic-y += math128.h
arch/microblaze/include/asm/Kbuild +1 -0
@@ -1,3 +1,4 @@ include include/asm-generic/Kbuild.asm header-y += elf.h +generic-y += math128.h
arch/mips/include/asm/Kbuild +1 -0
@@ -3,3 +3,4 @@ include include/asm-generic/Kbuild.asm header-y += cachectl.h header-y += sgidefs.h header-y += sysmips.h +generic-y += math128.h
arch/mn10300/include/asm/Kbuild +1 -0
@@ -1 +1,2 @@ include include/asm-generic/Kbuild.asm +generic-y += math128.h
arch/openrisc/include/asm/Kbuild +1 -0
@@ -66,3 +66,4 @@ generic-y += topology.h generic-y += types.h generic-y += ucontext.h generic-y += user.h +generic-y += math128.h
arch/parisc/include/asm/Kbuild +1 -0
@@ -1,3 +1,4 @@ include include/asm-generic/Kbuild.asm header-y += pdc.h +generic-y += math128.h
arch/powerpc/include/asm/Kbuild +1 -0
@@ -36,3 +36,4 @@ header-y += ucontext.h header-y += unistd.h generic-y += rwsem.h +generic-y += math128.h
arch/s390/include/asm/Kbuild +1 -0
@@ -13,3 +13,4 @@ header-y += tape390.h header-y += ucontext.h header-y += vtoc.h header-y += zcrypt.h +generic-y += math128.h
arch/score/include/asm/Kbuild +1 -0
@@ -1,3 +1,4 @@ include include/asm-generic/Kbuild.asm header-y += +generic-y += math128.h
arch/sh/include/asm/Kbuild +1 -0
@@ -9,3 +9,4 @@ header-y += ptrace_32.h header-y += ptrace_64.h header-y += unistd_32.h header-y += unistd_64.h +generic-y += math128.h
arch/sparc/include/asm/Kbuild +1 -0
@@ -21,3 +21,4 @@ generic-y += div64.h generic-y += local64.h generic-y += irq_regs.h generic-y += local.h +generic-y += math128.h
arch/tile/include/asm/Kbuild +1 -0
@@ -42,3 +42,4 @@ generic-y += termios.h generic-y += types.h generic-y += ucontext.h generic-y += xor.h +generic-y += math128.h
arch/um/include/asm/Kbuild +1 -0
@@ -2,3 +2,4 @@ generic-y += bug.h cputime.h device.h emergency-restart.h futex.h hardirq.h generic-y += hw_irq.h irq_regs.h kdebug.h percpu.h sections.h topology.h xor.h generic-y += ftrace.h pci.h io.h param.h delay.h mutex.h current.h exec.h generic-y += switch_to.h +generic-y += math128.h
arch/unicore32/include/asm/Kbuild +1 -0
@@ -58,3 +58,4 @@ generic-y += unaligned.h generic-y += user.h generic-y += vga.h generic-y += xor.h +generic-y += math128.h
arch/x86/include/asm/Kbuild +1 -0
@@ -26,3 +26,4 @@ header-y += vsyscall.h genhdr-y += unistd_32.h genhdr-y += unistd_64.h genhdr-y += unistd_x32.h +generic-y += math128.h
arch/xtensa/include/asm/Kbuild +1 -0
@@ -1 +1,2 @@ include include/asm-generic/Kbuild.asm +generic-y += math128.h
include/asm-generic/math128.h new file +4 -0
@@ -0,0 +1,4 @@ +#ifndef _ASM_GENERIC_MATH128_H +#define _ASM_GENERIC_MATH128_H + +#endif /*_ASM_GENERIC_MATH128_H */
include/linux/math128.h new file +180 -0
180 lines not on this page · raw message
lib/Makefile +1 -1
@@ -12,7 +12,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ idr.o int_sqrt.o extable.o prio_tree.o \ sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \ proportions.o prio_heap.o ratelimit.o show_mem.o \ - is_single_threaded.o plist.o decompress.o + is_single_threaded.o plist.o decompress.o math128.o lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o
lib/math128.c new file +40 -0
@@ -0,0 +1,40 @@ +#include <linux/math128.h> + +#ifndef mul_u64_u64 +/* +* a * b = (ah * 2^32 + al) * (bh * 2^32 + bl) = +* ah*bh * 2^64 + (ah*bl + bh*al) * 2^32 + al*bl +*/ +u128 mul_u64_u64 (u64 a,u64 b) +{ +u128 t1, t2, t3, t4; +u32 ah, al; +u32 bh, bl; + + ah = a >>32 ; + al = a; + + bh = b >>32 ; + bl = b; + + t1.lo =0 ; + t1.hi = (u64 )ah * bh; + + t2.lo = (u64 )ah * bl; + t2.hi = t2.lo >>32 ; + t2.lo <<=32 ; + + t3.lo = (u64 )al * bh; + t3.hi = t3.lo >>32 ; + t3.lo <<=32 ; + + t4.lo = (u64 )al * bl; + t4.hi =0 ; + + t1 =add_u128 (t1, t2); + t1 =add_u128 (t1, t3); + t1 =add_u128 (t1, t4); + +return t1; +} +#endif /* mul_u64_u64 */
Signature · 1 line
1.7.9.5
PATCH 2/15 math128, x86_64: Implement {mul,add}_u128 in 64bit asm
In reply to Juri LelliFrom: Peter Zijlstra <[email protected]>
Enable __int128 usage when available, if not, provide asm versions of mul_u64_u64 and add_u128.
--- arch/x86/include/asm/Kbuild | 1 - arch/x86/include/asm/math128.h | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 arch/x86/include/asm/math128.h
arch/x86/include/asm/Kbuild +0 -1
@@ -26,4 +26,3 @@ header-y += vsyscall.h genhdr-y += unistd_32.h genhdr-y += unistd_64.h genhdr-y += unistd_x32.h -generic-y += math128.h
arch/x86/include/asm/math128.h new file +39 -0
@@ -0,0 +1,39 @@ +#ifndef _ASM_MATH128_H +#define _ASM_MATH128_H + +#ifdef CONFIG_X86_64 + +#ifdef __SIZEOF_INT128__ +#define ARCH_HAS_INT128 +#endif + +#ifndef ARCH_HAS_INT128 + +static inline u128 mul_u64_u64 (u64 a,u64 b) +{ +u128 res; + + asm("mulq %2" + :"=a" (res.lo),"=d" (res.hi) + :"rm" (b),"0" (a)); + +return res; +} +#define mul_u64_u64 mul_u64_u64 + +static inline u128 add_u128 (u128 a,u128 b) +{ +u128 res; + + asm("addq %2,%0;\n" +"adcq %3,%1;\n" + :"=rm" (res.lo),"=rm" (res.hi) + :"r" (b.lo),"r" (b.hi),"0" (a.lo),"1" (a.hi)); + +return res; +} +#define add_u128 add_u128 + +#endif /* ARCH_HAS_INT128 */ +#endif /* CONFIG_X86_64 */ +#endif /* _ASM_MATH128_H */
Signature · 1 line
1.7.9.5
PATCH 3/15 sched: add sched_class->task_dead.
In reply to Juri LelliFrom: Dario Faggioli <[email protected]>
Add a new function to the scheduling class interface. It is called at the end of a context switch, if the prev task is in TASK_DEAD state.
It might be useful for the scheduling classes that want to be notified when one of their task dies, e.g. to perform some cleanup actions.
--- include/linux/sched.h | 1 + kernel/sched/core.c | 3 +++ 2 files changed, 4 insertions(+)
include/linux/sched.h +1 -0
@@ -1103,6 +1103,7 @@ struct sched_class {void (*set_curr_task) (struct rq *rq);void (*task_tick) (struct rq *rq,struct task_struct *p,int queued);void (*task_fork) (struct task_struct *p); +void (*task_dead) (struct task_struct *p);void (*switched_from) (struct rq *this_rq,struct task_struct *task);void (*switched_to) (struct rq *this_rq,struct task_struct *task);
kernel/sched/core.c +3 -0
@@ -1962,6 +1962,9 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev)if (mm)mmdrop (mm);if (unlikely (prev_state ==TASK_DEAD )) { +if (prev->sched_class->task_dead) + prev->sched_class->task_dead (prev); +/* * Remove function-return probe instances associated with this * task and put them back on the free list.
Signature · 1 line
1.7.9.5
PATCH 4/15 sched: add extended scheduling interface.
In reply to Juri LelliFrom: Dario Faggioli <[email protected]>
Add the interface bits needed for supporting scheduling algorithms with extended parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task, that executes for a given amount of runtime at each instance, and is scheduled according to the urgency of their own timing constraints, i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of the tasks and the system calls dealing with it must be extended. Unfortunately, modifying the existing struct sched_param would break the ABI and result in potentially serious compatibility issues with legacy binaries.
For these reasons, this patch:
- defines the new struct sched_param2, containing all the fields that are necessary for specifying a task in the computational model described above;
- defines and implements the new scheduling related syscalls that manipulate it, i.e., sched_setscheduler2(), sched_setparam2() and sched_getparam2().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a proof of concept and for developing and testing purposes. Making them available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch, the implementation of the new system calls is just identical to their already existing counterpart. Future patches that implement scheduling policies able to exploit the new data structure must also take care of modifying the *2() calls accordingly with their own purposes.
--- arch/arm/include/asm/unistd.h | 3 ++ arch/arm/kernel/calls.S | 3 ++ arch/x86/syscalls/syscall_32.tbl | 3 ++ arch/x86/syscalls/syscall_64.tbl | 3 ++ include/linux/sched.h | 50 +++++++++++++++++ include/linux/syscalls.h | 7 +++ kernel/sched/core.c | 110 ++++++++++++++++++++++++++++++++++++-- 7 files changed, 176 insertions(+), 3 deletions(-)
arch/arm/include/asm/unistd.h +3 -0
@@ -404,6 +404,9 @@#define __NR_setns (__NR_SYSCALL_BASE+375)#define __NR_process_vm_readv (__NR_SYSCALL_BASE+376)#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377) +#define __NR_sched_setscheduler2 (__NR_SYSCALL_BASE+378) +#define __NR_sched_setparam2 (__NR_SYSCALL_BASE+379) +#define __NR_sched_getparam2 (__NR_SYSCALL_BASE+380)/* * The following SWIs are ARM private.
arch/arm/kernel/calls.S +3 -0
@@ -387,6 +387,9 @@ /* 375 */ CALL(sys_setns) CALL(sys_process_vm_readv) CALL(sys_process_vm_writev) + CALL(sys_sched_setscheduler2) + CALL(sys_sched_setparam2) +/* 380 */ CALL(sys_sched_getparam2) #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted
arch/x86/syscalls/syscall_32.tbl +3 -0
@@ -355,3 +355,6 @@ 346 i386 setns sys_setns 347 i386 process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv 348 i386 process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev +349 i386 sched_setparam2 sys_sched_setparam2 +350 i386 sched_getparam2 sys_sched_getparam2 +351 i386 sched_setscheduler2 sys_sched_setscheduler2
arch/x86/syscalls/syscall_64.tbl +3 -0
@@ -318,6 +318,9 @@ 309 common getcpu sys_getcpu 310 64 process_vm_readv sys_process_vm_readv 311 64 process_vm_writev sys_process_vm_writev +312 common sched_setparam2 sys_sched_setparam2 +313 common sched_getparam2 sys_sched_getparam2 +314 common sched_setscheduler2 sys_sched_setscheduler2 # # x32-specific system call numbers start at 512 to avoid cache impact # for native 64-bit operation.
include/linux/sched.h +50 -0
62 lines not on this page · raw message
include/linux/syscalls.h +7 -0
@@ -38,6 +38,7 @@ struct rlimit;struct rlimit64 ;struct rusage ;struct sched_param ; +struct sched_param2 ;struct sel_arg_struct ;struct semaphore ;struct sembuf ;
@@ -328,11 +329,17 @@ asmlinkage long sys_clock_nanosleep(clockid_t which_clock, int flags,asmlinkage long sys_nice (int increment);asmlinkage long sys_sched_setscheduler (pid_t pid,int policy,struct sched_param __user *param); +asmlinkage long sys_sched_setscheduler2 (pid_t pid,int policy, +struct sched_param2 __user *param);asmlinkage long sys_sched_setparam (pid_t pid,struct sched_param __user *param); +asmlinkage long sys_sched_setparam2 (pid_t pid, +struct sched_param2 __user *param);asmlinkage long sys_sched_getscheduler (pid_t pid);asmlinkage long sys_sched_getparam (pid_t pid,struct sched_param __user *param); +asmlinkage long sys_sched_getparam2 (pid_t pid, +struct sched_param2 __user *param);asmlinkage long sys_sched_setaffinity (pid_t pid,unsigned int len,unsigned long __user *user_mask_ptr); asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len,
kernel/sched/core.c +107 -3
155 lines not on this page · raw message
Signature · 1 line
1.7.9.5
PATCH 5/15 sched: SCHED_DEADLINE structures & implementation.
In reply to Juri LelliFrom: Dario Faggioli <[email protected]>
Introduces the data structures, constants and symbols needed for SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their initializers. Hooks for checking if a task belong to the new policy are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called SCHED_DEADLINE. It is an implementation of the Earliest Deadline First (EDF) scheduling algorithm, augmented with a mechanism (called Constant Bandwidth Server, CBS) that makes it possible to isolate the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase (instance) which is activated on a periodic or sporadic fashion. The expected (maximum) duration of such computation is called the task's runtime; the time interval by which each instance need to be completed is called the task's relative deadline. The task's absolute deadline is dynamically calculated as the time instant a task (better, an instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute deadline as the one to be executed first, while the CBS ensures each task to run for at most its runtime every (relative) deadline length time interval, avoiding any interference between different tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with the computational model sketched above can effectively use the new policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new scheduling class file;
- provides all the glue code between the new scheduling class and the core scheduler and refines the interactions between sched/dl and the other existing scheduling classes.
--- include/linux/sched.h | 70 ++++- kernel/fork.c | 4 +- kernel/hrtimer.c | 2 +- kernel/sched/Makefile | 2 +- kernel/sched/core.c | 111 ++++++-- kernel/sched/dl.c | 688 ++++++++++++++++++++++++++++++++++++++++++++++ kernel/sched/sched.h | 26 ++ kernel/sched/stop_task.c | 2 +- 8 files changed, 883 insertions(+), 22 deletions(-) create mode 100644 kernel/sched/dl.c
include/linux/sched.h +68 -2
@@ -39,6 +39,7 @@#define SCHED_BATCH 3/* SCHED_ISO: reserved but not implemented yet */ #define SCHED_IDLE 5 +#define SCHED_DEADLINE 6/* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */ #define SCHED_RESET_ON_FORK 0x40000000
@@ -130,6 +131,10 @@ struct sched_param {* timing constraints. * * @__unused padding to allow future expansion without ABI issues +* +* As of now, the SCHED_DEADLINE policy (sched_dl scheduling class) is the +* only user of this new interface. More information about the algorithm +* available in the scheduling class file or in Documentation/. */ struct sched_param2 {int sched_priority;
@@ -1117,6 +1122,7 @@ struct sched_domain;#else #define ENQUEUE_WAKING 0#endif +#define ENQUEUE_REPLENISH 8#define DEQUEUE_SLEEP 1
@@ -1248,6 +1254,47 @@ struct sched_rt_entity {#endif }; +struct sched_dl_entity { +struct rb_node rb_node; +int nr_cpus_allowed; + +/* +* Original scheduling parameters. Copied here from sched_param2 +* during sched_setscheduler2(), they will remain the same until +* the next sched_setscheduler2(). +*/ +u64 dl_runtime;/* maximum runtime for each instance */ +u64 dl_deadline;/* relative deadline of each instance */ + +/* +* Actual scheduling parameters. Initialized with the values above, +* they are continously updated during task execution. Note that +* the remaining runtime could be < 0 in case we are in overrun. +*/ +s64 runtime;/* remaining runtime for this instance */ +u64 deadline;/* absolute deadline for this instance */ +unsigned int flags;/* specifying the scheduler behaviour */ + +/* +* Some bool flags: +* +* @dl_throttled tells if we exhausted the runtime. If so, the +* task has to wait for a replenishment to be performed at the +* next firing of dl_timer. +* +* @dl_new tells if a new instance arrived. If so we must +* start executing it with full runtime and reset its absolute +* deadline; +*/ +int dl_throttled, dl_new; + +/* +* Bandwidth enforcement timer. Each -deadline task has its +* own bandwidth to be enforced, thus we need one timer per task. +*/ +struct hrtimer dl_timer; +}; +/* * default timeslice is 100 msecs (used only for SCHED_RR tasks). * Timeslices get refilled after they expire.
@@ -1281,6 +1328,7 @@ struct task_struct {const struct sched_class *sched_class;struct sched_entity se;struct sched_rt_entity rt; +struct sched_dl_entity dl;#ifdef CONFIG_PREEMPT_NOTIFIERS /* list of struct preempt_notifier: */
@@ -1637,6 +1685,10 @@ struct task_struct {* user-space. This allows kernel threads to set their * priority to a value higher than any user task. Note: * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO. +* +* SCHED_DEADLINE tasks has negative priorities, reflecting +* the fact that any of them has higher prio than RT and +* NORMAL/BATCH tasks. */ #define MAX_USER_RT_PRIO 100
@@ -1645,9 +1697,23 @@ struct task_struct {#define MAX_PRIO (MAX_RT_PRIO + 40)#define DEFAULT_PRIO (MAX_RT_PRIO + 20) +#define MAX_DL_PRIO 0 + +static inline int dl_prio (int prio) +{ +if (unlikely (prio <MAX_DL_PRIO )) +return 1 ; +return 0 ; +} + +static inline int dl_task (struct task_struct *p) +{ +return dl_prio (p->prio); +} +static inline int rt_prio (int prio) { -if (unlikely (prio <MAX_RT_PRIO )) +if ((unsigned )prio <MAX_RT_PRIO )return 1 ;return 0 ; }
@@ -2214,7 +2280,7 @@ extern void wake_up_new_task(struct task_struct *tsk);#else static inline void kick_process (struct task_struct *tsk) { }#endif -extern void sched_fork (struct task_struct *p); +extern int sched_fork (struct task_struct *p);extern void sched_dead (struct task_struct *p);extern void proc_caches_init (void );
kernel/fork.c +3 -1
@@ -1310,7 +1310,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,#endif /* Perform scheduler related setup. Assign this task to a CPU. */ -sched_fork (p); + retval =sched_fork (p); +if (retval) + goto bad_fork_cleanup_policy; retval =perf_event_init_task (p);if (retval)
kernel/hrtimer.c +1 -1
@@ -1565,7 +1565,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,unsigned long slack; slack = current->timer_slack_ns; -if (rt_task (current)) +if (dl_task (current) ||rt_task (current)) slack =0 ;hrtimer_init_on_stack (&t.timer, clockid, mode);
kernel/sched/Makefile +1 -1
@@ -11,7 +11,7 @@ ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer endif -obj-y += core.o clock.o idle_task.o fair.o rt.o stop_task.o +obj-y += core.o clock.o idle_task.o fair.o rt.o dl.o stop_task.o obj-$(CONFIG_SMP) += cpupri.o obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o obj-$(CONFIG_SCHEDSTATS) += stats.o
kernel/sched/core.c +95 -16
240 lines not on this page · raw message
kernel/sched/dl.c new file +688 -0
688 lines not on this page · raw message
kernel/sched/sched.h +26 -0
@@ -50,11 +50,23 @@ static inline int rt_policy(int policy)return 0 ; } +static inline int dl_policy (int policy) +{ +if (unlikely (policy ==SCHED_DEADLINE )) +return 1 ; +return 0 ; +} +static inline int task_has_rt_policy (struct task_struct *p) {return rt_policy (p->policy); } +static inline int task_has_dl_policy (struct task_struct *p) +{ +return dl_policy (p->policy); +} +/* * This is the priority-queue data structure of the RT scheduling class: */
@@ -309,6 +321,15 @@ struct rt_rq {#endif }; +/* Deadline class' related fields in a runqueue */ +struct dl_rq { +/* runqueue is an rbtree, ordered by deadline */ +struct rb_root rb_root; +struct rb_node *rb_leftmost; + +unsigned long dl_nr_running; +}; +#ifdef CONFIG_SMP /*
@@ -370,6 +391,7 @@ struct rq {struct cfs_rq cfs;struct rt_rq rt; +struct dl_rq dl;#ifdef CONFIG_FAIR_GROUP_SCHED /* list of leaf cfs_rq on this cpu: */
@@ -844,6 +866,7 @@ enum cpuacct_stat_index {for (class = sched_class_highest; class; class = class->next) extern const struct sched_class stop_sched_class; +extern const struct sched_class dl_sched_class;extern const struct sched_class rt_sched_class;extern const struct sched_class fair_sched_class;extern const struct sched_class idle_sched_class;
@@ -876,6 +899,8 @@ extern void resched_cpu(int cpu);extern struct rt_bandwidth def_rt_bandwidth;extern void init_rt_bandwidth (struct rt_bandwidth *rt_b,u64 period,u64 runtime); +extern void init_dl_task_timer (struct sched_dl_entity *dl_se); +extern void update_idle_cpu_load (struct rq *this_rq);#ifdef CONFIG_CGROUP_CPUACCT
@@ -1143,6 +1168,7 @@ extern void print_rt_stats(struct seq_file *m, int cpu);extern void init_cfs_rq (struct cfs_rq *cfs_rq);extern void init_rt_rq (struct rt_rq *rt_rq,struct rq *rq); +extern void init_dl_rq (struct dl_rq *rt_rq,struct rq *rq);extern void unthrottle_offline_cfs_rqs (struct rq *rq);extern void account_cfs_bandwidth_used (int enabled,int was_enabled);
kernel/sched/stop_task.c +1 -1
@@ -83,7 +83,7 @@ get_rr_interval_stop(struct rq *rq, struct task_struct *task)* Simple, special scheduling class for the per-CPU stop tasks: */ const struct sched_class stop_sched_class = { - .next = &rt_sched_class, + .next = &dl_sched_class, .enqueue_task = enqueue_task_stop, .dequeue_task = dequeue_task_stop,
Signature · 1 line
1.7.9.5
PATCH 6/15 sched: SCHED_DEADLINE SMP-related data structures & logic.
In reply to Juri LelliIntroduces data structures relevant for implementing dynamic migration of -deadline tasks and the logic for checking if runqueues are overloaded with -deadline tasks and for choosing where a task should migrate, when it is the case.
Adds also dynamic migrations to SCHED_DEADLINE, so that tasks can be moved among CPUs when necessary. It is also possible to bind a task to a (set of) CPU(s), thus restricting its capability of migrating, or forbidding migrations at all.
The very same approach used in sched_rt is utilised:
- -deadline tasks are kept into CPU-specific runqueues,
- -deadline tasks are migrated among runqueues to achieve the following:
* on an M-CPU system the M earliest deadline ready tasks are always running;
* affinity/cpusets settings of all the -deadline tasks is always respected.
Therefore, this very special form of "load balancing" is done with an active method, i.e., the scheduler pushes or pulls tasks between runqueues when they are woken up and/or (de)scheduled.
IOW, every time a preemption occurs, the descheduled task might be sent to some other CPU (depending on its deadline) to continue executing (push). On the other hand, every time a CPU becomes idle, it might pull the second earliest deadline ready task from some other CPU.
To enforce this, a pull operation is always attempted before taking any scheduling decision (pre_schedule()), as well as a push one after each scheduling decision (post_schedule()). In addition, when a task arrives or wakes up, the best CPU where to resume it is selected taking into account its affinity mask, the system topology, but also its deadline. E.g., from the scheduling point of view, the best CPU where to wake up (and also where to push) a task is the one which is running the task with the latest deadline among the M executing ones.
In order to facilitate these decisions, per-runqueue "caching" of the deadlines of the currently running and of the first ready task is used. Queued but not running tasks are also parked in another rb-tree to speed-up pushes.
--- include/linux/sched.h | 1 + kernel/sched/core.c | 10 +- kernel/sched/dl.c | 936 +++++++++++++++++++++++++++++++++++++++++++++++-- kernel/sched/rt.c | 2 +- kernel/sched/sched.h | 33 ++ 5 files changed, 952 insertions(+), 30 deletions(-)
include/linux/sched.h +1 -0
@@ -1370,6 +1370,7 @@ struct task_struct {struct list_head tasks;#ifdef CONFIG_SMP struct plist_node pushable_tasks; +struct rb_node pushable_dl_tasks;#endif struct mm_struct *mm, *active_mm;
kernel/sched/core.c +9 -1
@@ -1811,6 +1811,7 @@ int sched_fork(struct task_struct *p)#endif #ifdef CONFIG_SMP plist_node_init (&p->pushable_tasks,MAX_PRIO ); +RB_CLEAR_NODE (&p->pushable_dl_tasks);#endif put_cpu ();
@@ -5164,6 +5165,7 @@ void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask)cpumask_copy (&p->cpus_allowed, new_mask); p->rt.nr_cpus_allowed =cpumask_weight (new_mask); + p->dl.nr_cpus_allowed =cpumask_weight (new_mask); }/*
@@ -5880,6 +5882,7 @@ static void free_rootdomain(struct rcu_head *rcu) struct root_domain *rd = container_of(rcu, struct root_domain, rcu);cpupri_cleanup (&rd->cpupri); +free_cpumask_var (rd->dlo_mask);free_cpumask_var (rd->rto_mask);free_cpumask_var (rd->online);free_cpumask_var (rd->span);
@@ -5931,8 +5934,10 @@ static int init_rootdomain(struct root_domain *rd) goto out;if (!alloc_cpumask_var (&rd->online,GFP_KERNEL )) goto free_span; -if (!alloc_cpumask_var (&rd->rto_mask,GFP_KERNEL )) +if (!alloc_cpumask_var (&rd->dlo_mask,GFP_KERNEL )) goto free_online; +if (!alloc_cpumask_var (&rd->rto_mask,GFP_KERNEL )) + goto free_dlo_mask;if (cpupri_init (&rd->cpupri) !=0 ) goto free_rto_mask;
@@ -5940,6 +5945,8 @@ static int init_rootdomain(struct root_domain *rd) free_rto_mask:free_cpumask_var (rd->rto_mask); +free_dlo_mask: +free_cpumask_var (rd->dlo_mask); free_online:free_cpumask_var (rd->online); free_span:
@@ -7060,6 +7067,7 @@ void __init sched_init_smp(void)free_cpumask_var (non_isolated_cpus);init_sched_rt_class (); + init_sched_dl_class(); }#else void __init sched_init_smp (void )
kernel/sched/dl.c +908 -28
1,056 lines not on this page · raw message
kernel/sched/rt.c +1 -1
@@ -1794,7 +1794,7 @@ static void task_woken_rt(struct rq *rq, struct task_struct *p) !test_tsk_need_resched (rq->curr) &&has_pushable_tasks (rq) && p->rt.nr_cpus_allowed >1 && -rt_task (rq->curr) && + (dl_task (rq->curr) ||rt_task (rq->curr)) && (rq->curr->rt.nr_cpus_allowed <2 || rq->curr->prio <= p->prio)) push_rt_tasks(rq);
kernel/sched/sched.h +33 -0
@@ -328,6 +328,31 @@ struct dl_rq {struct rb_node *rb_leftmost;unsigned long dl_nr_running; + +#ifdef CONFIG_SMP +/* +* Deadline values of the currently executing and the +* earliest ready task on this rq. Caching these facilitates +* the decision wether or not a ready but not running task +* should migrate somewhere else. +*/ +struct { +u64 curr; +u64 next; + } earliest_dl; + +unsigned long dl_nr_migratory; +unsigned long dl_nr_total; +int overloaded; + +/* +* Tasks on this rq that can be pushed away. They are kept in +* an rb-tree, ordered by tasks' deadlines, with caching +* of the leftmost (earliest deadline) element. +*/ +struct rb_root pushable_dl_tasks_root; +struct rb_node *pushable_dl_tasks_leftmost; +#endif };#ifdef CONFIG_SMP
@@ -348,6 +373,13 @@ struct root_domain {cpumask_var_t online;/* +* The bit corresponding to a CPU gets set here if such CPU has more +* than one runnable -deadline task (as it is below for RT tasks). +*/ +cpumask_var_t dlo_mask; +atomic_t dlo_count; + +/* * The "RT overload" flag: it gets set if a CPU has more than * one runnable RT task. */
@@ -890,6 +922,7 @@ extern void sched_init_granularity(void);extern void update_max_interval (void );extern void update_group_power (struct sched_domain *sd,int cpu);extern int update_runtime (struct notifier_block *nfb,unsigned long action,void *hcpu); +extern void init_sched_dl_class (void );extern void init_sched_rt_class (void );extern void init_sched_fair_class (void );
Signature · 1 line
1.7.9.5
PATCH 7/15 sched: SCHED_DEADLINE avg_update accounting.
In reply to Juri LelliFrom: Dario Faggioli <[email protected]>
Make the core scheduler and load balancer aware of the load produced by -deadline tasks, by updating the moving average like for sched_rt.
--- kernel/sched/dl.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/sched/dl.c +2 -0
@@ -554,6 +554,8 @@ static void update_curr_dl(struct rq *rq) curr->se.exec_start = rq->clock_task;cpuacct_charge (curr, delta_exec); +sched_rt_avg_update (rq, delta_exec); + dl_se->runtime -= delta_exec;if (dl_runtime_exceeded (rq, dl_se)) {__dequeue_task_dl (rq, curr,0 );
Signature · 1 line
1.7.9.5
PATCH 8/15 sched: add period support for -deadline tasks.
In reply to Juri LelliFrom: Harald Gustafsson <[email protected]>
Make it possible to specify a period (different or equal than deadline) for -deadline tasks.
--- include/linux/sched.h | 1 + kernel/sched/core.c | 15 ++++++++++++--- kernel/sched/dl.c | 10 +++++++--- 3 files changed, 20 insertions(+), 6 deletions(-)
include/linux/sched.h +1 -0
@@ -1265,6 +1265,7 @@ struct sched_dl_entity {*/ u64 dl_runtime;/* maximum runtime for each instance */ u64 dl_deadline;/* relative deadline of each instance */ +u64 dl_period;/* separation of two instances (period) */ /* * Actual scheduling parameters. Initialized with the values above,
kernel/sched/core.c +12 -3
@@ -1724,6 +1724,7 @@ static void __sched_fork(struct task_struct *p)hrtimer_init (&p->dl.dl_timer,CLOCK_MONOTONIC ,HRTIMER_MODE_REL ); p->dl.dl_runtime = p->dl.runtime =0 ; p->dl.dl_deadline = p->dl.deadline =0 ; + p->dl.dl_period =0 ; p->dl.flags =0 ;INIT_LIST_HEAD (&p->rt.run_list);
@@ -4092,6 +4093,10 @@ __setparam_dl(struct task_struct *p, const struct sched_param2 *param2)init_dl_task_timer (dl_se); dl_se->dl_runtime = param2->sched_runtime; dl_se->dl_deadline = param2->sched_deadline; +if (param2->sched_period !=0 ) + dl_se->dl_period = param2->sched_period; +else + dl_se->dl_period = dl_se->dl_deadline; dl_se->flags = param2->sched_flags; dl_se->dl_throttled =0 ; dl_se->dl_new =1 ;
@@ -4105,19 +4110,23 @@ __getparam_dl(struct task_struct *p, struct sched_param2 *param2) param2->sched_priority = p->rt_priority; param2->sched_runtime = dl_se->dl_runtime; param2->sched_deadline = dl_se->dl_deadline; + param2->sched_period = dl_se->dl_period; param2->sched_flags = dl_se->flags; }/* * This function validates the new parameters of a -deadline task. * We ask for the deadline not being zero, and greater or equal -* than the runtime. +* than the runtime, as well as the period of being zero or +* greater than deadline. */ static bool __checkparam_dl (const struct sched_param2 *prm) { -return prm && (&prm->sched_deadline) !=0 && - (s64)(&prm->sched_deadline - &prm->sched_runtime) >=0 ; +return prm && prm->sched_deadline !=0 && + (prm->sched_period ==0 || + (s64)(prm->sched_period - prm->sched_deadline) >=0 ) && + (s64)(prm->sched_deadline - prm->sched_runtime) >=0 ; }/*
kernel/sched/dl.c +7 -3
@@ -286,7 +286,7 @@ static void replenish_dl_entity(struct sched_dl_entity *dl_se)* arbitrary large. */ while (dl_se->runtime <=0 ) { - dl_se->deadline += dl_se->dl_deadline; + dl_se->deadline += dl_se->dl_period; dl_se->runtime += dl_se->dl_runtime; }
@@ -326,9 +326,13 @@ static void replenish_dl_entity(struct sched_dl_entity *dl_se)* * This function returns true if: * -* runtime / (deadline - t) > dl_runtime / dl_deadline , +* runtime / (deadline - t) > dl_runtime / dl_period , * * IOW we can't recycle current parameters. +* +* Notice that the bandwidth check is done against the period. For +* task with deadline equal to period this is the same of using +* dl_deadline instead of dl_period in the equation above. */ static bool dl_entity_overflow (struct sched_dl_entity *dl_se,u64 t) {
@@ -347,7 +351,7 @@ static bool dl_entity_overflow(struct sched_dl_entity *dl_se, u64 t)* to the (absolute) deadline. Therefore, overflowing the u64 * type is very unlikely to occur in both cases. */ - left =mul_u64_u64 (dl_se->dl_deadline, dl_se->runtime); + left =mul_u64_u64 (dl_se->dl_period, dl_se->runtime); right =mul_u64_u64 ((dl_se->deadline - t), dl_se->dl_runtime);if (cmp_u128 (left, right) >0 )
Signature · 1 line
1.7.9.5
PATCH 9/15 sched: add schedstats for -deadline tasks.
In reply to Juri LelliFrom: Dario Faggioli <[email protected]>
Add some typical sched-debug output to dl_rq(s) and some schedstats to -deadline tasks.
--- include/linux/sched.h | 13 +++++++++++++ kernel/sched/debug.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ kernel/sched/dl.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ kernel/sched/sched.h | 9 ++++++++- 4 files changed, 112 insertions(+), 1 deletion(-)
include/linux/sched.h +13 -0
@@ -1254,6 +1254,15 @@ struct sched_rt_entity {#endif }; +#ifdef CONFIG_SCHEDSTATS +struct sched_stats_dl { +u64 last_dmiss; +u64 last_rorun; +u64 dmiss_max; +u64 rorun_max; +}; +#endif +struct sched_dl_entity {struct rb_node rb_node;int nr_cpus_allowed;
@@ -1294,6 +1303,10 @@ struct sched_dl_entity {* own bandwidth to be enforced, thus we need one timer per task. */ struct hrtimer dl_timer; + +#ifdef CONFIG_SCHEDSTATS +struct sched_stats_dl stats; +#endif };/*
kernel/sched/debug.c +46 -0
64 lines not on this page · raw message
kernel/sched/dl.c +45 -0
66 lines not on this page · raw message
kernel/sched/sched.h +8 -1
@@ -329,6 +329,8 @@ struct dl_rq {unsigned long dl_nr_running; +u64 exec_clock; +#ifdef CONFIG_SMP /* * Deadline values of the currently executing and the
@@ -355,6 +357,11 @@ struct dl_rq {#endif }; +#ifdef CONFIG_SCHED_DEBUG +struct sched_dl_entity *__pick_dl_last_entity (struct dl_rq *dl_rq); +void print_dl_stats (struct seq_file *m,int cpu); +#endif +#ifdef CONFIG_SMP /*
@@ -1201,7 +1208,7 @@ extern void print_rt_stats(struct seq_file *m, int cpu);extern void init_cfs_rq (struct cfs_rq *cfs_rq);extern void init_rt_rq (struct rt_rq *rt_rq,struct rq *rq); -extern void init_dl_rq (struct dl_rq *rt_rq,struct rq *rq); +extern void init_dl_rq (struct dl_rq *dl_rq,struct rq *rq);extern void unthrottle_offline_cfs_rqs (struct rq *rq);extern void account_cfs_bandwidth_used (int enabled,int was_enabled);
Signature · 1 line
1.7.9.5
PATCH 10/15 sched: add latency tracing for -deadline tasks.
In reply to Juri LelliFrom: Dario Faggioli <[email protected]>
It is very likely that systems that wants/needs to use the new SCHED_DEADLINE policy also want to have the scheduling latency of the -deadline tasks under control.
For this reason a new version of the scheduling wakeup latency, called "wakeup_dl", is introduced.
As a consequence of applying this patch there will be three wakeup latency tracer:
* "wakeup", that deals with all tasks in the system;
* "wakeup_rt", that deals with -rt and -deadline tasks only;
* "wakeup_dl", that deals with -deadline tasks only.
--- kernel/trace/trace_sched_wakeup.c | 44 +++++++++++++++++++++++++++++++++---- kernel/trace/trace_selftest.c | 30 +++++++++++++++---------- 2 files changed, 58 insertions(+), 16 deletions(-)
kernel/trace/trace_sched_wakeup.c +40 -4
@@ -27,6 +27,7 @@ static int wakeup_cpu;static int wakeup_current_cpu;static unsigned wakeup_prio =-1 ;static int wakeup_rt; +static int wakeup_dl;static arch_spinlock_t wakeup_lock = (arch_spinlock_t )__ARCH_SPIN_LOCK_UNLOCKED;
@@ -428,9 +429,17 @@ probe_wakeup(void *ignore, struct task_struct *p, int success)tracing_record_cmdline (p);tracing_record_cmdline (current); -if ((wakeup_rt && !rt_task (p)) || - p->prio >= wakeup_prio || - p->prio >= current->prio) +/* +* Semantic is like this: +* - wakeup tracer handles all tasks in the system, independently +* from their scheduling class; +* - wakeup_rt tracer handles tasks belonging to sched_dl and +* sched_rt class; +* - wakeup_dl handles tasks belonging to sched_dl class only. +*/ +if ((wakeup_dl && !dl_task (p)) || + (wakeup_rt && !dl_task (p) && !rt_task (p)) || + (p->prio >= wakeup_prio || p->prio >= current->prio))return ; pc =preempt_count ();
@@ -442,7 +451,7 @@ probe_wakeup(void *ignore, struct task_struct *p, int success)arch_spin_lock (&wakeup_lock);/* check for races. */ -if (!tracer_enabled || p->prio >= wakeup_prio) +if (!tracer_enabled || (!dl_task (p) && p->prio >= wakeup_prio)) goto out_locked;/* reset the trace */
@@ -550,16 +559,25 @@ static int __wakeup_tracer_init(struct trace_array *tr)static int wakeup_tracer_init (struct trace_array *tr) { + wakeup_dl =0 ; wakeup_rt =0 ;return __wakeup_tracer_init (tr); }static int wakeup_rt_tracer_init (struct trace_array *tr) { + wakeup_dl =0 ; wakeup_rt =1 ;return __wakeup_tracer_init (tr); } +static int wakeup_dl_tracer_init (struct trace_array *tr) +{ + wakeup_dl =1 ; + wakeup_rt =0 ; +return __wakeup_tracer_init (tr); +} +static void wakeup_tracer_reset (struct trace_array *tr) {stop_wakeup_tracer (tr);
@@ -622,6 +640,20 @@ static struct tracer wakeup_rt_tracer __read_mostly = .use_max_tr = 1, }; +static struct tracer wakeup_dl_tracer__read_mostly = +{ + .name ="wakeup_dl" , + .init = wakeup_dl_tracer_init, + .reset = wakeup_tracer_reset, + .start = wakeup_tracer_start, + .stop = wakeup_tracer_stop, + .wait_pipe = poll_wait_pipe, + .print_max =1 , +#ifdef CONFIG_FTRACE_SELFTEST + .selftest = trace_selftest_startup_wakeup, +#endif +}; +__init static int init_wakeup_tracer (void ) {int ret;
@@ -634,6 +666,10 @@ __init static int init_wakeup_tracer(void)if (ret)return ret; + ret =register_tracer (&wakeup_dl_tracer); +if (ret) +return ret; +return 0 ; }device_initcall (init_wakeup_tracer);
kernel/trace/trace_selftest.c +18 -12
@@ -765,11 +765,17 @@ trace_selftest_startup_nop(struct tracer *trace, struct trace_array *tr)#ifdef CONFIG_SCHED_TRACER static int trace_wakeup_test_thread (void *data) { -/* Make this a RT thread, doesn't need to be too high */ -static const struct sched_param param = { .sched_priority =5 }; +/* Make this a -deadline thread */ +struct sched_param2 paramx = { + .sched_priority =0 , + .sched_runtime =100000ULL , + .sched_deadline =10000000ULL , + .sched_period =10000000ULL + .sched_flags =0 + };struct completion *x = data; -sched_setscheduler (current,SCHED_FIFO , ¶m); +sched_setscheduler2 (current,SCHED_DEADLINE , ¶mx);/* Make it know we have a new prio */ complete (x);
@@ -781,8 +787,8 @@ static int trace_wakeup_test_thread(void *data)/* we are awake, now wait to disappear */ while (!kthread_should_stop ()) {/* -* This is an RT task, do short sleeps to let -* others run. +* This will likely be the system top priority +* task, do short sleeps to let others run. */ msleep (100 ); }
@@ -795,21 +801,21 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr) {unsigned long save_max = tracing_max_latency;struct task_struct *p; -struct completion isrt; +struct completion is_ready;unsigned long count;int ret; -init_completion (&isrt); +init_completion (&is_ready); -/* create a high prio thread */ - p =kthread_run (trace_wakeup_test_thread, &isrt,"ftrace-test" ); +/* create a -deadline thread */ + p =kthread_run (trace_wakeup_test_thread, &is_ready,"ftrace-test" );if (IS_ERR (p)) {printk (KERN_CONT "Failed to create ftrace wakeup test thread " );return -1 ; } -/* make sure the thread is running at an RT prio */ -wait_for_completion (&isrt); +/* make sure the thread is running at -deadline policy */ +wait_for_completion (&is_ready);/* start the tracing */ ret =tracer_init (trace, tr);
@@ -821,7 +827,7 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr)/* reset the max latency */ tracing_max_latency =0 ; -/* sleep to let the RT thread sleep too */ +/* sleep to let the thread sleep too */ msleep (100 );/*
Signature · 1 line
1.7.9.5
PATCH 11/15 rtmutex: turn the plist into an rb-tree.
In reply to Juri LelliFrom: Peter Zijlstra <[email protected]>
Turn the pi-chains from plist to rb-tree, in the rt_mutex code, and provide a proper comparison function for -deadline and -priority tasks.
This is done mainly because:
- classical prio field of the plist is just an int, which might not be enough for representing a deadline;
- manipulating such a list would become O(nr_deadline_tasks), which might be to much, as the number of -deadline task increases.
Therefore, an rb-tree is used, and tasks are queued in it according to the following logic:
- among two -priority (i.e., SCHED_BATCH/OTHER/RR/FIFO) tasks, the one with the higher (lower, actually!) prio wins;
- among a -priority and a -deadline task, the latter always wins;
- among two -deadline tasks, the one with the earliest deadline wins.
Queueing and dequeueing functions are changed accordingly, for both the list of a task's pi-waiters and the list of tasks blocked on a pi-lock.
--- include/linux/init_task.h | 10 +++ include/linux/rtmutex.h | 18 ++---- include/linux/sched.h | 4 +- kernel/fork.c | 3 +- kernel/rtmutex-debug.c | 10 ++- kernel/rtmutex.c | 150 +++++++++++++++++++++++++++++++++++---------- kernel/rtmutex_common.h | 22 +++---- kernel/sched/core.c | 4 -- 8 files changed, 155 insertions(+), 66 deletions(-)
include/linux/init_task.h +10 -0
@@ -10,6 +10,7 @@#include <linux/pid_namespace.h> #include <linux/user_namespace.h> #include <linux/securebits.h> +#include <linux/rbtree.h> #include <net/net_namespace.h> #ifdef CONFIG_SMP
@@ -134,6 +135,14 @@ extern struct cred init_cred;#define INIT_TASK_COMM "swapper" +#ifdef CONFIG_RT_MUTEXES +# define INIT_RT_MUTEXES (tsk) \ + .pi_waiters = RB_ROOT, \ + .pi_waiters_leftmost = NULL, +#else +# define INIT_RT_MUTEXES (tsk) +#endif +/* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -200,6 +209,7 @@ extern struct cred init_cred; INIT_TRACE_RECURSION \ INIT_TASK_RCU_PREEMPT(tsk) \ INIT_CPUSET_SEQ \ + INIT_RT_MUTEXES(tsk) \ }
include/linux/rtmutex.h +6 -12
@@ -13,7 +13,7 @@#define __LINUX_RT_MUTEX_H#include <linux/linkage.h> -#include <linux/plist.h> +#include <linux/rbtree.h> #include <linux/spinlock_types.h> extern int max_lock_depth;/* for sysctl */
@@ -22,12 +22,14 @@ extern int max_lock_depth; /* for sysctl */* The rt_mutex structure * * @wait_lock: spinlock to protect the structure -* @wait_list: pilist head to enqueue waiters in priority order +* @waiters: rbtree root to enqueue waiters in priority order +* @waiters_leftmost: top waiter * @owner: the mutex owner */ struct rt_mutex {raw_spinlock_t wait_lock; -struct plist_head wait_list; +struct rb_root waiters; +struct rb_node *waiters_leftmost;struct task_struct *owner;#ifdef CONFIG_DEBUG_RT_MUTEXES int save_state;
@@ -66,7 +68,7 @@ struct hrtimer_sleeper;#define __RT_MUTEX_INITIALIZER (mutexname) \ { .wait_lock = __RAW_SPIN_LOCK_UNLOCKED(mutexname.wait_lock) \ - , .wait_list = PLIST_HEAD_INIT(mutexname.wait_list) \ + , .waiters = RB_ROOT \ , .owner = NULL \ __DEBUG_RT_MUTEX_INITIALIZER(mutexname)}
@@ -98,12 +100,4 @@ extern int rt_mutex_trylock(struct rt_mutex *lock);extern void rt_mutex_unlock (struct rt_mutex *lock); -#ifdef CONFIG_RT_MUTEXES -# define INIT_RT_MUTEXES (tsk) \ - .pi_waiters = PLIST_HEAD_INIT(tsk.pi_waiters), \ - INIT_RT_MUTEX_DEBUG(tsk) -#else -# define INIT_RT_MUTEXES (tsk) -#endif -#endif
include/linux/sched.h +3 -1
@@ -57,6 +57,7 @@ struct sched_param {#include <linux/types.h> #include <linux/timex.h> #include <linux/jiffies.h> +#include <linux/plist.h> #include <linux/rbtree.h> #include <linux/thread_info.h> #include <linux/cpumask.h>
@@ -1531,7 +1532,8 @@ struct task_struct {#ifdef CONFIG_RT_MUTEXES /* PI waiters blocked on a rt_mutex held by this task */ -struct plist_head pi_waiters; +struct rb_root pi_waiters; +struct rb_node *pi_waiters_leftmost;/* Deadlock detection and priority inheritance handling */ struct rt_mutex_waiter *pi_blocked_on;#endif
kernel/fork.c +2 -1
@@ -1111,7 +1111,8 @@ static void rt_mutex_init_task(struct task_struct *p) {raw_spin_lock_init (&p->pi_lock);#ifdef CONFIG_RT_MUTEXES -plist_head_init (&p->pi_waiters); + p->pi_waiters =RB_ROOT ; + p->pi_waiters_leftmost =NULL ; p->pi_blocked_on =NULL ;#endif }
kernel/rtmutex-debug.c +4 -6
@@ -23,7 +23,7 @@#include <linux/kallsyms.h> #include <linux/syscalls.h> #include <linux/interrupt.h> -#include <linux/plist.h> +#include <linux/rbtree.h> #include <linux/fs.h> #include <linux/debug_locks.h>
@@ -56,7 +56,7 @@ static void printk_lock(struct rt_mutex *lock, int print_owner)void rt_mutex_debug_task_free (struct task_struct *task) { -DEBUG_LOCKS_WARN_ON (!plist_head_empty (&task->pi_waiters)); +DEBUG_LOCKS_WARN_ON (!RB_EMPTY_ROOT (&task->pi_waiters));DEBUG_LOCKS_WARN_ON (task->pi_blocked_on); }
@@ -153,16 +153,14 @@ void debug_rt_mutex_proxy_unlock(struct rt_mutex *lock)void debug_rt_mutex_init_waiter (struct rt_mutex_waiter *waiter) {memset (waiter,0x11 ,sizeof (*waiter)); -plist_node_init (&waiter->list_entry,MAX_PRIO ); -plist_node_init (&waiter->pi_list_entry,MAX_PRIO ); +RB_CLEAR_NODE (&waiter->pi_tree_entry); +RB_CLEAR_NODE (&waiter->tree_entry); waiter->deadlock_task_pid =NULL ; }void debug_rt_mutex_free_waiter (struct rt_mutex_waiter *waiter) {put_pid (waiter->deadlock_task_pid); -DEBUG_LOCKS_WARN_ON (!plist_node_empty (&waiter->list_entry)); -DEBUG_LOCKS_WARN_ON (!plist_node_empty (&waiter->pi_list_entry));memset (waiter,0x22 ,sizeof (*waiter)); }
kernel/rtmutex.c +119 -31
261 lines not on this page · raw message
kernel/rtmutex_common.h +11 -11
@@ -40,13 +40,13 @@ extern void schedule_rt_mutex_test(struct rt_mutex *lock);* This is the control structure for tasks blocked on a rt_mutex, * which is allocated on the kernel stack on of the blocked task. * -* @list_entry: pi node to enqueue into the mutex waiters list -* @pi_list_entry: pi node to enqueue into the mutex owner waiters list +* @tree_entry: pi node to enqueue into the mutex waiters tree +* @pi_tree_entry: pi node to enqueue into the mutex owner waiters tree * @task: task reference to the blocked task */ struct rt_mutex_waiter { -struct plist_node list_entry; -struct plist_node pi_list_entry; +struct rb_node tree_entry; +struct rb_node pi_tree_entry;struct task_struct *task;struct rt_mutex *lock;#ifdef CONFIG_DEBUG_RT_MUTEXES
@@ -57,11 +57,11 @@ struct rt_mutex_waiter { };/* -* Various helpers to access the waiters-plist: +* Various helpers to access the waiters-tree: */ static inline int rt_mutex_has_waiters (struct rt_mutex *lock) { -return !plist_head_empty (&lock->wait_list); +return !RB_EMPTY_ROOT (&lock->waiters); } static inline struct rt_mutex_waiter *
@@ -69,8 +69,8 @@ rt_mutex_top_waiter(struct rt_mutex *lock) {struct rt_mutex_waiter *w; - w = plist_first_entry(&lock->wait_list, struct rt_mutex_waiter, - list_entry); + w = rb_entry(lock->waiters_leftmost, struct rt_mutex_waiter, + tree_entry);BUG_ON (w->lock != lock);return w;
@@ -78,14 +78,14 @@ rt_mutex_top_waiter(struct rt_mutex *lock)static inline int task_has_pi_waiters (struct task_struct *p) { -return !plist_head_empty (&p->pi_waiters); +return !RB_EMPTY_ROOT (&p->pi_waiters); }static inline struct rt_mutex_waiter *task_top_pi_waiter (struct task_struct *p) { - return plist_first_entry(&p->pi_waiters, struct rt_mutex_waiter, - pi_list_entry); + return rb_entry(p->pi_waiters_leftmost, struct rt_mutex_waiter, + pi_tree_entry); }/*
kernel/sched/core.c +0 -4
@@ -7245,10 +7245,6 @@ void __init sched_init(void)INIT_HLIST_HEAD (&init_task.preempt_notifiers);#endif -#ifdef CONFIG_RT_MUTEXES -plist_head_init (&init_task.pi_waiters); -#endif -/* * The boot idle thread does lazy MMU switching as well: */
Signature · 1 line
1.7.9.5
PATCH 12/15 sched: drafted deadline inheritance logic.
In reply to Juri LelliFrom: Dario Faggioli <[email protected]>
Some method to deal with rt-mutexes and make sched_dl interact with the current PI-coded is needed, raising all but trivial issues, that needs (according to us) to be solved with some restructuring of the pi-code (i.e., going toward a proxy execution-ish implementation).
This is under development, in the meanwhile, as a temporary solution, what this commits does is:
- ensure a pi-lock owner with waiters is never throttled down. Instead, when it runs out of runtime, it immediately gets replenished and it's deadline is postponed;
- the scheduling parameters (relative deadline and default runtime) used for that replenishments --during the whole period it holds the pi-lock-- are the ones of the waiting task with earliest deadline.
Acting this way, we provide some kind of boosting to the lock-owner, still by using the existing (actually, slightly modified by the previous commit) pi-architecture.
We would stress the fact that this is only a surely needed, all but clean solution to the problem. In the end it's only a way to re-start discussion within the community. So, as always, comments, ideas, rants, etc.. are welcome! :-)
--- include/linux/sched.h | 9 ++++- kernel/fork.c | 1 + kernel/rtmutex.c | 13 +++++-- kernel/sched/core.c | 34 +++++++++++++++--- kernel/sched/dl.c | 91 ++++++++++++++++++++++++++++--------------------- kernel/sched/sched.h | 14 ++++++++ 6 files changed, 116 insertions(+), 46 deletions(-)
include/linux/sched.h +8 -1
@@ -1296,8 +1296,12 @@ struct sched_dl_entity {* @dl_new tells if a new instance arrived. If so we must * start executing it with full runtime and reset its absolute * deadline; +* +* @dl_boosted tells if we are boosted due to DI. If so we are +* outside bandwidth enforcement mechanism (but only until we +* exit the critical section). */ -int dl_throttled, dl_new; +int dl_throttled, dl_new, dl_boosted;/* * Bandwidth enforcement timer. Each -deadline task has its
@@ -1536,6 +1540,8 @@ struct task_struct {struct rb_node *pi_waiters_leftmost;/* Deadlock detection and priority inheritance handling */ struct rt_mutex_waiter *pi_blocked_on; +/* Top pi_waiters task */ +struct task_struct *pi_top_task;#endif #ifdef CONFIG_DEBUG_MUTEXES
@@ -2187,6 +2193,7 @@ extern unsigned int sysctl_sched_cfs_bandwidth_slice;#ifdef CONFIG_RT_MUTEXES extern int rt_mutex_getprio (struct task_struct *p);extern void rt_mutex_setprio (struct task_struct *p,int prio); +extern struct task_struct *rt_mutex_get_top_task (struct task_struct *task);extern void rt_mutex_adjust_pi (struct task_struct *p);static inline bool tsk_is_pi_blocked (struct task_struct *tsk) {
kernel/fork.c +1 -0
@@ -1114,6 +1114,7 @@ static void rt_mutex_init_task(struct task_struct *p) p->pi_waiters =RB_ROOT ; p->pi_waiters_leftmost =NULL ; p->pi_blocked_on =NULL ; + p->pi_top_task =NULL ;#endif }
kernel/rtmutex.c +11 -2
@@ -199,6 +199,14 @@ int rt_mutex_getprio(struct task_struct *task) task->normal_prio); } +struct task_struct *rt_mutex_get_top_task (struct task_struct *task) +{ +if (likely (!task_has_pi_waiters (task))) +return NULL ; + +return task_top_pi_waiter (task)->task; +} +/* * Adjust the priority of a task, after its pi_waiters got modified. *
@@ -208,7 +216,7 @@ static void __rt_mutex_adjust_prio(struct task_struct *task) {int prio =rt_mutex_getprio (task); -if (task->prio != prio) +if (task->prio != prio ||dl_prio (prio))rt_mutex_setprio (task, prio); }
@@ -638,7 +646,8 @@ void rt_mutex_adjust_pi(struct task_struct *task)raw_spin_lock_irqsave (&task->pi_lock, flags); waiter = task->pi_blocked_on; -if (!waiter || waiter->task->prio == task->prio) { +if (!waiter || (waiter->task->prio == task->prio && + !dl_prio (task->prio))) {raw_spin_unlock_irqrestore (&task->pi_lock, flags);return ; }
kernel/sched/core.c +29 -5
@@ -3838,7 +3838,7 @@ EXPORT_SYMBOL(sleep_on_timeout);*/ void rt_mutex_setprio (struct task_struct *p,int prio) { -int oldprio, on_rq, running; +int oldprio, on_rq, running, enqueue_flag =0 ;struct rq *rq;const struct sched_class *prev_class;
@@ -3865,6 +3865,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio) }trace_sched_pi_setprio (p, prio); + p->pi_top_task =rt_mutex_get_top_task (p); oldprio = p->prio; prev_class = p->sched_class; on_rq = p->on_rq;
@@ -3874,19 +3875,42 @@ void rt_mutex_setprio(struct task_struct *p, int prio)if (running) p->sched_class->put_prev_task (rq, p); -if (dl_prio (prio)) +/* +* Boosting condition are: +* 1. -rt task is running and holds mutex A +* --> -dl task blocks on mutex A +* +* 2. -dl task is running and holds mutex A +* --> -dl task blocks on mutex A and could preempt the +* running task +*/ +if (dl_prio (prio)) { +if (!dl_prio (p->normal_prio) || (p->pi_top_task && +dl_entity_preempt (&p->pi_top_task->dl, &p->dl))) { + p->dl.dl_boosted =1 ; + p->dl.dl_throttled =0 ; + enqueue_flag =ENQUEUE_REPLENISH ; + }else + p->dl.dl_boosted =0 ; p->sched_class = &dl_sched_class; -else if (rt_prio (prio)) + }else if (rt_prio (prio)) { +if (dl_prio (oldprio)) + p->dl.dl_boosted =0 ; +if (oldprio < prio) + enqueue_flag =ENQUEUE_HEAD ; p->sched_class = &rt_sched_class; -else + }else { +if (dl_prio (oldprio)) + p->dl.dl_boosted =0 ; p->sched_class = &fair_sched_class; + } p->prio = prio;if (running) p->sched_class->set_curr_task (rq);if (on_rq) -enqueue_task (rq, p, oldprio < prio ?ENQUEUE_HEAD :0 ); +enqueue_task (rq, p, enqueue_flag);check_class_changed (rq, p, prev_class, oldprio); out_unlock:
kernel/sched/dl.c +53 -38
208 lines not on this page · raw message
kernel/sched/sched.h +14 -0
@@ -67,6 +67,20 @@ static inline int task_has_dl_policy(struct task_struct *p)return dl_policy (p->policy); } +static inline int dl_time_before (u64 a,u64 b) +{ +return (s64)(a - b) <0 ; +} + +/* +* Tells if entity @a should preempt entity @b. +*/ +static inline +int dl_entity_preempt (struct sched_dl_entity *a,struct sched_dl_entity *b) +{ +return dl_time_before (a->deadline, b->deadline); +} +/* * This is the priority-queue data structure of the RT scheduling class: */
Signature · 1 line
1.7.9.5
PATCH 13/15 sched: add bandwidth management for sched_dl.
In reply to Juri LelliFrom: Dario Faggioli <[email protected]>
In order of -deadline scheduling to be effective and useful, it is important that some method of having the allocation of the available CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed at all, no guarantee can be given on the actual scheduling of the -deadline tasks.
Since when RT-throttling has been introduced each task group have a bandwidth associated to itself, calculated as a certain amount of runtime over a period. Moreover, to make it possible to manipulate such bandwidth, readable/writable controls have been added to both procfs (for system wide settings) and cgroupfs (for per-group settings).
Therefore, the same interface is being used for controlling the bandwidth distrubution to -deadline tasks and task groups, i.e., new controls but with similar names, equivalent meaning and with the same usage paradigm are added.
However, more discussion is needed in order to figure out how we want to manage SCHED_DEADLINE bandwidth at the task group level. Therefore, this patch adds a less sophisticated, but actually very sensible, mechanism to ensure that a certain utilization cap is not overcome per each root_domain (the single rq for !SMP configurations).
Another main difference between deadline bandwidth management and RT-throttling is that -deadline tasks have bandwidth on their own (while -rt ones doesn't!), and thus we don't need an higher level throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces that the sum of how much bandwidth is being devoted to -rt -deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and be thus free of oversubscribing the system up to any arbitrary level.
--- include/linux/sched.h | 8 + kernel/sched/core.c | 413 ++++++++++++++++++++++++++++++++++++++++++++++--- kernel/sched/dl.c | 45 +++++- kernel/sched/sched.h | 67 +++++++- kernel/sysctl.c | 14 ++ 5 files changed, 518 insertions(+), 29 deletions(-)
include/linux/sched.h +8 -0
@@ -1276,6 +1276,7 @@ struct sched_dl_entity {u64 dl_runtime;/* maximum runtime for each instance */ u64 dl_deadline;/* relative deadline of each instance */ u64 dl_period;/* separation of two instances (period) */ +u64 dl_bw;/* dl_runtime / dl_deadline */ /* * Actual scheduling parameters. Initialized with the values above,
@@ -2168,6 +2169,13 @@ int sched_rt_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); +extern unsigned int sysctl_sched_dl_period; +extern int sysctl_sched_dl_runtime; + +int sched_dl_handler (struct ctl_table *table,int write, +void __user *buffer,size_t *lenp, +loff_t *ppos); +#ifdef CONFIG_SCHED_AUTOGROUP extern unsigned int sysctl_sched_autogroup_enabled;
kernel/sched/core.c +391 -22
530 lines not on this page · raw message
kernel/sched/dl.c +41 -4
87 lines not on this page · raw message
kernel/sched/sched.h +64 -3
118 lines not on this page · raw message
kernel/sysctl.c +14 -0
@@ -352,6 +352,20 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = sched_rt_handler, }, + { + .procname = "sched_dl_period_us", + .data = &sysctl_sched_dl_period, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = sched_dl_handler, + }, + { + .procname = "sched_dl_runtime_us", + .data = &sysctl_sched_dl_runtime, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = sched_dl_handler, + }, #ifdef CONFIG_SCHED_AUTOGROUP { .procname = "sched_autogroup_enabled",
Signature · 1 line
1.7.9.5
Peter Zijlstra
maintainerRe: [PATCH 13/15] sched: add bandwidth management for sched_dl.
Quoted 5 lines · Juri Lelli
+/*
+ * Coupling of -dl and -rt bandwidth.
+ *
+ * Here we check, while setting the system wide bandwidth available
+ * for -dl tasks and groups, if the new values are consistent with
Quoted 8 lines
+ * the system settings for the bandwidth available to -rt entities.
+ *
+ * IOW, we want to enforce that
+ *
+ *rt_bandwidth+dl_bandwidth<= 100%
+ *
+ * is always true.
+ */
I was thinking we could do it the other way around, have have dl_bandwidth included in rt_bandwidth.
Re: [PATCH 13/15] sched: add bandwidth management for sched_dl.
Hi,
Quoted 15 lines · Peter Zijlstra
Quoted 5 lines · Juri Lelli
+/*
+ * Coupling of -dl and -rt bandwidth.
+ *
+ * Here we check, while setting the system wide bandwidth available
+ * for -dl tasks and groups, if the new values are consistent withQuoted 8 lines
+ * the system settings for the bandwidth available to -rt entities.
+ *
+ * IOW, we want to enforce that
+ *
+ *rt_bandwidth+ dl_bandwidth<= 100%
+ *
+ * is always true.
+ */
Quoted 3 lines
I was thinking we could do it the other way around, have have
dl_bandwidthincluded inrt_bandwidth.
If I understand correctly, you are proposing to treat -dl tasks as a special case of "real-time" tasks. Then we could reserve some bw to "real-time" (rt_bandwidth cap) activities and give a piece of this bw to -dl tasks (what remains is for -rt tasks). This is in principle nice and useful, but I'm not quite sure that this is the right point to achieve this logical behavior.
I mean, -dl and -rt tasks are separately treated, so it is probably cleaner to manage their knobs separately. They have to coexist rather than be considered one a sub-case of the other. A better way to go for a common cap for them is probably the (long-term) hierarchical scheduling mechanism.
So, I would prefer to keep the interface as is for now, but I can also completely misunderstood your thoughts :-P.
Thanks and Regards,
- Juri
Peter Zijlstra
maintainerRe: [PATCH 13/15] sched: add bandwidth management for sched_dl.
Quoted 34 lines · Juri Lelli
Hi,
Quoted 15 lines · Peter Zijlstra
Quoted 5 lines · Juri Lelli
+/*
+ * Coupling of -dl and -rt bandwidth.
+ *
+ * Here we check, while setting the system wide bandwidth available
+ * for -dl tasks and groups, if the new values are consistent withQuoted 8 lines
+ * the system settings for the bandwidth available to -rt entities.
+ *
+ * IOW, we want to enforce that
+ *
+ *rt_bandwidth+ dl_bandwidth<= 100%
+ *
+ * is always true.
+ */Quoted 3 lines
I was thinking we could do it the other way around, have have
dl_bandwidthincluded inrt_bandwidth.If I understand correctly, you are proposing to treat -dl tasks as a special case of "real-time" tasks. Then we could reserve some bw to "real-time" (
rt_bandwidthcap) activities and give a piece of this bw to -dl tasks (what remains is for -rt tasks). This is in principle nice and useful, but I'm not quite sure that this is the right point to achieve this logical behavior.
I mean, -dl and -rt tasks are separately treated, so it is probably cleaner to manage their knobs separately. They have to coexist rather than be considered one a sub-case of the other. A better way to go for a common cap for them is probably the (long-term) hierarchical scheduling mechanism.
Quoted 2 lines
So, I would prefer to keep the interface as is for now, but I can also completely misunderstood your thoughts :-P.
The thing is, keeping it separate makes for an impossible configuration scenario. Esp. once we enable !root usage. The proposed 5% is very limiting and regular users won't have sufficient privilege to change it.
Also lowering FIFO/RR by default isn't a real option since people expect that to get all time already (however silly that expectation is).
Re: [PATCH 13/15] sched: add bandwidth management for sched_dl.
Quoted 35 lines · Peter Zijlstra
Quoted 34 lines · Juri Lelli
Hi,
Quoted 15 lines · Peter Zijlstra
Quoted 5 lines · Juri Lelli
+/*
+ * Coupling of -dl and -rt bandwidth.
+ *
+ * Here we check, while setting the system wide bandwidth available
+ * for -dl tasks and groups, if the new values are consistent withQuoted 8 lines
+ * the system settings for the bandwidth available to -rt entities.
+ *
+ * IOW, we want to enforce that
+ *
+ *rt_bandwidth+ dl_bandwidth<= 100%
+ *
+ * is always true.
+ */Quoted 3 lines
I was thinking we could do it the other way around, have have
dl_bandwidthincluded inrt_bandwidth.If I understand correctly, you are proposing to treat -dl tasks as a special case of "real-time" tasks. Then we could reserve some bw to "real-time" (
rt_bandwidthcap) activities and give a piece of this bw to -dl tasks (what remains is for -rt tasks). This is in principle nice and useful, but I'm not quite sure that this is the right point to achieve this logical behavior.
I mean, -dl and -rt tasks are separately treated, so it is probably cleaner to manage their knobs separately. They have to coexist rather than be considered one a sub-case of the other. A better way to go for a common cap for them is probably the (long-term) hierarchical scheduling mechanism.
Quoted 7 lines
Quoted 2 lines
So, I would prefer to keep the interface as is for now, but I can also completely misunderstood your thoughts :-P.
The thing is, keeping it separate makes for an impossible configuration scenario. Esp. once we enable !root usage. The proposed 5% is very limiting and regular users won't have sufficient privilege to change it.
Ok, now I understand your point better, and I agree that 5% is hardly usable for !root users. However, I also think this is probably more a system admin problem. I mean, a sys admin that wants his users to play with -deadline scheduling should have thought how to properly set up his system, and the fact that something must be configured by hand to give users a usable system is generally not a so bad idea.
Quoted 3 lines
Also lowering FIFO/RR by default isn't a real option since people expect that to get all time already (however silly that expectation is).
I agree. Don't want to spoil users expectations :-).
Thanks and regards,
- Juri
Peter Zijlstra
maintainerRe: [PATCH 13/15] sched: add bandwidth management for sched_dl.
Quoted 11 lines · Juri Lelli
Quoted 4 lines
The thing is, keeping it separate makes for an impossible configuration scenario. Esp. once we enable !root usage. The proposed 5% is very limiting and regular users won't have sufficient privilege to change it.
Ok, now I understand your point better, and I agree that 5% is hardly usable for !root users. However, I also think this is probably more a system admin problem. I mean, a sys admin that wants his users to play with -deadline scheduling should have thought how to properly set up his system, and the fact that something must be configured by hand to give users a usable system is generally not a so bad idea.
Yes, but lets not make the life of the unsuspecting admin harder than we absolutely have to.
Furthermore we should strive to make DL as useful as possible out-of-the-box.
One way to do this is to have rt and dl bandwidth constraints independent and put a 3rd combined limit in place. But what is the benefit of that over a single combined limit?
Re: [PATCH 13/15] sched: add bandwidth management for sched_dl.
Quoted 13 lines · Peter Zijlstra
Quoted 11 lines · Juri Lelli
Quoted 4 lines
The thing is, keeping it separate makes for an impossible configuration scenario. Esp. once we enable !root usage. The proposed 5% is very limiting and regular users won't have sufficient privilege to change it.
Ok, now I understand your point better, and I agree that 5% is hardly usable for !root users. However, I also think this is probably more a system admin problem. I mean, a sys admin that wants his users to play with -deadline scheduling should have thought how to properly set up his system, and the fact that something must be configured by hand to give users a usable system is generally not a so bad idea.
Quoted 6 lines
Yes, but lets not make the life of the unsuspecting admin harder than we absolutely have to.
Furthermore we should strive to make DL as useful as possible out-of-the-box.
Ok, I agree on this.
Quoted 3 lines
One way to do this is to have rt and dl bandwidth constraints independent and put a 3rd combined limit in place. But what is the benefit of that over a single combined limit?
In the end, a single limit is probably better. So, I'll leave rt_bandwidth at its default value and make dl_bandwidth a sort of sub-quota of it. To give the user an out-of-the-box usable system, I could raise dl_bandwith to, let's say, 40% (of 95%). Thus, in the default scenario, the user will be allowed to create _rt tasks up to 57% and _dl tasks up to 38% of the system capacity, sounds reasonable?
Thanks and regards,
- Juri
PATCH 14/15 sched: speed up -dl pushes with a push-heap.
In reply to Juri LelliData from tests confirmed that the original active load balancing logic didn't scale neither in the number of CPU nor in the number of tasks (as sched_rt does).
Here we provide a global data structure to keep track of deadlines of the running tasks in the system. The structure is composed by a bitmask showing the free CPUs and a max-heap, needed when the system is heavily loaded.
The implementation and concurrent access scheme are kept simple by design. However, our measurements show that we can compete with sched_rt on large multi-CPUs machines [1].
Only the push path is addressed, the extension to use this structure also for pull decisions is straightforward. However, we are currently evaluating different (in order to decrease/avoid contention) data structures to solve possibly both problems. We are also going to re-run tests considering recent changes inside cpupri [2].
[1] http://retis.sssup.it/~jlelli/papers/Ospert11Lelli.pdf
[2] http://www.spinics.net/lists/linux-rt-users/msg06778.html
--- kernel/sched/Makefile | 2 +- kernel/sched/core.c | 3 + kernel/sched/cpudl.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++ kernel/sched/cpudl.h | 33 ++++++++ kernel/sched/dl.c | 52 ++++--------- kernel/sched/sched.h | 2 + 6 files changed, 260 insertions(+), 40 deletions(-) create mode 100644 kernel/sched/cpudl.c create mode 100644 kernel/sched/cpudl.h
kernel/sched/Makefile +1 -1
@@ -12,7 +12,7 @@ CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer endif obj-y += core.o clock.o idle_task.o fair.o rt.o dl.o stop_task.o -obj-$(CONFIG_SMP) += cpupri.o +obj-$(CONFIG_SMP) += cpupri.o cpudl.o obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o obj-$(CONFIG_SCHEDSTATS) += stats.o obj-$(CONFIG_SCHED_DEBUG) += debug.o
kernel/sched/core.c +3 -0
@@ -6106,6 +6106,7 @@ static void free_rootdomain(struct rcu_head *rcu) struct root_domain *rd = container_of(rcu, struct root_domain, rcu);cpupri_cleanup (&rd->cpupri); +cpudl_cleanup (&rd->cpudl);free_cpumask_var (rd->dlo_mask);free_cpumask_var (rd->rto_mask);free_cpumask_var (rd->online);
@@ -6164,6 +6165,8 @@ static int init_rootdomain(struct root_domain *rd) goto free_dlo_mask;init_dl_bw (&rd->dl_bw); +if (cpudl_init (&rd->cpudl) !=0 ) + goto free_dlo_mask;if (cpupri_init (&rd->cpupri) !=0 ) goto free_rto_mask;
kernel/sched/cpudl.c new file +208 -0
208 lines not on this page · raw message
kernel/sched/cpudl.h new file +33 -0
@@ -0,0 +1,33 @@ +#ifndef _LINUX_CPUDL_H +#define _LINUX_CPUDL_H + +#include <linux/sched.h> + +#define IDX_INVALID -1 + +struct array_item { +u64 dl; +int cpu; +}; + +struct cpudl { +raw_spinlock_t lock; +int size; +int cpu_to_idx[NR_CPUS ]; +struct array_item elements[NR_CPUS ]; +cpumask_var_t free_cpus; +}; + + +#ifdef CONFIG_SMP +int cpudl_find (struct cpudl *cp,struct cpumask *dlo_mask, +struct task_struct *p,struct cpumask *later_mask); +void cpudl_set (struct cpudl *cp,int cpu,u64 dl,int is_valid); +int cpudl_init (struct cpudl *cp); +void cpudl_cleanup (struct cpudl *cp); +#else +#define cpudl_set (cp, cpu, dl) do { } while (0) +#define cpudl_init () do { } while (0) +#endif /* CONFIG_SMP */ + +#endif /* _LINUX_CPUDL_H */
kernel/sched/dl.c +13 -39
112 lines not on this page · raw message
kernel/sched/sched.h +2 -0
@@ -5,6 +5,7 @@#include <linux/stop_machine.h> #include "cpupri.h" +#include "cpudl.h" extern __read_mostly int scheduler_running;
@@ -444,6 +445,7 @@ struct root_domain {cpumask_var_t dlo_mask;atomic_t dlo_count;struct dl_bw dl_bw; +struct cpudl cpudl;/* * The "RT overload" flag: it gets set if a CPU has more than
Signature · 1 line
1.7.9.5
PATCH 15/15 sched: add sched_dl documentation.
In reply to Juri LelliFrom: Dario Faggioli <[email protected]>
Add in Documentation/scheduler/ some hints about the design choices, the usage and the future possible developments of the sched_dl scheduling class and of the SCHED_DEADLINE policy.
--- Documentation/scheduler/sched-deadline.txt | 164 ++++++++++++++++++++++++++++ kernel/sched/dl.c | 3 +- 2 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 Documentation/scheduler/sched-deadline.txt
Documentation/scheduler/sched-deadline.txt new file +164 -0
@@ -0,0 +1,164 @@ + Deadline Task and Group Scheduling + ---------------------------------- + +CONTENTS +======== + +0. WARNING +1. Overview +2. Task scheduling +2. The Interface +3. Bandwidth management + 3.1 System-wide settings + 2.2 Task interface + 2.4 Default behavior +3. Future plans + + +0. WARNING +========== + + Fiddling with these settings can result in an unpredictable or even unstable + system behavior. As for -rt (group) scheduling, it is assumed that root users + know what they're doing. + + +1. Overview +=========== + + The SCHED_DEADLINE policy contained inside the sched_dl scheduling class is + basically an implementation of the Earliest Deadline First (EDF) scheduling + algorithm, augmented with a mechanism (called Constant Bandwidth Server, CBS) + that makes it possible to isolate the behavior of tasks between each other. + + +2. Task scheduling +================== + + The typical -deadline task is composed of a computation phase (instance) + which is activated on a periodic or sporadic fashion. The expected (maximum) + duration of such computation is called the task's runtime; the time interval + by which each instance needs to be completed is called the task's relative + deadline. The task's absolute deadline is dynamically calculated as the + time instant a task (or, more properly) activates plus the relative + deadline. + + The EDF[1] algorithm selects the task with the smallest absolute deadline as + the one to be executed first, while the CBS[2,3] ensures that each task runs + for at most its runtime every period, avoiding any interference between + different tasks (bandwidth isolation). + Thanks to this feature, also tasks that do not strictly comply with the + computational model described above can effectively use the new policy. + IOW, there are no limitations on what kind of task can exploit this new + scheduling discipline, even if it must be said that it is particularly + suited for periodic or sporadic tasks that need guarantees on their + timing behavior, e.g., multimedia, streaming, control applications, etc. + + References: + 1 - C. L. Liu and J. W. Layland. Scheduling algorithms for multiprogram- + ming in a hard-real-time environment. Journal of the Association for + Computing Machinery, 20(1), 1973. + 2 - L. Abeni , G. Buttazzo. Integrating Multimedia Applications in Hard + Real-Time Systems. Proceedings of the 19th IEEE Real-time Systems + Symposium, 1998. http://retis.sssup.it/~giorgio/paps/1998/rtss98-cbs.pdf + 3 - L. Abeni. Server Mechanisms for Multimedia Applications. ReTiS Lab + Technical Report. http://xoomer.virgilio.it/lucabe72/pubs/tr-98-01.ps + +3. Bandwidth management +======================= + + In order for the -deadline scheduling to be effective and useful, it is + important to have some method to keep the allocation of the available CPU + bandwidth to the tasks under control. + This is usually called "admission control" and if it is not performed at all, + no guarantee can be given on the actual scheduling of the -deadline tasks. + + Since when RT-throttling has been introduced each task group has a bandwidth + associated, calculated as a certain amount of runtime over a period. + Moreover, to make it possible to manipulate such bandwidth, readable/writable + controls have been added to both procfs (for system wide settings) and cgroupfs + (for per-group settings). + Therefore, the same interface is being used for controlling the bandwidth + distrubution to -deadline tasks and task groups, i.e., new controls but with + similar names, equivalent meaning and with the same usage paradigm are added. + + However, more discussion is needed in order to figure out how we want to manage + SCHED_DEADLINE bandwidth at the task group level. Therefore, SCHED_DEADLINE + uses (for now) a less sophisticated, but actually very sensible, mechanism to + ensure that a certain utilization cap is not overcome per each root_domain. + + Another main difference between deadline bandwidth management and RT-throttling + is that -deadline tasks have bandwidth on their own (while -rt ones don't!), + and thus we don't need an higher level throttling mechanism to enforce the + desired bandwidth. + +3.1 System wide settings +------------------------ + +The system wide settings are configured under the /proc virtual file system: + + The per-group controls that are added to the cgroupfs virtual file system are: + * /proc/sys/kernel/sched_dl_runtime_us, + * /proc/sys/kernel/sched_dl_period_us, + + They accept (if written) and provides (if read) the new runtime and period, + respectively, for each CPU in each root_domain. + + This means that, for a root_domain comprising M CPUs, -deadline tasks + can be created until the sum of their bandwidths stay below: + + M * (sched_dl_runtime_us / sched_dl_period_us) + + It is also possible to disable this bandwidth management logic, and + be thus free of oversubscribing the system up to any arbitrary level. + This is done by writing -1 in /proc/sys/kernel/sched_dl_runtime_us. + + +2.2 Task interface +------------------ + + Specifying a periodic/sporadic task that executes for a given amount of + runtime at each instance, and that is scheduled according to the urgency of + its own timing constraints needs, in general, a way of declaring: + - a (maximum/typical) instance execution time, + - a minimum interval between consecutive instances, + - a time constraint by which each instance must be completed. + + Therefore: + * a new struct sched_param2, containing all the necessary fields is + provided; + * the new scheduling related syscalls that manipulate it, i.e., + sched_setscheduler2(), sched_setparam2() and sched_getparam2() + are implemented. + + +2.4 Default behavior +--------------------- + +The default values for SCHED_DEADLINE bandwidth is to have dl_runtime and +dl_period equal to 500000 and 1000000, respectively. This means -deadline +tasks can use at most 5%, multiplied by the number of CPUs that compose the +root_domain, for each root_domain. + +When a -deadline task fork a child, its dl_runtime is set to 0, which means +someone must call sched_setscheduler2() on it, or it won't even start. + + +3. Future plans +=============== + +Still missing: + + - refinements to deadline inheritance, especially regarding the possibility + of retaining bandwidth isolation among non-interacting tasks. This is + being studied from both theoretical and practical point of views, and + hopefully we should be able to produce some demonstrative code soon; + - (c)group based bandwidth management, and maybe scheduling; + - access control for non-root users (and related security concerns to + address), which is the best way to allow unprivileged use of the mechanisms + and how to prevent non-root users "cheat" the system? + +As already discussed, we are planning also to merge this work with the EDF +throttling patches [https://lkml.org/lkml/2010/2/23/239] but we still are in +the preliminary phases of the merge and we really seek feedback that would help us +decide on the direction it should take.
kernel/sched/dl.c +2 -1
@@ -346,7 +346,8 @@ static void replenish_dl_entity(struct sched_dl_entity *dl_se,* disrupting the schedulability of the system. Otherwise, we should * refill the runtime and set the deadline a period in the future, * because keeping the current (absolute) deadline of the task would -* result in breaking guarantees promised to other tasks. +* result in breaking guarantees promised to other tasks (refer to +* Documentation/scheduler/sched-deadline.txt for more informations). * * This function returns true if: *
Signature · 1 line
1.7.9.5
Peter Zijlstra
maintainerQuoted 2 lines · Juri Lelli
Still missing/incomplete:
- (c)group based bandwidth management, and maybe scheduling;
The b/w stuff for cgroups shouldn't be particularly hard, right? It shouldn't be more than ensuring the utilization sum of all children stays below the set value.
Or am I missing something?
Quoted 1 line
- bandwidth inheritance (to replace deadline/priority inheritance);
Yes please, but this is somewhat longer term, I think the band-aids in place are sufficient to allow us to move fwd.
Quoted 2 lines
- access control for non-root users (and related security concerns to address).
Right, so could you detail what all is needed to allow regular users to create dl tasks?
Aside from this, Ingo, Thomas, Steven do you agree in merging these patches as a suitable base to continue work from?
Quoted 15 lines · Peter Zijlstra
Quoted 2 lines · Juri Lelli
Still missing/incomplete:
- (c)group based bandwidth management, and maybe scheduling;The b/w stuff for cgroups shouldn't be particularly hard, right? It shouldn't be more than ensuring the utilization sum of all children stays below the set value.
Or am I missing something?
Quoted 1 line
- bandwidth inheritance (to replace deadline/priority inheritance);
Yes please, but this is somewhat longer term, I think the band-aids in place are sufficient to allow us to move fwd.
Quoted 8 lines
Quoted 2 lines
- access control for non-root users (and related security concerns to address).
Right, so could you detail what all is needed to allow regular users to create dl tasks?
Aside from this, Ingo, Thomas, Steven do you agree in merging these patches as a suitable base to continue work from?
I haven't looked in detail, but I didn't spot horrible things either. And yes, we should start with that set and improve from there.
Thanks,
tglx
Hi,
Quoted 10 lines · Peter Zijlstra
Quoted 2 lines · Juri Lelli
Still missing/incomplete:
- (c)group based bandwidth management, and maybe scheduling;The b/w stuff for cgroups shouldn't be particularly hard, right? It shouldn't be more than ensuring the utilization sum of all children stays below the set value.
Or am I missing something?
Yes, the sum of the bandwidths of entities (tasks and groups) belonging to a group stays below its own set bandwidth. Actually, I quoted this sentence from code that was included in previous versions (removed since v3). I tried to build historical reasons why it was removed, but I failed :-). Anyway, shouldn't be too hard to adapt that code to the new version and see if it will raise any new concern.
Quoted 5 lines
Quoted 1 line
- bandwidth inheritance (to replace deadline/priority inheritance);
Yes please, but this is somewhat longer term, I think the band-aids in place are sufficient to allow us to move fwd.
Yes, but I fear it could affect next point. Anyway, I agree that this is something that I would consider long-term.
Quoted 6 lines
Quoted 2 lines
- access control for non-root users (and related security concerns to address).
Right, so could you detail what all is needed to allow regular users to create dl tasks?
Ok, I'll try to summarize what I think it would be a _minimal_ set of requirements:
o define deadline(period) and runtime utilization caps; as it was in v3, RLIMIT_DLDLINE would be the minimum value a user task can use as its own deadline, while (as you pointed out) RLIMIT_DLRTIME would be a per user utilization cap, but it would also be tracked in user_struct to enforce a max utilization cap per user.
o At server parameters change/destruction some mechanism is needed to prevent possible attacks such as (ref. Tommaso's paper):
- an app creates a task with an associated server;
- when the runtime (budget) is about to be exhausted, the app destroys the server, returning the task to the default sched policy;
- then, the app immediately creates a new server for the task, and keeps repeating the loop over and over.
A possible solution is that, whenever a server is destroyed, the system doesn't completely forget about its existence, but it must continue to consider its utilization as not available until the next server period expired.
o The only "big problem" I fear is related to the current deadline inheritance mechanism. As Steven pointed out during the last review, a task could force more bandwidth than was allowed if:
- it takes a futex;
- it is boosted while holding it;
- never releases the futex;
and this is sadly achievable since, if boosted, a task inherits top waiter parameters and the enforcement mechanism is temporarily disabled for it.
Thanks and regards,
- Juri
Peter Zijlstra
maintainerQuoted 11 lines · Juri Lelli
o The only "big problem" I fear is related to the current deadline inheritance mechanism. As Steven pointed out during the last review, a task could force more bandwidth than was allowed if:
- it takes a futex;
- it is boosted while holding it;
- never releases the futex;and this is sadly achievable since, if boosted, a task inherits top waiter parameters and the enforcement mechanism is temporarily disabled for it.
/me goes read patch 12 in detail..
Wouldn't it be possible to enforce pi_se (aka. pi_task)'s bandwidth in the dl-boosts-dl case?
Since afaict that's the only case we need to worry about. If you can spawn FIFO/RR tasks you already loose bandwidth caps etc..