即使使用PCE设置,用户模式下的rdpmc也不起作用

时间:2014-03-10 19:04:39

标签: performance assembly linux-kernel x86 intel

根据Wikipedia entry以及英特尔手册,只要设置了rdpmc的{​​{1}},bit 8就可用于用户模式进程。但是,当尝试从用户空间运行CR4时,即使设置了该位,我仍然遇到general protection错误。

我在内核rdpmc上运行8核Intel X3470

这是我试图执行的用户模式程序:

2.6.32-279.el6.x86_64

这是内核模块,它设置该位并读出#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <inttypes.h> #include <sched.h> #include <assert.h> uint64_t read_pmc(int ecx) { unsigned int a, d; __asm __volatile("rdpmc" : "=a"(a), "=d"(d) : "c"(ecx)); return ((uint64_t)a) | (((uint64_t)d) << 32); } int main(int ac, char **av) { uint64_t start, end; cpu_set_t cpuset; unsigned int c; int i; if (ac != 3) { fprintf(stderr, "usage: %s cpu-id pmc-num\n", av[0]); exit(EXIT_FAILURE); } i = atoi(av[1]); c = atoi(av[2]); CPU_ZERO(&cpuset); CPU_SET(i, &cpuset); assert(sched_setaffinity(0, sizeof(cpuset), &cpuset) == 0); printf("%lu\n", read_pmc(c)); return 0; } ,以便我可以手动验证该位是否已设置。

CR4

2 个答案:

答案 0 :(得分:5)

显然,当英特尔说Bit 8时,他们指的是右边的第9位,因为他们的索引从0开始。用$(1 << 7)全局替换$(1 << 8)可解决此问题,并允许从用户模式调用rdpmc

这是更新的内核模块,也使用on_each_cpu来确保在每个核心上设置它。

/*  
 *  Read PMC in kernel mode.
 */
#include <linux/module.h>   /* Needed by all modules */
#include <linux/kernel.h>   /* Needed for KERN_INFO */

static void printc4(void) {
    typedef long unsigned int uint64_t;
    uint64_t output;
    // Read back CR4 to check the bit.
    __asm__("\t mov %%cr4,%0" : "=r"(output));
    printk(KERN_INFO "%lu", output);
}

static void setc4b8(void * info) {
    // Set CR4, Bit 8 (9th bit from the right)  to enable
__asm__("push   %rax\n\t"
                "mov    %cr4,%rax;\n\t"
                "or     $(1 << 8),%rax;\n\t"
                "mov    %rax,%cr4;\n\t"
                "wbinvd\n\t"
                "pop    %rax"
    );

    // Check which CPU we are on:
    printk(KERN_INFO "Ran on Processor %d", smp_processor_id());
    printc4();
}

static void clearc4b8(void * info) {
    printc4();
__asm__("push   %rax\n\t"
        "push   %rbx\n\t"
                "mov    %cr4,%rax;\n\t"
                "mov  $(1 << 8), %rbx\n\t"
                "not  %rbx\n\t"
                "and   %rbx, %rax;\n\t"
                "mov    %rax,%cr4;\n\t"
                "wbinvd\n\t"
                "pop    %rbx\n\t"
                "pop    %rax\n\t"
    );
    printk(KERN_INFO "Ran on Processor %d", smp_processor_id());
}



int init_module(void)
{
    on_each_cpu(setc4b8, NULL, 0);
    return 0;
}
void cleanup_module(void)
{
    on_each_cpu(clearc4b8, NULL, 0);
}

答案 1 :(得分:4)

向/ sys / bus / event_source / devices / cpu / rdpmc回显“2”允许用户进程 通过rdpmc指令访问性能计数器。 请注意,行为已更改。在4.0“1”之前意味着“启用” 而意思是“0”禁用。现在“1”表示仅允许具有活动perf事件的进程。更多详情:http://man7.org/linux/man-pages/man2/perf_event_open.2.html