0

I am totally beginning in Linux kernel development. I am trying to learn about processes and scheduling (I know what I want to do is not "useful" it is just to learn).

I wrote a syscall which returns me the id of the thread/logical core on which my process is running.

But now, what I would like to do is: write a syscall which returns me the id of the physical core on which my process is running.

I tried to read the task_struct, but I did not find any clue.

I am a lost with all this code. I have no idea where I can start my research, and so on.

I am interested by your methodology. I'm on x86_64 and I'm using Linux 5.6.2.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
Reginas
  • 3
  • 2
  • An OS designer would likely not put much effort into providing such ephemeral data, stale by the time it is available. – Martin James Apr 21 '20 at 17:58
  • I'm not sure to well-understand why those data would be ephemeral. Also, for instance, in /proc/cpuinfo we can retrieve which logical cores are in which physical core. So, in my mind, those information are somewhere in Linux. Or maybe I am totally wrong. – Reginas Apr 21 '20 at 18:33
  • ..because the thread may have moved to another core while the call is returning. – Martin James Apr 21 '20 at 18:37
  • Oh! Of course! I was just focus about how logical cores are mapped to physical core. – Reginas Apr 21 '20 at 18:41
  • You may look how `turbostat` utility finds that (it's x86 only solution, though). – 0andriy Apr 21 '20 at 20:45
  • @Reginas architecture and kernel version? – Marco Bonelli Apr 21 '20 at 22:49
  • @Marco Bonelli, I'm on x86_64 and I'm using the linux 5.6.2 – Reginas Apr 21 '20 at 23:03
  • @0andriy thank you for this tool! I'll look at it, it could be interesting. – Reginas Apr 21 '20 at 23:03
  • According to https://stackoverflow.com/a/22310678/634919 you can call `smp_processor_id()`. Not sure if this still applies to current Linux versions. – Nate Eldredge Apr 22 '20 at 00:33
  • @NateEldredge that returns the processor ID, OP wants the core ID associated with that. E.g. on an hyperthreaded scenario with N cores and 2N processors `smp_processor_id()` returns the logical core ID (`0..2N-1`), while OP wants the real core ID (`0..N-1`). – Marco Bonelli Apr 22 '20 at 04:18

1 Answers1

0

What you want to do is basically the same thing that /proc/cpuinfo already does:

$ cat /proc/cpuinfo
processor   : 0  <== you have this
...
core id     : 0  <== you want to obtain this
...

We can therefore take a look at how /proc/cpuinfo does this, in arch/x86/kernel/cpu/proc.c. By analyzing the code a little bit, we see that the CPU information is obtained calling cpu_data():

static void *c_start(struct seq_file *m, loff_t *pos)
{
    *pos = cpumask_next(*pos - 1, cpu_online_mask);
    if ((*pos) < nr_cpu_ids)
        return &cpu_data(*pos); // <=== HERE
    return NULL;
}

The cpu_data() macro returns a struct cpuinfo_x86, which contains all the relevant information, and is then used here to print the core ID:

seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);

Therefore, in a kernel module, you can do the following:

#include <linux/smp.h>     // get_cpu(), put_cpu()
#include <asm/processor.h> // cpu_data(), struct cpuinfo_x86

// ...

static int __init modinit(void)
{
    unsigned cpu;
    struct cpuinfo_x86 *info;

    cpu = get_cpu();
    info = &cpu_data(cpu);
    pr_info("CPU: %u, core: %d\n", cpu, info->cpu_core_id);
    put_cpu(); // Don't forget this!

    return 0;
}

Dmesg output on my machine after inserting/removing the module three times:

[14038.937774] cpuinfo: CPU: 1, core: 1
[14041.084951] cpuinfo: CPU: 5, core: 1
[14087.329053] cpuinfo: CPU: 6, core: 2

Which is consistent with the content of my /proc/cpuinfo:

$ cat /proc/cpuinfo | grep -e 'processor' -e 'core id'
processor   : 0
core id     : 0
processor   : 1
core id     : 1
processor   : 2
core id     : 2
processor   : 3
core id     : 3
processor   : 4
core id     : 0
processor   : 5
core id     : 1
processor   : 6
core id     : 2
processor   : 7
core id     : 3

Note that as Martin James rightfully pointed out, this information is not very useful since your process could be preempted and moved to a different core by the time your syscall finishes execution. If you want to avoid this you can use the sched_setaffinity() syscall in your userspace program to set the affinity to a single CPU.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
  • Thank you a lot for all of these details! Today, I read about the `sched_setaffinity` and it would seems that this syscall is not 100% reliable. I mean, from what I understood, the scheduler could choose another cpu (which is not in the cpu affinity mask).. Maybe for some optimization reasons? – Reginas Apr 22 '20 at 00:07
  • @Reginas you read wrong. Once you set the affinity the scheduler will respect it. You need to set it correctly though, of course. Also note that the `sched_setaffinity()` syscall is a privileged syscall (you may need to be root to use it). – Marco Bonelli Apr 22 '20 at 00:09