1ce38aceeSKonstantin Belousov /* 2ce38aceeSKonstantin Belousov * Copyright 2026 The FreeBSD Foundation 3ce38aceeSKonstantin Belousov * 4ce38aceeSKonstantin Belousov * SPDX-License-Identifier: BSD-2-Clause 5ce38aceeSKonstantin Belousov * 6ce38aceeSKonstantin Belousov * This software was developed by Konstantin Belousov <kib@FreeBSD.org> 7ce38aceeSKonstantin Belousov * under sponsorship from the FreeBSD Foundation. 8ce38aceeSKonstantin Belousov */ 9ce38aceeSKonstantin Belousov 10ce38aceeSKonstantin Belousov #include "opt_sched.h" 11ce38aceeSKonstantin Belousov 12ce38aceeSKonstantin Belousov #include <sys/systm.h> 13ce38aceeSKonstantin Belousov #include <sys/kernel.h> 14ce38aceeSKonstantin Belousov #include <sys/lock.h> 15ce38aceeSKonstantin Belousov #include <sys/proc.h> 16ce38aceeSKonstantin Belousov #include <sys/runq.h> 17ba8f429fSKonstantin Belousov #include <sys/sbuf.h> 18ce38aceeSKonstantin Belousov #include <sys/sched.h> 19*120ca8d7SKonstantin Belousov #include <sys/smp.h> 20bab24f22SKonstantin Belousov #include <sys/sysctl.h> 21ce38aceeSKonstantin Belousov #include <machine/ifunc.h> 22ce38aceeSKonstantin Belousov 23ce38aceeSKonstantin Belousov const struct sched_instance *active_sched; 24ce38aceeSKonstantin Belousov 25ce38aceeSKonstantin Belousov #ifndef __DO_NOT_HAVE_SYS_IFUNCS 26ce38aceeSKonstantin Belousov #define __DEFINE_SHIM(__m, __r, __n, __p, __a) \ 27ce38aceeSKonstantin Belousov DEFINE_IFUNC(, __r, __n, __p) \ 28ce38aceeSKonstantin Belousov { \ 29ce38aceeSKonstantin Belousov return (active_sched->__m); \ 30ce38aceeSKonstantin Belousov } 31ce38aceeSKonstantin Belousov #else 32ce38aceeSKonstantin Belousov #define __DEFINE_SHIM(__m, __r, __n, __p, __a) \ 33ce38aceeSKonstantin Belousov __r \ 34ce38aceeSKonstantin Belousov __n __p \ 35ce38aceeSKonstantin Belousov { \ 36ce38aceeSKonstantin Belousov return (active_sched->__m __a); \ 37ce38aceeSKonstantin Belousov } 38ce38aceeSKonstantin Belousov #endif 39ce38aceeSKonstantin Belousov #define DEFINE_SHIM0(__m, __r, __n) \ 40ce38aceeSKonstantin Belousov __DEFINE_SHIM(__m, __r, __n, (void), ()) 41ce38aceeSKonstantin Belousov #define DEFINE_SHIM1(__m, __r, __n, __t1, __a1) \ 42ce38aceeSKonstantin Belousov __DEFINE_SHIM(__m, __r, __n, (__t1 __a1), (__a1)) 43ce38aceeSKonstantin Belousov #define DEFINE_SHIM2(__m, __r, __n, __t1, __a1, __t2, __a2) \ 44ce38aceeSKonstantin Belousov __DEFINE_SHIM(__m, __r, __n, (__t1 __a1, __t2 __a2), (__a1, __a2)) 45ce38aceeSKonstantin Belousov 46ce38aceeSKonstantin Belousov DEFINE_SHIM0(load, int, sched_load) 47ce38aceeSKonstantin Belousov DEFINE_SHIM0(rr_interval, int, sched_rr_interval) 48ce38aceeSKonstantin Belousov DEFINE_SHIM0(runnable, bool, sched_runnable) 49ce38aceeSKonstantin Belousov DEFINE_SHIM2(exit, void, sched_exit, struct proc *, p, 50ce38aceeSKonstantin Belousov struct thread *, childtd) 51ce38aceeSKonstantin Belousov DEFINE_SHIM2(fork, void, sched_fork, struct thread *, td, 52ce38aceeSKonstantin Belousov struct thread *, childtd) 53ce38aceeSKonstantin Belousov DEFINE_SHIM1(fork_exit, void, sched_fork_exit, struct thread *, td) 54ce38aceeSKonstantin Belousov DEFINE_SHIM2(class, void, sched_class, struct thread *, td, int, class) 55ce38aceeSKonstantin Belousov DEFINE_SHIM2(nice, void, sched_nice, struct proc *, p, int, nice) 56ce38aceeSKonstantin Belousov DEFINE_SHIM0(ap_entry, void, sched_ap_entry) 57ce38aceeSKonstantin Belousov DEFINE_SHIM2(exit_thread, void, sched_exit_thread, struct thread *, td, 58ce38aceeSKonstantin Belousov struct thread *, child) 59ce38aceeSKonstantin Belousov DEFINE_SHIM1(estcpu, u_int, sched_estcpu, struct thread *, td) 60ce38aceeSKonstantin Belousov DEFINE_SHIM2(fork_thread, void, sched_fork_thread, struct thread *, td, 61ce38aceeSKonstantin Belousov struct thread *, child) 62ce38aceeSKonstantin Belousov DEFINE_SHIM2(ithread_prio, void, sched_ithread_prio, struct thread *, td, 63ce38aceeSKonstantin Belousov u_char, prio) 64ce38aceeSKonstantin Belousov DEFINE_SHIM2(lend_prio, void, sched_lend_prio, struct thread *, td, 65ce38aceeSKonstantin Belousov u_char, prio) 66ce38aceeSKonstantin Belousov DEFINE_SHIM2(lend_user_prio, void, sched_lend_user_prio, struct thread *, td, 67ce38aceeSKonstantin Belousov u_char, pri) 68ce38aceeSKonstantin Belousov DEFINE_SHIM2(lend_user_prio_cond, void, sched_lend_user_prio_cond, 69ce38aceeSKonstantin Belousov struct thread *, td, u_char, pri) 70ce38aceeSKonstantin Belousov DEFINE_SHIM1(pctcpu, fixpt_t, sched_pctcpu, struct thread *, td) 71ce38aceeSKonstantin Belousov DEFINE_SHIM2(prio, void, sched_prio, struct thread *, td, u_char, prio) 72ce38aceeSKonstantin Belousov DEFINE_SHIM2(sleep, void, sched_sleep, struct thread *, td, int, prio) 73ce38aceeSKonstantin Belousov DEFINE_SHIM2(sswitch, void, sched_switch, struct thread *, td, int, flags) 74ce38aceeSKonstantin Belousov DEFINE_SHIM1(throw, void, sched_throw, struct thread *, td) 75ce38aceeSKonstantin Belousov DEFINE_SHIM2(unlend_prio, void, sched_unlend_prio, struct thread *, td, 76ce38aceeSKonstantin Belousov u_char, prio) 77ce38aceeSKonstantin Belousov DEFINE_SHIM2(user_prio, void, sched_user_prio, struct thread *, td, 78ce38aceeSKonstantin Belousov u_char, prio) 79ce38aceeSKonstantin Belousov DEFINE_SHIM1(userret_slowpath, void, sched_userret_slowpath, 80ce38aceeSKonstantin Belousov struct thread *, td) 81ce38aceeSKonstantin Belousov DEFINE_SHIM2(add, void, sched_add, struct thread *, td, int, flags) 82ce38aceeSKonstantin Belousov DEFINE_SHIM0(choose, struct thread *, sched_choose) 83ce38aceeSKonstantin Belousov DEFINE_SHIM2(clock, void, sched_clock, struct thread *, td, int, cnt) 84ce38aceeSKonstantin Belousov DEFINE_SHIM1(idletd, void, sched_idletd, void *, dummy) 85ce38aceeSKonstantin Belousov DEFINE_SHIM1(preempt, void, sched_preempt, struct thread *, td) 86ce38aceeSKonstantin Belousov DEFINE_SHIM1(relinquish, void, sched_relinquish, struct thread *, td) 87ce38aceeSKonstantin Belousov DEFINE_SHIM1(rem, void, sched_rem, struct thread *, td) 88ce38aceeSKonstantin Belousov DEFINE_SHIM2(wakeup, void, sched_wakeup, struct thread *, td, int, srqflags) 89ce38aceeSKonstantin Belousov DEFINE_SHIM2(bind, void, sched_bind, struct thread *, td, int, cpu) 90ce38aceeSKonstantin Belousov DEFINE_SHIM1(unbind, void, sched_unbind, struct thread *, td) 91ce38aceeSKonstantin Belousov DEFINE_SHIM1(is_bound, int, sched_is_bound, struct thread *, td) 92ce38aceeSKonstantin Belousov DEFINE_SHIM1(affinity, void, sched_affinity, struct thread *, td) 93ce38aceeSKonstantin Belousov DEFINE_SHIM0(sizeof_proc, int, sched_sizeof_proc) 94ce38aceeSKonstantin Belousov DEFINE_SHIM0(sizeof_thread, int, sched_sizeof_thread) 95ce38aceeSKonstantin Belousov DEFINE_SHIM1(tdname, char *, sched_tdname, struct thread *, td) 96ce38aceeSKonstantin Belousov DEFINE_SHIM1(clear_tdname, void, sched_clear_tdname, struct thread *, td) 97c384b35eSKonstantin Belousov DEFINE_SHIM0(do_timer_accounting, bool, sched_do_timer_accounting) 98b602ba1bSKonstantin Belousov DEFINE_SHIM1(find_l2_neighbor, int, sched_find_l2_neighbor, int, cpu) 99ce38aceeSKonstantin Belousov DEFINE_SHIM0(init_ap, void, schedinit_ap) 100bab24f22SKonstantin Belousov 101a84a39dfSKonstantin Belousov 102a84a39dfSKonstantin Belousov SCHED_STAT_DEFINE(ithread_demotions, "Interrupt thread priority demotions"); 103a84a39dfSKonstantin Belousov SCHED_STAT_DEFINE(ithread_preemptions, 104a84a39dfSKonstantin Belousov "Interrupt thread preemptions due to time-sharing"); 105a84a39dfSKonstantin Belousov 1069409e869SKonstantin Belousov SDT_PROVIDER_DEFINE(sched); 1079409e869SKonstantin Belousov 1089409e869SKonstantin Belousov SDT_PROBE_DEFINE3(sched, , , change__pri, "struct thread *", 1099409e869SKonstantin Belousov "struct proc *", "uint8_t"); 1109409e869SKonstantin Belousov SDT_PROBE_DEFINE3(sched, , , dequeue, "struct thread *", 1119409e869SKonstantin Belousov "struct proc *", "void *"); 1129409e869SKonstantin Belousov SDT_PROBE_DEFINE4(sched, , , enqueue, "struct thread *", 1139409e869SKonstantin Belousov "struct proc *", "void *", "int"); 1149409e869SKonstantin Belousov SDT_PROBE_DEFINE4(sched, , , lend__pri, "struct thread *", 1159409e869SKonstantin Belousov "struct proc *", "uint8_t", "struct thread *"); 1169409e869SKonstantin Belousov SDT_PROBE_DEFINE2(sched, , , load__change, "int", "int"); 1179409e869SKonstantin Belousov SDT_PROBE_DEFINE2(sched, , , off__cpu, "struct thread *", 1189409e869SKonstantin Belousov "struct proc *"); 1199409e869SKonstantin Belousov SDT_PROBE_DEFINE(sched, , , on__cpu); 1209409e869SKonstantin Belousov SDT_PROBE_DEFINE(sched, , , remain__cpu); 1219409e869SKonstantin Belousov SDT_PROBE_DEFINE2(sched, , , surrender, "struct thread *", 1229409e869SKonstantin Belousov "struct proc *"); 1239409e869SKonstantin Belousov 124783b8a0fSKonstantin Belousov #ifdef KDTRACE_HOOKS 125783b8a0fSKonstantin Belousov #include <sys/dtrace_bsd.h> 126783b8a0fSKonstantin Belousov int __read_mostly dtrace_vtime_active; 127783b8a0fSKonstantin Belousov dtrace_vtime_switch_func_t dtrace_vtime_switch_func; 128783b8a0fSKonstantin Belousov #endif 129783b8a0fSKonstantin Belousov 130bab24f22SKonstantin Belousov static char sched_name[32] = "ULE"; 131bab24f22SKonstantin Belousov 132bab24f22SKonstantin Belousov SET_DECLARE(sched_instance_set, struct sched_selection); 133bab24f22SKonstantin Belousov 134bab24f22SKonstantin Belousov void 135bab24f22SKonstantin Belousov sched_instance_select(void) 136bab24f22SKonstantin Belousov { 137bab24f22SKonstantin Belousov struct sched_selection *s, **ss; 138bab24f22SKonstantin Belousov int i; 139bab24f22SKonstantin Belousov 140bab24f22SKonstantin Belousov TUNABLE_STR_FETCH("kern.sched.name", sched_name, sizeof(sched_name)); 141bab24f22SKonstantin Belousov SET_FOREACH(ss, sched_instance_set) { 142bab24f22SKonstantin Belousov s = *ss; 143bab24f22SKonstantin Belousov for (i = 0; s->name[i] == sched_name[i]; i++) { 144bab24f22SKonstantin Belousov if (s->name[i] == '\0') { 145bab24f22SKonstantin Belousov active_sched = s->instance; 146bab24f22SKonstantin Belousov return; 147bab24f22SKonstantin Belousov } 148bab24f22SKonstantin Belousov } 149bab24f22SKonstantin Belousov } 150bab24f22SKonstantin Belousov 151bab24f22SKonstantin Belousov /* 152bab24f22SKonstantin Belousov * No scheduler matching the configuration was found. If 153bab24f22SKonstantin Belousov * there is any scheduler compiled in, at all, use the first 154bab24f22SKonstantin Belousov * scheduler from the linker set. 155bab24f22SKonstantin Belousov */ 156bab24f22SKonstantin Belousov if (SET_BEGIN(sched_instance_set) < SET_LIMIT(sched_instance_set)) { 157bab24f22SKonstantin Belousov s = *SET_BEGIN(sched_instance_set); 158bab24f22SKonstantin Belousov active_sched = s->instance; 159bab24f22SKonstantin Belousov for (i = 0;; i++) { 160bab24f22SKonstantin Belousov sched_name[i] = s->name[i]; 161bab24f22SKonstantin Belousov if (s->name[i] == '\0') 162bab24f22SKonstantin Belousov break; 163bab24f22SKonstantin Belousov } 164bab24f22SKonstantin Belousov } 165bab24f22SKonstantin Belousov } 166bab24f22SKonstantin Belousov 167bab24f22SKonstantin Belousov void 168bab24f22SKonstantin Belousov schedinit(void) 169bab24f22SKonstantin Belousov { 170bab24f22SKonstantin Belousov if (active_sched == NULL) 171bab24f22SKonstantin Belousov panic("Cannot find scheduler %s", sched_name); 172bab24f22SKonstantin Belousov active_sched->init(); 173bab24f22SKonstantin Belousov } 174bab24f22SKonstantin Belousov 175*120ca8d7SKonstantin Belousov struct cpu_group __read_mostly *cpu_top; /* CPU topology */ 176*120ca8d7SKonstantin Belousov 1777efbfd6fSKonstantin Belousov static void 1787efbfd6fSKonstantin Belousov sched_setup(void *dummy) 1797efbfd6fSKonstantin Belousov { 180*120ca8d7SKonstantin Belousov cpu_top = smp_topo(); 1817efbfd6fSKonstantin Belousov active_sched->setup(); 1827efbfd6fSKonstantin Belousov } 1837efbfd6fSKonstantin Belousov SYSINIT(sched_setup, SI_SUB_RUN_QUEUE, SI_ORDER_FIRST, sched_setup, NULL); 1847efbfd6fSKonstantin Belousov 1857efbfd6fSKonstantin Belousov static void 1867efbfd6fSKonstantin Belousov sched_initticks(void *dummy) 1877efbfd6fSKonstantin Belousov { 1887efbfd6fSKonstantin Belousov active_sched->initticks(); 1897efbfd6fSKonstantin Belousov } 1907efbfd6fSKonstantin Belousov SYSINIT(sched_initticks, SI_SUB_CLOCKS, SI_ORDER_THIRD, sched_initticks, 1917efbfd6fSKonstantin Belousov NULL); 1927efbfd6fSKonstantin Belousov 1937efbfd6fSKonstantin Belousov static void 1947efbfd6fSKonstantin Belousov sched_schedcpu(void) 1957efbfd6fSKonstantin Belousov { 1967efbfd6fSKonstantin Belousov active_sched->schedcpu(); 1977efbfd6fSKonstantin Belousov } 1987efbfd6fSKonstantin Belousov SYSINIT(schedcpu, SI_SUB_LAST, SI_ORDER_FIRST, sched_schedcpu, NULL); 1997efbfd6fSKonstantin Belousov 2007efbfd6fSKonstantin Belousov SYSCTL_NODE(_kern, OID_AUTO, sched, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 2017efbfd6fSKonstantin Belousov "Scheduler"); 2027efbfd6fSKonstantin Belousov 203bab24f22SKonstantin Belousov SYSCTL_STRING(_kern_sched, OID_AUTO, name, CTLFLAG_RD, sched_name, 0, 204bab24f22SKonstantin Belousov "Scheduler name"); 205ba8f429fSKonstantin Belousov 206ba8f429fSKonstantin Belousov static int 207ba8f429fSKonstantin Belousov sysctl_kern_sched_available(SYSCTL_HANDLER_ARGS) 208ba8f429fSKonstantin Belousov { 209ba8f429fSKonstantin Belousov struct sched_selection *s, **ss; 210ba8f429fSKonstantin Belousov struct sbuf *sb, sm; 211ba8f429fSKonstantin Belousov int error; 212ba8f429fSKonstantin Belousov bool first; 213ba8f429fSKonstantin Belousov 214ba8f429fSKonstantin Belousov sb = sbuf_new_for_sysctl(&sm, NULL, 0, req); 215ba8f429fSKonstantin Belousov if (sb == NULL) 216ba8f429fSKonstantin Belousov return (ENOMEM); 217ba8f429fSKonstantin Belousov first = true; 218ba8f429fSKonstantin Belousov SET_FOREACH(ss, sched_instance_set) { 219ba8f429fSKonstantin Belousov s = *ss; 220ba8f429fSKonstantin Belousov if (first) 221ba8f429fSKonstantin Belousov first = false; 222ba8f429fSKonstantin Belousov else 223ba8f429fSKonstantin Belousov sbuf_cat(sb, ","); 224ba8f429fSKonstantin Belousov sbuf_cat(sb, s->name); 225ba8f429fSKonstantin Belousov } 226ba8f429fSKonstantin Belousov error = sbuf_finish(sb); 227ba8f429fSKonstantin Belousov sbuf_delete(sb); 228ba8f429fSKonstantin Belousov return (error); 229ba8f429fSKonstantin Belousov } 230ba8f429fSKonstantin Belousov 231ba8f429fSKonstantin Belousov SYSCTL_PROC(_kern_sched, OID_AUTO, available, 232ba8f429fSKonstantin Belousov CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 233ba8f429fSKonstantin Belousov NULL, 0, sysctl_kern_sched_available, "A", 234ba8f429fSKonstantin Belousov "List of available schedulers"); 235ff870b78SKonstantin Belousov 236ff870b78SKonstantin Belousov fixpt_t ccpu; 237ff870b78SKonstantin Belousov SYSCTL_UINT(_kern, OID_AUTO, ccpu, CTLFLAG_RD, &ccpu, 0, 238ff870b78SKonstantin Belousov "Decay factor used for updating %CPU"); 239*120ca8d7SKonstantin Belousov 240*120ca8d7SKonstantin Belousov /* 241*120ca8d7SKonstantin Belousov * Build the CPU topology dump string. Is recursively called to collect 242*120ca8d7SKonstantin Belousov * the topology tree. 243*120ca8d7SKonstantin Belousov */ 244*120ca8d7SKonstantin Belousov static int 245*120ca8d7SKonstantin Belousov sysctl_kern_sched_topology_spec_internal(struct sbuf *sb, 246*120ca8d7SKonstantin Belousov struct cpu_group *cg, int indent) 247*120ca8d7SKonstantin Belousov { 248*120ca8d7SKonstantin Belousov char cpusetbuf[CPUSETBUFSIZ]; 249*120ca8d7SKonstantin Belousov int i, first; 250*120ca8d7SKonstantin Belousov 251*120ca8d7SKonstantin Belousov if (cpu_top == NULL) { 252*120ca8d7SKonstantin Belousov sbuf_printf(sb, "%*s<group level=\"1\" cache-level=\"1\">\n", 253*120ca8d7SKonstantin Belousov indent, ""); 254*120ca8d7SKonstantin Belousov sbuf_printf(sb, "%*s</group>\n", indent, ""); 255*120ca8d7SKonstantin Belousov return (0); 256*120ca8d7SKonstantin Belousov } 257*120ca8d7SKonstantin Belousov 258*120ca8d7SKonstantin Belousov sbuf_printf(sb, "%*s<group level=\"%d\" cache-level=\"%d\">\n", indent, 259*120ca8d7SKonstantin Belousov "", 1 + indent / 2, cg->cg_level); 260*120ca8d7SKonstantin Belousov sbuf_printf(sb, "%*s <cpu count=\"%d\" mask=\"%s\">", indent, "", 261*120ca8d7SKonstantin Belousov cg->cg_count, cpusetobj_strprint(cpusetbuf, &cg->cg_mask)); 262*120ca8d7SKonstantin Belousov first = TRUE; 263*120ca8d7SKonstantin Belousov for (i = cg->cg_first; i <= cg->cg_last; i++) { 264*120ca8d7SKonstantin Belousov if (CPU_ISSET(i, &cg->cg_mask)) { 265*120ca8d7SKonstantin Belousov if (!first) 266*120ca8d7SKonstantin Belousov sbuf_cat(sb, ", "); 267*120ca8d7SKonstantin Belousov else 268*120ca8d7SKonstantin Belousov first = FALSE; 269*120ca8d7SKonstantin Belousov sbuf_printf(sb, "%d", i); 270*120ca8d7SKonstantin Belousov } 271*120ca8d7SKonstantin Belousov } 272*120ca8d7SKonstantin Belousov sbuf_cat(sb, "</cpu>\n"); 273*120ca8d7SKonstantin Belousov 274*120ca8d7SKonstantin Belousov if (cg->cg_flags != 0) { 275*120ca8d7SKonstantin Belousov sbuf_printf(sb, "%*s <flags>", indent, ""); 276*120ca8d7SKonstantin Belousov if ((cg->cg_flags & CG_FLAG_HTT) != 0) 277*120ca8d7SKonstantin Belousov sbuf_cat(sb, "<flag name=\"HTT\">HTT group</flag>"); 278*120ca8d7SKonstantin Belousov if ((cg->cg_flags & CG_FLAG_THREAD) != 0) 279*120ca8d7SKonstantin Belousov sbuf_cat(sb, "<flag name=\"THREAD\">THREAD group</flag>"); 280*120ca8d7SKonstantin Belousov if ((cg->cg_flags & CG_FLAG_SMT) != 0) 281*120ca8d7SKonstantin Belousov sbuf_cat(sb, "<flag name=\"SMT\">SMT group</flag>"); 282*120ca8d7SKonstantin Belousov if ((cg->cg_flags & CG_FLAG_NODE) != 0) 283*120ca8d7SKonstantin Belousov sbuf_cat(sb, "<flag name=\"NODE\">NUMA node</flag>"); 284*120ca8d7SKonstantin Belousov sbuf_cat(sb, "</flags>\n"); 285*120ca8d7SKonstantin Belousov } 286*120ca8d7SKonstantin Belousov 287*120ca8d7SKonstantin Belousov if (cg->cg_children > 0) { 288*120ca8d7SKonstantin Belousov sbuf_printf(sb, "%*s <children>\n", indent, ""); 289*120ca8d7SKonstantin Belousov for (i = 0; i < cg->cg_children; i++) 290*120ca8d7SKonstantin Belousov sysctl_kern_sched_topology_spec_internal(sb, 291*120ca8d7SKonstantin Belousov &cg->cg_child[i], indent + 2); 292*120ca8d7SKonstantin Belousov sbuf_printf(sb, "%*s </children>\n", indent, ""); 293*120ca8d7SKonstantin Belousov } 294*120ca8d7SKonstantin Belousov sbuf_printf(sb, "%*s</group>\n", indent, ""); 295*120ca8d7SKonstantin Belousov return (0); 296*120ca8d7SKonstantin Belousov } 297*120ca8d7SKonstantin Belousov 298*120ca8d7SKonstantin Belousov /* 299*120ca8d7SKonstantin Belousov * Sysctl handler for retrieving topology dump. It's a wrapper for 300*120ca8d7SKonstantin Belousov * the recursive sysctl_kern_smp_topology_spec_internal(). 301*120ca8d7SKonstantin Belousov */ 302*120ca8d7SKonstantin Belousov static int 303*120ca8d7SKonstantin Belousov sysctl_kern_sched_topology_spec(SYSCTL_HANDLER_ARGS) 304*120ca8d7SKonstantin Belousov { 305*120ca8d7SKonstantin Belousov struct sbuf *topo; 306*120ca8d7SKonstantin Belousov int err; 307*120ca8d7SKonstantin Belousov 308*120ca8d7SKonstantin Belousov topo = sbuf_new_for_sysctl(NULL, NULL, 512, req); 309*120ca8d7SKonstantin Belousov if (topo == NULL) 310*120ca8d7SKonstantin Belousov return (ENOMEM); 311*120ca8d7SKonstantin Belousov 312*120ca8d7SKonstantin Belousov sbuf_cat(topo, "<groups>\n"); 313*120ca8d7SKonstantin Belousov err = sysctl_kern_sched_topology_spec_internal(topo, cpu_top, 1); 314*120ca8d7SKonstantin Belousov sbuf_cat(topo, "</groups>\n"); 315*120ca8d7SKonstantin Belousov 316*120ca8d7SKonstantin Belousov if (err == 0) 317*120ca8d7SKonstantin Belousov err = sbuf_finish(topo); 318*120ca8d7SKonstantin Belousov sbuf_delete(topo); 319*120ca8d7SKonstantin Belousov return (err); 320*120ca8d7SKonstantin Belousov } 321*120ca8d7SKonstantin Belousov 322*120ca8d7SKonstantin Belousov SYSCTL_PROC(_kern_sched, OID_AUTO, topology_spec, CTLTYPE_STRING | 323*120ca8d7SKonstantin Belousov CTLFLAG_MPSAFE | CTLFLAG_RD, NULL, 0, 324*120ca8d7SKonstantin Belousov sysctl_kern_sched_topology_spec, "A", 325*120ca8d7SKonstantin Belousov "XML dump of detected CPU topology"); 326