Changeset View
Standalone View
sys/kern/subr_smp.c
Show First 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | |||||
#include <machine/cpu.h> | #include <machine/cpu.h> | ||||
#include <machine/smp.h> | #include <machine/smp.h> | ||||
#include "opt_sched.h" | #include "opt_sched.h" | ||||
#ifdef SMP | #ifdef SMP | ||||
MALLOC_DEFINE(M_TOPO, "toponodes", "SMP topology data"); | MALLOC_DEFINE(M_TOPO, "toponodes", "SMP topology data"); | ||||
int cpu_topo_probed = 0; | |||||
struct topo_node topo_root = TOPO_NODE_INITIALIZER(topo_root); | |||||
volatile cpuset_t stopped_cpus; | volatile cpuset_t stopped_cpus; | ||||
volatile cpuset_t started_cpus; | volatile cpuset_t started_cpus; | ||||
volatile cpuset_t suspended_cpus; | volatile cpuset_t suspended_cpus; | ||||
cpuset_t hlt_cpus_mask; | cpuset_t hlt_cpus_mask; | ||||
cpuset_t logical_cpus_mask; | cpuset_t logical_cpus_mask; | ||||
void (*cpustop_restartfunc)(void); | void (*cpustop_restartfunc)(void); | ||||
#endif | #endif | ||||
Show All 26 Lines | |||||
int smp_disabled = 0; /* has smp been disabled? */ | int smp_disabled = 0; /* has smp been disabled? */ | ||||
SYSCTL_INT(_kern_smp, OID_AUTO, disabled, CTLFLAG_RDTUN|CTLFLAG_CAPRD, | SYSCTL_INT(_kern_smp, OID_AUTO, disabled, CTLFLAG_RDTUN|CTLFLAG_CAPRD, | ||||
&smp_disabled, 0, "SMP has been disabled from the loader"); | &smp_disabled, 0, "SMP has been disabled from the loader"); | ||||
int smp_cpus = 1; /* how many cpu's running */ | int smp_cpus = 1; /* how many cpu's running */ | ||||
SYSCTL_INT(_kern_smp, OID_AUTO, cpus, CTLFLAG_RD|CTLFLAG_CAPRD, &smp_cpus, 0, | SYSCTL_INT(_kern_smp, OID_AUTO, cpus, CTLFLAG_RD|CTLFLAG_CAPRD, &smp_cpus, 0, | ||||
"Number of CPUs online"); | "Number of CPUs online"); | ||||
int smp_smt_threads_online = 1; /* how many SMT threads are running per core */ | |||||
SYSCTL_INT(_kern_smp, OID_AUTO, smt_threads_online, CTLFLAG_RD|CTLFLAG_CAPRD, | |||||
markj: "smt_threads_online" sounds like a total count of hardware threads. If you're open to other… | |||||
cemAuthorUnsubmitted Done Inline ActionsSure, I'd be happy to change this to threads_per_core. cem: Sure, I'd be happy to change this to threads_per_core. | |||||
&smp_smt_threads_online, 0, "Number of SMT threads online per core"); | |||||
int smp_cores = 1; /* how many physical cores running */ | |||||
SYSCTL_S32(_hw, OID_AUTO, physicalcpu, CTLFLAG_RD|CTLFLAG_CAPRD, &smp_cores, 0, | |||||
markjUnsubmitted Done Inline ActionsIt seems odd to me to name a single sysctl this way because MacOS does it. kern.smp.cores is consistent with FreeBSD naming, and OneFS already has it IIRC. hw.physicalcpu could be made an alias of kern.smp.cores, but I think the latter should exist. markj: It seems odd to me to name a single sysctl this way because MacOS does it. kern.smp.cores is… | |||||
cemAuthorUnsubmitted Done Inline ActionsYeah, I forgot OneFS had something like this. I'd be happy to make the default kern.smp.cores, and just add hw.physicalcpu as an OS-X compat shim/alias. cem: Yeah, I forgot OneFS had something like this. I'd be happy to make the default kern.smp.cores… | |||||
markjUnsubmitted Done Inline ActionsWhy add a compat shim for this one sysctl? markj: Why add a compat shim for this one sysctl? | |||||
cemAuthorUnsubmitted Done Inline ActionsAs in, why add the alias sysctl at all? Or did I use the wrong terminology in calling a 2nd sysctl a compat shim? I'm picturing just a 2nd sysctl attached to the same variable. As far as why — muscle memory / portability from MacOS. If someone writes a program that uses that sysctl there, it's one less porting barrier to FreeBSD. Ditto administrative use. I'll admit both of these are fairly weak reasons, and I'd be fine dropping the compatibility name. cem: As in, why add the alias sysctl at all? Or did I use the wrong terminology in calling a 2nd… | |||||
markjUnsubmitted Done Inline ActionsMy personal bar for something like that would to have at least one concrete example where having had that sysctl on FreeBSD would have helped someone. In the absence of that, the addition of a compat sysctl is speculative and adds that much more bloat to the kernel. markj: My personal bar for something like that would to have at least one concrete example where… | |||||
"Number of physical CPU cores online"); | |||||
int smp_topology = 0; /* Which topology we're using. */ | int smp_topology = 0; /* Which topology we're using. */ | ||||
SYSCTL_INT(_kern_smp, OID_AUTO, topology, CTLFLAG_RDTUN, &smp_topology, 0, | SYSCTL_INT(_kern_smp, OID_AUTO, topology, CTLFLAG_RDTUN, &smp_topology, 0, | ||||
"Topology override setting; 0 is default provided by hardware."); | "Topology override setting; 0 is default provided by hardware."); | ||||
#ifdef SMP | #ifdef SMP | ||||
/* Enable forwarding of a signal to a process running on a different CPU */ | /* Enable forwarding of a signal to a process running on a different CPU */ | ||||
static int forward_signal_enabled = 1; | static int forward_signal_enabled = 1; | ||||
SYSCTL_INT(_kern_smp, OID_AUTO, forward_signal_enabled, CTLFLAG_RW, | SYSCTL_INT(_kern_smp, OID_AUTO, forward_signal_enabled, CTLFLAG_RW, | ||||
Show All 35 Lines | |||||
SYSINIT(cpu_mp_setmaxid, SI_SUB_TUNABLES, SI_ORDER_FIRST, mp_setmaxid, NULL); | SYSINIT(cpu_mp_setmaxid, SI_SUB_TUNABLES, SI_ORDER_FIRST, mp_setmaxid, NULL); | ||||
/* | /* | ||||
* Call the MD SMP initialization code. | * Call the MD SMP initialization code. | ||||
*/ | */ | ||||
static void | static void | ||||
mp_start(void *dummy) | mp_start(void *dummy) | ||||
{ | { | ||||
struct topo_analysis topology; | |||||
mtx_init(&smp_ipi_mtx, "smp rendezvous", NULL, MTX_SPIN); | mtx_init(&smp_ipi_mtx, "smp rendezvous", NULL, MTX_SPIN); | ||||
/* Probe for MP hardware. */ | /* Probe for MP hardware. */ | ||||
if (smp_disabled != 0 || cpu_mp_probe() == 0) { | if (smp_disabled != 0 || cpu_mp_probe() == 0) { | ||||
mp_ncpus = 1; | mp_ncpus = 1; | ||||
CPU_SETOF(PCPU_GET(cpuid), &all_cpus); | CPU_SETOF(PCPU_GET(cpuid), &all_cpus); | ||||
return; | return; | ||||
} | } | ||||
cpu_mp_start(); | cpu_mp_start(); | ||||
printf("FreeBSD/SMP: Multiprocessor System Detected: %d CPUs\n", | printf("FreeBSD/SMP: Multiprocessor System Detected: %d CPUs\n", | ||||
mp_ncpus); | mp_ncpus); | ||||
/* | |||||
* Best guess, for lack of better information on any given arch. Allow | |||||
* archs to, e.g., override with known information in | |||||
* cpu_mp_announce(), without implementing full topology probing. | |||||
*/ | |||||
smp_cores = mp_ncpus; | |||||
cpu_mp_announce(); | cpu_mp_announce(); | ||||
/* Not all arch support probing this MI topology structure yet */ | |||||
markjUnsubmitted Done Inline ActionsStyle: missing period. markj: Style: missing period. | |||||
cemAuthorUnsubmitted Done Inline ActionsWill fix cem: Will fix | |||||
if (cpu_topo_probed == 0) | |||||
return; | |||||
if (topo_analyze(&topo_root, 0, &topology) == 0) | |||||
return; | |||||
if (topology.entities[TOPO_LEVEL_THREAD] > 1) | |||||
smp_smt_threads_online = topology.entities[TOPO_LEVEL_THREAD]; | |||||
if (topology.entities[TOPO_LEVEL_CORE] > 0) | |||||
smp_cores = topology.entities[TOPO_LEVEL_CORE]; | |||||
markjUnsubmitted Done Inline ActionsUnder what circumstances can this cause mp_ncpus and smp_cores to have different values? markj: Under what circumstances can this cause mp_ncpus and smp_cores to have different values? | |||||
cemAuthorUnsubmitted Done Inline ActionsWell, mp_ncpus includes hyperthreads, while [the goal] smp_cores doesn't. So on a HTT or SMT system, these will differ by the HTT/SMT factor. In practice, there is a bug here in that the CORE count needs to be multiplied by higher level topology factors. E.g., FreeBSD/SMP: Multiprocessor System Detected: 32 CPUs FreeBSD/SMP: 1 package(s) x 2 groups x 2 cache groups x 4 core(s) x 2 hardware threads # ^^^^^^^^^ ... kern.smp.cpus: 32 hw.ncpu: 32 kern.smp.smt_threads_online: 2 # ^^^ so far so good ... hw.physicalcpu: 4 # ^^^ wrong; that's cores per cache group. # Needs to be multiplied by 2 cache groups x 2 groups x 1 package to get # the correct value, 16. cem: Well, mp_ncpus includes hyperthreads, while [the goal] smp_cores doesn't. So on a HTT or SMT… | |||||
markjUnsubmitted Done Inline ActionsI see. Taking a step back, though, the code above will only compile on i386 and amd64, since no other platforms provide topo_analyze(). This might be a signal that smp_ncores should be set in machdep code. What other platforms besides powerpc support SMT? markj: I see. Taking a step back, though, the code above will only compile on i386 and amd64, since no… | |||||
cemAuthorUnsubmitted Done Inline Actionstopo_analyze() is in kern/subr_smp.c — it's not MD code. It should compile everywhere. That's why I selected it, vs adding more MD code. No other archs populate the topology tree that topo_analyze uses at this time, yes. They could, or they could just set the variables in MD code directly as a smaller step. Re: other platforms besides x86 and ppc: Doesn't sparc have SMT? And apparently there are MIPS SMT implementations. It might make sense to separate this into two commits
cem: `topo_analyze()` is in kern/subr_smp.c — it's not MD code. It should //compile// everywhere. | |||||
markjUnsubmitted Done Inline ActionsGot it, I got confused by topo_probe(). I would suggest trying to populate smp_cores in MD code, the same way smp_cpus is initialized. markj: Got it, I got confused by topo_probe().
I would suggest trying to populate smp_cores in MD… | |||||
} | } | ||||
SYSINIT(cpu_mp, SI_SUB_CPU, SI_ORDER_THIRD, mp_start, NULL); | SYSINIT(cpu_mp, SI_SUB_CPU, SI_ORDER_THIRD, mp_start, NULL); | ||||
void | void | ||||
forward_signal(struct thread *td) | forward_signal(struct thread *td) | ||||
{ | { | ||||
int id; | int id; | ||||
▲ Show 20 Lines • Show All 960 Lines • ▼ Show 20 Lines | |||||
* groups per package, the number of cachegroups per group, and the number of | * groups per package, the number of cachegroups per group, and the number of | ||||
* logical processors per cachegroup. 'all' parameter tells whether to include | * logical processors per cachegroup. 'all' parameter tells whether to include | ||||
* administratively disabled logical processors into the analysis. | * administratively disabled logical processors into the analysis. | ||||
*/ | */ | ||||
int | int | ||||
topo_analyze(struct topo_node *topo_root, int all, | topo_analyze(struct topo_node *topo_root, int all, | ||||
struct topo_analysis *results) | struct topo_analysis *results) | ||||
{ | { | ||||
KASSERT(cpu_topo_probed, | |||||
("cannot use %s before probing topology", __func__)); | |||||
results->entities[TOPO_LEVEL_PKG] = -1; | results->entities[TOPO_LEVEL_PKG] = -1; | ||||
results->entities[TOPO_LEVEL_CORE] = -1; | results->entities[TOPO_LEVEL_CORE] = -1; | ||||
results->entities[TOPO_LEVEL_THREAD] = -1; | results->entities[TOPO_LEVEL_THREAD] = -1; | ||||
results->entities[TOPO_LEVEL_GROUP] = -1; | results->entities[TOPO_LEVEL_GROUP] = -1; | ||||
results->entities[TOPO_LEVEL_CACHEGROUP] = -1; | results->entities[TOPO_LEVEL_CACHEGROUP] = -1; | ||||
if (!topo_analyze_table(topo_root, all, TOPO_LEVEL_PKG, results)) | if (!topo_analyze_table(topo_root, all, TOPO_LEVEL_PKG, results)) | ||||
Show All 10 Lines |
"smt_threads_online" sounds like a total count of hardware threads. If you're open to other suggestions, "threads_per_core" seems more intuitive to me.