Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Роббинс Д. - Отладка приложений для Microsoft .NET и Microsoft Windows - 2004

.pdf
Скачиваний:
350
Добавлен:
13.08.2013
Размер:
3.3 Mб
Скачать

ГЛАВА 19 Утилита Smooth Working Set

663

 

 

Страница 1

Страница 5

Fn 3

Запуск Fn

 

 

Fn 1

 

 

 

 

 

 

 

 

 

 

 

Fn 2

Fn 7

Страница 2

Страница 6

 

Fn 6

Fn 10

 

Страница 3

Страница 7

Fn 5

Fn 8

Страница 4

Страница 8

Fn 4

 

 

Fn 9

Рис. 19 1. Неоптимизированная система

Вся работа, связанная с подсчетом числа вызовов функций, скрыта в SWS; под робнее о необходимых для этого действиях см. раздел «Работа с SWS». Указать компоновщику порядок размещения функций проще простого. Для этого LINK.EXE поддерживает ключ командной строки /ORDER. В качестве параметра после ключа /ORDER просто указывается текстовый файл, называемый файлом порядка, в кото ром нужно привести список всех функций в желательном для вас порядке. Инте ресно, что имена всех функций должны быть указаны в файле порядка в полном, расширенном виде. Идея, лежащая в основе SWS, по сути заключается в создании файла порядка для вашей программы.

Возможно, у тех из вас, кто давно работает с Microsoft Windows, где то в со знании сейчас замаячили буквы WST. WST означает Working Set Tuner (средство настройки рабочего набора). Эту программу Microsoft распространяла вместе с Platform SDK для… хм, для настройки рабочего набора. Однако в связи с этим вам могут прийти в голову и три других факта: во первых, утилиту WST было очень сложно использовать, во вторых, в ней было несколько ошибок, и в третьих, она

664 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

больше не входит в состав Platform SDK. SWS — гораздо более простая в исполь зовании замена WST.

Страница 1

Fn 1

Fn 2

Fn 3

Fn 4

Fn 5

Fn 6

Страница 2

Fn 7

Fn 8

Fn 9

Fn 10

Страница 5

Страница 6

Страница 3

Страница 4

Страница 7

Страница 8

Рис. 19 2. Оптимизированная система

Если вам хочется больше узнать о настройке рабочего набора и получить пре красное пособие по производительности Windows, попытайтесь найти четвертый том книги «Microsoft Windows NT 3.51 Resource Kit» под названием «Optimizing Windows NT» (оптимизация Windows NT) (Microsoft Press, 1995). Этот том, напи санный Рассом Блейком (Russ Blake), представляет собой великолепное введение в указанную тему. В группе разработчиков Microsoft Windows NT Расс отвечал за настройку производительности системы. Эта книга раньше была в MSDN, но вне запно исчезла. Утилиту WST также разрабатывала группа Расса, и в своей книге он утверждает, что после использования программы оптимизации рабочего на бора вы должны достигнуть его уменьшения на 35–50%. Каждый раз, когда ваше приложение может сбросить такой вес, эту возможность определенно стоит рас смотреть повнимательней!

ГЛАВА 19 Утилита Smooth Working Set

665

 

 

Стандартный вопрос отладки

Могу ли я проверить процесс, выполняемый на главном сервере, на предмет утечки ресурсов без установки каких-либо программ?

Для выполнения быстрой проверки всегда подойдет PerfMon, однако нет ни чего лучше, чем удивительный диспетчер задач. Открыв вкладку Processes, вы увидите столбец, отображающий различную информацию о производи тельности. Так как работа с ресурсами основана на дескрипторах, следует отслеживать число дескрипторов процесса. Откройте вкладку Processes, вы берите в меню View (вид) пункт Select Columns (выбрать столбцы) и уста новите в диалоговом окне Select Columns (выбор столбцов) флажок Handle Count (счетчик дескрипторов). Если вы хотите следить за объектами GDI, установите также флажок GDI Objects (объекты GDI). Оба столбца, добав ленных в диспетчер задач и отсортированных по дескрипторам, показаны на рис. 19 3.

Рис. 19 3. Отображение дескрипторов и объектов GDI в диспетчере задач

По умолчанию диспетчер задач автоматически обновляет информацию каждые несколько секунд, но при этом вам нужно непрерывно следить за числом дескрипторов и объектов GDI, чтобы увидеть, когда оно начинает увеличиваться. Мне нравится приостанавливать обновление путем выбора пункта Paused (приостановить) в подменю Update Speed (скорость обнов ления) меню View. Благодаря этому я могу выполнить какую либо опера

см. след. стр.

666 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

цию, вернуться в диспетчер задач и нажать F5 для обновления экрана. На блюдайте и за столбцом Mem Usage (память), потому что числу дескрипто ров соответствует определенный объем памяти: если оба значения растут, утечка ресурсов в самом разгаре.

Прежде чем описать работу с SWS, я должен вернуть вас на землю. Во первых, SWS — не панацея. Если до запуска SWS быстродействие вашей программы было ужасным, таким оно и останется. Во вторых, оптимизацию рабочего набора сле дует выполнять в самом конце работы над производительностью приложения, после улучшения его алгоритмов и исправления всех найденных проблем с быстродей ствием. Наконец, использовать SWS следует только в конце цикла разработки. Максимальное преимущество SWS обеспечит, когда изменения кода приближаются к минимуму.

SWS может и не понадобиться. Разрабатывая небольшую программу, откомпи лированные файлы которой занимают не более 2–3 Мб, вы можете вообще не заметить уменьшения рабочего набора. Максимальной выгоды от оптимизации рабочего набора вы добьетесь, работая над более крупными приложениями, по тому что чем больше страниц требуется программе, тем больше возможностей для ее улучшения.

Работа с SWS

Работа с SWS состоит из трех этапов. На первом вы должны перекомпилировать свою программу для установки ловушки SWS, позволяющей накопить данные о вызовах функций. Второй этап заключается в выполнении с этой специальной откомпилированной версией программы ряда наиболее частых пользовательских сценариев. Для правильного использования SWS вам нужно определить эти сце нарии, чтобы вы могли точно их воспроизвести. Случайное выполнение программы под управлением SWS может вообще не привести к сокращению рабочего набо ра. Третий этап включает генерирование для компоновщика файла порядка (что очень просто) и интеграцию этого файла в заключительную компоновку программы.

Настройка компиляндов SWS

Необходимость отдельной компиляции программы для использования SWS объ ясняется тем, что в основе SWS лежат те же принципы, что и в WST. Хотя я мог написать огромную, сложную и подверженную ошибкам программу для получе ния информации о функциях вашего приложения «на лету», гораздо проще пре доставить установку функции ловушки компилятору. Ключ /Gh (включить функ цию ловушку _penter) приказывает компилятору разместить в начале пролога всех генерируемых функций вызов функции _penter. В SWS функция _penter уже реа лизована; чтобы она могла продемонстрировать все свои магические возможно сти, вы должны скомпоновать с ней свою программу.

Скомпилировать программу для использования с SWS обычно просто — для этого надо только кое что сделать.

1.Прежде всего убедитесь в правильности параметров заключительной компо новки своего проекта, так как эта конфигурация будет клонирована. Если вы

ГЛАВА 19 Утилита Smooth Working Set

667

 

 

установили при помощи надстройки SettingsMaster из главы 9 ключи компи лятора и компоновщика, которые я рекомендовал в главе 2, у вас все в порядке.

2.Клонируйте конфигурацию, с которой вы хотите работать. Нажмите правой кнопкой название решения в окне Solution Explorer (проводник решений) и выберите в меню пункт Configuration Manager (менеджер конфигураций), после чего появится одноименное диалоговое окно. Новый конфигурационный па раметр скрывается в списке Active Solution Configuration (активная конфигу рация решения). Доступ к нужному нам полю <New…> показан на рис. 19 4 (я искал его довольно долго). Как правило, следует клонировать заключительные компоновки. Открыв диалоговое окно New Solution Configuration (конфигура ция нового решения), дважды убедитесь в том, что вы выбрали нужное значе ние в списке Copy Settings From (копировать параметры из), потому что, если вы будете наследовать решение от <Default>, ваша конфигурация компоновки не будут перенесена. Называя новый проект, я предпочитаю указывать тип ком поновки и буквы « SWS», в результате чего получается имя Release SWS. Диало говое окно New Solution Configuration с этими новыми параметрами показано на рис. 19 5. Помните, что при создании новых решений каталог вывода и про межуточный каталог изменяются.

Рис. 19 4. Выбор новой конфигурации при помощи окна Configuration Manager

Рис. 19 5. Создание новой конфигурации Release$SWS

3.Если вы пользуетесь утилитой SettingsMaster (как и следует делать), настройка компилятора и компоновщика тривиальна. Нажмите кнопку SettingsMaster

668 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

Custom Project Update (обновление проекта) и, когда появится приглашение, выберите файл Release SWS.XML. Это установит минимально необходимые параметры. Чтобы использовать SWS с отладочной компоновкой, выберите файл Debug SWS.XML (оба файла находятся в каталоге SettingsMaster\SettingsMaster).

4.Если вы не используете SettingsMaster (позор!), вам нужно установить для проекта Release SWS следующие параметры компилятора (CL.EXE) (см. по этому пово ду главу 2):

/Zi (формат отладочной информации);

/Gy (включить компоновку на уровне функций);

/Gh (включить функцию ловушку _penter); стандартного способа установки этого ключа нет, поэтому вам придется выбрать в папке C/C++ пункт Com

mand Line (командная строка) и ввести его вручную.

Кроме того, для проекта Release SWS нужно задать ключи компоновщика (LINK.EXE):

/DEBUG (генерировать отладочную информацию);

/OPT:REF (оптимизация: удалять неиспользуемые функции).

5.Добавьте SWSDLL.LIB в список зависимостей (dependencies).

Чтобы сконфигурировать проект Debug SWS, установите ключ /Gh для компи лятора CL.EXE и добавьте зависимость от SWSDLL.LIB.

Выполнение приложений вместе с SWS

После настройки и компиляции приложения наступит самый трудный для вас этап работы с SWS — выполнение вашей программы. Вам придется самым тщательным образом обдумать, каковы наиболее частые сценарии использования вашего при ложения. Если вы оптимизируете готовую программу, вам, вероятно, следует по сетить своих клиентов, чтобы увидеть, что они чаще всего с ней делают. Если же вы работаете над новым приложением, обсудите это с сотрудниками службы мар кетинга или представителями заказчика. Определив сценарии, их нужно будет выполнить на разных машинах с различной загрузкой. Скорее всего вам захочет ся сделать эти сценарии воспроизводимыми при помощи такой утилиты автома тизации, как Tester из главы 16.

Запустив программу вместе с SWS, вы обнаружите два новых файла в каталоге, в котором находится каждый двоичный файл, скомпилированный для SWS: <имя файла>.SWS и <имя файла>.1.SWS. Файл SWS без цифры — это базовый файл, со держащий адреса и размеры каждой функции модуля, а также пространство для счетчиков числа вызовов. При каждом запуске вашей программы этот файл ко пируется в новый файл, чтобы избежать повторного просмотра символов. Файлы с цифрой соответствуют запускам программы и содержат счетчики вызовов. При каждом выполнении вашего специального откомпилированного двоичного фай ла создается новый — <имя файла>.#.SWS.

Нужные компоненты SWS находятся в исполняемом файле SWS.EXE. Эта про грамма позволяет просматривать отдельные SWS файлы, создавать новые файлы и выполнять финальную оптимизацию. Запустив SWS.EXE без всяких параметров или с ключом 6?, вы увидите:

 

 

 

 

ГЛАВА 19 Утилита Smooth Working Set

669

 

 

 

SWS (Smooth Working Set) 2.0

 

 

John Robbins 6 Debugging Applications for Microsoft .NET and Microsoft Windows

 

Usage: SWS [6t <module>]|[6d

<module>]|[6g <module>]|[6?] [6nologo]

 

6t

<module> 6 Tune the module's working set

 

 

 

 

(run from

directory with .SWS file)

 

6d

<module> 6

Dump the raw data for the module or #.SWS file

 

6g

<module> 6

Generate the initial SWS file for the module

 

6?

 

6

Show this

help screen

 

6nologo

6

Do not display the program information

 

Чтобы увидеть, какие именно функции вызываются, вы можете просматривать все итоговые файлы .SWS; это позволяет гарантировать, что вы выполняете имен но те функции, которые собирались. Вывод файла, соответствующего запуску ва шей программы (<имя файла>.#.SWS), имеет формат:

Link time

: 0x3E13849C

 

Entry count

: 12

 

 

Image base

: 0x00400000

 

Image size

: 0x00007000

 

Module name : SimpleSWSTest.exe

Address

Count

Size

Name

————— ————

—— ——

 

 

0x00401050

2

22

?Bar@@YAXXZ

0x00401066

2

22

?Baz@@YAXXZ

0x0040107C

2

22

?Bop@@YAXXZ

0x00401092

4

10

?Foo@@YAXXZ

0x0040109C

1

49

_wmain

0x004010CD

2

10

_YeOlCFunc

0x004011E0

0

422

_wmainCRTStartup

0x00401C50

0

63

__onexit

0x00401C90

0

24

_atexit

0x00401DC0

0

23

__setdefaultprecision

0x00401DE0

0

7

__matherr

0x00401DF0

0

7

__wsetargv

При запуске вашей программы, использующей функцию _penter утилиты SWS, первоначальный файл .SWS генерируется автоматически. Однако это требует зна чительного объема работы с символьной машиной DBGHELP.DLL, поэтому вы сможете уменьшить время запуска, если будете предварительно генерировать SWS файлы для модуля, указывая программе SWS.EXE ключ 6g.

Генерирование и использование файла порядка

После завершения всех запусков вашей программы вам нужно оптимизировать ее и сгенерировать файл порядка, который будет передан компоновщику. Для этого SWS.EXE предоставляет ключ командной строки 6t, после которого следует про сто указать имя модуля оптимизируемого двоичного файла. В результате оптими зации создается действительный файл порядка с расширением .PRF; я выбрал это расширение потому, что такие файлы генерировала программа Working Set Tuner.

670 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

Если вам хочется увидеть, что происходит при создании файла порядка, т. е. сам процесс «упаковки» и упорядочения функций, укажите SWS в командной строке ключ 6v. Понять подробный вывод легко:

Verbose output turned on

Action 6> Tuning for : SimpleSWSTest

Initializing the symbol engine.

Loading the symbols

Processing : SimpleSWSTest.1.SWS

Processing : SimpleSWSTest.2.SWS

Processing : SimpleSWSTest.3.SWS

Processing : SimpleSWSTest.4.SWS

Processing : SimpleSWSTest.5.SWS

Order file output: SimpleSWSTest.PRF

Page Remaining (4086) (0010) : (

20)

?Foo@@YAXXZ

Page Remaining (4064) (0022) : (

10)

?Bop@@YAXXZ

Page Remaining (4042)

(0022)

: (

10)

?Baz@@YAXXZ

Page Remaining (4032)

(0010)

: (

10)

_YeOlCFunc

Page Remaining (4010)

(0022)

: (

10)

?Bar@@YAXXZ

Page Remaining (3961)

(0049)

: (

5)

_wmain

Числа, которые вы видите после слов «Page Remaining», указывают на оставшееся пространство страницы, размер функции и число ее вызовов.

При создании файла .PRF утилита SWS генерирует не просто текстовый лис тинг функций в порядке убывания числа вызовов, так как это не учитывало бы размера страницы ОС. Если функция пересекает границу страницы, то для ее выполнения потребуется загрузить в память две страницы. SWS гарантирует, что во всех случаях функция будет размещаться на одной странице, а также пытается обеспечить максимальную заполненность каждой страницы. Именно поэтому вы можете встретить в начале итогового файла порядка редко вызываемые функции. Избегая пустот на страницах, вы снизите объем оперативной памяти, нужный вашей программе.

Рис. 19 6. Указание файла порядка для отладочной компоновки при помощи

ключа /ORDER

ГЛАВА 19 Утилита Smooth Working Set

671

 

 

После создания файла порядка нужно просто указать его компоновщику при помощи ключа /ORDER. Всегда сохраняйте файл порядка в том же каталоге, что и файл проекта и исходные файлы. Ключ /ORDER имеет одну особенность, которая часто вызывает замешательство: перед именем файла должен быть указан символ @. Если вы не используете SettingsMaster, вы можете указать файл порядка для двоичного файла своей заключительной компоновки, открыв окно Property Pages (страницы свойств), папку Linker (компоновщик), страницу Optimization и введя нужное выражение в поле Function Order (порядок функций) (рис. 19 6). При использовании SettingsMaster просто нажмите кнопку SettingsMaster Custom Project Update и выберите файл ReleaseOrderFile.XML.

Реализация SWS

Как это бывает со многими проектами, когда я впервые подумал о реализации SWS, это представлялось довольно сложным делом, однако при написании кода все оказалось проще. Я планировал сначала разобраться с функцией _penter, после это го — с двоичными файлами и перечислением символов и, наконец, — с перио дом выполнения и алгоритмом оптимизации.

Функция _penter

Должен признать, что до того, как я решил использовать функцию _penter при помощи ключа компилятора /Gh, я хотел заставить SWS работать с немодифици рованными двоичными файлами. Конечно, это возможно, но довольно затрудни тельно: во первых, чтобы гарантировать включение кода ловушки в первую оче редь, мне нужно было написать отладчик, а во вторых, я должен был включить 5 байтовые переходы для всех функций, обнаруживаемых в таблице символов. У меня был опыт разработки похожего кода для коммерческих программ, так что я знал, насколько это сложно. В конце концов я счел специальную компоновку вполне приемлемой, особенно когда у нас есть такие средства, как SettingsMaster, благо даря которым добавить в конфигурацию компоновки SWS совсем легко.

Разработав установку ловушки, я приступил к рассмотрению действий, кото рые нужно выполнять при каждом вызове _penter. Моя функция _penter и ее вспо могательный код приведены в листинге 19 1. Как вы можете видеть, она исполь зует соглашение вызова naked, поэтому я сам генерирую пролог и эпилог. Согла шение naked требуется в документации к _penter; кроме того, это облегчает полу чение адреса возврата из функции. К счастью, когда компилятор обещает, что он сгенерирует вызов _penter до всех остальных команд, он держит свое слово! Ре зультат установки ключа /Gh показан в дизассемблированном фрагменте, из ко торого видно, что вызов _penter выполняется даже до команды PUSH EBP, одного из элементов стандартного пролога функции:

Bar:

 

 

00401050: E8B7000000

call

_penter

00401055: 55

push

ebp

00401056: 8BEC

mov

ebp,esp

00401058: E8A8FFFFFF

call

ILT+0(?Foo

0040105D: 3BEC

cmp

ebp,esp

672

ЧАСТЬ IV

Мощные средства и методы отладки неуправляемого кода

 

 

 

0040105F: E8AE000000

call

_chkesp

00401064: 5D

pop

ebp

00401065: C3

ret

 

Немного пофантазировав, вы поймете, что ключ /Gh позволяет создать неко торые другие интересные утилиты. Первая, что пришла мне в голову, — это ути лита контроля производительности. Благодаря тому, что Microsoft уже предлага ет нам ключ /GH (включить функцию ловушку _pexit), использовать такое средство будет гораздо проще, так как вы будете знать момент окончания функции. Сове тую вам получше обдумать силу функций _penter и _pexit.

Стандартный вопрос отладки

Почему в окне Disassembly вызовы некоторых функций начинаются с «ILT»?

Вотрывке, сгенерированном ключом /Gh, вы видели вызов функции CALL ILT+0(?Foo, что многих прогhраммистов приводит в недоумение. Подобные вызовы свидетельствуют о магической компоновке с приращением в дей ствии. Аббревиатура ILT означает Incremental Link Table (таблица компоновки с приращением).

При создании отладочной компоновки компоновщик хочет скомпоно вать двоичный файл как можно быстрее. Для этого он добавляет в каждую функцию довольно много пустого места, благодаря чему при изменении функции ему нужно только перезаписать функцию, не перемещая код в двоичном файле. Между прочим, это пустое пространство заполняют коман ды INT 3. Однако размер функции может превысить объем выделенного места.

Вэтом случае компоновщик должен переместить функцию в другое место двоичного файла.

Если б каждая функция, вызывающая перемещенную функцию, делала это при помощи ее действительного адреса, то при каждом перемещении функции в результате новой компоновки компоновщик должен был бы искать и обновлять все команды CALL. Поэтому для экономии времени ком поновщик создает специальную таблицу компоновки с приращением, ко торую использует для всех вызовов. Теперь при изменении функции ком поновщик должен обновить в двоичном файле только одно выражение. Таблица ILT показана в листинге 19 1.

@ILT+0(_wmain):

 

00401005

jmp

wmain (401070h)

@ILT+5(??_GCResString@@UAEPAXI@Z):

0040100A

jmp

CResString::'scalar deleting destructor' (401B40h)

@ILT+10(?ParseCommandLine@@YAHHQAPAGAAUtag_CMDOPTS@@@Z):

0040100F

jmp

ParseCommandLine (401439h)

@ILT+15(?ShowHelp@@YAXXZ):

00401014

jmp

ShowHelp (401644h)

@ILT+20(??1CResString@@UAE@XZ):

00401019

jmp

CResString::~CResString (401A00h)

@ILT+25(?LoadStringW@CResString@@QAEPBGI@Z):

0040101E

jmp

CResString::LoadStringW (401A30h)

Соседние файлы в предмете Программирование на C++