How can I get the CPU core number from within a user-space app (Linux, C)?

Presumably there is a library or simple asm blob that can get me the number of the current CPU that I am executing on.


Solution 1:

Use sched_getcpu to determine the CPU on which the calling thread is running. See man getcpu (the system call) and man sched_getcpu (a library wrapper). However, note what it says:

The information placed in cpu is only guaranteed to be current at the time of the call: unless the CPU affinity has been fixed using sched_setaffinity(2), the kernel might change the CPU at any time. (Normally this does not happen because the scheduler tries to minimize movements between CPUs to keep caches hot, but it is possible.) The caller must be prepared to handle the situation when cpu and node are no longer the current CPU and node.

Solution 2:

You need to do something like:

  • Call sched_getaffinity and identify the CPU bits
  • Iterate over the CPUs, doing sched_setaffinity to each one (I'm not sure if after sched_setaffinity you're guaranteed to be on the CPU, or need to yield explicitly ?)
  • Execute CPUID (asm instruction)... there is a way of getting a unique per-core ID out of one of it's outputs (see Intel docs). I vaguely recall it's the "APIC ID".
  • Build a table (a std::map ?) from APIC IDs to a CPU number or affinity mask or something.
  • If you did this on your main thread, don't forget to set sched_setaffinity back to all CPUS!

Now you can CPUID again whenever you need to and lookup which core you're on.

But I'd query why you need to do this; normally you want to take control via sched_setaffinity rather than finding out which core you're on (and even that's a pretty rare thing to want/need). (That's why I don't know the crucial detail of what to pull out of CPUID exactly, sorry!)

Update: Just learned about sched_getcpu from litb's response here. Much better! (my Debian/etch libc is too old to have it though).

Solution 3:

I don't know of anything to get your current core id. With kernel level task/process migration, you wouldn't be guaranteed that it would remain constant for any length of time, unless you were running in some form of real-time mode.

If you want to be on a specific core, you can put use that sched_setaffinity() function or the taskset command to launch your program. I believe that these need elevated permissions to work, though. In your program, you could then run sched_getaffinity() to see the mask that was set earlier and use that as a best guess at the core on which you are executing.