Почему TSC больше в VirtualBox, когда я включаю "TiedToExecution"? - PullRequest
1 голос
/ 16 сентября 2011

Справочная информация (мое понимание того, как виртуализируется rdtsc): Я экспериментирую со значениями TSC в VirtualBox. Мое текущее понимание того, как VirtualBox эмулирует rdtsc, заключается в том, что в виртуальном режиме любой вызов rdtsc будет компенсирован заранее определенным результатом, который является значением, установленным в другом регистре. При запуске виртуальной машины это значение будет rdtsc на хосте.

Преимущество этой стратегии состоит в том, что rdtsc будет опережать время настенных часов ожидаемым образом, но недостатком является то, что процесс может воспринимать rdtsc, чтобы занять больше времени, чем ожидалось. Например, в простом коде, подобном этому:

x = rdtsc();
y = rdtsc();
z = y - x;
print z

выполняется на госте, z может быть больше, чем ожидалось, из-за затрат времени настенного времени, связанных с перехватом rdtsc. Было бы еще хуже, если бы между этими двумя вызовами хост-операционная система сменила процесс VirtualBox.

Из прочтения руководства VirtualBox (Изменить режим TSC) я прочитал, что существует альтернативный метод виртуализации, который должен непосредственно имитировать TSC. Насколько я понимаю, значение смещения будет учитывать только время, в течение которого гостевая ОС фактически использует процессор. Преимущество состоит в том, что в отношении доступных циклов TSC будет вести себя точно так же, как если бы он был на хост-компьютере. Недостатком является то, что TSC будет отклоняться от времени настенных часов, поскольку существуют «пропущенные циклы», о которых гостевая ОС не знает.

Моя цель: Я пытаюсь настроить VirtualBox на второй вариант. Я хочу эмулировать кратковременное поведение rdtsc, как если бы оно работало на аппаратном уровне как можно точнее, и мне все равно, не соответствует ли оно настенным часам. Я полностью осознаю, что это не "надежно" на SMP; это для экспериментов, а не для корпоративного программного обеспечения.

Что я сделал: Сначала я написал простую тестовую программу, которая несколько раз вызывает rdtsc, затем печатает результаты:

__inline__ uint64_t rdtsc()
{
    uint32_t lo, hi;
    __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
    return (uint64_t)hi << 32 | lo;
}

int main()
{
    int i;
    uint64_t val[8];

    val[0] = rdtsc();    
    val[0] = rdtsc();
    val[0] = rdtsc();
    val[0] = rdtsc();
    val[0] = rdtsc();
    val[0] = rdtsc();
    val[0] = rdtsc();
    val[0] = rdtsc();

    for (i = 0; i < 8; i++) {
        printf("rdtsc (%2d): %llX", i, val[i]);
        if (i > 0) {
            printf("\t\t (+%llX)", (val[i] - val[i - 1]));
        }
        printf("\n");
    }
    return 0;
}

Я пробовал эту программу на моем хост-компьютере. Затем я запустил его на своем компьютере VirtualBox. Дельты между rdtsc были практически идентичны - единственная разница заключалась в том, что само значение на моем хосте было примерно на 30T больше. Пример вывода:

rdtsc ( 0): 334F2252A1824
rdtsc ( 1): 334F2252A1836    (+12)
rdtsc ( 2): 334F2252A1853    (+1D)
rdtsc ( 3): 334F2252A1865    (+12)
rdtsc ( 4): 334F2252A1877    (+12)
rdtsc ( 5): 334F2252A1889    (+12)
rdtsc ( 6): 334F2252A18A6    (+1D)
rdtsc ( 7): 334F2252A18B8    (+12)

Затем я изменил флаг TSCTiedToExecution в VirtualBox, который, как я думал, должен был игнорировать настенные часы в пользу более точного подсчета виртуальных циклов. Я получил это на странице руководства, которую я упомянул выше:

./VBoxManage setextradata "HelloWorld" "VBoxInternal/TM/TSCTiedToExecution" 1

Однако это дало мне неожиданные результаты. Виртуальная программа теперь вернулась:

rdtsc ( 0): F2252A1824
rdtsc ( 1): F2252A1836   (+B12)
rdtsc ( 2): F2252A1853   (+B1D)
rdtsc ( 3): F2252A1865   (+AFF)
rdtsc ( 4): F2252A1877   (+B13)
rdtsc ( 5): F2252A1889   (+AF2)
rdtsc ( 6): F2252A18A6   (+B1D)
rdtsc ( 7): F2252A18B8   (+B0C)

При включенном TSCTiedToExecution rdtsc, похоже, выполняет около 1100 циклов ....

Вопрос: Во-первых, мне интересно, почему у меня такое поведение? Кажется, что это почти противоположно тому, что я ожидал, и, конечно, не соответствует моему пониманию того, как это реализовано.

Во-вторых, мне интересно, как я могу достичь своей первоначальной цели, состоящей в продвижении TSC для каждого виртуального цикла, как если бы это было на аппаратном обеспечении?

Моя настройка: Я работаю на 8-кратном процессоре Intel (R) Xeon (R) X5550 с частотой 2,67 ГГц. В VirtualBox включен VMX и вложенный пейджинг. Я скомпилировал его из исходного кода, версия: 4.1.2_OSE r38459.

Заранее спасибо.

P.S. Я получил награду за это, но до сих пор нет ответов ...

1 Ответ

0 голосов
/ 10 сентября 2013

Чтобы заставить себя плакать, попробуйте отключить «VBoxInternal / TM / TSCTiedToExecution» и снова запустить свою тестовую программу.Следующий код

ULONGLONG x1 = Cpu::Rdtsc();
ULONGLONG x2 = Cpu::Rdtsc();

DbgPrintUlong('D', x2 - x1, 30, 23);

, работающий на VirtualBox с отключенным отображением «VBoxInternal / TM / TSCTiedToExecution», что x2 - x1 занял около 200 000 циклов.Напротив, на машине с «VBoxInternal / TM / TSCTiedToExecution» это заняло всего 3 000 циклов jf.Я думаю, что это сокращение подразумевается в следующем отрывке из руководства VirtualBox «В особых случаях может быть полезно сделать так, чтобы TSC (счетчик меток времени) в гостевой системе отражал время, фактически потраченное на выполнение гостевой функции».* Итак, я думаю, что у нас не будет лучшей эмуляции TSC в VirtualBox в течение длительного времени.

Единственное, что я могу посоветовать, - это перейти на рабочую станцию ​​VmWare.У него гораздо лучшая эмуляция TSC.

...