2 * linux/kernel/vserver/sched.c
4 * Virtual Server: Scheduler Support
6 * Copyright (C) 2004 Herbert Pƶtzl
8 * V0.01 adapted Sam Vilains version to 2.6.3
9 * V0.02 removed legacy interface
13 #include <linux/config.h>
14 #include <linux/sched.h>
15 #include <linux/vinline.h>
16 #include <linux/vserver/context.h>
17 #include <linux/vserver/sched.h>
19 #include <asm/errno.h>
20 #include <asm/uaccess.h>
24 * recalculate the context's scheduling tokens
26 * ret > 0 : number of tokens available
27 * ret = 0 : context is paused
28 * ret < 0 : number of jiffies until new tokens arrive
31 int vx_tokens_recalc(struct vx_info *vxi)
33 long delta, tokens = 0;
35 if (__vx_flags(vxi->vx_flags, VXF_SCHED_PAUSE, 0))
39 delta = jiffies - vxi->sched.jiffies;
41 if (delta >= vxi->sched.interval) {
42 /* lockdown scheduler info */
43 spin_lock(&vxi->sched.tokens_lock);
45 /* calc integral token part */
46 delta = jiffies - vxi->sched.jiffies;
47 tokens = delta / vxi->sched.interval;
48 delta = tokens * vxi->sched.interval;
49 tokens *= vxi->sched.fill_rate;
51 atomic_add(tokens, &vxi->sched.tokens);
52 vxi->sched.jiffies += delta;
53 tokens = atomic_read(&vxi->sched.tokens);
55 if (tokens > vxi->sched.tokens_max) {
56 tokens = vxi->sched.tokens_max;
57 atomic_set(&vxi->sched.tokens, tokens);
59 spin_unlock(&vxi->sched.tokens_lock);
62 if ((tokens = vx_tokens_avail(vxi)) < vxi->sched.tokens_min) {
63 /* enough tokens will be available in */
64 if (vxi->sched.tokens_min == 0)
65 return delta - vxi->sched.interval;
66 return delta - vxi->sched.interval *
67 vxi->sched.tokens_min / vxi->sched.fill_rate;
70 /* we have some tokens left */
75 * effective_prio - return the priority that is based on the static
76 * priority but is modified by bonuses/penalties.
78 * We scale the actual sleep average [0 .... MAX_SLEEP_AVG]
79 * into a -4 ... 0 ... +4 bonus/penalty range.
81 * Additionally, we scale another amount based on the number of
82 * CPU tokens currently held by the context, if the process is
83 * part of a context (and the appropriate SCHED flag is set).
84 * This ranges from -5 ... 0 ... +15, quadratically.
86 * So, the total bonus is -9 .. 0 .. +19
87 * We use ~50% of the full 0...39 priority range so that:
89 * 1) nice +19 interactive tasks do not preempt nice 0 CPU hogs.
90 * 2) nice -20 CPU hogs do not get preempted by nice 0 tasks.
91 * unless that context is far exceeding its CPU allocation.
93 * Both properties are important to certain workloads.
95 int effective_vavavoom(task_t *p, int max_prio)
97 struct vx_info *vxi = p->vx_info;
100 /* lots of tokens = lots of vavavoom
101 * no tokens = no vavavoom */
102 if ((vavavoom = atomic_read(&vxi->sched.tokens)) >= 0) {
103 max = vxi->sched.tokens_max;
104 vavavoom = max - vavavoom;
106 vavavoom = max_prio * VAVAVOOM_RATIO / 100
107 * (vavavoom*vavavoom - (max >> 2)) / max;
108 /* alternative, geometric mapping
109 vavavoom = -( MAX_USER_PRIO*VAVAVOOM_RATIO/100 * vavavoom
110 / vxi->sched.tokens_max -
111 MAX_USER_PRIO*VAVAVOOM_RATIO/100/2); */
114 /* vavavoom = ( MAX_USER_PRIO*VAVAVOOM_RATIO/100*tokens_left(p) -
115 MAX_USER_PRIO*VAVAVOOM_RATIO/100/2); */
121 int vc_set_sched(uint32_t xid, void __user *data)
123 struct vcmd_set_sched_v2 vc_data;
126 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
129 vxi = find_vx_info(xid);
133 spin_lock(&vxi->sched.tokens_lock);
135 if (vc_data.interval != SCHED_KEEP)
136 vxi->sched.interval = vc_data.interval;
137 if (vc_data.fill_rate != SCHED_KEEP)
138 vxi->sched.fill_rate = vc_data.fill_rate;
139 if (vc_data.tokens_min != SCHED_KEEP)
140 vxi->sched.tokens_min = vc_data.tokens_min;
141 if (vc_data.tokens_max != SCHED_KEEP)
142 vxi->sched.tokens_max = vc_data.tokens_max;
143 if (vc_data.tokens != SCHED_KEEP)
144 atomic_set(&vxi->sched.tokens, vc_data.tokens);
146 /* Sanity check the resultant values */
147 if (vxi->sched.fill_rate <= 0)
148 vxi->sched.fill_rate = 1;
149 if (vxi->sched.interval <= 0)
150 vxi->sched.interval = HZ;
151 if (vxi->sched.tokens_max == 0)
152 vxi->sched.tokens_max = 1;
153 if (atomic_read(&vxi->sched.tokens) > vxi->sched.tokens_max)
154 atomic_set(&vxi->sched.tokens, vxi->sched.tokens_max);
155 if (vxi->sched.tokens_min > vxi->sched.tokens_max)
156 vxi->sched.tokens_min = vxi->sched.tokens_max;
158 spin_unlock(&vxi->sched.tokens_lock);