Крис Касперски
Многоядерные и Hyper-Threading-процессоры не только увеличивают
производительность, но и порождают многочисленные проблемы – некоторые
приложения (драйверы) начинают работать нестабильно, выбрасывая критические
ошибки или обрушивая систему в голубой экран смерти. В чем причина такого
поведения и как его избежать?
Многопроцессорные системы имеют свою специфику, с которой программисты,
работающие на IBM PC, долгое время оставались совершенно незнакомы. Поначалу
это не создавало никаких проблем, поскольку большинство людей видели
многопроцессорные системы только на картинках, и только единицы могли позволить
себе иметь такую штучку на рабочем столе.
Теперь же все изменилось. Исчерпав резервы
тактовой частоты, производители процессоров сначала предложили нам Hyper-Threading
(два виртуальных процессора в одном), а затем и многоядерные процессоры
(несколько полноценных процессоров на одном кристалле). И хотя до «эмуляции»
настоящей многопроцессорной системы им еще далеко (многоядерные процессоры
имеют одну шину, один контроллер прерываний и т. д.), дефекты программного
обеспечения уже начинают проявляться.
Проблема на самом деле очень серьезна и относится
не только к программистам-самоучкам, клепающим мелкие утилиты, но затрагивает и
весьма именитые корпорации, в том числе специализирующиеся на мобильных
устройствах. Вот что пишет AMD в руководстве по программированию под
многоядерные процессоры: «...the primary issues that the mobile industry typically
faced involved maximizing performance in a battery-operated environment, handling
sleep states and non-standard display and I/O subsystems, and low-voltage considerations.
Thus, many device drivers were tuned to maximize reliability and performance in
those singleprocessor mobile environments: and many haven’t even been tested in
a multiprocessor system, even in the manufacturer’s own test lab» («…основная
проблема в том, что мобильная индустрия в основном сосредоточена на
максимизации производительности в условиях питания от батарей, обработке
«спящего» состояния, нестандартных дисплеев, подсистемы ввода/вывода и уменьшении
питающего напряжения. Поэтому большинство драйверов нацелено на максимальную
надежность и производительность в однопроцессорном окружении. Многие из них не
были протестированы на многопроцессорных машинах, даже в производственных
тестовых лабораториях» (http://developer.amd.com/assets/16_Interrupts.pdf)).
Основной «удар» различий одно- и
многопроцессорных машин операционная система и BIOS берут на себя (примечание:
здесь и далее по тексту под термином «многопроцессорные машины» мы будем
понимать как истинно многопроцессорные системы, так и компьютеры, построенные
на базе многоядерных процессоров или процессоров с Hyper-Threading). Прикладное
приложение или драйвер устройства, спроектированный для однопроцессорной
системы, не требует никакой адаптации для переноса на многопроцессорную
систему, если, конечно, он спроектирован правильно. Многие типы ошибок (и в
особенности ошибки синхронизации) могут годами не проявляться в
однопроцессорных конфигурациях, но заваливают многопроцессорную машину каждые
десять минут, а то и чаще.
Исправление ошибок требует переделки исходных
текстов (иногда очень значительной), но… что делать, если все, что у нас есть –
это двоичный файл? Хорошо, если дефекты исправлены в новой версии (которая,
между прочим, денег стоит), а если нет?
Эта статья адресована как самим разработчикам,
так и продвинутым пользователям, умеющим держать hiew в руках и не шарахающихся
в сторону от дизассемблера. Мы постараемся рассмотреть как можно больше
способов решения проблем, а вопросы правомерности модификации двоичного кода
пускай решают юристы и… моралисты.