Обзор продуктов компании TurboPower Software

Часть 2. Утилиты для отладки и профилирования приложений

Юрий Зачесов

Введение

Memory Sleuth 1.59 for Borland Delphi

   Краткий обзор

   Использование Memory Sleuth

Sleuth CodeWatch (менеджер ресурсов)

   Особенности отладки приложений, использующих пакеты, динамические библиотеки времени выполнения и статически загружаемые DLL

   Режимы работы 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