automatic process renicing
Problem
Sometimes it's desirable to have children of a long-lived process be automatically reniced. We may not be able to interpose a shell script, nor may the parent process have a suitable configuration parameter.
Scripts
This script changes the "static_prio" field of each selected newborn "task_struct" by adding an offset to the value inherited from its parent. autonice.stp
global parent = @1 # parent execname string global offset = $2 # child nice offset %{ #include <linux/sched.h> %} function clamp_prio:long (p:long) %{ THIS->__retvalue = (THIS->p < MAX_USER_RT_PRIO ? MAX_USER_RT_PRIO : THIS->p >= MAX_PRIO ? MAX_PRIO-1 : THIS->p); %} probe kernel.function("sched_fork") { if (execname() != parent) next printf("%s %d forked %d nice %d ",execname(),pid(),$p->pid,$p->static_prio) $p->static_prio = clamp_prio ($p->static_prio + offset) printf ("-> %d\n", $p->static_prio) }
Output
This script is parametrized by the execname of the target parent process, and by the "nice" increment value to apply to the child process. Small positive or negative values may be appropriate.
# stap -g autonice.stp httpd 8 httpd 32022 forked 1111 nice 123 -> 131 httpd 32022 forked 1113 nice 123 -> 131 httpd 32118 forked 1200 nice 123 -> 131 httpd 32118 forked 1202 nice 123 -> 131 httpd 32118 forked 1208 nice 123 -> 131 httpd 32118 forked 1210 nice 123 -> 131 httpd 32118 forked 1220 nice 123 -> 131
Lessons
The clamp_prio function should go into the scheduling tapset. Even then, the script needs guru mode privileges because it modified the
Making the script conditional on userid or similar criteria is trivial. Changing the new priority computation is also straightforward.
Finding the right function (sched_fork) to probe involved searching through the kernel sources, starting at sys_fork/do_fork/copy_process. The ideal place to probe was a function that had ready access to the new task_struct object, but which had not yet been submitted to the scheduler system for run-queue placement and processing. The sched_fork() point was ideal for several kernel versions attempted.