1 /* $OpenBSD: kern_sched.c,v 1.62 2019/11/04 18:06:03 visa Exp $ */ 2 /* 3 * Copyright (c) 2007, 2008 Artur Grabowski <art@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 20 #include <sys/sched.h> 21 #include <sys/proc.h> 22 #include <sys/kthread.h> 23 #include <sys/systm.h> 24 #include <sys/resourcevar.h> 25 #include <sys/signalvar.h> 26 #include <sys/mutex.h> 27 #include <sys/task.h> 28 #include <sys/smr.h> 29 30 #include <uvm/uvm_extern.h> 31 32 void sched_kthreads_create(void *); 33 34 int sched_proc_to_cpu_cost(struct cpu_info *ci, struct proc *p); 35 struct proc *sched_steal_proc(struct cpu_info *); 36 37 /* 38 * To help choosing which cpu should run which process we keep track 39 * of cpus which are currently idle and which cpus have processes 40 * queued. 41 */ 42 struct cpuset sched_idle_cpus; 43 struct cpuset sched_queued_cpus; 44 struct cpuset sched_all_cpus; 45 46 /* 47 * Some general scheduler counters. 48 */ 49 uint64_t sched_nmigrations; /* Cpu migration counter */ 50 uint64_t sched_nomigrations; /* Cpu no migration counter */ 51 uint64_t sched_noidle; /* Times we didn't pick the idle task */ 52 uint64_t sched_stolen; /* Times we stole proc from other cpus */ 53 uint64_t sched_choose; /* Times we chose a cpu */ 54 uint64_t sched_wasidle; /* Times we came out of idle */ 55 56 #ifdef MULTIPROCESSOR 57 struct taskq *sbartq; 58 #endif 59 60 int sched_smt; 61 62 /* 63 * A few notes about cpu_switchto that is implemented in MD code. 64 * 65 * cpu_switchto takes two arguments, the old proc and the proc 66 * it should switch to. The new proc will never be NULL, so we always have 67 * a saved state that we need to switch to. The old proc however can 68 * be NULL if the process is exiting. NULL for the old proc simply 69 * means "don't bother saving old state". 70 * 71 * cpu_switchto is supposed to atomically load the new state of the process 72 * including the pcb, pmap and setting curproc, the p_cpu pointer in the 73 * proc and p_stat to SONPROC. Atomically with respect to interrupts, other 74 * cpus in the system must not depend on this state being consistent. 75 * Therefore no locking is necessary in cpu_switchto other than blocking 76 * interrupts during the context switch. 77 */ 78 79 /* 80 * sched_init_cpu is called from main() for the boot cpu, then it's the 81 * responsibility of the MD code to call it for all other cpus. 82 */ 83 void 84 sched_init_cpu(struct cpu_info *ci) 85 { 86 struct schedstate_percpu *spc = &ci->ci_schedstate; 87 int i; 88 89 for (i = 0; i < SCHED_NQS; i++) 90 TAILQ_INIT(&spc->spc_qs[i]); 91 92 spc->spc_idleproc = NULL; 93 94 kthread_create_deferred(sched_kthreads_create, ci); 95 96 LIST_INIT(&spc->spc_deadproc); 97 SIMPLEQ_INIT(&spc->spc_deferred); 98 99 /* 100 * Slight hack here until the cpuset code handles cpu_info 101 * structures. 102 */ 103 cpuset_init_cpu(ci); 104 105 #ifdef __HAVE_CPU_TOPOLOGY 106 if (!sched_smt && ci->ci_smt_id > 0) 107 return; 108 #endif 109 cpuset_add(&sched_all_cpus, ci); 110 } 111 112 void 113 sched_kthreads_create(void *v) 114 { 115 struct cpu_info *ci = v; 116 struct schedstate_percpu *spc = &ci->ci_schedstate; 117 static int num; 118 119 if (fork1(&proc0, FORK_SHAREVM|FORK_SHAREFILES|FORK_NOZOMBIE| 120 FORK_SYSTEM|FORK_SIGHAND|FORK_IDLE, sched_idle, ci, NULL, 121 &spc->spc_idleproc)) 122 panic("fork idle"); 123 124 /* Name it as specified. */ 125 snprintf(spc->spc_idleproc->p_p->ps_comm, 126 sizeof(spc->spc_idleproc->p_p->ps_comm), 127 "idle%d", num); 128 129 num++; 130 } 131 132 void 133 sched_idle(void *v) 134 { 135 struct schedstate_percpu *spc; 136 struct proc *p = curproc; 137 struct cpu_info *ci = v; 138 int s; 139 140 KERNEL_UNLOCK(); 141 142 spc = &ci->ci_schedstate; 143 144 /* 145 * First time we enter here, we're not supposed to idle, 146 * just go away for a while. 147 */ 148 SCHED_LOCK(s); 149 cpuset_add(&sched_idle_cpus, ci); 150 p->p_stat = SSLEEP; 151 p->p_cpu = ci; 152 atomic_setbits_int(&p->p_flag, P_CPUPEG); 153 mi_switch(); 154 cpuset_del(&sched_idle_cpus, ci); 155 SCHED_UNLOCK(s); 156 157 KASSERT(ci == curcpu()); 158 KASSERT(curproc == spc->spc_idleproc); 159 160 while (1) { 161 while (!cpu_is_idle(curcpu())) { 162 struct proc *dead; 163 164 SCHED_LOCK(s); 165 p->p_stat = SSLEEP; 166 mi_switch(); 167 SCHED_UNLOCK(s); 168 169 while ((dead = LIST_FIRST(&spc->spc_deadproc))) { 170 LIST_REMOVE(dead, p_hash); 171 exit2(dead); 172 } 173 } 174 175 splassert(IPL_NONE); 176 177 smr_idle(); 178 179 cpuset_add(&sched_idle_cpus, ci); 180 cpu_idle_enter(); 181 while (spc->spc_whichqs == 0) { 182 #ifdef MULTIPROCESSOR 183 if (spc->spc_schedflags & SPCF_SHOULDHALT && 184 (spc->spc_schedflags & SPCF_HALTED) == 0) { 185 cpuset_del(&sched_idle_cpus, ci); 186 SCHED_LOCK(s); 187 atomic_setbits_int(&spc->spc_schedflags, 188 spc->spc_whichqs ? 0 : SPCF_HALTED); 189 SCHED_UNLOCK(s); 190 wakeup(spc); 191 } 192 #endif 193 cpu_idle_cycle(); 194 } 195 cpu_idle_leave(); 196 cpuset_del(&sched_idle_cpus, ci); 197 } 198 } 199 200 /* 201 * To free our address space we have to jump through a few hoops. 202 * The freeing is done by the reaper, but until we have one reaper 203 * per cpu, we have no way of putting this proc on the deadproc list 204 * and waking up the reaper without risking having our address space and 205 * stack torn from under us before we manage to switch to another proc. 206 * Therefore we have a per-cpu list of dead processes where we put this 207 * proc and have idle clean up that list and move it to the reaper list. 208 * All this will be unnecessary once we can bind the reaper this cpu 209 * and not risk having it switch to another in case it sleeps. 210 */ 211 void 212 sched_exit(struct proc *p) 213 { 214 struct schedstate_percpu *spc = &curcpu()->ci_schedstate; 215 struct timespec ts; 216 struct proc *idle; 217 int s; 218 219 nanouptime(&ts); 220 timespecsub(&ts, &spc->spc_runtime, &ts); 221 timespecadd(&p->p_rtime, &ts, &p->p_rtime); 222 223 LIST_INSERT_HEAD(&spc->spc_deadproc, p, p_hash); 224 225 #ifdef MULTIPROCESSOR 226 /* This process no longer needs to hold the kernel lock. */ 227 KERNEL_ASSERT_LOCKED(); 228 __mp_release_all(&kernel_lock); 229 #endif 230 231 SCHED_LOCK(s); 232 idle = spc->spc_idleproc; 233 idle->p_stat = SRUN; 234 cpu_switchto(NULL, idle); 235 panic("cpu_switchto returned"); 236 } 237 238 /* 239 * Run queue management. 240 */ 241 void 242 sched_init_runqueues(void) 243 { 244 } 245 246 void 247 setrunqueue(struct cpu_info *ci, struct proc *p, uint8_t prio) 248 { 249 struct schedstate_percpu *spc; 250 int queue = prio >> 2; 251 252 if (ci == NULL) 253 ci = sched_choosecpu(p); 254 255 KASSERT(ci != NULL); 256 SCHED_ASSERT_LOCKED(); 257 258 p->p_cpu = ci; 259 p->p_stat = SRUN; 260 p->p_priority = prio; 261 262 spc = &p->p_cpu->ci_schedstate; 263 spc->spc_nrun++; 264 265 TAILQ_INSERT_TAIL(&spc->spc_qs[queue], p, p_runq); 266 spc->spc_whichqs |= (1 << queue); 267 cpuset_add(&sched_queued_cpus, p->p_cpu); 268 269 if (cpuset_isset(&sched_idle_cpus, p->p_cpu)) 270 cpu_unidle(p->p_cpu); 271 272 if (prio < spc->spc_curpriority) 273 need_resched(ci); 274 } 275 276 void 277 remrunqueue(struct proc *p) 278 { 279 struct schedstate_percpu *spc; 280 int queue = p->p_priority >> 2; 281 282 SCHED_ASSERT_LOCKED(); 283 spc = &p->p_cpu->ci_schedstate; 284 spc->spc_nrun--; 285 286 TAILQ_REMOVE(&spc->spc_qs[queue], p, p_runq); 287 if (TAILQ_EMPTY(&spc->spc_qs[queue])) { 288 spc->spc_whichqs &= ~(1 << queue); 289 if (spc->spc_whichqs == 0) 290 cpuset_del(&sched_queued_cpus, p->p_cpu); 291 } 292 } 293 294 struct proc * 295 sched_chooseproc(void) 296 { 297 struct schedstate_percpu *spc = &curcpu()->ci_schedstate; 298 struct proc *p; 299 int queue; 300 301 SCHED_ASSERT_LOCKED(); 302 303 #ifdef MULTIPROCESSOR 304 if (spc->spc_schedflags & SPCF_SHOULDHALT) { 305 if (spc->spc_whichqs) { 306 for (queue = 0; queue < SCHED_NQS; queue++) { 307 while ((p = TAILQ_FIRST(&spc->spc_qs[queue]))) { 308 remrunqueue(p); 309 setrunqueue(NULL, p, p->p_priority); 310 if (p->p_cpu == curcpu()) { 311 KASSERT(p->p_flag & P_CPUPEG); 312 goto again; 313 } 314 } 315 } 316 } 317 p = spc->spc_idleproc; 318 KASSERT(p); 319 KASSERT(p->p_wchan == NULL); 320 p->p_stat = SRUN; 321 return (p); 322 } 323 #endif 324 325 again: 326 if (spc->spc_whichqs) { 327 queue = ffs(spc->spc_whichqs) - 1; 328 p = TAILQ_FIRST(&spc->spc_qs[queue]); 329 remrunqueue(p); 330 sched_noidle++; 331 if (p->p_stat != SRUN) 332 panic("thread %d not in SRUN: %d", p->p_tid, p->p_stat); 333 } else if ((p = sched_steal_proc(curcpu())) == NULL) { 334 p = spc->spc_idleproc; 335 if (p == NULL) { 336 int s; 337 /* 338 * We get here if someone decides to switch during 339 * boot before forking kthreads, bleh. 340 * This is kind of like a stupid idle loop. 341 */ 342 #ifdef MULTIPROCESSOR 343 __mp_unlock(&sched_lock); 344 #endif 345 spl0(); 346 delay(10); 347 SCHED_LOCK(s); 348 goto again; 349 } 350 KASSERT(p); 351 p->p_stat = SRUN; 352 } 353 354 KASSERT(p->p_wchan == NULL); 355 return (p); 356 } 357 358 struct cpu_info * 359 sched_choosecpu_fork(struct proc *parent, int flags) 360 { 361 #ifdef MULTIPROCESSOR 362 struct cpu_info *choice = NULL; 363 fixpt_t load, best_load = ~0; 364 int run, best_run = INT_MAX; 365 struct cpu_info *ci; 366 struct cpuset set; 367 368 #if 0 369 /* 370 * XXX 371 * Don't do this until we have a painless way to move the cpu in exec. 372 * Preferably when nuking the old pmap and getting a new one on a 373 * new cpu. 374 */ 375 /* 376 * PPWAIT forks are simple. We know that the parent will not 377 * run until we exec and choose another cpu, so we just steal its 378 * cpu. 379 */ 380 if (flags & FORK_PPWAIT) 381 return (parent->p_cpu); 382 #endif 383 384 /* 385 * Look at all cpus that are currently idle and have nothing queued. 386 * If there are none, pick the one with least queued procs first, 387 * then the one with lowest load average. 388 */ 389 cpuset_complement(&set, &sched_queued_cpus, &sched_idle_cpus); 390 cpuset_intersection(&set, &set, &sched_all_cpus); 391 if (cpuset_first(&set) == NULL) 392 cpuset_copy(&set, &sched_all_cpus); 393 394 while ((ci = cpuset_first(&set)) != NULL) { 395 cpuset_del(&set, ci); 396 397 load = ci->ci_schedstate.spc_ldavg; 398 run = ci->ci_schedstate.spc_nrun; 399 400 if (choice == NULL || run < best_run || 401 (run == best_run &&load < best_load)) { 402 choice = ci; 403 best_load = load; 404 best_run = run; 405 } 406 } 407 408 return (choice); 409 #else 410 return (curcpu()); 411 #endif 412 } 413 414 struct cpu_info * 415 sched_choosecpu(struct proc *p) 416 { 417 #ifdef MULTIPROCESSOR 418 struct cpu_info *choice = NULL; 419 int last_cost = INT_MAX; 420 struct cpu_info *ci; 421 struct cpuset set; 422 423 /* 424 * If pegged to a cpu, don't allow it to move. 425 */ 426 if (p->p_flag & P_CPUPEG) 427 return (p->p_cpu); 428 429 sched_choose++; 430 431 /* 432 * Look at all cpus that are currently idle and have nothing queued. 433 * If there are none, pick the cheapest of those. 434 * (idle + queued could mean that the cpu is handling an interrupt 435 * at this moment and haven't had time to leave idle yet). 436 */ 437 cpuset_complement(&set, &sched_queued_cpus, &sched_idle_cpus); 438 cpuset_intersection(&set, &set, &sched_all_cpus); 439 440 /* 441 * First, just check if our current cpu is in that set, if it is, 442 * this is simple. 443 * Also, our cpu might not be idle, but if it's the current cpu 444 * and it has nothing else queued and we're curproc, take it. 445 */ 446 if (cpuset_isset(&set, p->p_cpu) || 447 (p->p_cpu == curcpu() && p->p_cpu->ci_schedstate.spc_nrun == 0 && 448 (p->p_cpu->ci_schedstate.spc_schedflags & SPCF_SHOULDHALT) == 0 && 449 curproc == p)) { 450 sched_wasidle++; 451 return (p->p_cpu); 452 } 453 454 if (cpuset_first(&set) == NULL) 455 cpuset_copy(&set, &sched_all_cpus); 456 457 while ((ci = cpuset_first(&set)) != NULL) { 458 int cost = sched_proc_to_cpu_cost(ci, p); 459 460 if (choice == NULL || cost < last_cost) { 461 choice = ci; 462 last_cost = cost; 463 } 464 cpuset_del(&set, ci); 465 } 466 467 if (p->p_cpu != choice) 468 sched_nmigrations++; 469 else 470 sched_nomigrations++; 471 472 return (choice); 473 #else 474 return (curcpu()); 475 #endif 476 } 477 478 /* 479 * Attempt to steal a proc from some cpu. 480 */ 481 struct proc * 482 sched_steal_proc(struct cpu_info *self) 483 { 484 struct proc *best = NULL; 485 #ifdef MULTIPROCESSOR 486 struct schedstate_percpu *spc; 487 int bestcost = INT_MAX; 488 struct cpu_info *ci; 489 struct cpuset set; 490 491 KASSERT((self->ci_schedstate.spc_schedflags & SPCF_SHOULDHALT) == 0); 492 493 /* Don't steal if we don't want to schedule processes in this CPU. */ 494 if (!cpuset_isset(&sched_all_cpus, self)) 495 return (NULL); 496 497 cpuset_copy(&set, &sched_queued_cpus); 498 499 while ((ci = cpuset_first(&set)) != NULL) { 500 struct proc *p; 501 int queue; 502 int cost; 503 504 cpuset_del(&set, ci); 505 506 spc = &ci->ci_schedstate; 507 508 queue = ffs(spc->spc_whichqs) - 1; 509 TAILQ_FOREACH(p, &spc->spc_qs[queue], p_runq) { 510 if (p->p_flag & P_CPUPEG) 511 continue; 512 513 cost = sched_proc_to_cpu_cost(self, p); 514 515 if (best == NULL || cost < bestcost) { 516 best = p; 517 bestcost = cost; 518 } 519 } 520 } 521 if (best == NULL) 522 return (NULL); 523 524 spc = &best->p_cpu->ci_schedstate; 525 remrunqueue(best); 526 best->p_cpu = self; 527 528 sched_stolen++; 529 #endif 530 return (best); 531 } 532 533 #ifdef MULTIPROCESSOR 534 /* 535 * Base 2 logarithm of an int. returns 0 for 0 (yeye, I know). 536 */ 537 static int 538 log2(unsigned int i) 539 { 540 int ret = 0; 541 542 while (i >>= 1) 543 ret++; 544 545 return (ret); 546 } 547 548 /* 549 * Calculate the cost of moving the proc to this cpu. 550 * 551 * What we want is some guesstimate of how much "performance" it will 552 * cost us to move the proc here. Not just for caches and TLBs and NUMA 553 * memory, but also for the proc itself. A highly loaded cpu might not 554 * be the best candidate for this proc since it won't get run. 555 * 556 * Just total guesstimates for now. 557 */ 558 559 int sched_cost_load = 1; 560 int sched_cost_priority = 1; 561 int sched_cost_runnable = 3; 562 int sched_cost_resident = 1; 563 #endif 564 565 int 566 sched_proc_to_cpu_cost(struct cpu_info *ci, struct proc *p) 567 { 568 int cost = 0; 569 #ifdef MULTIPROCESSOR 570 struct schedstate_percpu *spc; 571 int l2resident = 0; 572 573 spc = &ci->ci_schedstate; 574 575 /* 576 * First, account for the priority of the proc we want to move. 577 * More willing to move, the lower the priority of the destination 578 * and the higher the priority of the proc. 579 */ 580 if (!cpuset_isset(&sched_idle_cpus, ci)) { 581 cost += (p->p_priority - spc->spc_curpriority) * 582 sched_cost_priority; 583 cost += sched_cost_runnable; 584 } 585 if (cpuset_isset(&sched_queued_cpus, ci)) 586 cost += spc->spc_nrun * sched_cost_runnable; 587 588 /* 589 * Try to avoid the primary cpu as it handles hardware interrupts. 590 * 591 * XXX Needs to be revisited when we distribute interrupts 592 * over cpus. 593 */ 594 if (CPU_IS_PRIMARY(ci)) 595 cost += sched_cost_runnable; 596 597 /* 598 * Higher load on the destination means we don't want to go there. 599 */ 600 cost += ((sched_cost_load * spc->spc_ldavg) >> FSHIFT); 601 602 /* 603 * If the proc is on this cpu already, lower the cost by how much 604 * it has been running and an estimate of its footprint. 605 */ 606 if (p->p_cpu == ci && p->p_slptime == 0) { 607 l2resident = 608 log2(pmap_resident_count(p->p_vmspace->vm_map.pmap)); 609 cost -= l2resident * sched_cost_resident; 610 } 611 #endif 612 return (cost); 613 } 614 615 /* 616 * Peg a proc to a cpu. 617 */ 618 void 619 sched_peg_curproc(struct cpu_info *ci) 620 { 621 struct proc *p = curproc; 622 int s; 623 624 SCHED_LOCK(s); 625 atomic_setbits_int(&p->p_flag, P_CPUPEG); 626 setrunqueue(ci, p, p->p_usrpri); 627 p->p_ru.ru_nvcsw++; 628 mi_switch(); 629 SCHED_UNLOCK(s); 630 } 631 632 #ifdef MULTIPROCESSOR 633 634 void 635 sched_start_secondary_cpus(void) 636 { 637 CPU_INFO_ITERATOR cii; 638 struct cpu_info *ci; 639 640 CPU_INFO_FOREACH(cii, ci) { 641 struct schedstate_percpu *spc = &ci->ci_schedstate; 642 643 if (CPU_IS_PRIMARY(ci)) 644 continue; 645 atomic_clearbits_int(&spc->spc_schedflags, 646 SPCF_SHOULDHALT | SPCF_HALTED); 647 #ifdef __HAVE_CPU_TOPOLOGY 648 if (!sched_smt && ci->ci_smt_id > 0) 649 continue; 650 #endif 651 cpuset_add(&sched_all_cpus, ci); 652 } 653 } 654 655 void 656 sched_stop_secondary_cpus(void) 657 { 658 CPU_INFO_ITERATOR cii; 659 struct cpu_info *ci; 660 661 /* 662 * Make sure we stop the secondary CPUs. 663 */ 664 CPU_INFO_FOREACH(cii, ci) { 665 struct schedstate_percpu *spc = &ci->ci_schedstate; 666 667 if (CPU_IS_PRIMARY(ci)) 668 continue; 669 cpuset_del(&sched_all_cpus, ci); 670 atomic_setbits_int(&spc->spc_schedflags, SPCF_SHOULDHALT); 671 } 672 CPU_INFO_FOREACH(cii, ci) { 673 struct schedstate_percpu *spc = &ci->ci_schedstate; 674 struct sleep_state sls; 675 676 if (CPU_IS_PRIMARY(ci)) 677 continue; 678 while ((spc->spc_schedflags & SPCF_HALTED) == 0) { 679 sleep_setup(&sls, spc, PZERO, "schedstate"); 680 sleep_finish(&sls, 681 (spc->spc_schedflags & SPCF_HALTED) == 0); 682 } 683 } 684 } 685 686 struct sched_barrier_state { 687 struct cpu_info *ci; 688 struct cond cond; 689 }; 690 691 void 692 sched_barrier_task(void *arg) 693 { 694 struct sched_barrier_state *sb = arg; 695 struct cpu_info *ci = sb->ci; 696 697 sched_peg_curproc(ci); 698 cond_signal(&sb->cond); 699 atomic_clearbits_int(&curproc->p_flag, P_CPUPEG); 700 } 701 702 void 703 sched_barrier(struct cpu_info *ci) 704 { 705 struct sched_barrier_state sb; 706 struct task task; 707 CPU_INFO_ITERATOR cii; 708 709 if (ci == NULL) { 710 CPU_INFO_FOREACH(cii, ci) { 711 if (CPU_IS_PRIMARY(ci)) 712 break; 713 } 714 } 715 KASSERT(ci != NULL); 716 717 if (ci == curcpu()) 718 return; 719 720 sb.ci = ci; 721 cond_init(&sb.cond); 722 task_set(&task, sched_barrier_task, &sb); 723 724 task_add(systqmp, &task); 725 cond_wait(&sb.cond, "sbar"); 726 } 727 728 #else 729 730 void 731 sched_barrier(struct cpu_info *ci) 732 { 733 } 734 735 #endif 736 737 /* 738 * Functions to manipulate cpu sets. 739 */ 740 struct cpu_info *cpuset_infos[MAXCPUS]; 741 static struct cpuset cpuset_all; 742 743 void 744 cpuset_init_cpu(struct cpu_info *ci) 745 { 746 cpuset_add(&cpuset_all, ci); 747 cpuset_infos[CPU_INFO_UNIT(ci)] = ci; 748 } 749 750 void 751 cpuset_clear(struct cpuset *cs) 752 { 753 memset(cs, 0, sizeof(*cs)); 754 } 755 756 void 757 cpuset_add(struct cpuset *cs, struct cpu_info *ci) 758 { 759 unsigned int num = CPU_INFO_UNIT(ci); 760 atomic_setbits_int(&cs->cs_set[num/32], (1 << (num % 32))); 761 } 762 763 void 764 cpuset_del(struct cpuset *cs, struct cpu_info *ci) 765 { 766 unsigned int num = CPU_INFO_UNIT(ci); 767 atomic_clearbits_int(&cs->cs_set[num/32], (1 << (num % 32))); 768 } 769 770 int 771 cpuset_isset(struct cpuset *cs, struct cpu_info *ci) 772 { 773 unsigned int num = CPU_INFO_UNIT(ci); 774 return (cs->cs_set[num/32] & (1 << (num % 32))); 775 } 776 777 void 778 cpuset_add_all(struct cpuset *cs) 779 { 780 cpuset_copy(cs, &cpuset_all); 781 } 782 783 void 784 cpuset_copy(struct cpuset *to, struct cpuset *from) 785 { 786 memcpy(to, from, sizeof(*to)); 787 } 788 789 struct cpu_info * 790 cpuset_first(struct cpuset *cs) 791 { 792 int i; 793 794 for (i = 0; i < CPUSET_ASIZE(ncpus); i++) 795 if (cs->cs_set[i]) 796 return (cpuset_infos[i * 32 + ffs(cs->cs_set[i]) - 1]); 797 798 return (NULL); 799 } 800 801 void 802 cpuset_union(struct cpuset *to, struct cpuset *a, struct cpuset *b) 803 { 804 int i; 805 806 for (i = 0; i < CPUSET_ASIZE(ncpus); i++) 807 to->cs_set[i] = a->cs_set[i] | b->cs_set[i]; 808 } 809 810 void 811 cpuset_intersection(struct cpuset *to, struct cpuset *a, struct cpuset *b) 812 { 813 int i; 814 815 for (i = 0; i < CPUSET_ASIZE(ncpus); i++) 816 to->cs_set[i] = a->cs_set[i] & b->cs_set[i]; 817 } 818 819 void 820 cpuset_complement(struct cpuset *to, struct cpuset *a, struct cpuset *b) 821 { 822 int i; 823 824 for (i = 0; i < CPUSET_ASIZE(ncpus); i++) 825 to->cs_set[i] = b->cs_set[i] & ~a->cs_set[i]; 826 } 827 828 int 829 cpuset_cardinality(struct cpuset *cs) 830 { 831 int cardinality, i, n; 832 833 cardinality = 0; 834 835 for (i = 0; i < CPUSET_ASIZE(ncpus); i++) 836 for (n = cs->cs_set[i]; n != 0; n &= n - 1) 837 cardinality++; 838 839 return (cardinality); 840 } 841 842 int 843 sysctl_hwncpuonline(void) 844 { 845 return cpuset_cardinality(&sched_all_cpus); 846 } 847 848 int 849 cpu_is_online(struct cpu_info *ci) 850 { 851 return cpuset_isset(&sched_all_cpus, ci); 852 } 853 854 #ifdef __HAVE_CPU_TOPOLOGY 855 856 #include <sys/sysctl.h> 857 858 int 859 sysctl_hwsmt(void *oldp, size_t *oldlenp, void *newp, size_t newlen) 860 { 861 CPU_INFO_ITERATOR cii; 862 struct cpu_info *ci; 863 int err, newsmt; 864 865 newsmt = sched_smt; 866 err = sysctl_int(oldp, oldlenp, newp, newlen, &newsmt); 867 if (err) 868 return err; 869 if (newsmt > 1) 870 newsmt = 1; 871 if (newsmt < 0) 872 newsmt = 0; 873 if (newsmt == sched_smt) 874 return 0; 875 876 sched_smt = newsmt; 877 CPU_INFO_FOREACH(cii, ci) { 878 if (CPU_IS_PRIMARY(ci)) 879 continue; 880 if (ci->ci_smt_id == 0) 881 continue; 882 if (sched_smt) 883 cpuset_add(&sched_all_cpus, ci); 884 else 885 cpuset_del(&sched_all_cpus, ci); 886 } 887 888 return 0; 889 } 890 891 #endif 892