我正在使用 Linux 内核模块 (VMM) 来测试 Intel VMX,运行自制 VM(VM 以实模式启动,然后切换到启用分页的 32 位保护模式)。
VMM 配置为不使用 rdtsc 退出,并使用 rdtsc 偏移。
然后,VM 运行 rdtsc 来检查性能,如下所示。
static void cpuid(uint32_t code, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) {
__asm__ volatile(
"cpuid"
:"=a"(*eax),"=b"(*ebx),"=c"(*ecx), "=d"(*edx)
:"a"(code)
:"cc");
}
uint64_t rdtsc(void)
{
uint32_t lo, hi;
// RDTSC copies contents of 64-bit TSC into EDX:EAX
asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t)hi << 32 | lo;
}
void i386mode_tests(void)
{
u32 eax, ebx, ecx, edx;
u32 i = 0;
asm ("mov %%cr0, %%eax\n"
"mov %%eax, %0 \n" : "=m" (eax) : :);
my_printf("Guest CR0 = 0x%x\n", eax);
cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
vm_tsc[0]= rdtsc();
for (i = 0; i < 100; i ++) {
rdtsc();
}
vm_tsc[1]= rdtsc();
my_printf("Rdtsc takes %d\n", vm_tsc[1] - vm_tsc[0]);
}
输出是这样的,
Guest CR0 = 0x80050033
Rdtsc takes 2742
另一方面,我制作了一个主机应用程序来做同样的事情,就像上面一样
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
static void cpuid(uint32_t code, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) {
__asm__ volatile(
"cpuid"
:"=a"(*eax),"=b"(*ebx),"=c"(*ecx), "=d"(*edx)
:"a"(code)
:"cc");
}
uint64_t rdtsc(void)
{
uint32_t lo, hi;
// RDTSC copies contents of 64-bit TSC into EDX:EAX
asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t)hi << 32 | lo;
}
int main(int argc, char **argv)
{
uint64_t vm_tsc[2];
uint32_t eax, ebx, ecx, edx, i;
cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
vm_tsc[0]= rdtsc();
for (i = 0; i < 100; i ++) {
rdtsc();
}
vm_tsc[1]= rdtsc();
printf("Rdtsc takes %ld\n", vm_tsc[1] - vm_tsc[0]);
return 0;
}
它输出以下内容,
Rdtsc takes 2325
在 40 次迭代中运行以上两个代码以获得平均值如下,
avag(VM) = 3188.000000
avag(host) = 2331.000000
在 VM 和主机中运行代码时,性能差异不容忽视。这不是预期的。
我的理解是,使用 TSC 偏移 + 没有 RDTSC 退出,rdtsc 应该没有什么区别,运行在 VM 和主机上。
这是 VMCS 字段,
0xA501E97E = control_VMX_cpu_based
0xFFFFFFFFFFFFFFF0 = control_CR0_mask
0x0000000080050033 = control_CR0_shadow
在 EPT PTE 的最后一级,bit[5:3] = 6(回写),bit[6] = 1。EPTP[2:0] = 6(回写)
我在裸机和 VMware 中进行了测试,我得到了类似的结果。
我想知道在这种情况下我是否遗漏了什么。