C API to Get the Number of Physical Processors (Packages)

I'm able to get the number of physical processors (packages) by using lstopo command after installing hwloc.
As shown in the example below, there are 2 packages in the server.
Code:
# lstopo | grep Package
  Package L#0
  Package L#1
#

My questions:
  • are there some APIs in C (User/Kernel Mode) available to get the number of physical packages?
  • are there some OID available to get the number of physical packages (by using sysctl)?

Thanks in advance.
 
It's a sysctl(3) you can read.

These for example:
Code:
hw.machine: amd64
hw.model: 13th Gen Intel(R) Core(TM) i3-13100
hw.ncpu: 8
There are a couple more you could query.
 
It's a sysctl(3) you can read.

These for example:
Code:
hw.machine: amd64
hw.model: 13th Gen Intel(R) Core(TM) i3-13100
hw.ncpu: 8
There are a couple more you could query.
Thanks SirDice for the reply.
Yes, the sysctl can get the cpu number.
Do you know how to get the package number? Let's say a server has 2 packages, and each package has some cores...
 
What about dmesg?

dmesg|grep package
FreeBSD/SMP: 1 package(s) x 2 core(s) x 2 hardware threads

aarch64 rk3399 Does have a different output format though:
FreeBSD/SMP: Multiprocessor System Detected: 6 CPUs
 
Code:
 dmidecode -t processor
And look at source code -sysutils/dmidecode
Thanks _al for the reply.
After install dmidecode, can get the socket number as shown below.

# dmidecode -t processor | grep Socket
Socket Designation: CPU1
Socket Designation: CPU2
#

According to github dmidecode, dmidecode reports information about system's hardware as described in system BIOS according to the SMBIOS/DMI standard.
But its source code is complicated.
Do you know if a simple API in C (User/Kernel Mode) available to get the number of physical packages (sockets)?
I am working on a device driver so prefer a simpler solution.
Thanks in advance.
 
  • Thanks
Reactions: _al
Do you know if a simple API in C (User/Kernel Mode) available to get the number of physical packages (sockets)?
I am working on a device driver so prefer a simpler solution.
Well, the source is available for reading. Unfortunately, the code identifying actual physical CPUs seems to be platform-specific, you could start reading in sys/x86/x86/mp_x86.c for x86:
C:
void
cpu_mp_announce(void)
{
    struct topo_node *node;
    const char *hyperthread;
    struct topo_analysis topology;

    printf("FreeBSD/SMP: ");
    if (topo_analyze(&topo_root, 1, &topology)) {
        printf("%d package(s)", topology.entities[TOPO_LEVEL_PKG]);
        // [...]

What FreeBSD attempts to do is extracting a topology graph, which is also used by the scheduler. You can get an XML representation with sysctl kern.sched.topology_spec. Unfortunately, it won't tell you whether the top level is CPUs or already cores of one CPU.
 
Unfortunately, the code identifying actual physical CPUs seems to be platform-specific
topo_analyze() which is used here seems to be MI; from sys/kern/subr_smp.c:
Code:
/*
 * This module holds the global variables and machine independent functions
 * used for the kernel SMP support.
 */
 
topo_analyze() which is used here seems to be MI; from sys/kern/subr_smp.c:
I didn't follow all the code paths but just assumed this would itself call machine-specific code again :-/

But then, sure, you might be able to reuse this when writing kernel code yourself :)
 
... Do you know if a simple API in C (User/Kernel Mode) available to get the number of physical packages (sockets)?...
I'm not very good with the FreeBSD C API. There are experts on the forum who can help with this.
 
Thanks _al for the reply.
After install dmidecode, can get the socket number as shown below.

# dmidecode -t processor | grep Socket
Socket Designation: CPU1
Socket Designation: CPU2
#

According to github dmidecode, dmidecode reports information about system's hardware as described in system BIOS according to the SMBIOS/DMI standard.
But its source code is complicated.
Do you know if a simple API in C (User/Kernel Mode) available to get the number of physical packages (sockets)?
I am working on a device driver so prefer a simpler solution.
Thanks in advance.

Careful. That is probably reporting the number of sockets the board has, regardless of whether they are occupied or not.
 
Kind of the whole point of manuf. being able to noodle with packaging is that it's an implementation detail the end user isn't supposed to notice.
 
An example, unfortunately only single package, though.
Maybe group level="1" entry would appear multiple times if there are multiple sockets. Not sure whether implemented-but-enpty socket is ignored or group level="1" entry without any child entry in it is exposed.

% dmesg | rg SMP FreeBSD/SMP: Multiprocessor System Detected: 12 CPUs FreeBSD/SMP: 1 package(s) x 6 core(s) x 2 hardware threads

% sysctl kern.sched.topology_spec kern.sched.topology_spec: <groups> <group level="1" cache-level="3"> <cpu count="12" mask="fff,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11</cpu> <children> <group level="2" cache-level="2"> <cpu count="2" mask="3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">0, 1</cpu> <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags> </group> <group level="2" cache-level="2"> <cpu count="2" mask="c,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">2, 3</cpu> <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags> </group> <group level="2" cache-level="2"> <cpu count="2" mask="30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">4, 5</cpu> <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags> </group> <group level="2" cache-level="2"> <cpu count="2" mask="c0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">6, 7</cpu> <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags> </group> <group level="2" cache-level="2"> <cpu count="2" mask="300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">8, 9</cpu> <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags> </group> <group level="2" cache-level="2"> <cpu count="2" mask="c00,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">10, 11</cpu> <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags> </group> </children> </group> </groups>
 
An example, unfortunately only single package, though.
Maybe group level="1" entry would appear multiple times if there are multiple sockets.
Apparently not:

FreeBSD/SMP: Multiprocessor System Detected: 2 CPUs
FreeBSD/SMP: 2 package(s) x 1 core(s)

Code:
# sysctl kern.sched.topology_spec
kern.sched.topology_spec: <groups>
 <group level="1" cache-level="0">
  <cpu count="2" mask="3,0,0,0">0, 1</cpu>
 </group>
</groups>

FreeBSD/SMP: Multiprocessor System Detected: 20 CPUs
FreeBSD/SMP: 1 package(s) x 2 cache groups x 5 core(s) x 2 hardware threads

Code:
$ sysctl kern.sched.topology_spec
kern.sched.topology_spec: <groups>
 <group level="1" cache-level="0">
  <cpu count="20" mask="fffff,0,0,0">0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19</cpu>
  <children>
   <group level="2" cache-level="3">
    <cpu count="10" mask="3ff,0,0,0">0, 1, 2, 3, 4, 5, 6, 7, 8, 9</cpu>
    <flags><flag name="NODE">NUMA node</flag></flags>
    <children>
     <group level="3" cache-level="2">
      <cpu count="2" mask="3,0,0,0">0, 1</cpu>
      <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
     </group>
...

Hm, lets create another one:

FreeBSD/SMP: Multiprocessor System Detected: 8 CPUs
FreeBSD/SMP: 2 package(s) x 2 core(s) x 2 hardware threads

Code:
kern.sched.topology_spec: <groups>
 <group level="1" cache-level="0">
  <cpu count="8" mask="ff,0,0,0">0, 1, 2, 3, 4, 5, 6, 7</cpu>
  <children>
   <group level="2" cache-level="3">
    <cpu count="4" mask="f,0,0,0">0, 1, 2, 3</cpu>
    <children>
     <group level="3" cache-level="2">
      <cpu count="2" mask="3,0,0,0">0, 1</cpu>
      <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
     </group>

This is ugly to parse. The question would be: what is contained in the toplevel group?
-> nothing -> package count = cpu count
-> a NODE group -> package count = 1 (cluster-on-die) # unsure?
-> a TREAD group -> package count = 1 (single core with HT)
-> another group -> package count = cpu count(level 1) / cpu count(level 2)

For most device driver purposes, I would just use the sysctl vm.ndomains. (If they don't use numa, they want their cores treated as uniform mesh, disregarding packages. And if they have cluster-on-die active, they have reasons for that and want to see their cache-groups as separate entities)
 
So my assumption reading XML'ish sysctl outputs was wrong.:(
I don't have any, but if I recall correctly, Apple M1 Ultra has 2 M1 Max on package, not sharing caches (I could be wrong here, too). And, regardless one already exists or not, there can be modules having multiple CPU pacgages and some addidional components (memories, extended I/Os, and maybe more) on it and attached using "a socket per module" on motherboard.
How should we treat such ones? Maybe confusing for schedulers, too. Sigh.
 
Back
Top