This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / kernel / vserver / sched.c
1 /*
2  *  linux/kernel/vserver/sched.c
3  *
4  *  Virtual Server: Scheduler Support
5  *
6  *  Copyright (C) 2004  Herbert Pƶtzl
7  *
8  *  V0.01  adapted Sam Vilains version to 2.6.3
9  *  V0.02  removed legacy interface
10  *
11  */
12
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>
18
19 #include <asm/errno.h>
20 #include <asm/uaccess.h>
21
22
23 /*
24  * recalculate the context's scheduling tokens
25  *
26  * ret > 0 : number of tokens available
27  * ret = 0 : context is paused
28  * ret < 0 : number of jiffies until new tokens arrive
29  *
30  */
31 int vx_tokens_recalc(struct vx_info *vxi)
32 {
33         long delta, tokens = 0;
34
35         if (__vx_flags(vxi->vx_flags, VXF_SCHED_PAUSE, 0))
36                 /* we are paused */
37                 return 0;
38
39         delta = jiffies - vxi->sched.jiffies;
40
41         if (delta >= vxi->sched.interval) {
42                 /* lockdown scheduler info */
43                 spin_lock(&vxi->sched.tokens_lock);
44
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;
50
51                 atomic_add(tokens, &vxi->sched.tokens);
52                 vxi->sched.jiffies += delta;
53                 tokens = atomic_read(&vxi->sched.tokens);
54         
55                 if (tokens > vxi->sched.tokens_max) {
56                         tokens = vxi->sched.tokens_max;
57                         atomic_set(&vxi->sched.tokens, tokens);
58                 }
59                 spin_unlock(&vxi->sched.tokens_lock);
60         } else {
61                 /* no new tokens */
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;
68                 }
69         }
70         /* we have some tokens left */
71         return tokens;
72 }
73
74 /*
75  * effective_prio - return the priority that is based on the static
76  * priority but is modified by bonuses/penalties.
77  *
78  * We scale the actual sleep average [0 .... MAX_SLEEP_AVG]
79  * into a -4 ... 0 ... +4 bonus/penalty range.
80  *
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.
85  *
86  * So, the total bonus is -9 .. 0 .. +19
87  * We use ~50% of the full 0...39 priority range so that:
88  *
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.
92  *
93  * Both properties are important to certain workloads.
94  */
95 int effective_vavavoom(task_t *p, int max_prio)
96 {
97         struct vx_info *vxi = p->vx_info;
98         int vavavoom, max;
99
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;
105                 max = max * max;
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); */
112         } else
113                 vavavoom = 0;
114         /* vavavoom = ( MAX_USER_PRIO*VAVAVOOM_RATIO/100*tokens_left(p) -
115                 MAX_USER_PRIO*VAVAVOOM_RATIO/100/2); */
116
117         return vavavoom;
118 }
119
120
121 int vc_set_sched(uint32_t xid, void __user *data)
122 {
123         struct vcmd_set_sched_v2 vc_data;
124         struct vx_info *vxi;
125
126         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
127                 return -EFAULT;
128         
129         vxi = find_vx_info(xid);
130         if (!vxi)
131                 return -EINVAL;
132
133         spin_lock(&vxi->sched.tokens_lock);
134
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);
145
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;
157
158         spin_unlock(&vxi->sched.tokens_lock);
159         put_vx_info(vxi);
160         return 0;
161 }
162