Assembly 是否有一条“x86”指令来告诉该指令在哪个内核上运行?

Assembly 是否有一条“x86”指令来告诉该指令在哪个内核上运行?,assembly,x86,x86-64,Assembly,X86,X86 64,当我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\u cpu\u to\u apicid

当我
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\u cpu\u to\u 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.)

您看到的是8个“虚拟CPU”,而不是内核,因此如果您有一个4核常春藤网桥CPU,每个内核有2个硬件线程,那么您可以通过
/sys/devices/system/CPU/CPU[0-7]/topology/thread\u同胞\u list
中的条目看到哪些VCPU对共享一个内核

另一个答案很好地建议使用
cpuid
,但我认为您无法确定
cpuid
指令是否与感兴趣的指令在同一个vCPU上执行,除非您将线程固定到vCPU上(在这种情况下,这是非常多余的),因为您不知道在执行感兴趣的指令和执行
cpuid
指令之间,内核没有将线程从一个vCPU迁移到另一个vCPU


简言之,绝大多数情况下,两条“关闭”指令将在同一个vCPU上执行,但如果不固定线程,则无法保证这一点。如果已固定线程,则您已经知道它在哪个vCPU上运行,因此这有点无意义。

一些较新的x86/x86_64 CPU具有RDTSC指令的“
RDTSCP
”变体:

C7+意味着“0x0F01F9”指令是在某些“核心i7”中引入的

操作码

十六进制助记符编码长模式遗留模式描述

0F 01 F9 RDTSCP A有效

将64位时间戳计数器和32位IA32_TSC_AUX值读入EDX:EAX和ECX

操作系统应将核心id写入IA32_TSC_AUX(Linux),此值可通过
RDTSCP
访问


Linux numa id(除了已经描述的CPUID和RDTSCP指令之外,还有一条新的RDPID指令()正好用于此目的

描述

将IA32_TSC_辅助MSR(地址C0000103H)的值读取到目标寄存器中。CS.D的值 和操作数大小前缀(66H和REX.W)不会影响RDPID指令的行为

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.
注意事项:

RDPID将处理器核心id读取为uint32\u r或uint64\u r,因此读取值不在顺序范围[0,最大CPU计数]


RDPID是一种新指令,因此硬件不广泛支持它

最后,对于那些想从x86 intrinsic+
任务集中获得乐趣的人来说:

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;
}
然后,对于每次运行,显示CPU ID的第二行与taskset设置的值相匹配


使用英特尔Core i7-7820HQ在Ubuntu 19.04 amd64上测试。

后续,因为您提到“内核也知道”。如果我在内核模块内运行,有没有直接的方法来获取Linux内核的内核号?@merlin2011:你是否认为内核在你查询内核号和根据内核号做出决定之间不会发生变化?@merlin2011来吧,使用源代码!@Mehrdad,不,我正在尝试对哪个内核进行启发式理解e我的内核模块正在运行它的初始化。当我执行
insmod mymodule.ko
@Jester时,我正在寻找
2.6.32-71.el6.x86_64
。我还没有找到它。它并不是真的没用,因为CPU ID通常被用作性能优化而不是函数行为。例如,您可以使用current CPU ID索引到每个CPU计数器以避免争用,但在非常罕见的情况下,CPU在执行
getcpu
和使用该值之间发生变化,代码仍然会做正确的事情(争用可能略有增加)。什么CPU支持它,可以检查什么标志支持它?@BeeOnRope,rdpid的cpuid存在:eax=07H-ecx位22“位22:rdpid。如果为1,则支持读取处理器ID。”
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.
#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;
}
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o rdtscp.out rdtscp.c
./taskset -c 0 ./rdtscp.out
./taskset -c 1 ./rdtscp.out