Обзор продуктов компании TurboPower Software
Часть 2. Утилиты для отладки и профилирования приложений
Memory Sleuth 1.59 for Borland Delphi
Sleuth CodeWatch (менеджер ресурсов)
Режимы работы Sleuth CodeWatch
Sleuth StopWatch (менеджер приложения)
Sleuth Coverage Analyst (анализатор участков кода)
Sleuth LineProfiler (профилировщик строк кода)
Sleuth ActionRecorder (менеджер системных событий)
Введение
Американская фирма TurboPower является не только разработчиком широко известных компонентов для Delphi и C++ Builder, таких как Async Professional, Internet Professional, SysTools и др., но и создателем продуктов Memory Sleuth 1.5 и SleuthQA2 для контроля и анализа расходования памяти, а также других ресурсов детальной отладки и профилирования разрабатываемых приложений.
В предлагаемом обзоре рассматриваются системные приложения, позволяющие производить отладку и профилирование, для средства разработки Borland Delphi. Однако все изложенное ниже справедливо и для C++ Builder.
При установке вышеуказанных продуктов в меню Tools Delphi и C++ Builder появляются команды (Memory Sleuth, Sleuth ActionRecorder, Sleuth CodeWatch, Sleuth StopWatch, Sleuth LineProfiler, Sleuth CoverageAnalyst), при помощи которых можно легко запускать системные приложения.
Случалось ли вам, написав код, запустив его один раз и проверив результат, объявить, что код протестирован? Наверное, такое бывало не слишком часто. Обычно следует тестировать каждую строку кода при помощи отладчиков и оптимизировать код при помощи профилировщиков. Но даже при этом нельзя гарантировать полное отсутствие ошибок. Отладка и профилирование — важная задача в процессе разработки программного обеспечения. В TurboPower Memory Sleuth 1.5 и SleuthQA2 есть инструменты, позволяющие полностью отлаживать и профилировать программное обеспечение. Не пренебрегайте ими!
Memory Sleuth 1.59 for Borland Delphi
Memory Sleuth 1.5 представляет собой утилиту для контроля и анализа памяти и других потребляемых ресурсов 32-разрядного приложения Borland Delphi (слово Sleuth переводится как «сыщик», что вполне отражает назначение этого продукта). Помимо этого Memory Sleuth отслеживает неосвобожденные ресурсы. Этот продукт известен на рынкке программного обеспечения с 1996 года.
Краткий обзор
Memory Sleuth for Borland Delphi — автономное приложение, которое обрабатывает прерывания от вашего приложения и сообщает о текущем состоянии памяти и ресурсов во время выполнения приложения. После завершения приложения Memory Sleuth вычисляет максимальную величину используемой памяти, сообщает о потребляемых приложением ресурсах и выдает список неосвобожденных ресурсов. Элементы списка неосвобожденных ресурсов имеют ссылку на строку в исходном тексте, где эти ресурсы были затребованы.
Memory Sleuth может проверять факт совпадения записей в динамической памяти («куче»). Это возможно благодаря тому, что каждое распределение памяти дополнено четырьмя байтами. Дополнительным байтам присваивается значение $FEFEFEFE. При освобождении блока памяти Memory Sleuth делает в них пометку об освобождении.
Вы можете в любой момент сделать запись текущего состояния о потреблении ресурсов приложением, нажав кнопку Mark на инструментальной панели. Memory Sleuth также позволяет посылать сообщения от приложения, используя функцию Windows API OutputDebugString.
Для успешного использования Memory Sleuth приложение должно быть откомпилировано с отладочной информацией.
Использование Memory Sleuth
После запуска Memory Sleuth появляется главная форма системного приложения с меню, инструментальной панелью и тремя информационными страницами (рис. 1).
Вы можете обращаться ко всем функциям Memory Sleuth через меню. Часто используемые функции доступны на инструментальной панели. Информационные страницы отображают информацию относительно приложения, которое контролируется.
Чтобы использовать Memory Sleuth, необходимо выбрать приложение, используя опцию меню Open или значок Open на инструментальной панели, а затем, нажав кнопку Run, отслеживать на странице Running Status динамику выполнения приложения. По окончании приложения можно перейти на страницу Report, чтобы проанализировать, как выполнялось приложение (рис. 2).
Страница Debug output позволяет увидеть дополнительные отладочные сообщения, которые можно посылать из приложения.
Sleuth CodeWatch (менеджер ресурсов)
Sleuth CodeWatch представляет собой инструмент для контроля правильного выделения памяти и других ресурсов и может применяться со средствами разработки не только Borland, но и Microsoft. Sleuth CodeWatch не сможет отслеживать выполнение кода, если приложение является динамически загружаемой библиотекой или COM-объектом, а также делать сообщения о строках в исходном коде, вызвавших ошибки, если приложение скомпилировано без отладочных опций.
Для Delphi выберите опцию Project/Options/Compiler, пометьте все параметры в секции Debugging. Затем выберите опцию Project/Options/Linker и пометьте параметр Include TD32 debug info.
Для C++Builder выберите опцию Project/Options/Compiler, нажмите на кнопку Full debug — в секции Code optimization параметр будет установлен в режим None. Пометьте все параметры в секции Debugging и выключите параметр stack frames в секции Compiling. Если при инсталляции Sleuth QA Suite 2 был выбран режим добавления вызова пакета из интегрированной среды, Sleuth сам выполнит вышеперечисленные действия.
Для Visual C++ в диалоговом окне Project Settings выберите для параметра Settings For значение Win32 Release. На закладке C/C++ параметру General присвойте значение Category, а Debug Info — значение Program Database. На закладке Link параметру category присвойте значение Generate debug info. Наконец, можно набрать OPT:REF для параметра Project Options на закладке Link, что сделает выполняемый модуль больше — за счет включения в код функций, которые никогда не вызываются.
Для Visual Basic в диалоговом окне Project Properties на закладке Compile необходимо выбрать параметр Compile to Native Code и включить параметр Create Symbolic Debug Info.
Особенности отладки приложений, использующих пакеты, динамические библиотеки времени выполнения и статически загружаемые DLL
Sleuth CodeWatch выполняет анализ, вводя в отлаживаемое приложение функции перехвата вызова модулей, выбранных для анализа. Такая техника имеет ограничения, сказывающиеся на получаемых результатах, особенно если используются пакеты времени выполнения C++Builder, динамические или статически загружаемые RTL-компоненты, такие как BORLDNMM.DLL и библиотеки MFC.
Когда выбирается опция Run в Sleuth CodeWatch, загружается главная процедура EXE-приложения с необходимой отладочной информацией. Поскольку в Windows перед загрузкой главной процедуры приложения имеется возможность изменить порядок выполнения, Sleuth CodeWatch может загрузить свои функции и проинициализировать переменные, необходимые для анализа. Это означает, что впоследствии можно будет контролировать вызов любых функций приложения. К сожалению, последовательность событий, происходящих при использовании DLL, статически загруженных в приложения, не одинаковая. Windows загружает и инициализирует DLL-модули перед началом обработки процедур приложения. Поскольку Sleuth CodeWatch подключает свои функции после того, как Windows загрузит приложение, то возможность проверки кода инициализации в DLL отсутствует. Одним из типичных действий, осуществляемых при инициализации DLL, является инициализация местного менеджера «кучи», что обычно влечет выделение и/или инициализацию как минимум одной критической секции и некоторого количества глобальной памяти. Поскольку Sleuth CodeWatch ничего не знает об этих ресурсах, он не признает их, когда они упоминаются, и помечает эти ресурсы как ошибочные. Поэтому рекомендуется, по мере возможности, повторно собирать модули приложения и не использовать пакеты и DLL при применении Sleuth CodeWatch. Кроме того, пакеты Delphi и C++Builder, а также стандарные библиотеки RTL обычно не содержат отладочной информации (symbol information), а без нее Sleuth CodeWatch не может отфильтровать происходящие события.
Режимы работы Sleuth CodeWatch
Системное приложение можно запускать на выполнение как автономно — выполняя CodeWatch.exe, так и из интегрированной среды Delphi — выбирая опцию Tools/Sleuth CodeWatch. В обоих случаях появляется главная форма системного приложения с меню, инструментальной панелью и информационной страницей (рис. 3).
Вы можете обращаться ко всем функциям Sleuth CodeWatch через меню. Часто используемые функции доступны на инструментальной панели, расположенной слева и меняющейся в зависимости от выбранной закладки. На странице отображается информация относительно подконтрольного приложения в зависимости от выбранного типа анализа.
Для облегчения использования системного приложения допускается применение мастера, который поможет выбрать необходимые параметры для анализа приложения в диалоговом режиме. Возможные варианты анализа: только память; память и ресурсы; память, ресурсы и ошибки в Windows API; память, ресурсы, ошибки в Windows API и вызовы Windows API.
Выполняемое приложение находится под полным контролем Sleuth CodeWatch, который может прервать его в любой момент и не позволить завершить само себя, пока выполняется приложение. Интерфейс информационной страницы удобен для использования и снабжен графической информацией (рис. 4).
Sleuth StopWatch (менеджер приложения)
Sleuth StopWatch служит для анализа работы любого приложения. Он позволяет отслеживать время работы кода приложения во время выполнения этого приложения с целью идентификации критических параметров. В частности, Sleuth StopWatch может измерить время работы любой процедуры приложения и показать список процедур, вызванных из помеченной процедуры, вместе с временем выполнения каждой. Кроме того, Sleuth StopWatch содержит дизассемблер с отслеживанием времени выполнения операций.
Sleuth StopWatch позволяет выявить, на что у приложения уходит большая часть времени. С его помощью можно выполнять профилирование приложения и преобразовывать код в критических областях, чтобы повысить эффективность выполняемого кода.
Интерфейс инструментального средства идентичен интерфейсу Sleuth CodeWatch, за исключением инструментальной панели, где вместо таких опций Sleuth CodeWatch, как Modules, Parameters&failures, Debug Output и Report, находятся опции Sleuth StopWatch — Routines, Profile, Comparison, Trace. В утилите Sleuth StopWatch имеется отличный инструмент — дизассемблер кода (рис. 5), который можно использовать для получения важной информации. Этот инструмент применяется, если, например, вы создаете класс-наследник и хотите больше узнать об устройстве родительского класса, исходных текстов которого у вас нет.
Sleuth Coverage Analyst (анализатор участков кода)
Интерфейс этой утилиты аналогичен интерфейсу Sleuth CodeWatch, за исключением инструментальной панели, где имеются опции Routines, Module Coverage, Line Coverage, Trace.
Во многих проектах после их завершения остаются ошибки, так как во время отладки ошибочный код ни разу не получал управления. Использование Sleuth Coverage Analyst позволяет гарантировать, что все части проекта (API, DLL, COM и т.п.) будут выполнены во время испытаний.
Приведенный ниже пример показывает функцию для преобразования строки pascal в HTML-эквивалент. Как можно увидеть по цифрам из колонки под именем Hits, строка, содержащая кавычки, будет обработана неправильно, так как на этот блок в операторе case ни разу не будет передано управление.
Line Hits Source
27 - function AnsiToEscape(const S: string): string;
28 - {- returns the string with & escapes}
29 - var
30 - i : Integer;
31 2 begin
32 2 Result := S;
33 2 i := length(Result);
34 2 while i > 0 do begin
35 22 case Result[i] of
36 - '"' :
37 - begin
38 0 Result[i] := '&';
39 0 Insert('quot;', Result, i + 1);
40 - end;
41 - '&' :
42 1 Insert('amp;', Result, i + 1);
43 - '<' :
44 - begin
45 1 Result[i] := '&';
46 1 Insert('lt;', Result, i + 1);
47 - end;
48 - '>' :
49 - begin
50 1 Result[i] := '&';
51 1 Insert('gt;', Result, i + 1);
52 - end;
53 - end;
54 22 dec(i);
55 - end;
56 2 end;
Объединяя Sleuth CoverageAnalyst с Sleuth ActionRecorder (о нем будет рассказано позже), можно установить полностью автоматизированную процедуру для проверки всех аспектов работы модуля в соответствии с техническими требованиями. Иногда с помощью Sleuth CoverageAnalyst можно обнаружить неэффективные или ненужные участки кода, как в следующем примере.
Line Hits Source
71 - procedure Example(i : Integer);
72 1001 begin
73 1001 i := abs(i) + 2;
74 1001 i := i * i;
75 1001 if IsPrime(i) then
76 0 DoSomething(i)
77 - else
78 1001 DoSomethingElse(i);
79 1001 end;
Пример несколько искусственный, но в некоторых случаях может быть неочевидно, что функция типа IsPrime никогда не возвращает значение true. Другой вариант использования Sleuth CoverageAnalyst — выявление ситуаций, когда некоторые куски кода оказываются незадействованными.
Опция Trace весьма удобна для выявления «тупиков» и такого местоположения кода, которое приводит к зависанию (так как показывается количество раз выполнения операторов в колонке Hits).
Наконец, хотя Sleuth CoverageAnalyst и не является профилировщиком, таким как утилиты Sleuth StopWatch и Sleuth Line Profiler (последний будет рассмотрен позже), он может привлечь ваше внимание к строкам кода, которые выполняются либо слишком большое, либо слишком малое количество раз.
Line Hits Source
4722 - procedure TraverseClients(Container: TWinControl);
4723 - var
4724 - I: Integer;
4725 - Control: TControl;
4726 9172 begin
4727 9172 if Container.Showing then
4728 9172 for I := 0 to Container.ControlCount - 1 do
4729 - begin
4730 45860 Control := Container.Controls[I];
4731 45860 if (csActionClient in Control.ControlStyle) and
Control.Visible then
4732 0 Control.InitiateAction;
4733 45860 if Control is TWinControl then
4734 4586 TraverseClients(TWinControl(Control));
4735 45860 end;
4736 9172 end;
Из примера видно, что условие, проверяющее наличие флага csActionClient, никогда не будет выполнено, а следовательно, не будет выполнена и процедура InitiateAction, в результате чего может произойти «зацикливание» при рекурсивном вызове процедуры TraverseClients.
Кроме того, Sleuth CoverageAnalyst, как и Sleuth StopWatch, поддерживает дизассемблирование, а также просмотр исходных кодов.
Sleuth LineProfiler (профилировщик строк кода)
Sleuth LineProfiler — дополнительная утилита к Sleuth StopWatch, позволяющая после определения наиболее робастного модуля, процедуры или функции детализировать команды, на которые тратится большая часть времени.
Если вызвать утилиту для конкретного проекта при помощи опции меню tools/Sleuth LineProfiler, на экране появится главная форма (рис. 6).
Определив (например, двойным щелчком мыши) процедуры, подлежащие анализу, можно после выполнения приложения не только получить оценку количества вызовов данной процедуры, но и просмотреть исходные строки кода программы со статистикой вызовов по каждой строке. Так, в примере, приведенном на рис. 7, больше всего времени занимают вызовы процедуры VisualSwap — визуализации результатов.
Как и в других утилитах TurboPower, в этой утилите возможен просмотр не только исходного, но и дизассемблированного кода (рис. 8).
Sleuth ActionRecorder (менеджер системных событий)
Утилита Sleuth ActionRecorder позволяет создавать и воспроизводить последовательности входных событий типа действий с клавиатурой или мышью. При помощи этого продукта можно создавать испытательные сценарии, осуществляющие проверку правильности работы логики всего приложения или его части. Сценарии могут быть сохранены для последующего воспроизведения. Предусмотрена возможность запуска сценария из автономно работающей утилиты Sleuth ActionRecorder при работающем тестируемом приложении для проверки выполнения запланированных действий. Кроме того, Sleuth ActionRecorder позволяет манипулировать сценариями, составляя из простых сценариев последовательности более сложных, что упрощает их обслуживание.
Инструментальная панель Sleuth ActionRecorder содержит две опции: Project и Macro. При выборе опции Project рабочий стол содержит список сценариев, прикрепленных к данному проекту, которые двойным щелчком левой клавиши мыши или набором клавиш Ctrl+E могут быть включены в обработку или отключены от нее. Рабочий стол для опции Macro содержит список событий клавиатуры или мыши (например, wm_mousemove(548, 408)), которые требуется включить в текущий сценарий.
В случае Sleuth ActionRecorde утилита и исследуемое приложение запускаются отдельно. Если вызвать утилиту при помощи опции меню tools/ ActionRecorde, на экране появится главная форма (рис. 9).
Запись сценария инициируется командой record new macro. Завершение записи сценария инициируется набором клавиш Ctrl-break. Результат записи можно просмотреть, включив опцию Macro (рис. 10).
Отметим, что выведенный список может быть отредактирован — можно, например, удалить лишнее сообщение.
Заключение
Все утилиты Memory Sleuth 1.5 и SleuthQA2 способны экспортировать данные из текстовых, ХML-, HTML-файлов и электронных таблиц Microsoft Excel; включают поддержку 32-разрядных версий Borland Delphi, Borland C++Builder и других средств разработки; поддерживают СОМ, автоматизацию, так что разработчик может отлаживать и оптимизировать свои программы без изменения их интерфейса.
Таким образом, Memory Sleuth 1.5 и SleuthQA2 являются ценным дополнением к средствам отладки, имеющимся в современных средствах разработки. Утилиты фирмы TurboPower, служащие для профилирования и оптимизации приложений, трудно переоценить.
КомпьютерПресс 7'2001