Pull to refresh

Временной парадокс в многоядерных процессорах AMD

Reading time 3 min
Views 8.2K
Наконец-то разобрался с проблемой, мучавшей меня с самой покупки нового компьютера.
В некоторых играх (Neverwinter nights 1/2; SW: KoToR 1/2; WarCraft 3; Avatar) графика прыгала, будто пропускалась большая часть кадров, в Bully слишком быстро шло время — час игрового времени пролетал за пару секунд (минутная стрелка на часах не доходила даже до 10 минут и время уходило на час вперёд). В 2007-м думал на дрова, их менял, обновлял DirectX — ноль эмоций. В 2008-м думал на Windows, переустанавливал — всё оставалось как прежде. В 2009 на видеокарту, но уже третью поставил, и всё равно результата НОЛЬ, хотя предыдущем компьютере те же самые игры работали нормально (из тех, которые вообще запускались на 256 МБ ОЗУ). Единственный глюк в компьютере кроме прыгающей графики был только в трейсерте и ping.exe — иногда выдавались ненормально большие числа мс (больше миллиарда) и даже отрицательные. Так как пинг, по моему мнению, никак не был связан с графикой, я не считал, что причина глюков в одном и том же месте.

Причина
Оказалось, причина в кривой синхронизации многоядерных систем с процессорами AMD, пока включена Cool'n'Quiet. Вот такой мой код выдавал прелестные результаты.

uses windows, SysUtils;
var
 Frequency, lpPerformanceCount1, lpPerformanceCount2, k:Int64;
 {$apptype console}
begin
 QueryPerformanceFrequency(Frequency);
 writeln(Frequency);
 writeln('Looking for a bug');
 while true do begin
  k:=0;
  repeat
   QueryPerformanceCounter(lpPerformanceCount1);
   QueryPerformanceCounter(lpPerformanceCount2);
   inc(k);
  until lpPerformanceCount1>lpPerformanceCount2;

  writeln(TimeToStr(now),': A bug found!');
  writeln(k,': ',IntToStr(lpPerformanceCount2 - lpPerformanceCount1));
 end;
end.


QueryPerformanceCounter базируется на процессорной инструкции rdtsc и пишет в передаваемый аргумент количество тактов с момента последнего сброса процессора. Другими словами эта функция не может выдавать результат меньше, если она была запущена позже, так же как часы не могут показать в следующую секунду время на секунду раньше. Естественно, что этот код нe может дойти до строки «found», но он доходит. Вот такой вот time paradox. Запускалась эта маленькая программа на моём компьютере, на другом двухъядернике AMD, в виртуальной машине (где эмулировалась одноядерная система AMD), на двухъядернике Intel. Ошибка выскакивала только на моём и другом 2-хъядерном AMD. Так же проверял работу этой программы в режиме совместимости — у некоторых игр в режиме совместимости Win98/WinME глюки ускорения пропадали, но трейсерт и пинг так не позапускаешь — до found в моей программе также не доходило.

Решение
Решения три:
  1. Установить драйвера на процессор. Моя программа перестала доходить до «found», в пинге/трейсерте не выдавались числа меньше 1 миллисекунды/больше миллиарда миллисекунд, в играх графика наконец-то стала нормальной.
  2. Отключить Cool'n'Quiet.
  3. Через Task Manager форсированно запретить использовать нужным программам более одного ядра.
Между прочим, AMD’шный установщик косячит и в boot.ini пишет лишние параметры. Что бы система-таки запускалась на настройках boot.ini «по умолчанию» пришлось убирать из секции «Boot Loader» (но НЕ из «Operating Systems») /usepmtimer. Хотя здесь возможна уникальная для моего компьютера несовместимость.

TimTowdy подсказывает, что уже было год назад.
Tags:
Hubs:
+37
Comments 62
Comments Comments 62

Articles