]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/sched_grrr.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / kern / sched_grrr.c
CommitLineData
6d2010ae 1/*
39037602 2 * Copyright (c) 2009-2016 Apple Inc. All rights reserved.
6d2010ae
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
39037602 5 *
6d2010ae
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
39037602 14 *
6d2010ae
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
39037602 17 *
6d2010ae
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
39037602 25 *
6d2010ae
A
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <mach/mach_types.h>
30#include <mach/machine.h>
31#include <mach/policy.h>
32#include <mach/sync_policy.h>
33#include <mach/thread_act.h>
34
35#include <machine/machine_routines.h>
36#include <machine/sched_param.h>
37#include <machine/machine_cpu.h>
38
39#include <kern/kern_types.h>
40#include <kern/clock.h>
41#include <kern/counters.h>
42#include <kern/cpu_number.h>
43#include <kern/cpu_data.h>
44#include <kern/debug.h>
6d2010ae
A
45#include <kern/macro_help.h>
46#include <kern/machine.h>
47#include <kern/misc_protos.h>
48#include <kern/processor.h>
49#include <kern/queue.h>
50#include <kern/sched.h>
51#include <kern/sched_prim.h>
52#include <kern/syscall_subr.h>
53#include <kern/task.h>
54#include <kern/thread.h>
6d2010ae
A
55
56#include <vm/pmap.h>
57#include <vm/vm_kern.h>
58#include <vm/vm_map.h>
59
60#include <mach/sdt.h>
61
62#include <sys/kdebug.h>
63
64#if defined(CONFIG_SCHED_GRRR_CORE)
65
66static void
67grrr_priority_mapping_init(void);
68
69static boolean_t
70grrr_enqueue(
0a7de745
A
71 grrr_run_queue_t rq,
72 thread_t thread);
39037602 73
6d2010ae
A
74static thread_t
75grrr_select(
0a7de745 76 grrr_run_queue_t rq);
6d2010ae
A
77
78static void
79grrr_remove(
0a7de745
A
80 grrr_run_queue_t rq,
81 thread_t thread);
6d2010ae
A
82
83
84static void
85grrr_sorted_list_insert_group(grrr_run_queue_t rq,
0a7de745 86 grrr_group_t group);
6d2010ae
A
87
88static void
89grrr_rescale_work(grrr_run_queue_t rq);
90
91static void
0a7de745 92grrr_runqueue_init(grrr_run_queue_t runq);
6d2010ae
A
93
94/* Map Mach priorities to ones suitable for proportional sharing */
95static grrr_proportional_priority_t grrr_priority_mapping[NRQS];
96
97/* Map each proportional priority to its group */
98static grrr_group_index_t grrr_group_mapping[NUM_GRRR_PROPORTIONAL_PRIORITIES];
99
0a7de745 100uint32_t grrr_rescale_tick;
6d2010ae
A
101
102#endif /* defined(CONFIG_SCHED_GRRR_CORE) */
103
104#if defined(CONFIG_SCHED_GRRR)
105
106static void
107sched_grrr_init(void);
108
109static void
110sched_grrr_timebase_init(void);
111
112static void
113sched_grrr_processor_init(processor_t processor);
114
115static void
116sched_grrr_pset_init(processor_set_t pset);
117
118static void
119sched_grrr_maintenance_continuation(void);
120
121static thread_t
0a7de745
A
122sched_grrr_choose_thread(processor_t processor,
123 int priority,
124 ast_t reason);
6d2010ae
A
125
126static thread_t
0a7de745 127sched_grrr_steal_thread(processor_set_t pset);
6d2010ae 128
3e170ce0
A
129static int
130sched_grrr_compute_priority(thread_t thread);
6d2010ae
A
131
132static processor_t
0a7de745
A
133sched_grrr_choose_processor( processor_set_t pset,
134 processor_t processor,
135 thread_t thread);
6d2010ae
A
136
137static boolean_t
138sched_grrr_processor_enqueue(
0a7de745
A
139 processor_t processor,
140 thread_t thread,
cb323159 141 sched_options_t options);
6d2010ae
A
142
143static void
144sched_grrr_processor_queue_shutdown(
0a7de745 145 processor_t processor);
6d2010ae
A
146
147static boolean_t
148sched_grrr_processor_queue_remove(
0a7de745
A
149 processor_t processor,
150 thread_t thread);
6d2010ae
A
151
152static boolean_t
0a7de745 153sched_grrr_processor_queue_empty(processor_t processor);
6d2010ae
A
154
155static boolean_t
0a7de745
A
156sched_grrr_processor_queue_has_priority(processor_t processor,
157 int priority,
158 boolean_t gte);
6d2010ae
A
159
160static boolean_t
161sched_grrr_priority_is_urgent(int priority);
162
163static ast_t
164sched_grrr_processor_csw_check(processor_t processor);
165
166static uint32_t
167sched_grrr_initial_quantum_size(thread_t thread);
168
169static sched_mode_t
170sched_grrr_initial_thread_sched_mode(task_t parent_task);
171
6d2010ae 172static boolean_t
0a7de745 173sched_grrr_can_update_priority(thread_t thread);
6d2010ae
A
174
175static void
0a7de745 176sched_grrr_update_priority(thread_t thread);
6d2010ae
A
177
178static void
0a7de745 179sched_grrr_lightweight_update_priority(thread_t thread);
6d2010ae 180
6d2010ae 181static int
0a7de745 182sched_grrr_processor_runq_count(processor_t processor);
6d2010ae
A
183
184static uint64_t
185sched_grrr_processor_runq_stats_count_sum(processor_t processor);
186
fe8ab488 187static int
0a7de745 188sched_grrr_processor_bound_count(processor_t processor);
fe8ab488
A
189
190static void
3e170ce0 191sched_grrr_thread_update_scan(sched_update_scan_context_t scan_context);
fe8ab488 192
6d2010ae 193const struct sched_dispatch_table sched_grrr_dispatch = {
3e170ce0 194 .sched_name = "grrr",
fe8ab488
A
195 .init = sched_grrr_init,
196 .timebase_init = sched_grrr_timebase_init,
197 .processor_init = sched_grrr_processor_init,
198 .pset_init = sched_grrr_pset_init,
199 .maintenance_continuation = sched_grrr_maintenance_continuation,
200 .choose_thread = sched_grrr_choose_thread,
0a7de745 201 .steal_thread_enabled = sched_steal_thread_DISABLED,
fe8ab488 202 .steal_thread = sched_grrr_steal_thread,
3e170ce0 203 .compute_timeshare_priority = sched_grrr_compute_priority,
f427ee49 204 .choose_node = sched_choose_node,
fe8ab488
A
205 .choose_processor = sched_grrr_choose_processor,
206 .processor_enqueue = sched_grrr_processor_enqueue,
207 .processor_queue_shutdown = sched_grrr_processor_queue_shutdown,
208 .processor_queue_remove = sched_grrr_processor_queue_remove,
209 .processor_queue_empty = sched_grrr_processor_queue_empty,
210 .priority_is_urgent = sched_grrr_priority_is_urgent,
211 .processor_csw_check = sched_grrr_processor_csw_check,
212 .processor_queue_has_priority = sched_grrr_processor_queue_has_priority,
213 .initial_quantum_size = sched_grrr_initial_quantum_size,
214 .initial_thread_sched_mode = sched_grrr_initial_thread_sched_mode,
215 .can_update_priority = sched_grrr_can_update_priority,
216 .update_priority = sched_grrr_update_priority,
217 .lightweight_update_priority = sched_grrr_lightweight_update_priority,
3e170ce0 218 .quantum_expire = sched_default_quantum_expire,
fe8ab488
A
219 .processor_runq_count = sched_grrr_processor_runq_count,
220 .processor_runq_stats_count_sum = sched_grrr_processor_runq_stats_count_sum,
fe8ab488
A
221 .processor_bound_count = sched_grrr_processor_bound_count,
222 .thread_update_scan = sched_grrr_thread_update_scan,
3e170ce0
A
223 .multiple_psets_enabled = TRUE,
224 .sched_groups_enabled = FALSE,
5ba3f43e
A
225 .avoid_processor_enabled = FALSE,
226 .thread_avoid_processor = NULL,
227 .processor_balance = sched_SMT_balance,
228
f427ee49
A
229 .rt_runq = sched_rtlocal_runq,
230 .rt_init = sched_rtlocal_init,
231 .rt_queue_shutdown = sched_rtlocal_queue_shutdown,
232 .rt_runq_scan = sched_rtlocal_runq_scan,
233 .rt_runq_count_sum = sched_rtlocal_runq_count_sum,
5ba3f43e
A
234
235 .qos_max_parallelism = sched_qos_max_parallelism,
236 .check_spill = sched_check_spill,
237 .ipi_policy = sched_ipi_policy,
238 .thread_should_yield = sched_thread_should_yield,
cb323159
A
239 .run_count_incr = sched_run_incr,
240 .run_count_decr = sched_run_decr,
241 .update_thread_bucket = sched_update_thread_bucket,
242 .pset_made_schedulable = sched_pset_made_schedulable,
6d2010ae
A
243};
244
0a7de745 245extern int max_unsafe_quanta;
6d2010ae
A
246
247static uint32_t grrr_quantum_us;
248static uint32_t grrr_quantum;
249
0a7de745 250static uint64_t sched_grrr_tick_deadline;
6d2010ae
A
251
252static void
253sched_grrr_init(void)
254{
0a7de745 255 if (default_preemption_rate < 1) {
6d2010ae 256 default_preemption_rate = 100;
0a7de745 257 }
6d2010ae 258 grrr_quantum_us = (1000 * 1000) / default_preemption_rate;
39037602 259
6d2010ae
A
260 printf("standard grrr timeslicing quantum is %d us\n", grrr_quantum_us);
261
262 grrr_priority_mapping_init();
263}
264
265static void
266sched_grrr_timebase_init(void)
267{
0a7de745 268 uint64_t abstime;
6d2010ae
A
269
270 /* standard timeslicing quantum */
271 clock_interval_to_absolutetime_interval(
0a7de745 272 grrr_quantum_us, NSEC_PER_USEC, &abstime);
6d2010ae
A
273 assert((abstime >> 32) == 0 && (uint32_t)abstime != 0);
274 grrr_quantum = (uint32_t)abstime;
39037602 275
6d2010ae
A
276 thread_depress_time = 1 * grrr_quantum;
277 default_timeshare_computation = grrr_quantum / 2;
278 default_timeshare_constraint = grrr_quantum;
39037602 279
6d2010ae
A
280 max_unsafe_computation = max_unsafe_quanta * grrr_quantum;
281 sched_safe_duration = 2 * max_unsafe_quanta * grrr_quantum;
6d2010ae
A
282}
283
284static void
285sched_grrr_processor_init(processor_t processor)
286{
287 grrr_runqueue_init(&processor->grrr_runq);
288}
289
290static void
291sched_grrr_pset_init(processor_set_t pset __unused)
292{
293}
294
295static void
296sched_grrr_maintenance_continuation(void)
297{
0a7de745 298 uint64_t abstime = mach_absolute_time();
39037602 299
6d2010ae 300 grrr_rescale_tick++;
39037602 301
6d2010ae
A
302 /*
303 * Compute various averages.
304 */
39236c6e 305 compute_averages(1);
39037602 306
0a7de745 307 if (sched_grrr_tick_deadline == 0) {
6d2010ae 308 sched_grrr_tick_deadline = abstime;
0a7de745 309 }
39037602 310
0a7de745
A
311 clock_deadline_for_periodic_event(10 * sched_one_second_interval, abstime,
312 &sched_grrr_tick_deadline);
39037602 313
6d2010ae
A
314 assert_wait_deadline((event_t)sched_grrr_maintenance_continuation, THREAD_UNINT, sched_grrr_tick_deadline);
315 thread_block((thread_continue_t)sched_grrr_maintenance_continuation);
316 /*NOTREACHED*/
317}
318
6d2010ae 319static thread_t
0a7de745
A
320sched_grrr_choose_thread(processor_t processor,
321 int priority __unused,
322 ast_t reason __unused)
6d2010ae 323{
0a7de745 324 grrr_run_queue_t rq = &processor->grrr_runq;
39037602 325
0a7de745 326 return grrr_select(rq);
6d2010ae
A
327}
328
329static thread_t
0a7de745 330sched_grrr_steal_thread(processor_set_t pset)
6d2010ae
A
331{
332 pset_unlock(pset);
39037602
A
333
334 return THREAD_NULL;
6d2010ae
A
335}
336
3e170ce0
A
337static int
338sched_grrr_compute_priority(thread_t thread)
6d2010ae 339{
3e170ce0 340 return thread->base_pri;
6d2010ae
A
341}
342
343static processor_t
0a7de745
A
344sched_grrr_choose_processor( processor_set_t pset,
345 processor_t processor,
346 thread_t thread)
6d2010ae
A
347{
348 return choose_processor(pset, processor, thread);
349}
350
351static boolean_t
352sched_grrr_processor_enqueue(
0a7de745
A
353 processor_t processor,
354 thread_t thread,
cb323159 355 sched_options_t options __unused)
6d2010ae 356{
0a7de745
A
357 grrr_run_queue_t rq = &processor->grrr_runq;
358 boolean_t result;
39037602 359
6d2010ae 360 result = grrr_enqueue(rq, thread);
39037602 361
6d2010ae 362 thread->runq = processor;
39037602 363
6d2010ae
A
364 return result;
365}
366
367static void
368sched_grrr_processor_queue_shutdown(
0a7de745 369 processor_t processor)
6d2010ae 370{
0a7de745
A
371 processor_set_t pset = processor->processor_set;
372 thread_t thread;
373 queue_head_t tqueue, bqueue;
39037602 374
6d2010ae
A
375 queue_init(&tqueue);
376 queue_init(&bqueue);
39037602 377
fe8ab488 378 while ((thread = sched_grrr_choose_thread(processor, IDLEPRI, AST_NONE)) != THREAD_NULL) {
6d2010ae
A
379 if (thread->bound_processor == PROCESSOR_NULL) {
380 enqueue_tail(&tqueue, (queue_entry_t)thread);
381 } else {
39037602 382 enqueue_tail(&bqueue, (queue_entry_t)thread);
6d2010ae
A
383 }
384 }
39037602 385
39236c6e 386 while ((thread = (thread_t)(void *)dequeue_head(&bqueue)) != THREAD_NULL) {
6d2010ae 387 sched_grrr_processor_enqueue(processor, thread, SCHED_TAILQ);
39037602
A
388 }
389
6d2010ae 390 pset_unlock(pset);
39037602 391
39236c6e 392 while ((thread = (thread_t)(void *)dequeue_head(&tqueue)) != THREAD_NULL) {
6d2010ae 393 thread_lock(thread);
39037602 394
6d2010ae 395 thread_setrun(thread, SCHED_TAILQ);
39037602 396
6d2010ae
A
397 thread_unlock(thread);
398 }
399}
400
401static boolean_t
402sched_grrr_processor_queue_remove(
0a7de745
A
403 processor_t processor,
404 thread_t thread)
6d2010ae 405{
39037602
A
406 processor_set_t pset = processor->processor_set;
407
408 pset_lock(pset);
409
6d2010ae
A
410 if (processor == thread->runq) {
411 /*
412 * Thread is on a run queue and we have a lock on
413 * that run queue.
414 */
0a7de745 415 grrr_run_queue_t rq = &processor->grrr_runq;
6d2010ae
A
416
417 grrr_remove(rq, thread);
418 } else {
419 /*
420 * The thread left the run queue before we could
39037602 421 * lock the run queue.
6d2010ae
A
422 */
423 assert(thread->runq == PROCESSOR_NULL);
39037602 424 processor = PROCESSOR_NULL;
6d2010ae 425 }
39037602
A
426
427 pset_unlock(pset);
428
0a7de745 429 return processor != PROCESSOR_NULL;
6d2010ae 430}
39037602 431
6d2010ae 432static boolean_t
0a7de745 433sched_grrr_processor_queue_empty(processor_t processor __unused)
6d2010ae
A
434{
435 boolean_t result;
39037602 436
6d2010ae 437 result = (processor->grrr_runq.count == 0);
39037602 438
6d2010ae
A
439 return result;
440}
441
442static boolean_t
0a7de745
A
443sched_grrr_processor_queue_has_priority(processor_t processor,
444 int priority,
445 boolean_t gte __unused)
6d2010ae 446{
0a7de745
A
447 grrr_run_queue_t rq = &processor->grrr_runq;
448 unsigned int i;
6d2010ae
A
449
450 i = grrr_group_mapping[grrr_priority_mapping[priority]];
0a7de745
A
451 for (; i < NUM_GRRR_GROUPS; i++) {
452 if (rq->groups[i].count > 0) {
39037602 453 return TRUE;
0a7de745 454 }
6d2010ae 455 }
39037602
A
456
457 return FALSE;
6d2010ae
A
458}
459
460/* Implement sched_preempt_pri in code */
461static boolean_t
462sched_grrr_priority_is_urgent(int priority)
463{
0a7de745 464 if (priority <= BASEPRI_FOREGROUND) {
6d2010ae 465 return FALSE;
0a7de745 466 }
39037602 467
0a7de745 468 if (priority < MINPRI_KERNEL) {
6d2010ae 469 return TRUE;
0a7de745 470 }
6d2010ae 471
0a7de745 472 if (priority >= BASEPRI_PREEMPT) {
6d2010ae 473 return TRUE;
0a7de745 474 }
39037602 475
6d2010ae
A
476 return FALSE;
477}
478
479static ast_t
480sched_grrr_processor_csw_check(processor_t processor)
481{
0a7de745 482 int count;
39037602 483
6d2010ae 484 count = sched_grrr_processor_runq_count(processor);
39037602 485
0a7de745 486 if (count > 0) {
6d2010ae 487 return AST_PREEMPT;
0a7de745 488 }
39037602 489
6d2010ae
A
490 return AST_NONE;
491}
492
493static uint32_t
494sched_grrr_initial_quantum_size(thread_t thread __unused)
495{
496 return grrr_quantum;
497}
498
499static sched_mode_t
500sched_grrr_initial_thread_sched_mode(task_t parent_task)
501{
0a7de745 502 if (parent_task == kernel_task) {
6d2010ae 503 return TH_MODE_FIXED;
0a7de745 504 } else {
39037602 505 return TH_MODE_TIMESHARE;
0a7de745 506 }
6d2010ae
A
507}
508
6d2010ae 509static boolean_t
0a7de745 510sched_grrr_can_update_priority(thread_t thread __unused)
6d2010ae
A
511{
512 return FALSE;
513}
514
515static void
0a7de745 516sched_grrr_update_priority(thread_t thread __unused)
6d2010ae 517{
39037602 518 return;
6d2010ae
A
519}
520
521static void
0a7de745 522sched_grrr_lightweight_update_priority(thread_t thread __unused)
6d2010ae
A
523{
524 return;
525}
526
6d2010ae 527static int
0a7de745 528sched_grrr_processor_runq_count(processor_t processor)
6d2010ae
A
529{
530 return processor->grrr_runq.count;
531}
532
533static uint64_t
0a7de745 534sched_grrr_processor_runq_stats_count_sum(processor_t processor)
6d2010ae
A
535{
536 return processor->grrr_runq.runq_stats.count_sum;
537}
538
fe8ab488 539static int
0a7de745 540sched_grrr_processor_bound_count(__unused processor_t processor)
fe8ab488
A
541{
542 return 0;
543}
544
545static void
3e170ce0 546sched_grrr_thread_update_scan(__unused sched_update_scan_context_t scan_context)
fe8ab488 547{
39037602 548 return;
fe8ab488
A
549}
550
6d2010ae
A
551#endif /* defined(CONFIG_SCHED_GRRR) */
552
553#if defined(CONFIG_SCHED_GRRR_CORE)
554
555static void
556grrr_priority_mapping_init(void)
557{
558 unsigned int i;
39037602 559
6d2010ae 560 /* Map 0->0 up to 10->20 */
0a7de745 561 for (i = 0; i <= 10; i++) {
f427ee49 562 grrr_priority_mapping[i] = (grrr_proportional_priority_t)(2 * i);
6d2010ae 563 }
39037602 564
6d2010ae 565 /* Map user priorities 11->33 up to 51 -> 153 */
0a7de745 566 for (i = 11; i <= 51; i++) {
f427ee49 567 grrr_priority_mapping[i] = (grrr_proportional_priority_t)(3 * i);
6d2010ae 568 }
39037602 569
6d2010ae 570 /* Map high priorities 52->180 up to 127->255 */
0a7de745 571 for (i = 52; i <= 127; i++) {
f427ee49 572 grrr_priority_mapping[i] = (grrr_proportional_priority_t)(128 + i);
6d2010ae 573 }
39037602 574
6d2010ae 575 for (i = 0; i < NUM_GRRR_PROPORTIONAL_PRIORITIES; i++) {
39037602 576#if 0
6d2010ae
A
577 unsigned j, k;
578 /* Calculate log(i); */
0a7de745
A
579 for (j = 0, k = 1; k <= i; j++, k *= 2) {
580 ;
581 }
6d2010ae 582#endif
39037602 583
6d2010ae 584 /* Groups of 4 */
f427ee49 585 grrr_group_mapping[i] = (grrr_group_index_t)(i >> 2);
6d2010ae 586 }
6d2010ae
A
587}
588
589static thread_t
590grrr_intragroup_schedule(grrr_group_t group)
591{
592 thread_t thread;
593
594 if (group->count == 0) {
595 return THREAD_NULL;
596 }
39037602 597
6d2010ae
A
598 thread = group->current_client;
599 if (thread == THREAD_NULL) {
39236c6e 600 thread = (thread_t)(void *)queue_first(&group->clients);
6d2010ae 601 }
39037602 602
6d2010ae 603 if (1 /* deficit */) {
39236c6e 604 group->current_client = (thread_t)(void *)queue_next((queue_entry_t)thread);
6d2010ae 605 if (queue_end(&group->clients, (queue_entry_t)group->current_client)) {
39236c6e 606 group->current_client = (thread_t)(void *)queue_first(&group->clients);
6d2010ae 607 }
39037602 608
6d2010ae
A
609 thread = group->current_client;
610 }
39037602 611
6d2010ae
A
612 return thread;
613}
614
615static thread_t
616grrr_intergroup_schedule(grrr_run_queue_t rq)
617{
618 thread_t thread;
619 grrr_group_t group;
39037602 620
6d2010ae
A
621 if (rq->count == 0) {
622 return THREAD_NULL;
623 }
39037602 624
6d2010ae 625 group = rq->current_group;
39037602 626
6d2010ae
A
627 if (group == GRRR_GROUP_NULL) {
628 group = (grrr_group_t)queue_first(&rq->sorted_group_list);
629 }
39037602 630
6d2010ae 631 thread = grrr_intragroup_schedule(group);
39037602 632
0a7de745 633 if ((group->work >= (UINT32_MAX - 256)) || (rq->last_rescale_tick != grrr_rescale_tick)) {
6d2010ae
A
634 grrr_rescale_work(rq);
635 }
636 group->work++;
39037602 637
6d2010ae
A
638 if (queue_end(&rq->sorted_group_list, queue_next((queue_entry_t)group))) {
639 /* last group, go back to beginning */
640 group = (grrr_group_t)queue_first(&rq->sorted_group_list);
641 } else {
642 grrr_group_t nextgroup = (grrr_group_t)queue_next((queue_entry_t)group);
643 uint64_t orderleft, orderright;
39037602 644
6d2010ae
A
645 /*
646 * The well-ordering condition for intergroup selection is:
647 *
648 * (group->work+1) / (nextgroup->work+1) > (group->weight) / (nextgroup->weight)
649 *
650 * Multiply both sides by their denominators to avoid division
651 *
652 */
653 orderleft = (group->work + 1) * ((uint64_t)nextgroup->weight);
654 orderright = (nextgroup->work + 1) * ((uint64_t)group->weight);
655 if (orderleft > orderright) {
656 group = nextgroup;
657 } else {
658 group = (grrr_group_t)queue_first(&rq->sorted_group_list);
659 }
660 }
39037602 661
6d2010ae 662 rq->current_group = group;
39037602 663
6d2010ae
A
664 return thread;
665}
666
667static void
0a7de745 668grrr_runqueue_init(grrr_run_queue_t runq)
6d2010ae
A
669{
670 grrr_group_index_t index;
39037602 671
6d2010ae 672 runq->count = 0;
39037602 673
6d2010ae
A
674 for (index = 0; index < NUM_GRRR_GROUPS; index++) {
675 unsigned int prisearch;
676
677 for (prisearch = 0;
0a7de745
A
678 prisearch < NUM_GRRR_PROPORTIONAL_PRIORITIES;
679 prisearch++) {
6d2010ae
A
680 if (grrr_group_mapping[prisearch] == index) {
681 runq->groups[index].minpriority = (grrr_proportional_priority_t)prisearch;
682 break;
683 }
684 }
39037602 685
6d2010ae
A
686 runq->groups[index].index = index;
687
688 queue_init(&runq->groups[index].clients);
689 runq->groups[index].count = 0;
690 runq->groups[index].weight = 0;
691 runq->groups[index].work = 0;
692 runq->groups[index].current_client = THREAD_NULL;
693 }
39037602 694
6d2010ae
A
695 queue_init(&runq->sorted_group_list);
696 runq->weight = 0;
697 runq->current_group = GRRR_GROUP_NULL;
698}
699
700static void
701grrr_rescale_work(grrr_run_queue_t rq)
702{
703 grrr_group_index_t index;
704
705 /* avoid overflow by scaling by 1/8th */
706 for (index = 0; index < NUM_GRRR_GROUPS; index++) {
707 rq->groups[index].work >>= 3;
708 }
709
710 rq->last_rescale_tick = grrr_rescale_tick;
711}
712
713static boolean_t
714grrr_enqueue(
0a7de745
A
715 grrr_run_queue_t rq,
716 thread_t thread)
39037602 717{
0a7de745
A
718 grrr_proportional_priority_t gpriority;
719 grrr_group_index_t gindex;
720 grrr_group_t group;
6d2010ae
A
721
722 gpriority = grrr_priority_mapping[thread->sched_pri];
723 gindex = grrr_group_mapping[gpriority];
724 group = &rq->groups[gindex];
725
6d2010ae
A
726 if (group->count == 0) {
727 /* Empty group, this is the first client */
728 enqueue_tail(&group->clients, (queue_entry_t)thread);
729 group->count = 1;
730 group->weight = gpriority;
731 group->current_client = thread;
732 } else {
733 /* Insert before the current client */
734 if (group->current_client == THREAD_NULL ||
0a7de745 735 queue_first(&group->clients) == (queue_entry_t)group->current_client) {
6d2010ae
A
736 enqueue_head(&group->clients, (queue_entry_t)thread);
737 } else {
738 insque((queue_entry_t)thread, queue_prev((queue_entry_t)group->current_client));
739 }
740 SCHED_STATS_RUNQ_CHANGE(&rq->runq_stats, rq->count);
741 group->count++;
742 group->weight += gpriority;
743
744 /* Since there was already a client, this is on the per-processor sorted list already */
745 remqueue((queue_entry_t)group);
746 }
39037602 747
6d2010ae
A
748 grrr_sorted_list_insert_group(rq, group);
749
750 rq->count++;
751 rq->weight += gpriority;
39037602
A
752
753 return FALSE;
6d2010ae
A
754}
755
756static thread_t
0a7de745 757grrr_select(grrr_run_queue_t rq)
6d2010ae 758{
0a7de745 759 thread_t thread;
6d2010ae
A
760
761 thread = grrr_intergroup_schedule(rq);
762 if (thread != THREAD_NULL) {
0a7de745
A
763 grrr_proportional_priority_t gpriority;
764 grrr_group_index_t gindex;
765 grrr_group_t group;
39037602 766
6d2010ae
A
767 gpriority = grrr_priority_mapping[thread->sched_pri];
768 gindex = grrr_group_mapping[gpriority];
769 group = &rq->groups[gindex];
39037602 770
6d2010ae
A
771 remqueue((queue_entry_t)thread);
772 SCHED_STATS_RUNQ_CHANGE(&rq->runq_stats, rq->count);
773 group->count--;
774 group->weight -= gpriority;
775 if (group->current_client == thread) {
776 group->current_client = THREAD_NULL;
777 }
39037602 778
6d2010ae
A
779 remqueue((queue_entry_t)group);
780 if (group->count == 0) {
781 if (rq->current_group == group) {
782 rq->current_group = GRRR_GROUP_NULL;
783 }
784 } else {
785 /* Need to re-insert in sorted location */
786 grrr_sorted_list_insert_group(rq, group);
787 }
39037602 788
6d2010ae
A
789 rq->count--;
790 rq->weight -= gpriority;
39037602 791
6d2010ae 792 thread->runq = PROCESSOR_NULL;
39037602
A
793 }
794
795 return thread;
6d2010ae
A
796}
797
798static void
799grrr_remove(
0a7de745
A
800 grrr_run_queue_t rq,
801 thread_t thread)
39037602 802{
0a7de745
A
803 grrr_proportional_priority_t gpriority;
804 grrr_group_index_t gindex;
805 grrr_group_t group;
39037602 806
6d2010ae
A
807 gpriority = grrr_priority_mapping[thread->sched_pri];
808 gindex = grrr_group_mapping[gpriority];
809 group = &rq->groups[gindex];
39037602 810
6d2010ae
A
811 remqueue((queue_entry_t)thread);
812 SCHED_STATS_RUNQ_CHANGE(&rq->runq_stats, rq->count);
813 group->count--;
814 group->weight -= gpriority;
815 if (group->current_client == thread) {
816 group->current_client = THREAD_NULL;
817 }
39037602 818
6d2010ae
A
819 remqueue((queue_entry_t)group);
820 if (group->count == 0) {
821 if (rq->current_group == group) {
822 rq->current_group = GRRR_GROUP_NULL;
823 }
824 } else {
825 /* Need to re-insert in sorted location */
826 grrr_sorted_list_insert_group(rq, group);
827 }
39037602 828
6d2010ae
A
829 rq->count--;
830 rq->weight -= gpriority;
39037602 831
6d2010ae
A
832 thread->runq = PROCESSOR_NULL;
833}
834
835static void
836grrr_sorted_list_insert_group(grrr_run_queue_t rq,
0a7de745 837 grrr_group_t group)
6d2010ae
A
838{
839 /* Simple insertion sort */
840 if (queue_empty(&rq->sorted_group_list)) {
841 enqueue_tail(&rq->sorted_group_list, (queue_entry_t)group);
842 } else {
843 grrr_group_t search_group;
39037602 844
6d2010ae
A
845 /* Start searching from the head (heaviest weight) for the first
846 * element less than us, so we can insert before it
847 */
848 search_group = (grrr_group_t)queue_first(&rq->sorted_group_list);
0a7de745 849 while (!queue_end(&rq->sorted_group_list, (queue_entry_t)search_group)) {
6d2010ae
A
850 if (search_group->weight < group->weight) {
851 /* we should be before this */
852 search_group = (grrr_group_t)queue_prev((queue_entry_t)search_group);
853 break;
0a7de745
A
854 }
855 if (search_group->weight == group->weight) {
6d2010ae
A
856 /* Use group index as a tie breaker */
857 if (search_group->index < group->index) {
858 search_group = (grrr_group_t)queue_prev((queue_entry_t)search_group);
859 break;
860 }
861 }
39037602 862
6d2010ae
A
863 /* otherwise, our weight is too small, keep going */
864 search_group = (grrr_group_t)queue_next((queue_entry_t)search_group);
865 }
39037602 866
6d2010ae
A
867 if (queue_end(&rq->sorted_group_list, (queue_entry_t)search_group)) {
868 enqueue_tail(&rq->sorted_group_list, (queue_entry_t)group);
869 } else {
870 insque((queue_entry_t)group, (queue_entry_t)search_group);
871 }
872 }
873}
874
875#endif /* defined(CONFIG_SCHED_GRRR_CORE) */