我试图测量内存访问时间并需要降低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]
如果我理解正确,将使用RDI中的字节值调用invlpg,但宁愿需要QWORD地址。
然而,第二个链接说" m指针指向逻辑地址,而不是物理地址或虚拟地址:ds段的偏移量"
那么INVLPG需要偏离ds段吗?但ds64段已不再用于AMD64,是吗?
有人可以解释一下如何在AMD64上使用INVLPG指令或如何在此架构上逐出TLB条目吗?
答案 0 :(得分:5)
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