patch-2_6_7-vs1_9_1_12
[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/vs_base.h>
16 #include <linux/vs_context.h>
17 #include <linux/vserver/context.h>
18 #include <linux/vserver/sched.h>
19
20 #include <asm/errno.h>
21 #include <asm/uaccess.h>
22
23
24 /*
25  * recalculate the context's scheduling tokens
26  *
27  * ret > 0 : number of tokens available
28  * ret = 0 : context is paused
29  * ret < 0 : number of jiffies until new tokens arrive
30  *
31  */
32 int vx_tokens_recalc(struct vx_info *vxi)
33 {
34         long delta, tokens = 0;
35
36         if (__vx_flags(vxi->vx_flags, VXF_SCHED_PAUSE, 0))
37                 /* we are paused */
38                 return 0;
39
40         delta = jiffies - vxi->sched.jiffies;
41
42         if (delta >= vxi->sched.interval) {
43                 /* lockdown scheduler info */
44                 spin_lock(&vxi->sched.tokens_lock);
45
46                 /* calc integral token part */
47                 delta = jiffies - vxi->sched.jiffies;
48                 tokens = delta / vxi->sched.interval;
49                 delta = tokens * vxi->sched.interval;
50                 tokens *= vxi->sched.fill_rate;
51
52                 atomic_add(tokens, &vxi->sched.tokens);
53                 vxi->sched.jiffies += delta;
54                 tokens = atomic_read(&vxi->sched.tokens);
55         
56                 if (tokens > vxi->sched.tokens_max) {
57                         tokens = vxi->sched.tokens_max;
58                         atomic_set(&vxi->sched.tokens, tokens);
59                 }
60                 spin_unlock(&vxi->sched.tokens_lock);
61         } else {
62                 /* no new tokens */
63                 if ((tokens = vx_tokens_avail(vxi)) < vxi->sched.tokens_min) {
64                         /* enough tokens will be available in */
65                         if (vxi->sched.tokens_min == 0)
66                                 return delta - vxi->sched.interval;
67                         return delta - vxi->sched.interval *
68                                 vxi->sched.tokens_min / vxi->sched.fill_rate;
69                 }
70         }
71         /* we have some tokens left */
72         return tokens;
73 }
74
75 /*
76  * effective_prio - return the priority that is based on the static
77  * priority but is modified by bonuses/penalties.
78  *
79  * We scale the actual sleep average [0 .... MAX_SLEEP_AVG]
80  * into a -4 ... 0 ... +4 bonus/penalty range.
81  *
82  * Additionally, we scale another amount based on the number of
83  * CPU tokens currently held by the context, if the process is
84  * part of a context (and the appropriate SCHED flag is set).
85  * This ranges from -5 ... 0 ... +15, quadratically.
86  *
87  * So, the total bonus is -9 .. 0 .. +19
88  * We use ~50% of the full 0...39 priority range so that:
89  *
90  * 1) nice +19 interactive tasks do not preempt nice 0 CPU hogs.
91  * 2) nice -20 CPU hogs do not get preempted by nice 0 tasks.
92  *    unless that context is far exceeding its CPU allocation.
93  *
94  * Both properties are important to certain workloads.
95  */
96 int effective_vavavoom(task_t *p, int max_prio)
97 {
98         struct vx_info *vxi = p->vx_info;
99         int vavavoom, max;
100
101         /* lots of tokens = lots of vavavoom
102          *      no tokens = no vavavoom      */
103         if ((vavavoom = atomic_read(&vxi->sched.tokens)) >= 0) {
104                 max = vxi->sched.tokens_max;
105                 vavavoom = max - vavavoom;
106                 max = max * max;
107                 vavavoom = max_prio * VAVAVOOM_RATIO / 100
108                         * (vavavoom*vavavoom - (max >> 2)) / max;
109                 /*  alternative, geometric mapping
110                 vavavoom = -( MAX_USER_PRIO*VAVAVOOM_RATIO/100 * vavavoom
111                         / vxi->sched.tokens_max -
112                         MAX_USER_PRIO*VAVAVOOM_RATIO/100/2); */
113         } else
114                 vavavoom = 0;
115         /* vavavoom = ( MAX_USER_PRIO*VAVAVOOM_RATIO/100*tokens_left(p) -
116                 MAX_USER_PRIO*VAVAVOOM_RATIO/100/2); */
117
118         return vavavoom;
119 }
120
121
122 int vc_set_sched(uint32_t xid, void __user *data)
123 {
124         struct vcmd_set_sched_v2 vc_data;
125         struct vx_info *vxi;
126
127         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
128                 return -EFAULT;
129         
130         vxi = locate_vx_info(xid);
131         if (!vxi)
132                 return -EINVAL;
133
134         spin_lock(&vxi->sched.tokens_lock);
135
136         if (vc_data.interval != SCHED_KEEP)
137                 vxi->sched.interval = vc_data.interval;
138         if (vc_data.fill_rate != SCHED_KEEP)
139                 vxi->sched.fill_rate = vc_data.fill_rate;
140         if (vc_data.tokens_min != SCHED_KEEP)
141                 vxi->sched.tokens_min = vc_data.tokens_min;
142         if (vc_data.tokens_max != SCHED_KEEP)
143                 vxi->sched.tokens_max = vc_data.tokens_max;
144         if (vc_data.tokens != SCHED_KEEP)
145                 atomic_set(&vxi->sched.tokens, vc_data.tokens);
146
147         /* Sanity check the resultant values */
148         if (vxi->sched.fill_rate <= 0)
149                 vxi->sched.fill_rate = 1;
150         if (vxi->sched.interval <= 0)
151                 vxi->sched.interval = HZ;
152         if (vxi->sched.tokens_max == 0)
153                 vxi->sched.tokens_max = 1;
154         if (atomic_read(&vxi->sched.tokens) > vxi->sched.tokens_max)
155                 atomic_set(&vxi->sched.tokens, vxi->sched.tokens_max);
156         if (vxi->sched.tokens_min > vxi->sched.tokens_max)
157                 vxi->sched.tokens_min = vxi->sched.tokens_max;
158
159         spin_unlock(&vxi->sched.tokens_lock);
160         put_vx_info(vxi);
161         return 0;
162 }
163