Глава 3. Стратегии профилирования

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

Если Вы поначалу не уверены в своих предположениях о том, какие из участков Вашей программы являются ее «узкими местами», то, при помощи системы Turbo Profiler, получите ее профиль с теми значениями параметров профилирования, которые установлены по умолчанию. После этого, посмотрев на результаты профилирования, появившиеся в окне Execution Profile (Профиль выполнения), Вы получите представление о том, какие из подпрограмм Вашей программы потребляют большую часть времени ее выполнения. Сопоставив временные и количественные данные, Вы поймете какие участки Вашей программы наиболее дорогостоящи в смысле времени, затрачиваемого на одно выполнение. Вооруженные этими знаниями, Вы можете смело начинать атаку неэффективных участков Вашей программы.

Система Turbo Profiler имеет несколько различных окон отчета, предназначенных для изображения и анализа полученных статистических данных. Также Вы можете распечатать содержимое такого окна на бумаге, либо записать его на диск для учета этапов повышения быстродействия Вашей программы. В окнах отчета Вы можете увидеть количественную и временную информацию о процессе выполнения Вашей программы, данные о ее работе с файлами, информацию об использовании прерываний DOS, работе механизма оверлеев, а также о вызовах подпрограмм.

Как же Вам распорядиться всей этой мощностью и гибкостью? Как использовать систему Turbo Profiler наиболее оптимальным образом и получать при этом максимальную отдачу? В чем заключаются хитрости профилирования? Очевидно, что в этой главе мы просто не сможем исчерпывающе ответить на все поставленные вопросы. Но, тем не менее, мы опишем некоторые основные принципы, приемы и стратегии для того, чтобы придать Вам начальное ускорение.

Примечание: Вы можете обратиться к большому количеству книг и статей, содержащих общие сведения о профилировании.

При получении первого профиля Вашей программы система Turbo Profiler производит следующие действия:

* автоматически просматривает текст Вашего EXE-файла в поисках головного модуля Вашей программы;

* устанавливает маркеры «областей» для Вашей программы;

* определяет какой из из модулей исходного текста Вашей программы содержит в себе ее головную часть;

* загружает этот головной модуль в окно Module (Модуль);

* устанавливает курсор на начальную точку головного модуля.

Модуль исходного текста Вашей программы является головным в том случае, если он содержит в себе строку, выполняющуюся самой первой после запуска программы. Маркеры «областей» отмечают участки Вашей программы, для которых Вы хотите собрать статистические данные. Число установленных маркеров зависит от количества символических имен, найденных в отладочной информации Вашей программы.

И всякий раз, когда Вы выходите из системы Turbo Profiler происходит автоматическое сохранение информации о «областях», помеченных в Вашей программе, в файле с именем TFA, где совпадает с именем Вашей программы. Каждый раз при загрузке Вашей программы в систему Turbo Profiler происходит поиск соответствующего файла с расширением. TFA, и, в случае наличия такого файла, происходит автоматическое задание «областей» на основании имеющейся в данном файле информации.

Также Вы можете сохранить результаты профилирования в файле с расширением. TFS, используя для этого команду Statistics| Save (Статистика| Сохранить). По умолчанию, имя такого файла будет иметь вид: TFS. Вы можете воспользоваться именем, задаваемым по умолчанию, либо изменить его (в том случае, если Вы хотите сохранить несколько профилей одной и той же программы).

Примечание: Мы рекомендуем Вам сохранять результаты профилирования, получение которых заняло много времени, на тот случай, если у Вас вдруг возникнет желание снова взглянуть на эти данные.

Подготовка к получению профиля.

Примеры первой главы были небольшими и достаточно простыми, они были созданы для того, чтобы в общих чертах показать процесс профилирования. Основной задачей, поставленной в первой главе было скорее совершенствование программы prime, чем поиск «узких мест» данной программы.

На самом же деле необходимость использования профилировщика возникает в гораздо большей степени при написании программ большого размера, чем в случае, когда программы малы, так как сначала необходимо выявить «узкие места» программы, а уже потом пытаться понять то, каким образом можно усовершенствовать каждое из них. Вследствие ряда причин найти «узкие места» легче, чем придумать как с ними лучше поступить.

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

Преобразование текста Вашей программы.

Первое, что вам необходимо сделать — это привести вашу программу к такому виду, который позволит вам понять, какие именно данные вам необходимо получить в результате профилирования. Например, если вы разрабатываете интерактивную программу, в которой часто происходит выполнение операторов ввода с клавиатуры, то вам совсем неинтересно будет узнать о том, что большая часть времени выполнения вашей программы тратиться на ожидание того момента, когда пользователь нажмет на какую-либо клавишу.

Вот некоторые основные технические приемы, используемые при поиске «узких мест» в больших программах:

* Задавайте вашим программам достаточно большие наборы входных данных, для получения наиболее информативных профилей.

Если вы попытаетесь профилировать программу поиска подстрок, подавая ей на вход файл, состоящий из трех строчек, то вы не сможете почерпнуть многого из полученных в результате этого данных. Точно также поиск коротких подстрок, входящих почти в каждую из строк файла (с общим числом строк равным 10000), даст профиль совершенно непохожий на тот, который получился бы в случае поиска длинной подстроки, встречающейся в данном файле один единственный раз.

Примечание: Выбор входных данных для вашей программы это очень важный момент на который следует обратить особое внимание.

* Если ваша программа работает достаточно быстро, то вы можете собрать данные о нескольких ее выполнениях. (Для этого необходимо изменить соответствующим образом значение параметра Run Count (Число выполнений) в блоке диалога Profiling Options (Параметры профилирования.))

* Модифицируйте вашу программу таким образом, чтобы она работала независимо от ввода с клавиатуры, или просто уберите маркеры с тех «областей», внутри которых такой ввод используется.

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

* Изолируйте модули программы, про которые заведомо известно, что они нуждаются в улучшении.

Компиляция вашей программы.

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

Turbo Profiler можно использовать со следующими версиями программных продуктов фирмы Borland: если Вы работаете в системе Turbo Pascal, то она должна быть версии 5.0 или более высокой, системы Turbo C++ и Turbo Assembler должны иметь версию 1.0 или более позднюю. Вы должны задать такие значения параметров компиляции Ваших программ, которые обеспечивают наличие полной отладочной информации о символических именах.

Примечание: Файлы, скомпилированные Вами для того, чтобы отлаживать их в системе Turbo Debugger, могут, без какой-либо дополнительной обработки, использоваться в системе Turbo Profiler.

* Turbo Pascal: параметры Standalone Debugging (Самостоятельная отладка) и Debug Information (Отладочная информация) должны быть установлены в состояние On (Включен).

* Turbo C++: Должна быть активирована селективная кнопка Standalone (Самостоятельная).

* Turbo C: Должно быть указано значение Standalone (Самостоятельная) параметра Debug| Source Debugging (Отладчик| Отладка исходного текста).

* Turbo Assembler: Исходный текст должен ассемблироваться с заданием параметра /zl командной строки и, затем, при помощи программы TLINK, запускаемой с указанием параметра /v должен быть построен загрузочный модуль.

Также, при использовании системы Turbo Profiler, Вы можете обрабатывать файлы, полученные на выходе компилятора Microsoft C или ассемблера MASM, если Вы их предварительно преобразуете при помощи программы TDCONVRT или TDMAP. (Посмотрите документацию по утилитам системы Turbo Debugger, включенную в файл MANUAL.DOC.)

При работе в системе Turbo Profiler необходимо иметь как. EXE-файл, так и файлы с исходным текстом Вашей программы. Turbo Profiler ищет файлы с исходными текстами в следующих директориях (обращение к директориям происходит в том порядке, в котором они перечислены):

1. в директории, в которой они находились во время компиляции (эта информация имеется в выполнимом файле);

2. в директории, задаваемой командой Options| Path for Source (Параметры| Путь для поиска исходных текстов);

3. в текущей директории;

4. в директории, содержащей EXE-файл профилируемой в данный момент программы.

Задание «областей» профилирования.

Как только Вы привели текст программы к виду, позволяющему сконцентрировать внимание на ее «узких местах» и скомпилировали Вашу программу в режиме с созданием отладочной информации, Вы готовы к тому, чтобы выполнять ее в среде профилировщика и собирать статистические данные для отдельных «областей». Вы можете начать с получения профиля всей программы целиком, и затем постепенно фокусировать свое внимание на все более мелких деталях по мере того, как будут выявляться подозрительные участки программы. Начните с задания «областей», установленного по умолчанию. Система Turbo Profiler самостоятельно пометит «области», основываясь при этом на информации о символических именах, присоединенной к выполнимому файлу.

Напомним, что «областью» называется участок Вашей программы о котором Вы желаете получить статистические данные. «Областью» может быть одна строка, оператор, например, такой как оператор цикла, или целая подпрограмма. Маркер «области» устанавливает, в месте своего расположения, контрольную точку прерывания выполнения программы. Как только профилировщик встречает такую точку, он выполняет некоторое определенное множество команд, зависящих от того, каким образом были заданы значения параметров для данной «области». Это множество команд может быть как подпрограммой для ведения учета статистических данных, так и единственной командой остановки выполнения программы.

Вот те действия, которые может производить профилировщик при пересечении границы «области»:

Режим работы — Что происходит в данном режиме

Normal (Нормальный) — Начинается сбор статистических данных (для каждой помеченной области собирается количественная и временная статистика).

Enable (Включить) — Включается процесс сбора статистики (в том случае, если перед этим он был выключен).

Disable (Выключить) — Отключается только процесс сбора статистических данных, выполнение программы продолжается. Если начинает выполняться «область» программы, для которой задан режим Enable (Включить), то профилировщик возобновляет сбор статистических данных.

Stop (Останов) — Выполнение программы прекращается и управление передается в среду системы Turbo Profiler. В этот момент Вы можете посмотреть собранные статистические данные, а затем опять возобновить выполнение программы.

По умолчанию, система Turbo Profiler подсчитывает сколько раз, за время выполнения программы, управление попадает на входную точку каждой «области» и сколько времени отнимает выполнение каждой «области». Вы можете изменить действия профилировщика, которые он производит при входе в «область», установив соответствующим образом параметр Operation (Режим работы) в блоке диалога Areas Options (Параметры «области»), который можно вызвать из локальных меню окна Module (Модуль) и Areas («Области»).

Когда Вы помечаете «области» в своей программе перед тем, как начать получение ее профиля, Вам необходимо рассмотреть следующие вопросы:

* Для какого количества «областей» должна собираться статистика?

* Профиль каких участков программы должен быть получен?

* Какие действия должны выполняться в каждой из помеченных «областей»?

Какой уровень детализации Вам следует выбрать?

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

* Для небольшой программы у Вас возможно возникнет желание получить статистическую информацию для каждой выполняемой строки, что является максимально возможным уровнем детализации.

* Для большой программы необходима меньшая степень подробности, скорее всего достаточно подсчитать лишь количество времени, затрачиваемого на выполнение каждой из процедур.

Понятие «большая» является довольно расплывчатым, но очевидно, что нужно принимать во внимание такие характеристики программы, как количество модулей в исходном тексте, количество подпрограмм и количество строк.

Если Ваш исходный текст состоит из 10 000 строк, содержащихся в 10 модулях, то было бы вполне разумно профилировать их по одиночке и в режиме активного анализа. (Ведь Ваша программа разбита на отдельные функциональные модули, не так ли?)

С другой стороны, если размер Вашей программы составляет менее 100 строк и Вам необходим ее детальный анализ, то Вы, возможно, захотите получить статистические данные для каждой из строк.

Если время выполнения Вашей программы не превышает пяти секунд, то Вы получите более объективные результаты профилирования, если выполните эту программу несколько раз и затем усредните полученные данные (установите число выполнений Вашей программы при помощи команды Statistics| Profiling command (Статистика| Команды профилирования). Если Ваша программа, даже без учета времени, расходующегося на получение статистических данных, выполняется в течение часа, будьте осторожны при пометке «областей», если Вы пометите их слишком много, то время выполнения Вашей программы может стать неприемлемо большим.

Вы разбиваете Вашу программу на ряд «областей», выбрав для этого команду Add Areas (Добавить «области») в локальном меню окна Module (Модуль), затем выполняете Вашу программу, для того, чтобы получить статистические данные для каждой из «областей».

Если Вы не укажете системе Turbo Profiler, каким образом пометить «области» в Вашей программе, то она использует схему, задаваемую по умолчанию для того, чтобы попытаться сделать это самостоятельно каким-то разумным образом. Основываясь на таблице символических имен данной программы, система Turbo Profiler выбирает один из двух вариантов задания «областей» в Вашей программе:

* Если в таблице символических имен содержится мало элементов и программа состоит из одного модуля, система Turbo Profiler по умолчанию помечает в качестве «области» каждую строку в модуле (Every Line in Module).

* Если таблица символических имен для данной программы велика и сама программа состоит из нескольких модулей, то в качестве «областей» по умолчанию помечаются все подпрограммы (All Routines).

Рекомендация: Если Ваша программа имеет очень большой размер, то сначала, для получения общей картины, мы советуем получить ее профиль, работая в пассивном режиме, и, затем, на основании полученной информации, выбрать некоторые «области» для более детального изучения.

Какие данные Вам необходимо получить в процессе профилирования?

По умолчанию, система Turbo Profiler собирает следующую информацию о помеченных Вами «областях»:

* число обращений к данной «области»;

* общее количество времени, затраченное на выполнение данной «области» (это относится только к активному режиму профилирования);

* число импульсов таймера сгенерированных во время выполнения данной «области».

Но Вы можете собрать во время профилирования и более обширную информацию:

* Активировав параметр Statistics| Callers (Статистика| Вызывающие подпрограммы) и установив соответствующим образом параметры Call Stack (Стек вызовов) в блоке диалога Area Options (Параметры «области») Вы можете проследить, какими подпрограммами вызывается помеченная подпрограмма, как часто это происходит, а также каковы пути этих вызовов.

* Если активирован параметр Statistics| Files (Статистика| Файлы), то Вам становится доступной информация о работе Вашей программы с файлами.

* Вы можете проследить за использованием Вашей программой оверлейных файлов, активировав для этого параметр Statistics| Overlays (Статистика| Оверлеи).

Как только Вы активировали соответствующие параметры меню Statistics (Статистика), Вы можете открыть соответствующие окна отчета о профилировании (использовав для этого меню View (Просмотр), затем вызвать локальные меню для каждого из окон, для того, чтобы указать детали, относящиеся к данным, которые Вы хотите получить.

Помните о том, что для получения отчета о профилировании в желаемом виде, необходимо установить соответствующие параметры до того, как Вы начнете выполнять Вашу программу.

В какой момент следует начать сбор данных?

Часто Вам необходимо собрать временные данные только о выполнении какого-то конкретного участка Вашей программы. Для того, чтобы это сделать, начните выполнение Вашей программы, вообще не собирая никакой статистической информации, установите для этого параметр Statistics| Accumulation (Статистика| Накопление) в состояние Disabled (Отключен). Вы можете в любое время посмотреть какое значение имеет параметр Accumulation (Накопление), вызвав для этого на экран блок File| Get Info (Файл| Получить информацию) и посмотрев состояние параметра Collection (Сбор).

В том случае, если параметр Accumulation (Накопление) отключен, Вы должны включить этот параметр для маркера «области», информацию о которой Вы хотите получить, и затем отключить этот параметр для маркера «области» в которой Вы хотите запретить сбор статистических данных. Число таких точек, в которых включается и выключается сбор статистических данных ограничено лишь количеством доступной оперативной памяти, как правило Вы можете задать столько таких точек, сколько Вам требуется.

Каким образом сгруппировать временные данные?

Профилировщик может изобразить временные данные для каждой из подпрограмм отдельно от других, а может объединить их с данными, соответствующими тем подпрограммам, которыми были вызваны вышеупомянутые подпрограммы.

По умолчанию предполагается, что как только активная в данный момент времени подпрограмма вызывает какую-либо другую подпрограмму, помеченную маркером «области», профилировщик помещает первую из этих подпрограмм в стек вызовов и считает, что с этого момента она находится в пассивном состоянии. И до тех пор пока управление программы находится в вызванной подпрограмме, профилировщик относит каждый импульс таймера исключительно к данной подпрограмме, забывая на это время о том, откуда она была вызвана.

Тем не менее, если Вы укажете, что вызывающая подпрограмма должна использовать объединенные часы (а не отдельные часы), то профилировщик будет относить импульсы таймера, происходящие во время выполнения вызванной подпрограммы, к обеим подпрограммам сразу.

* Если подпрограмма А не вызывает никакие другие подпрограммы, то она не появится в качестве «области» в окне Execution Profile (Профиль выполнения). Вместо этого в данном окне фигурирует подпрограмма, вызвавшая подпрограмму А, причем в качестве времени ее выполнения показывается сумма времен выполнения каждой из этих подпрограмм.

* Если подпрограмма А вызывает какие-либо другие подпрограммы, то данная подпрограмма появляется в окне Execution Profile (Профиль выполнения). И время ее выполнения включает в себя сумму времени выполнения всех подпрограмм, вызываемых данной.

Режим работы системы Turbo Profiler, задаваемый по умолчанию, использует отдельный таймер для каждой помеченной подпрограммы. Поэтому обычно время выполнения подпрограммы измеряется не учитывая времени выполнения вызываемых ею подпрограмм. Если Вы хотите, чтобы это время включалось во время выполнения рассматриваемой подпрограммы, то для этого необходимо выбрать в блоке диалога Options (Параметры) окна Areas («Области») значение параметра Timing (Подсчет времени), равное Combined (Объединенный).

Какие данные Вам необходимо просматривать?

Очень важно знать, каким образом можно контролировать количество информации, сначала собираемой, а затем отображаемой на экране профилировщиком, особенно в том случае, если Вы желаете получить подробную информацию всего лишь о некоторой части какой-то большой программы.

Система Turbo Profiler предлагает два способа для управления количеством информации о Вашей программе, выдаваемой на экран:

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

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

В окнах Module (Модуль), Areas («Области») и Interrupt (Прерывания) Вы можете указывать системе Turbo Profiler для каких участков Вашей программы необходимо собирать статистические данные, и насколько эти данные должны быть подробны. Выбор степени детальности рассмотрения Вашей программы может варьироваться, начиная с рассмотрения всех подпрограмм в данном модуле и заканчивая одним единственным оператором. Вы можете собирать только временную статистику (установив режим анализа в состояние Passive (Пассивный), или же собирать полную гамму данных (все доступные данные), включающие в себя полный перечень стеков вызовов, обращений к файлам и оверлеям, а также все вызовы прерываний DOS. Вы можете увеличивать или уменьшать интервалы времени, отсчитываемые таймером, тем самым меняя степень разрешения полученного профиля программы (данная возможность имеется только в пассивном режиме работы).

Важное замечание: При выборе количества собираемых данных Вы вынуждены принимать какие-то компромиссные решения. Так как, чем более обширную и подробную информацию собирает система Turbo Profiler, тем медленнее происходит процесс получения профиля, и тем большее количество оперативной памяти требуется для собранной статистики.

Если же Вы уже получили какие-то статистические данные, то при помощи ряда команд, задаваемых в окнах, в которых находится отчет о профилировании, Вы можете временно исключить из рассмотрения некоторые из них. (смотрите соответствующий раздел данного руководства где изложена более подробная информация о фильтрации изображаемой статистики).

Получение профиля Вашей программы.

Как только Вы пометили «области», приступайте к получению профиля Вашей программы. Вы можете сохранить результаты профилирования с помощью команды Statistics| Save (Статистика| Сохранить). В результате выполнения этой команды статистика сохраняется в файле с расширением TFS (Turbo Profiler Statistics (Статистика системы Turbo Profiler). Если Вы хотите сохранить результаты нескольких сеансов профилирования, лучше всего было бы назвать файлы, в которых будут храниться эти результаты, используя некоторые соглашения, позволяющие однозначно определять в каком из файлов находятся данные каждого из сеансов (например, RUN.TFS, RUN2.TFS и т. д.). Подобные названия файлов делают более простым последующее сравнение этих данных.

Примечание: Заключение о том, что какой-либо профиль заслуживает сохранения, можно сделать лишь ознакомившись с содержанием нескольких окон Execution Profile (Профиль выполнения).

После того как Вы сохраните статистические данные в файле с рассширением. TFS, Вы можете приступить к их изучению путем просмотра информации, находящейся в различных окнах отчета о профилировании (profile report windows), причем для наилучшего понимания значения этих данных Вы имеете возможность выводить их на экран в отфильтрованном и отсортированном различными способами виде. При этом Вы не утратите каких-либо маркеров или статистических данных, так как в любое время Вы можете воспроизвести их первоначальный вид (просто загрузив информацию в профилировщик из соответствующего файла с расширением. TFS). Общее правило таково: если на получение профиля программы было затрачено большое количество времени, то следует сохранить этот профиль, за исключением, конечно, того случая, когда Вы абсолютно уверены в том, что впоследствии он Вам не понадобится.

Что Вы пытаетесь понять в ходе процесса профилирования?

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

* Насколько эффективен данный алгоритм? (Тестирование алгоритма).

* Делает ли данная программа то, что по моему мнению она должна делать? Все ли части данной программы работоспособны?

(Верификация и тестирование)

* Сколько времени затрачивается на выполнение каждой из подпрограмм? В течение какого промежутка времени Ваша программа использует те или иные ресурсы? (Подсчет времен выполнения и контроль за использованием ресурсов (resource monitoring)

* Какова структура данной программы? (Анализ структуры программы).

Следующая таблица связывает между собой цель профилирования и тип собираемой Вами информации, необходимой для достижения данной цели.


Таблица 3.1 Способы применения профилировщика

Цель профилирования — Тип собираемой информации

Тестирование алгоритма — Информация о количестве выполнений строк; Отчет о динамике вызовов подпрограмм.

Верификация и тестирование — Информация о количестве выполнений подпрограмм, (возможно, и строк тоже); Отчет о динамике вызовов подпрограмм.

Подсчет времен выполнения и контроль за использованием ресурсов — Временная статистика; количественная статистика; данные об использовании прерываний; данные об обращениях к файлам; информация об использовании оверлеев.

Анализ структуры программы — Отчет о динамике вызовов подпрограмм; данные об обращениях к файлам; профиль выполнения (включающий временную и количественную статистику); данные об использовании прерываний; информация об использовании оверлеев.


Тестирование алгоритма.

В случае анализа алгоритма Ваше внимание сосредотачивается на небольшом количестве подпрограмм, поэтому информация о количестве выполнений строк программы имеет большее значение, чем временные данные. Вам необходимо произвести следующие действия:

1. Выделить алгоритм и все поддерживающие подпрограммы, пометив их как «области».

2. Убедиться в том, что Вы установили маркеры «области» на каждой строке всех подпрограмм, реализующих рассматриваемый алгоритм.

Примеры Главы 1 демонстрируют анализ алгоритма, причем этот анализ проводится в основном с точки зрения времени выполнения.

Верификация и тестирование программ.

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

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

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

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

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

1. сколько времени тратится на выполнение каждой подпрограммы;

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

Перед тем как начать подсчет временных соотношений процесса выполнения, Вам необходимо установить маркеры «областей» для всех подпрограмм, фигурирующих в исходном тексте. В случае очень больших программ приходится ограничиваться только лишь одним модулем.

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

* Используйте фильтры для того, чтобы сделать невидимой информацию, которая Вас в данный момент не интересует (это можно сделать при помощи команды Filter (Фильтр) локального меню окна Execution Profile (Профиль выполнения);

* Убирайте маркеры «области», помечающие подпрограммы, которые Вас в данный момент не интересуют (это можно сделать при помощи команды Remove (Убрать) локальных меню окон Modulе (Модуль), Execution Profile (Профиль выполнения) и Areas («Области»));

* Объединяйте времена выполнения для рассматриваемых подпрограмм (это можно сделать, установив соответствующим образом параметр Timer (Таймер), при помощи команды Statistics|Profiling Options (Статистика|Параметры профилирования) либо команды Options (Параметры) локального меню окна Areas (Области).

Если Вы получаете профиль программы, внутренняя структура которой вам неизвестна, то Вы можете параллельно подсчитывать временные соотношения и изучать структуру программы.

Изучение структуры незнакомой программы.

Одним из наилучших путей изучения структуры незнакомой программы является анализ истории вызовов подпрограмм, которая отображается системой Turbo Profiler в окне Callers (Вызывающие подпрограммы). Эта история вызовов демонстрирует иерархическую структуру программы, для которой был получен профиль. Хотя в каждый из моментов времени в окне Callers (Вызывающие подпрограммы) могут находиться пути вызова только какой-то одной подпрограммы, Вы, тем не менее, имеете возможность распечатать все истории путей вызовов, полученные в данном сеансе профилирования. Для этого необходимо, открыв окно Callers (Вызывающие подпрограммы), воспользоваться командой Print| Statistics (Печать|Статистика).

Рис. 3.1 Окно Callers (Вызывающие подпрограммы).

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

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

Окна профилировщика Execution Profile (Профиль выполнения), Module (Модуль) и Areas («Области») связаны между собой, что позволяет быстро перемещаться по содержимому этих окон, устанавливая курсор на заданные, функционально зависимые, но физически удаленные друг от друга участки исходного текста Вашей программы.

Какой режим профилирования Вы используете?

В процессе получения профиля программы очень важное значение имеет выбор режима работы, который может быть активным или пассивным. Режим устанавливается при помощи кнопки Profile Options (Параметры профилирования). По умолчанию Turbo Profiler работает в режиме активного анализа, в котором автоматически собирается как количественная, так и временная статистика, а так же другие данные (такие, например, как история вызовов подпрограмм или информация о использовании прерываний), учет которых задан текущей конфигурацией параметров меню Statistics (Статистика). Если же Ваша программа работает очень медленно и Вы можете обойтись без количественной статистики и истории вызовов подпрограмм, то Вам необходимо использовать режим пассивного анализа, в котором профилировщик собирает только временные данные о помеченных «областях» (такие как время выполнения; время, затраченное на вызовы прерываний и обращения к файлам) и поэтому процесс получения профиля происходит гораздо быстрее.

Активный анализ.

При работе в активном режиме большую роль играет то, насколько часто в процессе выполнения управление попадает на маркеры «областей». Например Вы можете пометить каждую строчку Вашей программы за исключением одного оператора цикла, но, если на работу данного оператора тратится 95 % времени выполнения всей программы, то количество помеченных «областей» не сможет оказать значительного влияния на время работы программы.

Примечание: С другими способами, позволяющими ускорить процесс получения профиля Вы можете познакомиться в разделе «Как ускорить профилирование», расположенном ниже.

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

Пассивный анализ.

В режиме пассивного анализа Turbo Profile регулярно прерывает процесс выполнения программы для того, чтобы проверить значение счетчика команд, CS: IP. Если значение данного счетчика указывает на адрес, находящийся внутри помеченной «области», то профилировщик увеличивает значение переменной в которой накапливаются временные данные для данной «области». Если значение счетчика CS: IP не указывает на внутренность какой либо помеченной области (к примеру это значение может указывать на адрес прерывания DOS или вызова BIOS), то профилировщик никак не учитывает импульс таймера, вызвавший данное прерывание работы программы.

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

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

При профилировании в пассивном режиме Вы получаете более адекватные статистические данные несколько раз (для этого необходимо присвоить параметру Run Count (Счетчик числа выполнений), находящемуся в блоке диалога Profiling Options (Параметры профилирования), значение, превышающее 1).

Примечание: За то, что пассивный анализ не сильно увеличивает время работы программы, Вам приходиться платить некоторой неполнотой полученного профиля.

Некоторые вещи, на которые стоит обратить внимание.

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

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

* Когда Ваша программа обращается к какому-либо прерыванию, не помеченному как «область», то профилировщик прибавляет время, затрачиваемое на обработку прерывания ко времени выполнения подпрограммы, из тела которой произошло обращение к данному прерыванию, если анализ происходит в активном режиме, если же задан пассивный режим работы, то это время просто игнорируется.

Профилирование объектно-ориентированных программ.

В общем случае, профилирование объектно-ориентированных программ не очень сильно отличается от профилирования обыкновенных программ. Вы можете обращаться с этими программами точно так же, как со всеми остальными, рассматривая при этом методы в качестве вызовов подпрограмм.

Как ускорить процесс получения профиля.

Каждый раз, когда управление Вашей программы передается какой-либо подпрограмме, помеченной в качестве «области», Turbo Profiler выполняет ряд определенных действий для учета статистической информации. Скорость выполнения программы в процессе получения ее профиля зависит от того, как часто управление попадает на маркеры «областей», а так же от типа данных, собираемых профилировщиком для тех «областей», который выполняются наиболее часто. Чем более подробная информация собирается о какой либо «области», тем больше времени требуется профилировщику для ее учета.

В некоторых случаях Turbo Profiler может замедлить работу Вашей программы до неприемлемого уровня. Такая ситуация возможна в случае частых обращений к какой-либо подпрограмме если пути ее вызова имеют большую длину и параметры, регулирующие сбор информации о стеках вызовов имеют значения, задающие режим в котором происходит запоминание всех стеков вызовов во всех «областях». Если Вы пометите такую глубоко вложенную подпрограмму в качестве «области», то системе Turbo Profiler придется затрачивать большое количество времени на отслеживание путей вызова этой подпрограммы.

Примечание: Даже в случае когда при профилировании ваша программа работает медленнее чем на самом деле все временные данные, получаемые системой Turbo Profiler соответствуют действительности.

Для обнаружения того, что Ваша программа часто вызывает некоторую подпрограмму, находящуюся на низком уровне иерархии, необходимо переключиться на работу в окне Execution Profile (Профиль выполнения) и отобразить на экране количественную статистику. Для этого необходимо вызвать локальное меню и задать значение Counts (Подсчет) для параметра Display (Изображение). В результате на экране должна появиться гистограмма, отражающая сколько раз была выполнена каждая «область» и упорядоченная по числу выполнений.

Если одна или несколько подпрограмм вызываются Вашей программой гораздо чаще чем остальные, то Вы можете заблокировать выдачу на экран статистической информации о этих подпрограммах при помощи команды Filter| Current (Отфильтровать| Текущую) локального меню окна Execution Profile (Профиль выполнения). Также Вы можете снять пометку с «областей», соответствующих данным подпрограммам при помощи команды Remove (Убрать), имеющейся в локальных меню окон Module (Модуль), Areas (Области) и Execution Profile (Профиль выполнения).

Как повысить точность статистических данных.

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

Недостаточное количество данных.

Для повышения точности временных статистических данных, а так же для получения статистически значимой выборки этих данных, необходимо произвести несколько запусков Вашей программы, используя для задания их числа параметр Run Count (Счетчик запусков), находящийся в блоке диалога Profiling Options (Параметры профилирования). При каждом запуске Вашей программы профилировщик добавляет полученные временные данные к соответствующим данным, собранным во время предыдущих запусков. Это продолжается до тех пор пока число произведенных запусков не станет равно значению параметра Run Count (Счетчик запусков).

Резонанс.

Если причиной неточности статистических данных является резонанс, то в этом случае следует воспользоваться параметром Clock Speed (Скорость часов), находящемся в блоке диалога Profiling Options (Параметры профилирования), и позволяющим устанавливать частоту работы таймера профилировщика в диапазоне от 18 до 1000 импульсов в секунду. Необходимо выбрать такую частоту, которая не является делителем резонансной частоты и не может быть получена из нее при помощи умножения на целое число. Например если при работе таймера с частотой 100 импульсов в секунду Вы наблюдаете явление резонанса, то можно попробовать изменить частоту его работы на 70 или 130 импульсов в секунду. (В том случае, когда у Вас возникает подозрение о наличии явления резонанса, попробуйте задать различные частоты работы таймера, не являющиеся целочисленными произведениями друг друга, и сравнить получающуюся при этом статистику. Если Ваши подозрения справедливы, то наборы данных для различных частот должны значительно отличаться друг от друга).

Чем выше частота работы таймера, тем точнее временные данные, получаемые системой Turbo Profiler.

Получите ли Вы очень точные временные данные если зададите частоту работы таймера равной 1000 импульсов в секунду? Совсем необязательно. Но чем выше частота с которой таймер профилировщика генерирует импульсы, тем медленнее работает Ваша программа (так как системе Turbo Profiler приходится выполнять соответствующие действия по учету данных для каждого импульса таймера).

Поэтому в случае, когда Вы хотите получить временные данные с точностью, большей чем та, которая соответствует частоте работы таймера задаваемой по умолчанию (она равна 100 импульсам в секунду), необходимо увеличивать эту частоту до тех пор пока не будет достигнуто неприемлемое замедление работы программы.

Примечание: Изменение скорости работы часов возможно в режиме пассивного профилирования, в активном же режиме этого сделать нельзя.

Некоторые замечания о получении профилей программ, использующих оверлеи.

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

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

Для того, чтобы оптимизировать работу с оверлеями, необходимо, во-первых, правильно выбрать размер оверлейного буфера, во — вторых, выбрать алгоритмы работы с оверлеями, находящимися в этом буфере и, в-третьих установить соответствующие параметры таким образом, чтобы наиболее часто используемые оверлейные модули находились в оперативной памяти как можно дольше. Вы можете избежать снижения эффективности работы с оверлеями, возникающего вследствие чрезмерного количества запросов на их подкачку, посредством более длительного хранения в оперативной памяти наиболее часто используемых оверлеев.

В окне профилировщика Overlay (Оверлей) отображаются следующие статистические данные:

* количество загрузок с диска каждого из оверлеев;

* упорядоченная по времени последовательность в которой Ваша программа загружала оверлей.

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

Имея историю загрузки оверлеев Вы можете выбрать оптимальные алгоритмы для управления буфером оверлеев. Изучив список оверлеев и посмотрев в какие моменты выполнения программы и как часто загружался каждый из них, Вы можете сделать заключение о том, каким из модулей Вашей программы лучше работать в качестве оверлеев, а каким наоборот необходимо стать частью основной программы.

Интерпретация и использование результатов профилирования.

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

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

Как анализировать данные профилирования.

Окна системы Turbo Profiler, используемые Вами для изучения полученной статистики, делятся на два вида: окна исходного текста программы и окна отчета о профилировании.

К окнам исходного текста относятся следующие окна системы Turbo Profiler: Module (Модуль), Areas («Области»), Routines (Подпрограммы) и Disassembly (CPU) (Дисассемблер (ЦПУ)). Перед тем как начать получение профиля Вы в основном пользуетесь окнами исходного текста для того, чтобы пометить «области» и задать действия профилировщика по сбору статистических данных для каждой из этих «областей».

После того, как Вы ознакомитесь со статистикой, находящейся в одном или нескольких окнах отчета, Вы опять возвращаетесь к окнам исходного текста для того, чтобы проанализировать текст Вашей программы.

Окна отчета системы Turbo Profiler это следующие окна: Execution Profile (Профиль выполнения), Callers (Вызывающие подпрограммы), Overlays (Оверлеи), Interrupts (Прерывания) и Files (Файлы). Окна отчета служат для отображения статистических данных, полученных в ходе сеанса профилирования, а также позволяют проанализировать полученные данные и решить какие участки программы необходимо изменить для того, чтобы повысить скорость ее работы.

Окно Execution Profile (Профиль выполнения).

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

Окно Callers (Вызывающие подпрограммы).

Если Вы решили оптимизировать работу какой-либо подпрограммы, то Вы можете с помощью информации, находящейся в окне Callers (Вызывающие подпрограммы), обнаружить все участки Вашей программы из которых производится вызов рассматриваемой подпрограммы. В окне Callers (Вызывающие подпрограммы) отображаются данные о том, сколько раз и из каких именно участков программы вызывалась рассматриваемая подпрограмма.

Окно Overlays (Оверлеи).

Информация, отображаемая в окне Overlays (Оверлеи), позволяет Вам обнаружить чрезмерно частые обращения к оверлеям, для того чтобы исключить такие ситуации при помощи включения этих оверлейных модулей в текст основной программы.

Окно Interrupts (Прерывания).

В окне Interrupts (Прерывания) перечислены все случаи обращения Вашей программы к избранным Вами прерываниям. Эта информация может подсказать Вам необходимость объединения вывода на экран, производящегося в нескольких строках Вашей программы. А в случае программ, интенсивно обменивающихся данными с дисковыми файлами, Вы, на основании информации, расположенной в данном окне, можете прийти к выводу о целесообразности буферизации этого обмена.

Окно Files (Файлы).

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

Как отфильтровать полученные данные.

Команды локального меню окна отчета Execution Profile (Профиль выполнения) позволяют устанавливать временные и постоянные фильтры, регулирующие выдачу на экран статистических данных. Ниже приводится таблица, в которой содержатся команды, используемые для фильтрации статистических данных:.

Таблица 3.2 Команды локального меню для фильтрации собранных статистических данных.

Окно……………………………………….Команда локального меню…………………Действие команды.

Execution Profile(Профиль выполнения)…Filter (Фильтр)…………………………Временно удаляет с экрана статистику,

относящуюся к текущей «области», или же вызывает изображение статистики, относящейся только к текущему модулю,

или восстанавливает в окне все полученные статистические данные. (Меню, появляющееся в результате выбора команды


Filter (Фильтр), включает в себя следующие варианты: Current (Текущая), Module (Модуль) и All (Вся)).

…………………………………………….Remove (Удалить)………………….Убирает из полученного набора статистических данных, без возможности последующего восстановления, те из них, которые относятся к текущей «области». Пользоваться этой командой надо очень осторожно.


Files (Файлы)…………………………….Collection (Сбор статистики) (верхняя панель)….. В отключенном состоянии блокирует сбор статистической информации о файлах.

…………………………………………..Detail (Уровень детализации)(верхняя панель)……В отключенном состоянии приводит к учету только операций по открытию и закрытию файлов, во включенном состоянии добавляется учет операций чтения и записи.

…………………………………………..Display (Изображение)…………………………. Отображает каждое из учитывемых действий либо в качестве элемента гистограммы, либо в текстовом виде, показывающем точное время начала и продолжительность данного действия.

Interrupts (Прерывания)……………….Remove (Удалить) (верхняя панель)……………Убирает выбранное в данный момент прерывание с верхней панели.

………………………………………….Display (Изображение) (нижняя панель)……………Изображает данные об обращениях к прерываниям либо в виде гистограмм в которых суммируются обращения к прерываниям и время,

затрачиваемое на эти обращения либо в качестве подробного перечня всех обращений к прерываниям

Overlays (Оверлеи)…………………….Display (Изображение)………………………….Изображает данные, полученные для каждого из оверлеев либо в виде (1) Count (Подсчет), в котором фигурируют общее количество занимаемой памяти и количество обращений к данному оверлею, либо в виде (2) History (История) в котором перечислены все случаи загрузки оверлеев, сопровождаемые подробной информацией.


Когда Вы выбираете Remove (Удалить) в локальном меню окна Execution Profile (Профиль выполнения), для того, чтобы насовсем убрать статистические данные какой либо «области» профилировщик выполняет следующие действия:

* корректирует отчет о профилировании, убирая из рассмотрения время, затраченное в данной области;

* корректирует процентное выражение времени выполнения оставшихся «областей», путем подсчета того, сколько процентов оно составляет от скорректированного общего времени выполнения программы:


<скорректированное общее время>=<общее время>-<время выполнения удаленной области>;


* снимает пометку этой «области» в окне Module (Модуль);

* удаляет данную «область» из списка «областей», находящегося в окне Areas («Области»).

Пересмотрите Вашу программу.

Приведем общую схему поиска подпрограмм, в которых простые изменения, внесенные в управляющие конструкции, могут привести к улучшению рабочих характеристик программы:

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

2. Попытайтесь выявить операторы и подпрограммы для которых велико значение отношения общего времени их выполнения к количеству выполнений этих операторов и подпрограмм. Установите значение Both (Оба) или Рer Call (На один вызов) параметра Display (Изображение), находящегося в локальном меню окна Execution Profile (Профиль выполнения). Затем посмотрите для каких областей строка гистограммы, отражающая время работы, велика, а строка, соответствующая числу вызовов мала. Обычно такими свойствами обладают неэффективно работающие операторы и подпрограммы. Перепишите их таким образом, чтобы тот же самый результат достигался с меньшими затратами.

3. И, в качестве последнего средства, мы можем предложить Вам заняться оптимизацией циклов, находящихся на самых нижних уровнях иерархии Вашей программы. При этом можно воспользоваться следующими приемами:

* разворачивание циклов;

* помещение в сверхоперативную память временных результатов, вычисляемых на каждой итерации;

* вынос вычислений, для которых это возможно, за пределы циклов;

* кодирование циклов на языке ассемблера.

Как правило при внесении изменений в управляющие конструкции, алгоритмы и структуры данных достигается больший эффект чем при модификации внутренних циклов.

Кроме трех вышеперечисленных процедур при повышении быстродействия Ваших программ можно производить следующие действия:

* Модифицировать структуры данных и алгоритмы;

* Заранее вычислять и хранить в памяти некоторые результаты;

* Помещать в оперативную память часто используемые данные;

* Вычислять значения, только в тех случаях, когда это непосредственно необходимо;

* Оптимизировать циклы, процедуры и выражения.

Модификация структур данных.

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

Для того чтобы вычисления производились более быстро необходимо, по возможности, использовать целые числа вместо вещественных, например в случае работы с окнами и строками в подпрограммах экранного ввода/вывода и графических подпрограммах. Используйте числа типа long integer во всех случаях, не требующих точности вещественных чисел.

Вместо того, чтобы сортировать массив, состоящий из строк текста, используйте массив указателей на строки текста. Весь доступ к тексту осуществляйте при помощи этих указателей. Для того, чтобы произвести сортировку строк или вставить какую-либо строку необходимо только лишь переупорядочить указатели, не затрагивая при этом самого текста.

Используйте заранее вычисленные данные.

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

Производите буферизацию доступа к часто используемым данным.

При чтении символов из файла на низком уровне в С происходит буферизация этого процесса. Функция getc считывает с диска в буфер целый сектор, но в качестве своего значения возвращает только лишь первый символ из этого буфера. Следующий вызов функции getc возвращает следующий из символов, находящихся в буфере, и это происходит до тех пор пока буфер не будет исчерпан. Когда же это произойдет, getc считывает с диска следующий сектор. Паскалевская подпрограмма Read работает аналогичным образом.

В системе Turbo Pascal имеется также подпрограмма SetTextBuff, позволяющая сократить количество обращений к диску. С помощью этой подпрограммы Вы можете создать в памяти текстовый буфер большого размера, позволяющий сократить количество обращений к диску необходимых для подкачки текста.

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

Организуйте вычисления рациональным образом.

Упорядочивайте условные выражения и операторы выбора таким образом, чтобы первыми вычислялись те условия, которые с большей вероятностью могут дать положительный результат.

В случае справочных таблиц большого размера, вычисляйте элементы этих таблиц только в случае потребности в них, и используйте дополнительный массив для хранения уже вычисленных значений.

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

Оптимизируйте имеющийся текст программы.

Циклы, процедуры и выражения всегда являются потенциально улучшаемыми.

Циклы.

* При каждой возможности выносите вычисления за пределы циклов. Повторяющиеся вычисления одного и того же значения не являются необходимыми и, к тому же, отнимают время;

* Запоминайте результаты вычислений, требующих большого количества времени (при помощи команды Statistics|Save (Статистика|Сохранить);.

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

* Если в двух циклах выполняются одни и те же операции над одинаковыми данными, то следует объединить эти циклы в один;

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

Например можно добавить дополнительный элемент в конец массива и присвоить ему некоторое специальное значение, которое вызовет завершение цикла. (Именно таким образом в С обрабатываются текстовые строки).

* Разворачивайте циклы.

Например, выражение вида:

for (x = 0; x

< 4; x++) y += items[x];

можно заменить на следующее выражение:

y += items[0];

y += items[1];

y += items[2];

y += items[3];


Подпрограммы.

* Оформите наиболее часто вызываемые подпрограммы как подставляемые, или замените их определения подставляемыми макроопределениями.

* Используйте сопрограммы для реализации многопроходных алгоритмов обработки больших файлов. (Посмотрите на функции С setjmp и longjmp). (В Паскале ознакомтесь с процедурными типами (procedural types), которые позволяют Вам обращаться с подпрограммами и функциями как с переменными с целью выполнения сопрограмм).

* Перепишите рекурсивные подпрограммы таким образом, чтобы они пользовались стеком данных, управление которым происходит явным образом.

Выражения.

* Используйте инициализацию переменных, происходящую на этапе компиляции.

* При одном вызове функции возвращайте несколько результатов. Например, можно написать подпрограммы одновременно возвращающие синус и косинус, частное и остаток, или пару координат экрана х-у.

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

Резюме.

В данной главе мы описали большую часть из тех вещей, которые необходимо иметь в виду перед началом, во время и после завершения сеанса профилирования. Мы объяснили каким образом Вам следует подготовить вашу программу и самого себя к сеансу профилирования; мы дали Вам ряд советов и предостережений, относящихся к самому процессу профилирования; так же мы изложили некоторые соображения относительно применения результатов профилирования. В следующей главе мы опишем все меню и блоки диалога среды системы Turbo Profiler.







 


Главная | В избранное | Наш E-MAIL | Добавить материал | Нашёл ошибку | Другие сайты | Наверх