theNoobProgrammer
theNoobProgrammer

Reputation: 932

Nice level code location in linux kernel

I have read this page regarding how nice levels work: http://oakbytes.wordpress.com/2012/06/06/linux-scheduler-cfs-and-nice/

Does anyone know the file within the kernel code-base where the formula "1024 / (1.25)^ (nice)" is implemented to assign the weight of a process?

Upvotes: 0

Views: 1143

Answers (1)

Peter L.
Peter L.

Reputation: 1041

Although the calculation referenced in the question is not used as-is (the kernel uses only integer math with few or no exceptions), the nice syscall is implemented here. After some sanity and security checking, it ultimately calls set_user_nice() which uses macros to convert the user-specified nice value to a kernel priority value.

void set_user_nice(struct task_struct *p, long nice)
{
        int old_prio, delta, queued;
        unsigned long flags;
        struct rq *rq;

        if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE)
                return;
        /*
         * We have to be careful, if called from sys_setpriority(),
         * the task might be in the middle of scheduling on another CPU.
         */
        rq = task_rq_lock(p, &flags);
        /*
         * The RT priorities are set via sched_setscheduler(), but we still
         * allow the 'normal' nice value to be set - but as expected
         * it wont have any effect on scheduling until the task is
         * SCHED_DEADLINE, SCHED_FIFO or SCHED_RR:
         */
         if (task_has_dl_policy(p) || task_has_rt_policy(p)) {
                p->static_prio = NICE_TO_PRIO(nice);
                goto out_unlock;
         }
         queued = task_on_rq_queued(p);
         if (queued)
                 dequeue_task(rq, p, 0);

         p->static_prio = NICE_TO_PRIO(nice);
         set_load_weight(p);
         old_prio = p->prio;
         p->prio = effective_prio(p);
         delta = p->prio - old_prio;

         if (queued) {
                 enqueue_task(rq, p, 0);
                 /*
                  * If the task increased its priority or is running and
                  * lowered its priority, then reschedule its CPU:
                  */
                 if (delta < 0 || (delta > 0 && task_running(rq, p)))
                         resched_curr(rq);
         }
out_unlock:
         task_rq_unlock(rq, p, &flags);
}
EXPORT_SYMBOL(set_user_nice);

The macros are defined here:

#define MAX_NICE        19
#define MIN_NICE        -20
#define NICE_WIDTH      (MAX_NICE - MIN_NICE + 1)

/*
 * Priority of a process goes from 0..MAX_PRIO-1, valid RT
 * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
 * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
 * values are inverted: lower p->prio value means higher priority.
 *
 * The MAX_USER_RT_PRIO value allows the actual maximum
 * RT priority to be separate from the value exported to
 * 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.
 */

#define MAX_USER_RT_PRIO        100
#define MAX_RT_PRIO             MAX_USER_RT_PRIO

#define MAX_PRIO                (MAX_RT_PRIO + NICE_WIDTH)
#define DEFAULT_PRIO            (MAX_RT_PRIO + NICE_WIDTH / 2)

/*
 * Convert user-nice values [ -20 ... 0 ... 19 ]
 * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
 * and back.
 */
#define NICE_TO_PRIO(nice)      ((nice) + DEFAULT_PRIO)
#define PRIO_TO_NICE(prio)      ((prio) - DEFAULT_PRIO)

/*
 * 'User priority' is the nice value converted to something we
 * can work with better when scaling various scheduler parameters,
 * it's a [ 0 ... 39 ] range.
 */
#define USER_PRIO(p)            ((p)-MAX_RT_PRIO)
#define TASK_USER_PRIO(p)       USER_PRIO((p)->static_prio)
#define MAX_USER_PRIO           (USER_PRIO(MAX_PRIO))

See this document for an explanation of the design.

Upvotes: 1

Related Questions