Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

articles:s2k3-soft-ice [2017/09/05 02:55] (текущий)
Строка 1: Строка 1:
 +====== s2k3-soft-ice ======
 +<​sub>​{{s2k3-soft-ice.odt|Original file}}</​sub>​
 +
 +====== поиск бутылочного горлышка вместе с soft-ice ======
 +
 +крис касперски,​ ака мыщъх, a.k.a. nezumi, a.k.a. souriz, a.k.a. elraton, no-email
 +
 +**производительность сервера зависит не только от мощности аппаратной части, но и программной оснастки. один "​кривой"​ драйвер (приложение) способен сожрать все ресурсы,​ затормозив систему до уровня асфальтового катка и системный монитор не покажет ровным счетом ничего! как найти виновника?​! из множества программ самым доступным,​ точным и надежным инструментом как ни странно оказывается отладчик ****soft-ice**
 +
 +===== введение =====
 +
 +Операционные системы семейства NT поддерживают развитую систему мониторинга счетчиков производительности,​ отображающих в реальном времени сколько "​тиков"​ ушло на ту или иную операцию. Не отстают от них и процессоры,​ позволяющие регистрировать практически любые события от количества переключений контекста до интенсивности кэш-промахов. Специальные программы,​ называющие профилировщиками,​ обобщают эту информацию,​ выявляя так называемые "​горячие точки",​ в которых система проводит наибольшую часть своего времени,​ однако,​ точность измерений невелика и прежде чем приступать к профилировке (или снятию показаний счетчиков производительности) требуется устранить все побочные факторы,​ способные ввести профилировщик в заблуждение. В противном случае,​ приходится исходить из предположения,​ что все приложения и драйвера работают правильно,​ чего в жизни, увы, практически никогда не наблюдается.
 +
 +Soft-Ice, будучи отладчиком уровня ядра, позволяет остановить систему в любой момент и посмотреть какими интересными делами она сейчас занимается. С Soft-Ice в руках поиск "​бутылочного горлышка"​ занимает буквально считанные минуты,​ причем,​ результат абсолютно надежен. От него не скрыться ни "​кривым"​ драйверам,​ ни некорректно работающему аппаратному обеспечению. Кстати,​ знания ассемблера для этого не потребуется. Невероятно,​ но факт! Достаточно освоить несколько несложных команд,​ а все остальное Soft-Ice сделает за нас!
 +
 +===== >>>​ врезка почему счетчики производительности ненадежны =====
 +
 +Индикатор загрузки процессора (отображаемый Диспетчером Задач, Системным Монитором или Системным Проводником от Марка Руссиновича) является весьма популярным средством измерений,​ на основании которого делается вывод достаточна ли мощность процессора (процессоров) для решения текущий задач или необходимо подкинуть в топку еще одну вязанку тактов.
 +
 +На самом деле, сплошь и рядом приходится сталкиваться с ситуацией,​ когда при нулевой (по индикатору) загрузке,​ процессор работает во всю мощь или же наоборот,​ загрузка вплотную приближается к 100%, но процессор не выполняет никакой полезной работы,​ например,​ мотая холостой цикл или ожидая сигнала от внешних устройств. В такой ситуации необходимо менять не процессор,​ а криво написанное программное обеспечение.
 +
 +Почему же ошибаются счетчики производительности и, в частности,​ индикатор загрузки процессора?​ Дело в том, что под "​загрузкой процессора"​ создатели NT понимают отнюдь не загрузку процессора,​ как таковую,​ а готовность потока поделиться остатками кванта отпущенного ему процессорного времени. На хакерских конференциях было продемонстрировано большое количество exploit'​ов,​ отдающих ~3%-5% от полного кванта времени и заставляющих счетчик производительности отображать загрузку близкую к нулевой,​ чем с успехом пользуются многие зловредные программы,​ использующие распределенные сети для взлома паролей например.
 +
 +Другой источник ошибок — асинхронные операции ввода/​вывода,​ поддерживаемые ядром. При чтении данных с диска или файла подкачки,​ поток "​замораживается"​ системой,​ передающей управление потокам этого же или другого процесса,​ в результате чего поток, инициирующий процесс чтения,​ показывает намного более низкое потребление процессорного времени,​ чем происходит в действительности. Строго говоря,​ индикатор загрузки не лжет. Поток, действительно,​ "​спит"​ во время чтения с диска, но ведь нас интересует отнюдь не формальная сторона проблемы,​ а полное время, включающее в себя длительность всех операций ввода/​вывода,​ поскольку,​ интенсивный ввод/​вывод — отличное средство торможения!
 +
 +Наконец,​ счетчик загрузки ЦП не учитывает время, потребляемое драйверами. "​Загрузка ядра"​ более или менее корректно вычисляется только для некоторых системных вызовов,​ да и то с кучей оговорок и ограничений.
 +
 +{{s2k3-soft-ice_Image_0.png}}
 +
 +Рисунок 1 счетчики производительности — популярный,​ но крайне ненадежный способ измерений
 +
 +===== сеанс черной магией с полным ее разоблачением =====
 +
 +Как узнать:​ на что уходит львиная доля системного времени?​ Очень просто — установить Soft-Ice, вызывать его комбинацией <​CTRL-D>,​ посмотреть чем занимается сервер,​ выйти из Soft-Ice по <​CTRL-D>​ или команде "​x;<​ENTER>",​ затем тут же вызывать его вновь: чем занимается система на этот раз? Повторяя данную операцию в цикле, мы достаточно быстро соберем богатый статистический материал. Совершенно очевидно:​ истинное процессорное время, потребляемое каждым компонентом,​ прямо пропорционально частоте его появления при вызове отладчика.
 +
 +Когда сервер вообще ничем не нагружен,​ свыше 90% "​всплытий"​ приходится на превдопроцесс "​Idle",​ означающий,​ что текущие операции выполняются так быстро,​ что мы их просто не засекаем,​ т.к. они занимают ничтожные доли процессорного времени,​ при этом сервер может обслуживать достаточно большое количество пользователей,​ дефрагментировать жесткий диск в фоновом режиме и заниматься прочими делами. Вот так парадокс! Сервер работает,​ а процессор — отдыхает,​ что означает,​ что конфигурация сервера имеет определенный избыток по мощности и узких мест в ней нет.
 +
 +При дальнейшем росте загрузки,​ мы получаем более или менее "​гладкое"​ распределение,​ попадая то в интерпретатор PHP, то в процесс,​ обслуживающий SQL, то в другой "​демон",​ на языке Microsoft, называемый сервисом. Это вполне нормальное явление,​ однако,​ доминирование одного процесса над другим — плохой признак,​ указывающий на дефекты проектирования программы. В нормальной ситуации свыше 90% машинного времени уходит на ввод/​вывод,​ в течении которого процессы,​ инициировавшие запрос ввода/​вывода,​ спят как младенцы независимо от того, справляется дисковая подсистема/​сетевая карта со своей работой или нет.
 +
 +Повышения активность процессов свидетельствует о "​тяжелых"​ операциях типа криптографии,​ упаковке/​распаковке потока данных и прочих "​наукоемких"​ задачах,​ большинство из которых,​ кстати говоря,​ сугубо опционально. В частности,​ шифрование можно либо вообще отключить,​ либо выбрать "​легкие"​ алгоритмы. Аналогичным образом обстоит и с упаковкой. Естественно,​ ситуацию с вещанием цифрового аудио/​видео мы в расчет не берем. Тут, понятное дело, требуется мощный процессор с емкой кэш-памятью. А как узнать,​ что кэш памяти достаточно для решения поставленной задачи?​ Очень просто! Если Soft-Ice останавливается на произвольных машинных инструкциях — все ОК, а вот если доминируют инструкции чтения/​записи в память (MOV плюс что-то в квадратных скобках,​ а так же MOVSx, CMPSx и STOSx), то установка процессора с более емком кэш-памятью существенно поднимет производительность!
 +
 +Но это все голимая теория,​ переходим к практике и вещам далеко не очевидным даже для тех, кто давно использует Soft-Ice. Имя процесса,​ исполняемого в данный момент,​ отображается в правом нижнем углу, а текущий исполняемый код — в окне CODE, расположенным посередине экрана. В правильно сконструированной программе,​ процесс останавливается каждый раз в случайном месте. То есть колонка адресов будет каждый раз разная. Можно даже сказать очень сильно разная. Это означает,​ что в исследуемом процессе нет горячих точек или они выражены крайне слабо. Напротив,​ если какие-то диапазоны адресов встречаются чаще остальных — мы поймали горячую точку, которую разработчики программы должны были устранить еще на стадии проектирования,​ ну или на худой конец в процессе оптимизации своего продукта перед выбросом его на рынок. Впрочем,​ если они его не устранили,​ это не повод для паники,​ ибо, как мы уже говорили,​ ресурсоемкие операции типа криптографии занимают намного более времени,​ чем, например,​ отдача пользователю файла в том виде, в котором он записан на диске.
 +
 +Однако,​ достаточно часто приходится сталкиваться с горячими точками,​ не имеющими ничего общего с вычислениями. Как правило,​ это циклы, ожидающие наступления определенных событий. Правильно спроектированная программа никогда не прибегает к такому тупизму,​ она просто вгоняет поток в сон, указывая при каких обстоятельствах он должен проснуться. Конечно,​ распознать циклы, не имея опыта дизассемблирования,​ не так-то просто,​ но их можно запеленговать и по диапазону принадлежащим им адресов — если они появляются с огромным отрывом от всех остальных — отправляем программу на свалку,​ благо практически для всего ПО можно подобрать аналог.
 +
 +В качестве наглядного примера рассмотрим простую программу,​ мотающую холостой цикл, исходный код который укладывается в несколько строк на Си:
 +
 +main()
 +
 +{
 +
 +while(1);
 +
 +}
 +
 +Листинг 1 исходный текст программы hCPUl.c
 +
 +Откомпилируем ее без опций оптимизации (в случае MS VC это: cl.exe hCPUl.c), чтобы оптимизатор не выбросил ненужный с его точки зрения цикл while и запустим ее на выполнение. На однопроцессорных машинах мы получим 100% загрузку по индикатору,​ на двухпроцессорных (или однопроцессорных с двумя ядрами) — 50%, соответственно,​ четыре процессора/​ядра дадут всего лишь 25%, хотя Soft-Ice при каждом вызове будет всплывать в одном и том же процессе — hCPUl, исполняющемся в одном и том же месте — в цикле while, то есть, согласно,​ Soft-Ice, загрузка процессора близка к 100%. Это одновременно верно и нет. С одной стороны,​ поток, в котором исполняется цикл while, нагружает всего лишь один процессор/​ядро из всех имеющихся,​ совсем не препятствуя исполнению потоков других процессов на оставшихся процессорах (ядрах),​ однако,​ реальное торможение намного больше,​ чем это следует из простых арифметических расчетов. Системный планировщик распределяет очереди потоков равномерно между всеми процессорами (ядрами) и если один из процессоров (ядер) захватывается "​неправильным"​ потоком,​ планировщик начинает оптимизировать очередь потоков,​ но эффективность такой оптимизации невелика,​ в чем нетрудно убедиться,​ измерив реакционноспособность сервера с запущенной программой hCPUl и без нее.
 +
 +Теперь перейдем к более сложным вопросам,​ зарывшись в недра драйверов. Soft-Ice _всегда_ отображает имя процесса в правом нижнем углу, вне зависимости от того, находится ли система на прикладном (user-land) или ядерном (kernel-space) уровне. А что у нас в ядре? Ну, например,​ драйвера,​ которые могут вообще не иметь _никакого_ отношения к отображаемому процессу. Просто драйвер получил управление (например,​ по прерыванию,​ поступившему извне) именно в том момент,​ когда система переключила контекст на данный процесс. А может быть, совсем другой процесс прямо или косвенно инициировал вызов драйвера и тут же заснул,​ система переключила контекст на следующий процесс,​ а драйвер… как бы выразиться поделикатнее… если не завис, то конкретно застрял. Соответственно,​ при вызове отладчика,​ мы будет оказываться в нем чаще, чем в остальных,​ но имя процесса,​ отображаемое в нижнем углу, тут не причем. Оно может быть как одним и тем же, так и меняется в произвольном порядке,​ но даже если процесс каждый раз один и тот же, он, скорее всего тут не причем.
 +
 +Определить,​ что система находится в kernel-space очень просто. В конфигурации по умолчанию,​ нижняя половина адресного пространства принадлежит прикладным программам,​ а верхняя — ядру. Соответственно,​ если мы наблюдаем колонку адресов <​ 80000000h,​ отладчик находится внутри прикладных программ,​ в противном случае — это ядро или один из его драйверов. Селектор (то, что записано в регистре CS и то, что находится перед адресом,​ отдельное от него знаком двоеточия) в прикладном режиме равен 1Bh и 08h в режиме ядра.
 +
 +(Примечание:​ при указании ключа 3GB в boot.ini, ядро с драйверами "​ужимается"​ до 1 Гбайта,​ соответственно,​ граница ядерных земель отодвигается на 40000000h, во всяком случае,​ в 32-битном режиме все происходит именно так, а в 64-битном все совсем не так, но поскольку,​ Soft-Ice работает только в 32-битном режиме,​ оставим проблемы 64-битных серверов за рамками данной статьи).
 +
 +{{s2k3-soft-ice_Image_1.png}}
 +
 +Рисунок 2 Soft-Ice считает,​ что он остановился внутри процесса VMwareService,​ но колонка адресов,​ выходящая за пределы user-land, указывает,​ что мы находится в одном из драйверов
 +
 +Допустим,​ Soft-Ice остановится в некотором процессе,​ скажем,​ VMwareService,​ но столбец адресов выходит за пределы 80000000h и текущая исполняемая команда,​ выделенная инверсной строкой,​ расположена по BFF0ACE2h (см. рис. 02). Как узнать какому из драйверов она принадлежит?​! Нет ничего проще! Даем команду "​DRIVER"​ или "​MOD"​ и смотрим на базовые адреса загрузки драйверов. К сожалению,​ Soft-Ice не сортирует их по списку возрастания,​ но этот недостаток легко исправить! Достаточно выйти из Soft-Ice, запустить поставляемый вместе с ним Symbol Loader и сохранить историю команд в текстовой файл, а затем посредством MS Word или MS Excel преобразовать ее в таблицу.
 +
 +Драйвер,​ в чьих границах находится обозначенный адрес, и есть "​виновник"​. В данном случае (см. рис. 03) это NDIS – низкоуровневый сетевой драйвер. При интенсивной работе сетевой карте его появление в Soft-Ice вполне объяснимо,​ приемлемо и понятно,​ однако,​ это должна быть действительно _очень_ высокая нагрузка,​ в противном случае,​ это кривой драйвер или неправильная сетевая карта, смена которой (вместе с драйвером) ощутимо повысит общую производительность сервера,​ причем (внимание!) факт подобной "​кривизны"​ не определяет ни системный монитор,​ ни легион программ,​ предназначенных для тюнинга сервера,​ поскольку все они работают на более высоком уровне.
 +
 +{{s2k3-soft-ice_Image_2.png}}
 +
 +Рисунок 3 ловля драйвера на живца
 +
 +Другая широко распространенная ситуация — Soft-Ice начинает часто всплывает на команде чтения (реже — записи) в/из порт ввода-вывода,​ обычно представленный машинными командами IN Ax DX/​OUT DX,​Ax соответственно (см. рис. 04). Это плохой признак!!! Нормальное железо,​ управляемое правильными драйверами,​ работает по прерыванию,​ обмениваясь данными через DMA. Обращение к портам лишь инициируют ту или иную операцию,​ а потому занимают ничтожное время.
 +
 +Интенсивная работа с портами ввода/​вывода нагружает системную шину, снижая производительность всех подсистем компьютера в целом, а потому,​ такой ситуации необходимо избегать любой ценой. Легко сказать — избегать! А для этого, как минимум,​ необходимо определить к какому именно оборудованию обращается система. No problem, как говорят в Одессе,​ ща определим!
 +
 +{{s2k3-soft-ice_Image_3.png}}
 +
 +Рисунок 4 знакомство с портами ввода/​вывода
 +
 +Смотрим на значение,​ содержащееся в регистре DX (младшие 16-бит регистра EDX или, выражаясь человеческим языком,​ крайние четыре цифры справа),​ выходим из отладчика,​ запускаем "​Диспетчер устройств"​ в меню "​Вид"​ выбираем сортировку устройств по ресурсам и в портах ввода/​вывода тут же находим наш порт, равный в данном случае 379h и принадлежащий LPT1 – порту принтера,​ который вообще не установлен на обозначенной системе. Хм, странно,​ принтера нет, а обращение к порту происходят с чрезвычайно высокой степенью интенсивности,​ причем,​ не по прерыванию,​ а по опросу (готовности устройства).
 +
 +Лезем в очередь печати и видим, что в ней каким-то чудом оказался документ,​ отправленный на печать,​ и какой-то левый принтер (в смысле его драйвер) "​мистическим"​ образом повешен на LPT1, хотя физическим принтера нет. Очищаем очередь печати — не очищается!!! Сносим к черту драйвер — обращение к порту исчезает,​ а машина летит вперед с такой производительностью,​ что буквально отрывается от асфальта. Причем,​ другим путем обнаружить "​бутылочное горлышко"​ не удавалось — системный монитор упорно твердил,​ что все нормально,​ никаких косяков.
 +
 +{{s2k3-soft-ice_Image_4.png}}
 +
 +Рисунок 5 определение оборудования,​ к которому происходит обращение через "​Диспетчер устройств"​
 +
 +Наконец,​ Soft-Ice может останавливаться не только внутри драйверов,​ но и ядерных функций,​ лежащих в области адресов 8xxxxxxxh, где находится ntoskrnl.exe. Само ядро тут, понятное дело, не причем. Это просто какой-то противный драйвер напрягает его вызовом тех или иных функций. Что же это за драйвер такой?
 +
 +Даем команду "​STACK"​ и смотрим на левую колонку адресов (см. рис. 06),​ по которой и определяем драйвер описанным выше способом. В данным случае им оказался драйвер DVD-привода,​ автоматически установленный системой. Тщательное расследование выяснило,​ что к драйверу никаких претензий нет, а вот дефект проектирования DVD-привода привел к тому, что драйвер начинал обмениваться с ними каким-то командами (так и не найдены в стандарте на ATAPI-команды) даже если в лотке отсутствовал диск. Смена DVD-привода "​утихомирила"​ драйвер,​ "​мистический"​ обмен прекратился,​ а общая производительность системы опять-таки возросла.
 +
 +{{s2k3-soft-ice_Image_5.png}}
 +
 +Рисунок 6 просмотр стека позволяет определить какой именно драйвер вызывает функции ядра
 +
 +===== заключение =====
 +
 +Мы убедились,​ что поиск "​узких"​ мест сервера при помощи Soft-Ice – это простой,​ но чрезвычайно точный и надежный способ,​ охватывающий абсолютно все уровни:​ аппаратный,​ ядерный и программный. Конечно,​ не стоит ждать от Soft-Ice точных "​телеметрических"​ показаний,​ выраженных в численном виде. Да этого, в общем-то,​ и не нужно. Если в системе имеется "​бутылочное горлышко",​ то Soft-Ice обнаружит его практически сразу после пяти-шести вызовов.
 +
 +К недостаткам описанного способа следует в первую очередь отнести,​ что Soft-Ice "​мертв"​. На Server 2003 в 32-разрядном режиме он еще работает (да и то не со всеми видео-картами и чипсетами),​ но более новые системы ему не по зубам. К тому же, Soft-Ice способен обрушивать систему,​ вызывая голубые экраны смерти,​ зависания (от которых порой не спасает и RESET, а только "​передерживание"​ питания) и перезагрузки.
 +
 +Последние два случая очень опасны — сброса дисковых буферов не происходит и раздел,​ с которым ведется активная работа на чтение/​запись,​ рискует отправиться к праотцам. Но даже если "​полет нормальный",​ в момент вызова Soft-Ice,​сервер останавливает системные часы (которые потом нам придется корректировать) и прекращает весь сетевой обмен, что при продолжительном пребывании в отладчике ведет к обрыву TCP/IP соединений,​ вызывая естественное недовольство пользователей.
 +
 +