Справочная информация (мое понимание того, как виртуализируется 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. Я получил награду за это, но до сих пор нет ответов ...