我正在尝试测量内存访问时间,并需要减少 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/