【发布时间】:2014-04-14 01:55:17
【问题描述】:
根据Wikipedia entry 以及英特尔手册,只要设置了CR4 的bit 8,rdpmc 就应该可用于用户模式进程。但是,即使设置了该位,我在尝试从用户空间运行 rdpmc 时仍然遇到 general protection 错误。
我在内核 2.6.32-279.el6.x86_64 上运行 8 核 Intel X3470。
这是我正在尝试执行的用户模式程序:
#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 的内核模块,因此我可以手动验证该位是否已设置。
/*
* Enable PMC in user mode.
*/
#include <linux/module.h>
#include <linux/kernel.h>
int init_module(void)
{
typedef long unsigned int uint64_t;
uint64_t output;
// Set CR4, Bit 8 to enable PMC
__asm__("push %rax\n\t"
"mov %cr4,%rax;\n\t"
"or $(1 << 7),%rax;\n\t"
"mov %rax,%cr4;\n\t"
"wbinvd\n\t"
"pop %rax"
);
// Read back CR4 to check the bit.
__asm__("\t mov %%cr4,%0" : "=r"(output));
printk(KERN_INFO "%lu", output);
return 0;
}
void cleanup_module(void)
{
__asm__("push %rax\n\t"
"push %rbx\n\t"
"mov %cr4,%rax;\n\t"
"mov $(1 << 7), %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"
);
}
【问题讨论】:
-
既然你不知道内核设置在哪个cpu上
CR4我假设你在测试程序中尝试了所有? -
是的。我最初希望我的模块在所有内核上设置 CR4,但我不知道如何在模块内设置 CPU 亲和性。
-
您可以使用
on_each_cpu或on_each_cpu_maskfromsmp.h -
@Jester,它看起来很有希望,但我不确定如何解释
wait的参数on_each_cpu并且顶部的评论并没有说明任何问题。wait应该是布尔值还是超时?如果超时,它的单位是多少? -
这是一个布尔值。我相信你自己也能找到。
标签: performance assembly linux-kernel x86 intel