Проблема производительности VMX с rdtsc (без выхода rdtsc, с использованием удаления rdtsc) - PullRequest
0 голосов
/ 07 июня 2018

Я работаю с модулем ядра Linux (VMM) для тестирования Intel VMX, чтобы запустить самодельную виртуальную машину (виртуальная машина запускается в реальном режиме, а затем переключается в 32-битный защищенный режим с включенной функцией пейджинга).
VMMнастроено на НЕ использование выхода rdtsc и использование смещения rdtsc.
Затем виртуальная машина запускает 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

Разница в производительности НЕ может быть проигнорирована при выполнении кодов в ВМ и в хосте.Это НЕ ожидается.
Насколько я понимаю, при использовании смещения TSC + отсутствие выхода RDTSC, должно быть небольшое различие в rdtsc, работающем на ВМ и хосте.
Вот поля VMCS,

 0xA501E97E = control_VMX_cpu_based  
 0xFFFFFFFFFFFFFFF0 = control_CR0_mask  
 0x0000000080050033 = control_CR0_shadow  

На последнем уровне EPT PTE, бит [5: 3] = 6 (обратная запись), бит [6] = 1. EPTP [2: 0] = 6 (обратная запись)
Я тестировал на голом металлеи в VMware я получил аналогичные результаты.
Мне интересно, есть ли что-то, что я пропустил в этом случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...