Разбор полетов и крушений
Последствия чрезмерного разгона всем хорошо известны— это критические ошибки приложений и "голубые экраны смерти". С первого взгляда ничего удивительно тут нет. Какой-то из модулей процессора не выдержал издевательств и поехал крышей, возвратив некорректный результат. Какое-то время мыщъх не уделял этому вопросу особого внимания, но потом заинтересовался и решил исследовать: какой же из блоков сбоит чаще всего?
Исследования на "голом" железе без операционной системы, показали, что АЛУ (арифимитическо-логическое устройство) сохраняет работоспособность и всегда возвращает правильный результат даже на запредельных тактовых частотах, при которых стабильно завешивается MS-DOS, ну а Windows даже и не пытается загружаться! Почему?!
Снижаем тактовую частоту до такого уровня, при котором Windows успевает выдать сообщение о критической ошибке, сохранив дамп памяти (если исключение произошло в ядре) или сгенерировав отчет Доктора Ватсона (если исключение произошло на прикладном уровне). Анализ полученных данных долгое временя не давал никакой осмысленной информации. Ошибки происходили по разным адресам, охватывая практически весь набор инструкций: от целочисленных до MMX/SSE, и, казалось, что эксперименты (загубившие немало процессоров) пора прекращать, поскольку, никакого полезного выхлопа они все равно не принесут.
К тому же, некоторые дампы с точки зрения здравого смысла выглядели абсолютно бессмысленными и даже мистическими. Как-то раз Доктор Ватсон заявил, что машинная команда XOR ECX, ECX возбудила исключение типа Access Violation по адресу C23BD2BAh, тогда как сам ECX равнялся 87h. Но ведь этого не может быть!!! Это же полная и абсолютная ерунда!!! Инструкция XOR ECX, ECX _вообще_ не обращается к памяти!!! Но… протокол Доктора Ватсона есть протокол (читай — документ) и одним движением хвоста в корзину его не выбросишь…
Озарение, как обычно, пришло после хорошей травы, тьфу, то есть во сне, точнее не совсем во сне, а на границе сумеречной зоны, отделяющий один мир от другого, когда после 30 часов непрерывного траханья с Доктором Ватсоном, ты спишь наяву, уткнувшись в очередной фрагмент кода, вызвавший сбой:
00000000: 33C9 XOR ECX, ECX ; (начальное значение ECX == 87h)
00000002: 33D2 XOR EDX, EDX
00000004: 3BC2 CMP EAX, EDX
Листинг 1 инструкция XOR ECX, ECX ( для наглядности выделенная полужирным шрифтом) вызвала нарушение доступа, обратившись к памяти по адресу C23BD2BAh
Ничего не напоминает?! Постойте-постойте! Но ведь… адрес, вызывавший исключение, содержит в себе байты инструкции CMP EAX, EDX и частично XOR EDX, EDX, а если записать опкоды этих команд и сложить их со значением регистра ECX, получится: C23BD233h + 87h == C23BD2BAh, то есть тот самый непонятно откуда взявшийся адрес исключения (ну это раньше он был непонятным, теперь же все стало ясно). Записав инструкцию XOR ECX,ECX в двоичном виде (00011 0011 1100 100) и изменив всего один бит, превращающий C9h в 89h, мы получим… мы получим вот что!
00000000: 338933D23BC2 XOR ECX,[ECX][0C23BD233]
Листинг 2 предыдущий фрагмент кода, в котором искажен всего один бит в инструкции XOR (C9h à 89h)
Оторвать мне хвост!!! Вот как оказывается в _действительности_ выглядела машинная команда, возбудившая исключение и вызвавшая сбой. Сразу видно, что АЛУ тут совершенно не причем. Процессор функционировал в общем-то исправно. Весь вопрос в том, почему Доктор Ватсон показал не "XOR ECX, [ECX][0C23BD233]", а "XOR ECX, ECX"?! Да потому, что искажение бита произошло в кэш-памяти первого уровня, а при составлении отчета Доктор Ватсон возвратил неискаженное содержимое кэш-памяти второго уровня!!! Откуда у меня такая уверенность, что все именно так и происходило? Так ведь процессор использует раздельную кэш память первого уровня для кода и данных, поэтому, прочитать истинное содержимое инструкции, вызывавшей сбой, Доктор Ватсон просто физически не в состоянии и это можно установить только косвенным путем.
Так, значит, главный виновник — это кэш? Дальнейшие эксперименты показали, что все обстоит именно так.Причем, сбои происходят в кэш памяти обоих уровней и вероятность их возникновения напрямую связана с интенсивностью кэш-промахов (т. е когда приложение обновляет большое количества кода/данных). С другой стороны, длительное хранение кода/данных без их модификации, создает другую угрозу — угрозу "загнивания" байт, особенно часто случающуюся при некачественном питании.
Изменить тактовую частоту кэш-модуля невозможно, но… если пораскинуть хвостом, можно найти довольно простое и элегантное решение.