当我执行cat /proc/cpuinfo
命令时,可以看到8个内核,其ID从0
到7
。
是否有一个x86
指令可报告当前指令所在的核心id?
我查了一下cpuid
,但似乎在任何参数设置下都不返回coreid
。
英特尔® 64和IA-32体系结构软件开发人员手册第3A卷:系统编程指南,第1部分中的8.4.5在MP系统中识别逻辑处理器一节列出了以下内容:
这个APIC ID由CPUID.0BH:EDX[31:0]报告。
请注意,这不直接等同于Linux内核的编号。在内核中,有一个 x86_cpu_to_apicid
表可以查看。当然,内核也知道代码正在执行的CPU,而无需咨询APIC:
* smp_processor_id(): get the current CPU ID.
*
* if DEBUG_PREEMPT is enabled then we check whether it is
* used in a preemption-safe way. (smp_processor_id() is safe
* if it's used in a preemption-off critical section, or in
* a thread that is bound to the current CPU.)
一些较新的 x86/x86_64 CPU 具有 RDTSC 指令的“RDTSCP
”变体:
http://ref.x86asm.net/coder32-abc.html#R
RDTSC EAX EDX IA32_TIM… 0F 31
P1+ f2 Read Time-Stamp Counter
RDTSCP EAX EDX ECX ... 0F 01 F9 7
C7+ f2 Read Time-Stamp Counter and Processor ID
RDTSCP
访问此值。341 if (cpu_has(&cpu_data(cpu), X86_FEATURE_RDTSCP))
342 write_rdtscp_aux((node << 12) | cpu);
343
344 /*
345 * Store cpu number in limit so that it can be loaded quickly
346 * in user space in vgetcpu. (12 bits for the CPU and 8 bits for the node)
347 */
getcpu
("__vdso_getcpu")用于通过rdtscp
(如果CPU支持该指令)或通过GDT - GDT_ENTRY_PER_CPU访问CPU ID:来自3.13的include/asm/vsyscall.h中的__getcpu。从手册中可以看到:
3.2 使用RDTSCP指令进行优化getcpu()在2.6.19内核中添加了x86_64和i386。
Linux尽最大努力使此调用尽可能快。getcpu()的目的是允许程序对每个CPU数据进行优化或进行NUMA优化。
我是一名帮助翻译的助手。以下是需要翻译的内容:
此外,这里还提供了描述http://www.felixcloutier.com/x86/RDTSCP.html的链接,该链接是https://github.com/zneak/x86doc的克隆版本。
更新:将会有RDPID
指令,专门用于读取IA32_TSC_AUX寄存器,而无需使用时间戳计数器(就像RDTSCP指令一样)。
https://hjlebbink.github.io/x86doc/html/RDPID.html
Reads the value of the IA32_TSC_AUX MSR (address C0000103H) into the destination register. The value of CS.D and operand-size prefixes (66H and REX.W) do not affect the behavior of the RDPID instruction.
F3 0F C7 /7 RDPID r32 M N.E./V RDPID Read IA32_TSC_AUX into r32. F3 0F C7 /7 RDPID r64 M V/N.E. RDPID Read IA32_TSC_AUX into r64.
根据https://software.intel.com/sites/default/files/managed/c5/15/architecture-instruction-set-extensions-programming-reference.pdf 319433-030 OCTOBER 2017的声明,自从"Ice Lake"微架构(2018)以来,它将被启用。
描述
将IA32_TSC_AUX MSR(地址C0000103H)的值读入目标寄存器。 CS.D的值和操作数大小前缀(66H和REX.W)不会影响RDPID指令的行为。
注意:
RDPID将处理器核心ID作为uint32_r或uint64_r读取,因此读取的值不会在顺序范围[0,MAX_CPU_COUNT]内。
RDPID是一种新指令,因此硬件支持程度不广泛。
/sys/devices/system/cpu/cpu[0-7]/topology/thread_siblings_list
中的条目查看哪些vCPU对共享一个核心。
另一个答案提出了使用cpuid
的好建议,但我认为你无法确定cpuid
指令是否在与感兴趣的指令相同的vCPU上执行,除非你将线程固定到一个vCPU上(在这种情况下,它有些多余),因为你无法知道内核是否在执行感兴趣的指令和执行cpuid
指令之间将你的线程从一个vCPU迁移到另一个vCPU。
简而言之,大部分时间,两个“接近”的指令将在同一个vCPU上执行,但如果没有固定,则不能保证,如果你已经将线程固定,那么你已经知道它正在运行的vCPU是什么,所以有点无意义。getcpu
和使用该值之间 CPU 发生变化时,代码仍将执行正确操作(可能略微增加争用)。 - BeeOnRopetaskset
+ __rdtscp
可执行示例
最后,对于那些想要使用x86内部函数和taskset
玩耍的人:
rdtscp.c
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <x86intrin.h>
int main(void) {
uint32_t pid;
printf("0x%016" PRIX64 "\n", (uint64_t)__rdtscp(&pid));
printf("0x%08" PRIX32 "\n", pid);
return EXIT_SUCCESS;
}
然后使用taskset
控制编译和运行时所在的核心:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o rdtscp.out rdtscp.c
./taskset -c 0 ./rdtscp.out
./taskset -c 1 ./rdtscp.out
然后对于每个运行,第二行显示的CPU ID与taskset设置的值匹配。
在Ubuntu 19.04 amd64上测试,使用Intel Core i7-7820HQ。
insmod mymodule.ko
时,我的内核模块在哪个核心上进行初始化。 - merlin20112.6.32-71.el6.x86_64
的源代码。但我还没有找到它。 - merlin2011