我正在尝试测量内存访问时间,并需要减少 TLB 命中和未命中产生的噪音

为了从 TLB 中清除特定页面,我尝试使用 INVLPG 指令,遵循以下两个示例:http://wiki.osdev.org/Paging
http://wiki.osdev.org/Inline_Assembly/Examples

我写了以下代码:

static inline void __native_flush_tlb_single(unsigned long addr)
{
   asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
}

但是生成的二进制文件在执行时会抛出一个 SIGSEGV。
由于我更喜欢​​英特尔语法,我查看了特定的反汇编:
invlpg BYTE PTR [rdi]

如果我理解正确,invlpg 将使用 RDI 处的字节值调用,但更需要 QWORD 地址。

然而,第二个链接说“m 指针指向一个逻辑地址,而不是物理或虚拟地址:ds 段的偏移量”

那么 INVLPG 需要从 ds 段偏移吗?但是 ds 段在 AMD64 中不再使用了,是吗?

有人可以向我解释如何在 AMD64 中使用 INVLPG 指令或如何在此架构上驱逐 TLB 条目吗?

最佳答案

发生 SIGSEGV 是因为 INVLPG 是一条特权指令,只能从内核代码中调用(感谢 Cody Gray )。

为了演示 INVLPG 的使用,我写了一个小 LKM invlpg_mod.c :

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <linux/types.h>

// LICENSE
MODULE_LICENSE("GPL");

static inline void invlpg(unsigned long addr) {
    asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
}


// init module
static int __init module_load(void) {
    int mem;
    invlpg((unsigned long) &mem);
    printk("Evicted %p from TLB", &mem);
}


//unload modules
static void __exit module_unload(void) {
    printk("Goodbye.");
}

module_init(module_load);
module_exit(module_unload);

确保安装了 linux-headers 并使用此 Makefile 构建 LKM:
KDIR = /lib/modules/$(shell uname -r)/build
PWD = $(shell pwd)

obj-m = invlpg_mod.o

all:
    make -C $(KDIR) M=$(PWD) modules

clean:
    make -C $(KDIR) M=$(PWD) clean

加载 LKM:
 sudo insmod invlpg_mod.ko

并卸载它:
sudo rmmod invlpg_mod.ko

查看输出:
dmesg | tail

关于c - 如何在 x86-64 架构上使用 INVLPG?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37752664/

10-11 15:21