测量读写msr寄存器的耗时

msr寄存器的读写有两个指令rdmsr和wrmsr。他们可以用来读写一些系统相关的寄存器。格式是:

首先向ecx写入msr寄存器的地址,这要查一下手册。对于rdmsr,会将读到的信息,一个64bit数据,高32bit放到edx,低32存访到eax。对于wrmsr,除了向ecx写入msr寄存器的地址,还要向edx和eax写入要写入的值。

读写msr需要在kernel态进行,因此,我们用一个kernel module来实现。下面是一个例子:

#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/slab.h>
 
MODULE_LICENSE("GPL");
 
static inline void mywrmsr(void) {
    unsigned int flag = 0x1d9;
    unsigned int high = 0x0, low = 0;
    unsigned int loop = 100000;
    __asm__ __volatile__ (
        "mov %2, %%ecx\n\t"
        "mov %3, %%ebx\n\t"
        "rdmsr\n\t"
        "1:\n\t"
        "wrmsr\n\t"
        "dec %%ebx\n\t"
        "jnz 1b\n\t"
        : "=r"(high), "=r"(low)
        : "r"(flag), "r"(loop)
        : "%edx", "%eax","%ecx", "%ebx", "memory"
    );
}
 
static inline void myrdmsr(void) {
        unsigned int flag = 0x1d9;
        unsigned int high = 0, low = 0, loop = 100000;
        __asm__ __volatile__(
        "movl %2, %%ecx\n\t"
        "mov %3, %%ebx\n\t"
        "1:\n\t"
        "rdmsr\n\t"
        "dec %%ebx\n\t"
        "mov %%edx, %0\n\t"
        "mov %%eax, %1\n\t"
        "jnz 1b\n\t"
        : "=r"(high), "=r"(low)
        : "r"(flag), "r"(loop)
        : "%eax", "%edx", "%ecx", "%ebx", "memory"
        );
}
 
static inline uint64_t myrdtsc(void) {
    uint32_t low, high;
    __asm__ __volatile__ ("rdtsc" : "=a" (low), "=d" (high));
    return ((uint64_t)high << 32) | low;
}
 
static int mymsr_init(void)
{
    uint64_t start, end, diff, start_ns, end_ns, diff_ns;
 
    start_ns = ktime_get_raw_ns();
    start = myrdtsc();
 
    mywrmsr();
 
    end = myrdtsc();
    end_ns = ktime_get_raw_ns();
    diff = end - start;
    diff_ns = end_ns - start_ns;
    pr_info("%llu cycles, %llu ns elpased\n", diff, diff_ns);
    return 0;
}
static void mymsr_exit(void)
{
        pr_info("Goodbye mymsr\n");
}
 
module_init(mymsr_init);
module_exit(mymsr_exit);

这个例子在inline 汇编中执行读写msr的循环,从而测量出耗时。

posted on 2024-09-14 18:16  半山随笔  阅读(5)  评论(0编辑  收藏  举报

导航