Разгон… Sound Blaster’а
Сказали бы мне некоторое время назад, что обычный Sound Blaster
может самым бессовестным образом тормозить всю систему, я бы просто не поверил.
Но именно такой экземпляр Blaster’а мне попал недавно в руки, причем, как показало
небольшое расследование, это был дефект не конкретного экземпляра, а непосредственно
самой модели, и не одной, а сразу нескольких!
Изменением всего одного байта драйвера звуковой карты мне удалось значительно
увеличить производительность системы, к тому же безо всякого ущерба для функциональности!
О том, как был найден этот зловредный байт, и рассказывает настоящая статья.
се началось с того, что я, заинтересовавшись новыми мультимедийными командами, решился приобрести Pentium III, поскольку мой старичок Celeron-300A их не поддерживал. Понятное дело, вместе с процессором пришлось купить и новую материнскую плату, а поскольку на современных «мамах» ISA-слоты отсутствуют, то потребовалось менять звуковую карту Gold Edison на что-нибудь поновее. Выбор пал на Sound Blaster-128 PCI <CT 4830/PCI> от Creative (ничего более стоящего в магазине и не было).
Ничуть не стремясь к чудесам производительности (и на прежнем процессоре все буквально летало), я все же ожидал, что Pentium III 733 будет по крайней мере не медленнее. Но как бы не так: производительность системы после апгрейда существенно упала и работа с ней превратилась в сплошное мучение. Постоянно используемые мною приложения Adobe Acrobat Reader и компьютерный словарь Lingvo выдерживали 5-7-секундную паузу при загрузке (тогда как прежде они запускались практически мгновенно), такая же пауза наблюдалась у Microsoft Word и Microsoft Visual Studio при первом обращении к панелям инструментов и меню. Особенно замедлилась скорость открывания файлов в «Универсальном проигрывателе»: прежде выполняясь практически мгновенно, теперь эта операция отнимала несколько секунд.
Перерыв все настойки BIOS и даже переустановив операционную систему (Windows 2000 для справки), я не добился ровным счетом ничего, однако выяснил, что на Windows 98 все работает отлично — ни задержек, ни тормозов там нет и все приложения грузятся как из пушки, значительно быстрее, чем раньше. В конце туннеля появился свет: раз под Windows 98 система работает, значит, это не аппаратный, а программный глюк Windows 2000. Что ж, будем лечить!
Первым делом требовалось установить, что именно вызывает задержку. Традиционно такие задачи решаются с помощью профилировщика, но как назло ни одного из них не оказалось под рукой, а бежать покупать диск посреди ночи как-то не хотелось. На выручку пришел отладчик, интегрированный в Visual Studio (впрочем, подошел бы и любой другой, например Soft-Ice или Windeb).
Рассуждал я следующим образом. Раз и Word, и Visual Studio, и многие другие приложения при первом обращении к меню вызывают задержку, то очевидно, виновники не они, а какой-то системный компонент, загружаемый ими. Если этот злополучный компонент автоматически загружается вместе с самим приложением, то пауза возникает при его запуске (как, например, в Adobe Acrobat Reader). Если же он загружается динамически при возникновении в нем необходимости — задержка появляется при обращении к меню.
Загрузив Word в отладчик и щелкнув мышкой по меню, я с удовлетворением отметил, что в окне DEBUG появились следующие строки:
Loaded ‘C:\WINNT\system32\winmm.dll’, no matching symbolic information found. Loaded ‘C:\WINNT\system32\wdmaud.drv’, no matching symbolic information found. Loaded ‘C:\WINNT\system32\wdmaud.drv’, no matching symbolic information found. Loaded ‘C:\WINNT\system32\wdmaud.drv’, no matching symbolic information found.
Уже неплохо: все-таки что-то грузится! Остается только разобраться, что… Заглянув в Platform SDK, я выяснил, что динамическая библиотека winmm.dll обеспечивает работу со звуком и мультимедиа, а загрузив ее в HEX-редактор, быстро нашел текстовую строку wdmaud.drv, красноречиво свидетельствующую о том, что именно winmm.dll грузит wdmaud.drv.
Логично, что wdmaud.drv предназначается для вывода звука, и это действительно так, поскольку его имя обнаружилось во вкладке «Драйверы» Sound Blaster’a в «Устройствах системы». Может ли Blaster или его драйвер вызывать торможение? А почему бы и нет! Чтобы проверить это предположение, я решился временно удалить winmm.dll из папки SYSTEM32. Но под Windows 2000 это сделать не так-то просто! Во-первых, winmm.dll уже используется системой и, стало быть, доступ к этой библиотеке заблокирован даже для администраторов, а во-вторых, даже если ее и удалить, она все равно будет автоматически восстановлена операционной системой из резервной копии!
Чтобы воспрепятствовать этому, необходимо заблаговременно удалить winmm.dll из папки WINNT\system32\dllcache, а затем переименовать winmm.dll во что-нибудь другое, скажем в winmm.dl_. Весь фокус в том, что переименования используемых динамических библиотек система не запрещает, автоматически корректируя все активные ссылки, но после перезагрузки приложения будут по-прежнему пытаться загрузить именно winmm.dll (откуда же им знать о переименовании?), но, естественно, не найдут ее (что, мне собственно, и нужно).
После удаления winmm.dll все тормоза мигом исчезли, но… вместе с ними исчез и звук, а что за компьютер без звука! Правда, таким приложениям, как Word, Visual Studio, Adobe Acrobat Reader, звук совсем ни к чему (у меня, во всяком случае, отключена «озвучка» пунктов меню и закрытия/открытия окон). Так почему бы не подсунуть им «пустышку» — динамическую библиотеку, имеющую то же самое имя, но не выполняющую никаких действий (просто возвращающую управление при вызове), а всем остальным приложениям (действительно нуждающимся в звуке) позволить обращаться к настоящей winmm.dll?
Сказано — сделано! Наскоро склепав dll’ку, не экспортирующую ни одной функции, я раскидал ее по всем каталогам, в которых находились исполняемые файлы Word, Visual Studio и других приложений. Дело в том, что при загрузке динамических библиотек система сначала ищет их в каталоге приложения и только потом, если ее там нет, переходит к системному каталогу Windows.
C Word и Visual Studio этот фокус удался, а вот с Acrobat не прошел: не понравилось ему, что в «пустышке» отсутствует функция timeGetTime. Но трудно, что ли, ее создать (тем более что ее прототип присутствует в SDK)?
Наконец-то с новым компьютером стало можно работать, а не мучиться, как раньше! Просто прелесть — ни тормозов, ни задержек! Все буквально летает: не успеваешь щелкнуть по иконке, как приложение уже появляется на экране! Но подобный «грязный хак» не мог вызвать у меня полного удовлетворения, ведь я не нашел причину глюка, а всего лишь загнал его поглубже внутрь.
И вот на Новый год, когда чудом выдалось несколько часов свободного времени, я решил взять врага если не штурмом, то осадой. Пошагово трассируя стартовую процедуру этой злосчастной DLL, я искал функцию, вызывающую задержку, а находя такую, перебирал все вложенные в нее функции одну за одной, а затем вложенные во вложенные... (В том, что тормоза вызвала как раз стартовая процедура, у меня не было никаких сомнений, поскольку задержка возникала именно при инициализации.)
Через десяток минут я был вознагражден! Следы вели к функции OpenDriver, что выглядело логично, ибо наличие бага в штатной библиотеке winmm.dll производства Microsoft Corporation мне казалось сомнительным: она едина на все карты, да и с прежним Blaster’ом работала без нареканий. А вот драйвер нового Blaster’а — дело другое. Нет ничего невероятного в том, что его инициализация (то бишь «открытие») происходит с задержкой. Итак, круг подозреваемых сузился, но все же не было ясно, кто истинный виновник: непосредственно железяка или ее родной драйвер.
Пройдясь несколько раз дизассемблером по драйверу Blaster’a, я не нашел ничего, способного вызывать задержку. Напротив — очень аккуратный и профессионально составленный код. Выходит, все же железка?! Эх, если бы не новогодние праздники, можно было бы вернуть ее продавцу для обмена… А вдруг не железка? Может, «мама»? Теоретически мог иметь место конфликт с контроллером PCI-шины или просто кривой контроллер…
Продолжая копаться в недрах драйвера, я неожиданно заметил, что OpenDriver вызывается четырежды с последовательной инициализацией портов «wave», «midi», «mixer» и «aux», причем первые три инициализации пролетали на ура, а последняя-то и вызывала задержку. Значит, виновата все же железка! AUX-порт на Blaster’е действительно был (хотя мною никак не использовался) и даже успешно функционировал, хотя ужасно медленно инициализировался.
А зачем мне AUX-порт? Мне и обычных портов с лихвой хватает! Стоит ли ради него терпеть задержки?! В общем, я решил запретить драйверу инициализацию AUX’а (действительно, глупо инициализировать то, с чем все равно не работаешь). Конечно, правильнее всего было бы переписать код winmm.dll, однако вносить исправления в двоичный файл чрезвычайно сложно и весьма небезопасно. Поэтому я ограничился тем, что забил строку AUX нулями (в моей версии файла она расположена по адресу .7752BB18). Функция OpenDriver, получив на вход пустую строки, ничего не инициируя, просто возвращает управление.
Итак, что же конкретно должны сделать читатели, желающие устранить подобный дефект у себя? Распишу все действия по шагам.
Шаг первый. Зайдя в систему под именем (или с правами) администратора, переместите “winmm.dll” из каталога WINNT\system32\ dllcache в какой-нибудь другой каталог, где вы храните резервные файлы (на тот случай, если вы передумаете и захотите вернуть все на место).
Шаг второй. Скопируйте WINNT\system32\ winmm.dll в winmm.dl1 и откройте его в любом HEX-редакторе (например, в Hiew’e, Qview’e или на худой конец в том, что встроен в популярную файловую оболочку DOS Navigator).
Шаг третий. В winmm.dll найдите строку AUX, завершаемую одним или несколькими нулями. Если это та строка, которая вам действительно нужна, то поблизости должны быть строки WAWE и MIXER или MIDI (в winmm.dll может быть несколько строк aux, использующихся различными ветвями программы).
Шаг четвертый. Забейте строку AUX нулями (то есть символами с кодом \x00, а не символами нуля с кодом \x30). Хотя на самом деле нулем достаточно затереть первую букву A, но это будет не так аккуратно.
Шаг пятый. Создайте командный файл следующего содержания:
ren WINNT\system32\winmm.dll WINNT\system32\winmm.dl_
ren WINNT\system32\winmm.dl1 WINNT\system32\winmm.dll
и запустите его на выполнение.
Шаг шестой. Перезагрузитесь.
Шаг седьмой. Удалите WINNT\system32\ winmm.dl_ и созданный вами командный файл.
Шаг восьмой. Скопируйте измененную WINNT\system32\winmm.dll в папку WINNT\system32\dllcache.
Вот и все! Удачной работы! Если же у вас не все будет гладко получаться, обращайтесь к автору этой статьи.
КомпьютерПресс 2'2002