debuggers.hg
annotate xen/common/sched_bvt.c @ 3658:0ef6e8e6e85d
bitkeeper revision 1.1159.212.71 (4200f0afX_JumfbEHQex6TdFENULMQ)
Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno-xenod/BK/xen-unstable.bk
into labyrinth.cl.cam.ac.uk:/auto/groups/xeno/users/iap10/xeno-clone/xen-unstable.bk
Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno-xenod/BK/xen-unstable.bk
into labyrinth.cl.cam.ac.uk:/auto/groups/xeno/users/iap10/xeno-clone/xen-unstable.bk
author | iap10@labyrinth.cl.cam.ac.uk |
---|---|
date | Wed Feb 02 15:24:31 2005 +0000 (2005-02-02) |
parents | c6f1bab39d4f 10a0f6b0a996 |
children | bbe8541361dd 4294cfa9fad3 |
rev | line source |
---|---|
mwilli2@1232 | 1 /* -*- Mode:C; c-basic-offset:4; tab-width:4 -*- |
mwilli2@1232 | 2 **************************************************************************** |
mwilli2@1232 | 3 * (C) 2002-2003 - Rolf Neugebauer - Intel Research Cambridge |
mwilli2@1232 | 4 * (C) 2002-2003 University of Cambridge |
mwilli2@1232 | 5 * (C) 2004 - Mark Williamson - Intel Research Cambridge |
mwilli2@1232 | 6 **************************************************************************** |
mwilli2@1232 | 7 * |
mwilli2@1232 | 8 * File: common/schedule.c |
mwilli2@1232 | 9 * Author: Rolf Neugebauer & Keir Fraser |
mwilli2@1232 | 10 * Updated for generic API by Mark Williamson |
mwilli2@1232 | 11 * |
mwilli2@1232 | 12 * Description: CPU scheduling |
mwilli2@1232 | 13 * implements A Borrowed Virtual Time scheduler. |
mwilli2@1232 | 14 * (see Duda & Cheriton SOSP'99) |
mwilli2@1232 | 15 */ |
mwilli2@1232 | 16 |
kaf24@1248 | 17 #include <xen/config.h> |
kaf24@1248 | 18 #include <xen/init.h> |
kaf24@1248 | 19 #include <xen/lib.h> |
kaf24@1248 | 20 #include <xen/sched.h> |
kaf24@1248 | 21 #include <xen/delay.h> |
kaf24@1248 | 22 #include <xen/event.h> |
kaf24@1248 | 23 #include <xen/time.h> |
kaf24@1248 | 24 #include <xen/ac_timer.h> |
kaf24@1248 | 25 #include <xen/perfc.h> |
kaf24@1248 | 26 #include <xen/sched-if.h> |
kaf24@1248 | 27 #include <xen/slab.h> |
kaf24@1916 | 28 #include <xen/softirq.h> |
mwilli2@1232 | 29 |
mwilli2@1232 | 30 /* all per-domain BVT-specific scheduling info is stored here */ |
cl349@2957 | 31 struct bvt_edom_info |
cl349@2957 | 32 { |
cl349@2957 | 33 struct list_head run_list; /* runqueue list pointers */ |
cl349@2957 | 34 u32 avt; /* actual virtual time */ |
cl349@2957 | 35 u32 evt; /* effective virtual time */ |
cl349@2957 | 36 struct exec_domain *exec_domain; |
cl349@2957 | 37 struct bvt_dom_info *inf; |
cl349@2957 | 38 }; |
cl349@2957 | 39 |
mwilli2@1232 | 40 struct bvt_dom_info |
mwilli2@1232 | 41 { |
gm281@1937 | 42 struct domain *domain; /* domain this info belongs to */ |
gm281@2096 | 43 u32 mcu_advance; /* inverse of weight */ |
gm281@1937 | 44 int warpback; /* warp? */ |
gm281@2096 | 45 int warp; /* warp set and within the warp |
kaf24@2633 | 46 limits*/ |
gm281@2096 | 47 s32 warp_value; /* virtual time warp */ |
gm281@2096 | 48 s_time_t warpl; /* warp limit */ |
gm281@2096 | 49 struct ac_timer warp_timer; /* deals with warpl */ |
gm281@2096 | 50 s_time_t warpu; /* unwarp time requirement */ |
gm281@2096 | 51 struct ac_timer unwarp_timer; /* deals with warpu */ |
cl349@2957 | 52 |
cl349@2957 | 53 struct bvt_edom_info ed_inf[MAX_VIRT_CPUS]; |
mwilli2@1232 | 54 }; |
mwilli2@1232 | 55 |
mwilli2@1232 | 56 struct bvt_cpu_info |
mwilli2@1232 | 57 { |
kaf24@2633 | 58 struct list_head runqueue; |
kaf24@2633 | 59 unsigned long svt; |
mwilli2@1232 | 60 }; |
mwilli2@1232 | 61 |
kaf24@1234 | 62 #define BVT_INFO(p) ((struct bvt_dom_info *)(p)->sched_priv) |
cl349@2957 | 63 #define EBVT_INFO(p) ((struct bvt_edom_info *)(p)->ed_sched_priv) |
kaf24@1234 | 64 #define CPU_INFO(cpu) ((struct bvt_cpu_info *)(schedule_data[cpu]).sched_priv) |
cl349@2957 | 65 #define RUNLIST(p) ((struct list_head *)&(EBVT_INFO(p)->run_list)) |
gm281@2017 | 66 #define RUNQUEUE(cpu) ((struct list_head *)&(CPU_INFO(cpu)->runqueue)) |
kaf24@1234 | 67 #define CPU_SVT(cpu) (CPU_INFO(cpu)->svt) |
mwilli2@1232 | 68 |
mwilli2@1232 | 69 #define MCU (s32)MICROSECS(100) /* Minimum unit */ |
mwilli2@1232 | 70 #define MCU_ADVANCE 10 /* default weight */ |
mwilli2@1232 | 71 #define TIME_SLOP (s32)MICROSECS(50) /* allow time to slip a bit */ |
mwilli2@1232 | 72 static s32 ctx_allow = (s32)MILLISECS(5); /* context switch allowance */ |
mwilli2@1232 | 73 |
cl349@2957 | 74 static inline void __add_to_runqueue_head(struct exec_domain *d) |
gm281@2017 | 75 { |
gm281@2017 | 76 list_add(RUNLIST(d), RUNQUEUE(d->processor)); |
gm281@2017 | 77 } |
gm281@2017 | 78 |
cl349@2957 | 79 static inline void __add_to_runqueue_tail(struct exec_domain *d) |
gm281@2017 | 80 { |
gm281@2017 | 81 list_add_tail(RUNLIST(d), RUNQUEUE(d->processor)); |
gm281@2017 | 82 } |
gm281@2017 | 83 |
cl349@2957 | 84 static inline void __del_from_runqueue(struct exec_domain *d) |
gm281@2017 | 85 { |
gm281@2017 | 86 struct list_head *runlist = RUNLIST(d); |
gm281@2017 | 87 list_del(runlist); |
gm281@2017 | 88 runlist->next = NULL; |
gm281@2017 | 89 } |
gm281@2017 | 90 |
cl349@2957 | 91 static inline int __task_on_runqueue(struct exec_domain *d) |
gm281@2017 | 92 { |
gm281@2017 | 93 return (RUNLIST(d))->next != NULL; |
gm281@2017 | 94 } |
gm281@2017 | 95 |
gm281@2096 | 96 |
gm281@2096 | 97 /* Warp/unwarp timer functions */ |
gm281@2096 | 98 static void warp_timer_fn(unsigned long pointer) |
gm281@2096 | 99 { |
gm281@2096 | 100 struct bvt_dom_info *inf = (struct bvt_dom_info *)pointer; |
cl349@2957 | 101 unsigned int cpu = inf->domain->exec_domain[0]->processor; |
gm281@2129 | 102 |
kaf24@2633 | 103 spin_lock_irq(&schedule_data[cpu].schedule_lock); |
kaf24@2633 | 104 |
gm281@2096 | 105 inf->warp = 0; |
kaf24@2633 | 106 |
gm281@2096 | 107 /* unwarp equal to zero => stop warping */ |
kaf24@2633 | 108 if ( inf->warpu == 0 ) |
gm281@2096 | 109 { |
gm281@2096 | 110 inf->warpback = 0; |
kaf24@2633 | 111 cpu_raise_softirq(cpu, SCHEDULE_SOFTIRQ); |
gm281@2096 | 112 } |
gm281@2096 | 113 |
gm281@2096 | 114 /* set unwarp timer */ |
gm281@2096 | 115 inf->unwarp_timer.expires = NOW() + inf->warpu; |
gm281@2096 | 116 add_ac_timer(&inf->unwarp_timer); |
gm281@2096 | 117 |
kaf24@2633 | 118 spin_unlock_irq(&schedule_data[cpu].schedule_lock); |
gm281@2096 | 119 } |
gm281@2096 | 120 |
gm281@2096 | 121 static void unwarp_timer_fn(unsigned long pointer) |
gm281@2096 | 122 { |
kaf24@2633 | 123 struct bvt_dom_info *inf = (struct bvt_dom_info *)pointer; |
cl349@2957 | 124 unsigned int cpu = inf->domain->exec_domain[0]->processor; |
gm281@2096 | 125 |
kaf24@2633 | 126 spin_lock_irq(&schedule_data[cpu].schedule_lock); |
kaf24@2633 | 127 |
kaf24@2633 | 128 if ( inf->warpback ) |
gm281@2096 | 129 { |
gm281@2096 | 130 inf->warp = 1; |
kaf24@2633 | 131 cpu_raise_softirq(cpu, SCHEDULE_SOFTIRQ); |
gm281@2096 | 132 } |
kaf24@2633 | 133 |
kaf24@2633 | 134 spin_unlock_irq(&schedule_data[cpu].schedule_lock); |
gm281@2096 | 135 } |
gm281@2096 | 136 |
cl349@2957 | 137 static inline u32 calc_avt(struct exec_domain *d, s_time_t now) |
gm281@2063 | 138 { |
gm281@2063 | 139 u32 ranfor, mcus; |
cl349@2957 | 140 struct bvt_dom_info *inf = BVT_INFO(d->domain); |
cl349@2957 | 141 struct bvt_edom_info *einf = EBVT_INFO(d); |
gm281@2063 | 142 |
gm281@2063 | 143 ranfor = (u32)(now - d->lastschd); |
gm281@2063 | 144 mcus = (ranfor + MCU - 1)/MCU; |
gm281@2063 | 145 |
cl349@2957 | 146 return einf->avt + mcus * inf->mcu_advance; |
gm281@2063 | 147 } |
gm281@2063 | 148 |
gm281@2017 | 149 /* |
mwilli2@1232 | 150 * Calculate the effective virtual time for a domain. Take into account |
mwilli2@1232 | 151 * warping limits |
mwilli2@1232 | 152 */ |
cl349@2957 | 153 static inline u32 calc_evt(struct exec_domain *d, u32 avt) |
mwilli2@1232 | 154 { |
cl349@2957 | 155 struct bvt_dom_info *inf = BVT_INFO(d->domain); |
kaf24@2633 | 156 /* TODO The warp routines need to be rewritten GM */ |
gm281@2063 | 157 |
gm281@2096 | 158 if ( inf->warp ) |
gm281@2096 | 159 return avt - inf->warp_value; |
mwilli2@1232 | 160 else |
gm281@2063 | 161 return avt; |
mwilli2@1232 | 162 } |
mwilli2@1232 | 163 |
mwilli2@1232 | 164 /** |
mwilli2@1232 | 165 * bvt_alloc_task - allocate BVT private structures for a task |
mwilli2@1232 | 166 * @p: task to allocate private structures for |
mwilli2@1232 | 167 * |
mwilli2@1232 | 168 * Returns non-zero on failure. |
mwilli2@1232 | 169 */ |
cl349@2957 | 170 int bvt_alloc_task(struct exec_domain *ed) |
mwilli2@1232 | 171 { |
cl349@2957 | 172 struct domain *d = ed->domain; |
cl349@2957 | 173 if ( (d->sched_priv == NULL) ) { |
iap10@3652 | 174 if ( (d->sched_priv = xmalloc(struct bvt_dom_info)) == NULL ) |
cl349@2957 | 175 return -1; |
cl349@2957 | 176 memset(d->sched_priv, 0, sizeof(struct bvt_dom_info)); |
cl349@2957 | 177 } |
cl349@2957 | 178 ed->ed_sched_priv = &BVT_INFO(d)->ed_inf[ed->eid]; |
cl349@2957 | 179 BVT_INFO(d)->ed_inf[ed->eid].inf = BVT_INFO(d); |
cl349@2964 | 180 BVT_INFO(d)->ed_inf[ed->eid].exec_domain = ed; |
mwilli2@1232 | 181 return 0; |
mwilli2@1232 | 182 } |
mwilli2@1232 | 183 |
mwilli2@1232 | 184 /* |
mwilli2@1232 | 185 * Add and remove a domain |
mwilli2@1232 | 186 */ |
cl349@2957 | 187 void bvt_add_task(struct exec_domain *d) |
mwilli2@1232 | 188 { |
cl349@2957 | 189 struct bvt_dom_info *inf = BVT_INFO(d->domain); |
cl349@2957 | 190 struct bvt_edom_info *einf = EBVT_INFO(d); |
mwilli2@1232 | 191 ASSERT(inf != NULL); |
kaf24@2633 | 192 ASSERT(d != NULL); |
mwilli2@1232 | 193 |
cl349@2964 | 194 if (d->eid == 0) { |
cl349@2964 | 195 inf->mcu_advance = MCU_ADVANCE; |
cl349@2964 | 196 inf->domain = d->domain; |
cl349@2964 | 197 inf->warpback = 0; |
cl349@2964 | 198 /* Set some default values here. */ |
cl349@2964 | 199 inf->warp = 0; |
cl349@2964 | 200 inf->warp_value = 0; |
cl349@2964 | 201 inf->warpl = MILLISECS(2000); |
cl349@2964 | 202 inf->warpu = MILLISECS(1000); |
cl349@2964 | 203 /* initialise the timers */ |
cl349@2964 | 204 init_ac_timer(&inf->warp_timer); |
cl349@2964 | 205 inf->warp_timer.cpu = d->processor; |
cl349@2964 | 206 inf->warp_timer.data = (unsigned long)inf; |
cl349@2964 | 207 inf->warp_timer.function = &warp_timer_fn; |
cl349@2964 | 208 init_ac_timer(&inf->unwarp_timer); |
cl349@2964 | 209 inf->unwarp_timer.cpu = d->processor; |
cl349@2964 | 210 inf->unwarp_timer.data = (unsigned long)inf; |
cl349@2964 | 211 inf->unwarp_timer.function = &unwarp_timer_fn; |
cl349@2964 | 212 } |
cl349@2964 | 213 |
cl349@2957 | 214 einf->exec_domain = d; |
cl349@2964 | 215 |
cl349@2957 | 216 if ( d->domain->id == IDLE_DOMAIN_ID ) |
mwilli2@1232 | 217 { |
cl349@2957 | 218 einf->avt = einf->evt = ~0U; |
mwilli2@1232 | 219 } |
mwilli2@1232 | 220 else |
mwilli2@1232 | 221 { |
mwilli2@1232 | 222 /* Set avt and evt to system virtual time. */ |
cl349@2957 | 223 einf->avt = CPU_SVT(d->processor); |
cl349@2957 | 224 einf->evt = CPU_SVT(d->processor); |
kaf24@2633 | 225 } |
mwilli2@1232 | 226 } |
mwilli2@1232 | 227 |
cl349@2957 | 228 int bvt_init_idle_task(struct exec_domain *p) |
gm281@1937 | 229 { |
kaf24@2633 | 230 if ( bvt_alloc_task(p) < 0 ) |
kaf24@2633 | 231 return -1; |
gm281@1937 | 232 |
kaf24@2217 | 233 bvt_add_task(p); |
gm281@1937 | 234 |
cl349@2957 | 235 set_bit(EDF_RUNNING, &p->ed_flags); |
gm281@2017 | 236 if ( !__task_on_runqueue(p) ) |
gm281@2017 | 237 __add_to_runqueue_head(p); |
gm281@2007 | 238 |
gm281@1937 | 239 return 0; |
gm281@1937 | 240 } |
gm281@1937 | 241 |
cl349@2957 | 242 void bvt_wake(struct exec_domain *d) |
gm281@2007 | 243 { |
cl349@2957 | 244 struct bvt_edom_info *einf = EBVT_INFO(d); |
cl349@2957 | 245 struct exec_domain *curr; |
gm281@2063 | 246 s_time_t now, r_time; |
gm281@2007 | 247 int cpu = d->processor; |
gm281@2063 | 248 u32 curr_evt; |
gm281@2007 | 249 |
gm281@2017 | 250 if ( unlikely(__task_on_runqueue(d)) ) |
gm281@2007 | 251 return; |
gm281@2007 | 252 |
gm281@2017 | 253 __add_to_runqueue_head(d); |
gm281@2007 | 254 |
gm281@2007 | 255 now = NOW(); |
gm281@2007 | 256 |
gm281@2035 | 257 /* Set the BVT parameters. AVT should always be updated |
kaf24@2633 | 258 if CPU migration ocurred.*/ |
cl349@2957 | 259 if ( einf->avt < CPU_SVT(cpu) || |
cl349@2957 | 260 unlikely(test_bit(EDF_MIGRATED, &d->ed_flags)) ) |
cl349@2957 | 261 einf->avt = CPU_SVT(cpu); |
gm281@2007 | 262 |
gm281@2007 | 263 /* Deal with warping here. */ |
cl349@2957 | 264 einf->evt = calc_evt(d, einf->avt); |
gm281@2007 | 265 |
gm281@2007 | 266 curr = schedule_data[cpu].curr; |
gm281@2063 | 267 curr_evt = calc_evt(curr, calc_avt(curr, now)); |
gm281@2063 | 268 /* Calculate the time the current domain would run assuming |
gm281@2063 | 269 the second smallest evt is of the newly woken domain */ |
gm281@2063 | 270 r_time = curr->lastschd + |
cl349@2957 | 271 ((einf->evt - curr_evt) / BVT_INFO(curr->domain)->mcu_advance) + |
kaf24@2633 | 272 ctx_allow; |
gm281@2007 | 273 |
cl349@2957 | 274 if ( is_idle_task(curr->domain) || (einf->evt <= curr_evt) ) |
gm281@2007 | 275 cpu_raise_softirq(cpu, SCHEDULE_SOFTIRQ); |
gm281@2063 | 276 else if ( schedule_data[cpu].s_timer.expires > r_time ) |
gm281@2063 | 277 mod_ac_timer(&schedule_data[cpu].s_timer, r_time); |
gm281@2007 | 278 } |
gm281@2007 | 279 |
gm281@2007 | 280 |
cl349@2957 | 281 static void bvt_sleep(struct exec_domain *d) |
gm281@2007 | 282 { |
cl349@2957 | 283 if ( test_bit(EDF_RUNNING, &d->ed_flags) ) |
gm281@2007 | 284 cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); |
kaf24@2633 | 285 else if ( __task_on_runqueue(d) ) |
kaf24@2633 | 286 __del_from_runqueue(d); |
gm281@2007 | 287 } |
gm281@2007 | 288 |
mwilli2@1232 | 289 /** |
mwilli2@1232 | 290 * bvt_free_task - free BVT private structures for a task |
kaf24@2633 | 291 * @d: task |
mwilli2@1232 | 292 */ |
kaf24@2633 | 293 void bvt_free_task(struct domain *d) |
mwilli2@1232 | 294 { |
kaf24@2633 | 295 ASSERT(d->sched_priv != NULL); |
iap10@3651 | 296 xfree(d->sched_priv); |
mwilli2@1232 | 297 } |
mwilli2@1232 | 298 |
mwilli2@1232 | 299 /* Control the scheduler. */ |
mwilli2@1232 | 300 int bvt_ctl(struct sched_ctl_cmd *cmd) |
mwilli2@1232 | 301 { |
mwilli2@1232 | 302 struct bvt_ctl *params = &cmd->u.bvt; |
mwilli2@1284 | 303 |
mwilli2@1284 | 304 if ( cmd->direction == SCHED_INFO_PUT ) |
mwilli2@1284 | 305 ctx_allow = params->ctx_allow; |
mwilli2@1284 | 306 else |
mwilli2@1284 | 307 params->ctx_allow = ctx_allow; |
mwilli2@1232 | 308 |
mwilli2@1232 | 309 return 0; |
mwilli2@1232 | 310 } |
mwilli2@1232 | 311 |
mwilli2@1232 | 312 /* Adjust scheduling parameter for a given domain. */ |
kaf24@2633 | 313 int bvt_adjdom( |
kaf24@2633 | 314 struct domain *d, struct sched_adjdom_cmd *cmd) |
mwilli2@1232 | 315 { |
mwilli2@1232 | 316 struct bvt_adjdom *params = &cmd->u.bvt; |
kaf24@2633 | 317 |
mwilli2@1284 | 318 if ( cmd->direction == SCHED_INFO_PUT ) |
mwilli2@1284 | 319 { |
gm281@2096 | 320 u32 mcu_adv = params->mcu_adv; |
gm281@2096 | 321 u32 warpback = params->warpback; |
gm281@2096 | 322 s32 warpvalue = params->warpvalue; |
gm281@2096 | 323 s_time_t warpl = params->warpl; |
gm281@2096 | 324 s_time_t warpu = params->warpu; |
mwilli2@1284 | 325 |
kaf24@2633 | 326 struct bvt_dom_info *inf = BVT_INFO(d); |
mwilli2@1284 | 327 |
mwilli2@1284 | 328 /* Sanity -- this can avoid divide-by-zero. */ |
kaf24@2633 | 329 if ( (mcu_adv == 0) || (warpl < 0) || (warpu < 0) ) |
mwilli2@1284 | 330 return -EINVAL; |
kaf24@2633 | 331 |
mwilli2@1284 | 332 inf->mcu_advance = mcu_adv; |
gm281@2129 | 333 inf->warpback = warpback; |
gm281@2129 | 334 /* The warp should be the same as warpback */ |
gm281@2129 | 335 inf->warp = warpback; |
gm281@2096 | 336 inf->warp_value = warpvalue; |
gm281@2138 | 337 inf->warpl = MILLISECS(warpl); |
gm281@2138 | 338 inf->warpu = MILLISECS(warpu); |
gm281@2138 | 339 |
gm281@2138 | 340 /* If the unwarp timer set up it needs to be removed */ |
gm281@2138 | 341 rem_ac_timer(&inf->unwarp_timer); |
gm281@2138 | 342 /* If we stop warping the warp timer needs to be removed */ |
kaf24@2633 | 343 if ( !warpback ) |
gm281@2138 | 344 rem_ac_timer(&inf->warp_timer); |
mwilli2@1284 | 345 } |
mwilli2@1284 | 346 else if ( cmd->direction == SCHED_INFO_GET ) |
mwilli2@1284 | 347 { |
kaf24@2633 | 348 struct bvt_dom_info *inf = BVT_INFO(d); |
gm281@2096 | 349 params->mcu_adv = inf->mcu_advance; |
gm281@2096 | 350 params->warpvalue = inf->warp_value; |
gm281@2096 | 351 params->warpback = inf->warpback; |
gm281@2096 | 352 params->warpl = inf->warpl; |
gm281@2096 | 353 params->warpu = inf->warpu; |
mwilli2@1284 | 354 } |
mwilli2@1284 | 355 |
mwilli2@1232 | 356 return 0; |
mwilli2@1232 | 357 } |
mwilli2@1232 | 358 |
mwilli2@1232 | 359 |
mwilli2@1232 | 360 /* |
mwilli2@1232 | 361 * The main function |
mwilli2@1232 | 362 * - deschedule the current domain. |
mwilli2@1232 | 363 * - pick a new domain. |
mwilli2@1232 | 364 * i.e., the domain with lowest EVT. |
mwilli2@1232 | 365 * The runqueue should be ordered by EVT so that is easy. |
mwilli2@1232 | 366 */ |
mwilli2@1232 | 367 static task_slice_t bvt_do_schedule(s_time_t now) |
mwilli2@1232 | 368 { |
cl349@2957 | 369 struct domain *d; |
cl349@2957 | 370 struct exec_domain *prev = current, *next = NULL, *next_prime, *ed; |
mwilli2@1232 | 371 int cpu = prev->processor; |
mwilli2@1232 | 372 s32 r_time; /* time for new dom to run */ |
mwilli2@1232 | 373 u32 next_evt, next_prime_evt, min_avt; |
cl349@2957 | 374 struct bvt_dom_info *prev_inf = BVT_INFO(prev->domain); |
cl349@2957 | 375 struct bvt_edom_info *prev_einf = EBVT_INFO(prev); |
cl349@2957 | 376 struct bvt_edom_info *p_einf = NULL; |
cl349@2957 | 377 struct bvt_edom_info *next_einf = NULL; |
cl349@2957 | 378 struct bvt_edom_info *next_prime_einf = NULL; |
mwilli2@1232 | 379 task_slice_t ret; |
mwilli2@1232 | 380 |
cl349@2957 | 381 ASSERT(prev->ed_sched_priv != NULL); |
cl349@2957 | 382 ASSERT(prev_einf != NULL); |
gm281@2017 | 383 ASSERT(__task_on_runqueue(prev)); |
mwilli2@1232 | 384 |
cl349@2957 | 385 if ( likely(!is_idle_task(prev->domain)) ) |
mwilli2@1232 | 386 { |
cl349@2957 | 387 prev_einf->avt = calc_avt(prev, now); |
cl349@2957 | 388 prev_einf->evt = calc_evt(prev, prev_einf->avt); |
gm281@2096 | 389 |
gm281@2129 | 390 if(prev_inf->warpback && prev_inf->warpl > 0) |
gm281@2129 | 391 rem_ac_timer(&prev_inf->warp_timer); |
gm281@2129 | 392 |
gm281@2017 | 393 __del_from_runqueue(prev); |
mwilli2@1232 | 394 |
kaf24@1543 | 395 if ( domain_runnable(prev) ) |
gm281@2017 | 396 __add_to_runqueue_tail(prev); |
mwilli2@1232 | 397 } |
mwilli2@1232 | 398 |
gm281@1937 | 399 |
mwilli2@1232 | 400 /* We should at least have the idle task */ |
gm281@1937 | 401 ASSERT(!list_empty(RUNQUEUE(cpu))); |
mwilli2@1232 | 402 |
mwilli2@1232 | 403 /* |
mwilli2@1232 | 404 * scan through the run queue and pick the task with the lowest evt |
mwilli2@1232 | 405 * *and* the task the second lowest evt. |
mwilli2@1232 | 406 * this code is O(n) but we expect n to be small. |
mwilli2@1232 | 407 */ |
cl349@2957 | 408 next_einf = EBVT_INFO(schedule_data[cpu].idle); |
cl349@2957 | 409 next_prime_einf = NULL; |
mwilli2@1232 | 410 |
mwilli2@1232 | 411 next_evt = ~0U; |
mwilli2@1232 | 412 next_prime_evt = ~0U; |
mwilli2@1232 | 413 min_avt = ~0U; |
mwilli2@1232 | 414 |
kaf24@3571 | 415 list_for_each_entry ( p_einf, RUNQUEUE(cpu), run_list ) |
mwilli2@1232 | 416 { |
cl349@2957 | 417 if ( p_einf->evt < next_evt ) |
mwilli2@1232 | 418 { |
cl349@2957 | 419 next_prime_einf = next_einf; |
gm281@1937 | 420 next_prime_evt = next_evt; |
cl349@2957 | 421 next_einf = p_einf; |
cl349@2957 | 422 next_evt = p_einf->evt; |
mwilli2@1232 | 423 } |
mwilli2@1232 | 424 else if ( next_prime_evt == ~0U ) |
mwilli2@1232 | 425 { |
cl349@2957 | 426 next_prime_evt = p_einf->evt; |
cl349@2957 | 427 next_prime_einf = p_einf; |
mwilli2@1232 | 428 } |
cl349@2957 | 429 else if ( p_einf->evt < next_prime_evt ) |
mwilli2@1232 | 430 { |
cl349@2957 | 431 next_prime_evt = p_einf->evt; |
cl349@2957 | 432 next_prime_einf = p_einf; |
mwilli2@1232 | 433 } |
mwilli2@1232 | 434 |
mwilli2@1232 | 435 /* Determine system virtual time. */ |
cl349@2957 | 436 if ( p_einf->avt < min_avt ) |
cl349@2957 | 437 min_avt = p_einf->avt; |
mwilli2@1232 | 438 } |
gm281@2007 | 439 |
cl349@2957 | 440 if(next_einf->inf->warp && next_einf->inf->warpl > 0) |
gm281@2129 | 441 { |
gm281@2129 | 442 /* Set the timer up */ |
cl349@2957 | 443 next_einf->inf->warp_timer.expires = now + next_einf->inf->warpl; |
gm281@2129 | 444 /* Add it to the heap */ |
cl349@2957 | 445 add_ac_timer(&next_einf->inf->warp_timer); |
gm281@2129 | 446 } |
gm281@2129 | 447 |
gm281@1937 | 448 /* Extract the domain pointers from the dom infos */ |
cl349@2957 | 449 next = next_einf->exec_domain; |
cl349@2957 | 450 next_prime = next_prime_einf->exec_domain; |
gm281@1937 | 451 |
mwilli2@1232 | 452 /* Update system virtual time. */ |
mwilli2@1232 | 453 if ( min_avt != ~0U ) |
mwilli2@1232 | 454 CPU_SVT(cpu) = min_avt; |
mwilli2@1232 | 455 |
mwilli2@1232 | 456 /* check for virtual time overrun on this cpu */ |
mwilli2@1232 | 457 if ( CPU_SVT(cpu) >= 0xf0000000 ) |
mwilli2@1232 | 458 { |
kaf24@2633 | 459 ASSERT(!local_irq_is_enabled()); |
kaf24@2633 | 460 |
kaf24@2844 | 461 write_lock(&domlist_lock); |
gm281@2007 | 462 |
cl349@2957 | 463 for_each_domain ( d ) |
mwilli2@1232 | 464 { |
cl349@2957 | 465 for_each_exec_domain (d, ed) { |
cl349@2957 | 466 if ( ed->processor == cpu ) |
cl349@2957 | 467 { |
cl349@2957 | 468 p_einf = EBVT_INFO(ed); |
cl349@2957 | 469 p_einf->evt -= 0xe0000000; |
cl349@2957 | 470 p_einf->avt -= 0xe0000000; |
cl349@2957 | 471 } |
mwilli2@1232 | 472 } |
mwilli2@1232 | 473 } |
gm281@2007 | 474 |
kaf24@2844 | 475 write_unlock(&domlist_lock); |
gm281@2007 | 476 |
mwilli2@1232 | 477 CPU_SVT(cpu) -= 0xe0000000; |
mwilli2@1232 | 478 } |
mwilli2@1232 | 479 |
mwilli2@1232 | 480 /* work out time for next run through scheduler */ |
cl349@2957 | 481 if ( is_idle_task(next->domain) ) |
mwilli2@1232 | 482 { |
mwilli2@1232 | 483 r_time = ctx_allow; |
mwilli2@1232 | 484 goto sched_done; |
mwilli2@1232 | 485 } |
mwilli2@1232 | 486 |
cl349@2957 | 487 if ( (next_prime == NULL) || is_idle_task(next_prime->domain) ) |
mwilli2@1232 | 488 { |
mwilli2@1232 | 489 /* We have only one runnable task besides the idle task. */ |
mwilli2@1232 | 490 r_time = 10 * ctx_allow; /* RN: random constant */ |
mwilli2@1232 | 491 goto sched_done; |
mwilli2@1232 | 492 } |
mwilli2@1232 | 493 |
mwilli2@1232 | 494 /* |
mwilli2@1232 | 495 * If we are here then we have two runnable tasks. |
mwilli2@1232 | 496 * Work out how long 'next' can run till its evt is greater than |
mwilli2@1232 | 497 * 'next_prime's evt. Take context switch allowance into account. |
mwilli2@1232 | 498 */ |
cl349@3037 | 499 ASSERT(next_prime_einf->evt >= next_einf->evt); |
mwilli2@1232 | 500 |
cl349@2957 | 501 r_time = ((next_prime_einf->evt - next_einf->evt)/next_einf->inf->mcu_advance) |
mwilli2@1232 | 502 + ctx_allow; |
mwilli2@1232 | 503 |
mwilli2@1232 | 504 ASSERT(r_time >= ctx_allow); |
mwilli2@1232 | 505 |
mwilli2@1232 | 506 sched_done: |
mwilli2@1232 | 507 ret.task = next; |
mwilli2@1232 | 508 ret.time = r_time; |
mwilli2@1232 | 509 return ret; |
mwilli2@1232 | 510 } |
mwilli2@1232 | 511 |
mwilli2@1232 | 512 |
cl349@2957 | 513 static void bvt_dump_runq_el(struct exec_domain *p) |
mwilli2@1232 | 514 { |
cl349@2957 | 515 struct bvt_edom_info *inf = EBVT_INFO(p); |
mwilli2@1232 | 516 |
gm281@2096 | 517 printk("mcua=%d ev=0x%08X av=0x%08X ", |
cl349@2957 | 518 inf->inf->mcu_advance, inf->evt, inf->avt); |
mwilli2@1232 | 519 } |
mwilli2@1232 | 520 |
mwilli2@1232 | 521 static void bvt_dump_settings(void) |
mwilli2@1232 | 522 { |
mwilli2@1232 | 523 printk("BVT: mcu=0x%08Xns ctx_allow=0x%08Xns ", (u32)MCU, (s32)ctx_allow ); |
mwilli2@1232 | 524 } |
mwilli2@1232 | 525 |
mwilli2@1232 | 526 static void bvt_dump_cpu_state(int i) |
mwilli2@1232 | 527 { |
kaf24@3571 | 528 struct list_head *queue; |
gm281@1937 | 529 int loop = 0; |
cl349@2957 | 530 struct bvt_edom_info *d_inf; |
cl349@2957 | 531 struct exec_domain *d; |
gm281@1937 | 532 |
mwilli2@1232 | 533 printk("svt=0x%08lX ", CPU_SVT(i)); |
gm281@1937 | 534 |
gm281@1937 | 535 queue = RUNQUEUE(i); |
gm281@1937 | 536 printk("QUEUE rq %lx n: %lx, p: %lx\n", (unsigned long)queue, |
kaf24@2633 | 537 (unsigned long) queue->next, (unsigned long) queue->prev); |
gm281@1937 | 538 |
kaf24@3571 | 539 list_for_each_entry ( d_inf, queue, run_list ) |
gm281@1937 | 540 { |
cl349@2957 | 541 d = d_inf->exec_domain; |
cl349@2957 | 542 printk("%3d: %u has=%c ", loop++, d->domain->id, |
cl349@2957 | 543 test_bit(EDF_RUNNING, &d->ed_flags) ? 'T':'F'); |
gm281@1937 | 544 bvt_dump_runq_el(d); |
gm281@1937 | 545 printk("c=0x%X%08X\n", (u32)(d->cpu_time>>32), (u32)d->cpu_time); |
kaf24@3571 | 546 printk(" l: %p n: %p p: %p\n", |
kaf24@3571 | 547 &d_inf->run_list, d_inf->run_list.next, d_inf->run_list.prev); |
gm281@1937 | 548 } |
gm281@1937 | 549 } |
mwilli2@1232 | 550 |
mwilli2@1232 | 551 /* Initialise the data structures. */ |
mwilli2@1232 | 552 int bvt_init_scheduler() |
mwilli2@1232 | 553 { |
mwilli2@1232 | 554 int i; |
mwilli2@1232 | 555 |
mwilli2@1232 | 556 for ( i = 0; i < NR_CPUS; i++ ) |
mwilli2@1232 | 557 { |
iap10@3650 | 558 schedule_data[i].sched_priv = xmalloc(struct bvt_cpu_info); |
gm281@2007 | 559 |
kaf24@1627 | 560 if ( schedule_data[i].sched_priv == NULL ) |
mwilli2@1232 | 561 { |
kaf24@1234 | 562 printk("Failed to allocate BVT scheduler per-CPU memory!\n"); |
mwilli2@1232 | 563 return -1; |
mwilli2@1232 | 564 } |
mwilli2@1232 | 565 |
gm281@2007 | 566 INIT_LIST_HEAD(RUNQUEUE(i)); |
gm281@2007 | 567 |
mwilli2@1232 | 568 CPU_SVT(i) = 0; /* XXX do I really need to do this? */ |
mwilli2@1232 | 569 } |
mwilli2@1232 | 570 |
mwilli2@1232 | 571 return 0; |
mwilli2@1232 | 572 } |
mwilli2@1232 | 573 |
mwilli2@1232 | 574 struct scheduler sched_bvt_def = { |
mwilli2@1232 | 575 .name = "Borrowed Virtual Time", |
mwilli2@1232 | 576 .opt_name = "bvt", |
mwilli2@1232 | 577 .sched_id = SCHED_BVT, |
mwilli2@1232 | 578 |
mwilli2@1232 | 579 .init_scheduler = bvt_init_scheduler, |
gm281@1937 | 580 .init_idle_task = bvt_init_idle_task, |
mwilli2@1232 | 581 .alloc_task = bvt_alloc_task, |
mwilli2@1232 | 582 .add_task = bvt_add_task, |
mwilli2@1232 | 583 .free_task = bvt_free_task, |
mwilli2@1232 | 584 .do_schedule = bvt_do_schedule, |
mwilli2@1232 | 585 .control = bvt_ctl, |
mwilli2@1232 | 586 .adjdom = bvt_adjdom, |
mwilli2@1232 | 587 .dump_settings = bvt_dump_settings, |
mwilli2@1232 | 588 .dump_cpu_state = bvt_dump_cpu_state, |
kaf24@1916 | 589 .sleep = bvt_sleep, |
kaf24@1916 | 590 .wake = bvt_wake, |
mwilli2@1232 | 591 }; |