Tempora mutantur, et nos mutamur in illis




НазваниеTempora mutantur, et nos mutamur in illis
страница2/9
Дата публикации09.03.2013
Размер1.08 Mb.
ТипДокументы
uchebilka.ru > Информатика > Документы
1   2   3   4   5   6   7   8   9
^

Часть 0
Профилировка программ


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

Согласно правилу "10/90", десять процентов кода съедают девяносто процентов производительности системы (равно как и десять процентов людей выпивают девяносто процентов всего пива). Если время, потраченное на выполнение каждой машинной инструкции, изобразить графически в порядке возрастания их линейных адресов, на полученной диаграмме мы обнаружим несколько высоченных пиков, горделиво возвышающихся над практически пустой равниной, усеянной множеством низеньких холмиков (см. рис. 0x001) Вот эти самые пики – "горячие" точки и есть.

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

Громоздкие и тормозные, но редко вызываемые функции оптимизировать нет какой нужды, – это практически не увеличит быстродействия приложения (ну разве что они совсем уж криво будет написаны).

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

Профилировщик (так же называемый "профайлером") – основной инструмент оптимизатора программ. Оптимизация "в слепую" редко дает хороший результат. Помните пословицу "самый медленный верблюд определяет скорость каравана"? Программный код ведет себя полностью аналогичным образом и производительность приложения определяется самым узким его участком. Бывает, что виновницей оказывается одна – единственная машинная инструкция (например, инструкция деления, многократно выполняющаяся в глубоко вложенном цикле). Программист, затратив воистину титанические усилия на улучшение остального кода, окажется премного удивлен, что производительность приложения едва ли возросла процентов на десять – пятнадцать.

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


^

Цели и задачи профилировки


Основная цель профилировки – исследовать характер поведения приложения во всех его точках. Под "точкой" в зависимости от степени детализации может подразумеваться как отдельная машинная команда, так целая конструкция языка высокого уровня (например: функция, цикл или одна-единственная строка исходного текста).

Большинство современных профилировщиков поддерживают следующий набор базовых операций:


  • определение общего времени исполнения каждой точки программы (total [spots] timing)

  • определение удельного времени исполнения каждой точки программы ([spots] timing)

  • определение причины и/или источника конфликтов и пенальти (penalty information)

  • определение количества вызовов той или иной точки программы ([spots] count)

  • определение степени покрытия программы ([spots] covering)


^

Общее время исполнения


Сведения о времени, которое приложение тратит на выполнение каждой точки программы, позволяют выявить его наиболее горячие участки. Правда, здесь необходимо сделать одно уточнение. Непосредственный замер покажет, что по крайней мере 99,99% всего времени выполнения профилируемая программа проводит внутри функции main, но ведь очевидно, что "горячей" является отнюдь не main, а вызываемые ею функции! Чтобы не вызывать у программистов недоумения, профилировщики обычно вычитают время, потраченное на выполнение дочерних функций, из общего времени выполнения каждой функции программы.

Рассмотрим, например, результат профилировки некоторого приложения профилировщиком profile.exe, входящего в комплект поставки компилятора Microsoft Visual C++.
Func Func+Child Hit

Time % Time % Count Function

---------------------------------------------------------

350,192 95,9 360,982 98,9 10000 _do_pswd (pswd_x.obj)

5,700 1,6 5,700 1,6 10000 _CalculateCRC (pswd_x.obj)

5,090 1,4 10,790 3,0 10000 _CheckCRC (pswd_x.obj)

2,841 0,8 363,824 99,6 1 _gen_pswd (pswd_x.obj)

1,226 0,3 365,148 100,0 1 _main (pswd_x.obj)

0,098 0,0 0,098 0,0 1 _print_dot (pswd_x.obj)
В средней колонке (Func + Child Time) приводится полное время исполнения каждой функции, львиная доля которого принадлежит функции main (ну этого следовало ожидать), за ней с минимальным отрывом следует gen_pswd со своими 99,5%, далее идет do_pswd – 98,9% и, сильно отставая от нее, где-то там на отшибе плетется CheckCRC, оттягивая на себя всего лишь 3,0%. А функцией Calculate CRC, робко откусывающей 1,6%, на первый взгляд можно и вовсе пренебречь! Итак, судя по всему, мы имеем три горячих точки: main, gen_pswd и do_pswd (см. рис. graph 0x002).


^ Рисунок 1 graph 0x002 Диаграмма, иллюстрирующая общее время выполнения каждой из функций. Кажется мы имеем три горячих точки, но на самом деле это не так.
Впрочем, main можно откинуть сразу. Она – понятное дело – ни в чем не "виновата". Остаются gen_pswd и do_pswd. Если бы это были абсолютно независимые функции, то горячих точек было бы и впрямь две, но в нашем случае это не так. И, если из полного времени выполнения функции gen_pswd, вычесть время выполнения ее дочерней функции do_pswd у матери останется всего лишь… 0,8%. Да! Меньше процента времени выполнения!

Обратимся к крайней левой колонке таблицы профилировщика (funct time), чтобы подтвердить наши предположения. Действительно, в программе присутствует всего лишь одна горячая точка – do_pswd, и только ее оптимизация способна существенно увеличить быстродействие приложения.


Рисунок 2 graph 0x003 Диаграмма, иллюстрирующие чистое время работы каждой из функций (т.е. с вычетом времени дочерних функций). Как видно, в программе есть одна, но чрезвычайно горячая точка.
Хорошо, будем считать, что наиболее горячая функция определена и теперь мы горим желанием ее оптимизировать. А для этого недурно бы узнать картину распределения температуры внутри самой функции. К сожалению, профилировщик profile.exe (и другие подобные ему) не сможет ничем нам помочь, поскольку его разрешающая способность ограничивается именно функциями.

Но, на наше счастье существуют и более продвинутые профилировщики, уверенно различающие отдельные строки и даже машинные команды! К таким профилировщикам в частности относится VTune от Intel. Давайте запустим его и заглянем внутрь функции do_pswd (подробнее о технике работы с VTune см. "Практический сеанс профилировки с VTune").
Line Clock ticks Source temperature

105 729 while((++pswd[p])>'z'){ **************************>>>

106 14 pswd[p] = '!'; **************

107 1 y = y | y << 8; *

108 2 x -= k; **

109 k = k << 8; *

110 3 k += 0x59; ***

111 2 p++; **

112 1 } *
^ Листинг 1 Карта распределения "температуры" внутри функции do_pswd, полученная с помощью профилировщика VTune.
Вот теперь совсем другое дело – сразу видно, что целесообразно оптимизировать, а что и без того уже вылизано по самые помидоры. Горячие точки главным образом сосредоточены вокруг конструкции pswd[p], – она очень медленно выполняется. Почему? Исходный текст не дает непосредственного ответа на поставленный вопрос и потому совсем не ясно: что конкретно следует сделать для понижения температуры горячих точек.

Приходится спускаться на уровень "голых" машинных команд (благо VTune это позволяет). Вот, например, во что компилятор превратил безобидный на вид оператор присвоения pswd[p] = '!'
Line Instructions Cycles Count temperature

107 mov edx, DWORD PTR [ebp+0ch] 143 11 *****************************

107 ^ загрузить в регистр EDX указатель pswd
107 add edx, DWORD PTR [ebp-4] 22 11 *****

107 ^ сложить EDX с переменной p
107 mov BYTE PTR [edx], 021h 33 11 *******

107 ^ по полученному смещению записать значение 0х21 ('!')
Листинг 2 Исследование температуры машинных команд внутри конструкции pswd[p]='!'
Смотрите! В одной строке исходного текста происходит целых три обращения к памяти! Сначала указатель pswd загружается в регистр EDX, затем он суммируется с переменной p, которая так же расположена в памяти, и лишь затем по рассчитанному смещению в память благополучно записывается константа '!' (021h). Тем не менее, все равно остается не ясно почему загрузка указателя pswd занимает столько времени. Может быть, кто-то постоянно вытесняет pswd из кэша, заставляя процессор обращаться к медленной оперативной памяти? Так ведь нет! Программа работает с небольшим количеством переменных, заведомо умещающихся в кэше второго уровня.


^

Удельное время выполнения


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

Очень немногие профилировщики могут похвастаться способностью засекать удельное время выполнения машинных команд (еще называемое растактовкой). К счастью, VTune это умеет! Обратимся к сгенерированному им протоколу динамического анализа. Быть может, он поможет нам разрешить загадку "неповоротливости" загрузки указателя pswd?
^ Line Instructions Dyn-Retirement Cycles

107 pswd[p] = '!';

107 mov edx, DWORD PTR [ebp+0ch] 13 ************

107 ; ^ загрузить в регистр EDX указатель pswd
107 add edx, DWORD PTR [ebp-4] 2 **

107 ; ^ сложить регистр EDX с переменной p
107 mov BYTE PTR [edx], 021h 3 ***

107 ; ^ записать в *(pswd+p) значение '!'
109 y = y | y << 8;

109 mov eax, DWORD PTR [ebp-28] 2 **

109 ; ^ загрузить в регистр EAX переменную y
109 shl eax, 08h 1 *

109 ; ^ сдвинуть EAX на 8 позиций влево
109 mov ecx, DWORD PTR [ebp-28] (0,7.3,80)

109 ; ^ загрузить в регистр ECX переменную y *******
109 or ecx, eax 1 *

109 ; ^ ECX = ECX | EAX (tmp = y | y)
109 mov DWORD PTR [ebp-28], ecx 1 *

109 ; ^ записать полученный результат в y
110 x -= k;

110 mov edx, DWORD PTR [ebp-24] 0

110 ; ^ загрузить в регистр EDX переменную x
110 sub edx, DWORD PTR [ebp-36] 1 *

110 ; ^ вычесть из регистра EDX переменную k
110 mov DWORD PTR [ebp-24], edx 1 *

110 ; ^ записать полученный результат в x

Листинг 3 Удельное время выполнения машинных команд внутри профилируемого фрагмента программы
Ну вот опять, – все команды, как команды, а загрузка указателя pswd разлеглась прямо как объевшаяся свинья, сожравшая целых тринадцать тактов, в то время как остальные свободно укалываются в один-два такта, а некоторые и вовсе занимают ноль, ухитряясь завершится одновременно с предыдущей инструкций.

За исключением команды, загружающей содержимое переменной y в регистр ECX, время выполнения всех остальных команд строго постоянно и не меняется от случая к случаю. Наша же "подопечная" в зависимости от еще не выясненных обстоятельств, может отъедать аж восемьдесят тактов, что на время делает ее самой горячей точкой данного фрагмента программы. Восемьдесят тактов – это вообще полный беспредел! И пускай среднеарифметическое время ее выполнения составляет всего лишь семь тактов, а минимальное – и вовсе ноль, мы не успокоимся пока не выясним: на что и при каких именно обстоятельствах уходит такое количество тактов?


^

Информация о пенальти


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

Возвращаясь к предыдущему вопросу: почему указатель pswd загружается так долго? И при каких именно обстоятельствах загрузка y "подскакивает" со своих обычных семи до восьмидесяти тактов? Судя по всему, процессору что-то не понравилось и он обложил эти две машинные команды штрафом (penalty), на время притормозив их исполнение. Можем ли мы узнать когда и за какой проступок это произошло? Не прибегая к полной эмуляции процессора – навряд ли (хотя современные x86 с некоторыми ограничениями позволяют получить эту информацию и так).

Гранды компьютерной индустрии – Intel и AMD уже давно выпустили свои профилировщики, содержащие полноценные эмуляторы выпускаемых ими процессоров, позволяющие визуализировать нюансы выполнения каждой машинной инструкции.

Просто щелкните по строке "mov ecx, DWORD PTR [ebp-28]" и VTune выдаст всю, имеющуюся у него информацию:
Decoder Minimum Clocks = 1 ; ^ Минимальное время декодирования – 1 такт

Decoder Average Clocks = 8.7 ; Эффективное время декодирования – 8,7 тактов

Decoder Maximum Clocks = 86 ; Максимальное время декодирования – 86 тактов
Retirement Minimum Clocks = 0, ; Минимальное время завершения – 0 тактов

Retirement Average Clocks = 7.3 ; ^ Эффективное время завершения – 7,3 такта

Retirement Maximum Clocks = 80 ; Максимальное время завершения – 80 тактов
Total Cycles = 80 (00,65%) ; Всего времени исполнения – 80 тактов
Micro-Ops for this instruction = 1 ; Кол-во микроопераций в инструкции – 1
The instruction had to wait 0 cycles for it's sources to be ready

("^ Инструкция ждала 0 тактов пока подготавливались ее операнды, т.е. попросту она их не ждала совсем")

Dynamic Penalty: IC_miss

The instruction was not in the instruction cache, so the processor loads the instruction from the L2 cache or main memory.

("^ Инструкция отсутствовала в кодовом кэше, и процессор был вынужден загружать ее из кэша второго уровня или основной оперативной памяти")

Occurances = 1 ; Такое случалось 1 раз

^ Dynamic Penalty: L2instr_miss

The instruction was not in the L2 cache, so the processor loads the instruction from main memory.

("Инструкция отсутствовала в кэше второго уровня и процессор был вынужден загружать ее из основной оперативной памяти")

Occurances = 1 ; Такое случалось 1 раз

^ Dynamic Penalty: Store_addr_unknown

The load instruction stalls due to the address calculation of the previous store instruction.

("Загружающая инструкция простаивала по той причине, что адрес источника рассчитывался предыдущей инструкцией записи")

Occurances = 10 ; Такое случалось 10 раз
Так, кажется, наше расследование превращается в самый настоящий детектив, еще более запутанный, чем у Агаты Кристи. Если приложить к полученному результату даже самый скромный арифметических аппарат, получится полная чепуха и полная расхождение дебита с кредитом. Судите сами. Полное время выполнения инструкции – 80 тактов, причем, известно, что она выполнялась 11 раз (см. колонку count в листинге 1). А наихудшее время выполнения инструкции составило… 80 тактов! А наихудшее время декодирования и вовсе – 86! То есть, худшее время декодирования инструкции превышает общее время ее исполнения и при этом в десяти итерациях она еще ухитряется простаивать как минимум один такт за каждую итерацию по причине занятости блока расчета адресов. Да… тут есть от чего поехать крышей!

Причина такого несоответствия заключается в относительности самого понятия времени. Вы думаете время относительно только у Эйнштейна? Отнюдь! В конвейерных процессорах (в частности процессорах Pentium и AMD K6/Athlon) понятие "времени выполнения инструкции" вообще не существует в принципе (см. "Фундаментальные проблемы профилировки в малом. Конвейеризация или пропускная способность vs латентность"). В силу того, что несколько инструкций могут выполняться параллельно, простое алгебраическое суммирование времени их исполнения даст значительно больший результат, нежели исполнение занимает в действительности.

Ладно, оставим разборки с относительностью до более поздних времен, а пока обратим внимание на тот факт, что в силу отсутствия нашей инструкции в кэше (она как раз находится на границе двух кэш линеек) и вытекающей отсюда необходимости загружать ее из основной памяти, в первой итерации цикла она выполняется значительно медленнее, чем во всех последующих. Отсюда, собственно, и берутся эти пресловутые восемьдесят тактов. При большом количестве итераций (а при "живом" исполнении программы оно и впрямь велико) временем начальной загрузки можно и пренебречь, но… Стоп! Ведь профилировщик исполнил тело данного цикла всего 11 раз, в результате чего среднее время выполнения этой инструкции составило 7,6 тактов, что совершенно не соответствует реальной действительности! Ой! Оказывается, это вовсе не горячая точка! И тут совершенного нечего оптимизировать. Если мы увеличим количество прогонов профилировщика хотя бы в четыре раза, среднее время выполнения нашей инструкции понизится до 1,8 тактов и она окажется одним из самых холодных мест программы! Точнее – это вообще абсолютный ноль, поскольку эффективное время исполнения данной инструкции – ноль тактов (т.е. она завершается одновременно с предыдущей машинной командой). Словом, мы навернулись по полной программе.

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

Короткое лирическое отступление на тему: почему же все так произошло. По умолчанию VTune прогоняет профилируемый фрагмент 1.000 раз. Много? Не спешите с ответом. Наш хитрый цикл устроен так, что его тело получает управление лишь каждые 'z'   '!' == 0x59 итераций. Таким образом, за все время анализа тело цикла будет исполнено всего лишь 1.000/89 == 11 раз!!! Причем, ни в коем случае нельзя сказать, что это надуманный пример. Напротив! В программном коде такое встречается сплошь и рядом.
while((++pswd[p])>'z') //  данный цикл прогоняется профилировщиком 1.000 раз

{

pswd[p] = '!'; //  данная инструкция прогоняется всего 11 раз



}

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

Впрочем нет, постойте. Нам еще предстоит разобраться со второй "горячей" точкой и на удивление тормозной скоростью загрузки указателя pswd. Опытные программисты, вероятно, уже догадались в чем тут дело. Действительно, – строка pswd[p] = '!' – это первая строка тела цикла, получающая управление каждые 0x59 итераций, что намного превосходит "проницательность" динамического алгоритма предсказания ветвлений, используемого процессором для предотвращения остановки вычислительного конвейера. Следовательно, данное ветвление всегда предсказывается ошибочно и выполнение это инструкции процессору приходится начинать с нуля. А процессорный конвейер – длинный. Пока он заполниться… Собственно, тут виновата вовсе не команда "mov edx,  DWORD PTR [ebp+0ch]" – любая другая команда на ее месте исполнялась бы столь же непроизводительно! "Паяльная грелка", до красна нагревающая эту точку программы, находится совсем в другом месте!

Поднимем курсор чуть выше, на инструкцию условного перехода предшествующую этой команде, и дважды щелкнем мышкой. Профилировщик VTune выдаст следующую информацию:
Decoder Minimum Clocks = 0 ; ^ Минимальное время декодирования – 0 тактов

Decoder Average Clocks = 0 ; Эффективное время декодирования – 0 тактов

Decoder Maximum Clocks = 4 ; Максимальное время декодирования – 4 такта
Retirement Average Clocks = 1 ; Эффективное время завершения – 1 такт
Total Cycles = 1011 (08,20%) ; ^ Всего времени исполнения – 1010 тактов (8,2%)
Micro-Ops for this instruction = 1 ; Кол-во микроопераций в инструкции – 1
The instruction had to wait (8,11.1,113) cycles for it's sources to be ready

("Эта инструкция ждала минимально 8, максимально 113, а в основном 11,1 тактов пока ее операнды не были готовы")
Dynamic Penalty: BTB_Miss_Penalty ; Штраф типа BTB_Miss_Penalty

This instruction stalls because the branch was mispredicted.

("Эта инструкция простаивала потому что ветвление не было предсказано")

Occurances = 13 ; Такое случалось 13 раз
Наша гипотеза полностью подтверждается. Это ветвление тринадцать раз предсказывалась неправильно, о чем VTune и свидетельствует! Постой, как тринадцать?! Ведь тело цикла исполняется только одиннадцать! Да, правильно, одиннадцать. Но ведь процессор наперед этого не знал, и дважды пытался передать на него управление, и лишь затем, увидев, что ни одно из двух предсказаний не сбылось, плюнул и поклялся, что никогда – никогда не поставит свои фишки на эту ветку.

ОК. Когда загадки разрешаются – это приятно. Но главный вопрос несколько в другом: как именно их разрешать? Хорошо, что в нашем случае непредсказуемый условный переход находился так близко к "горячей" точке, но ведь в некоторых (и не таких уж редких) случаях "виновник" бывает расположен даже в других модулях программы! Ну что на это сказать… Подходите к профилировке комплексно и всегда думайте головой. Пожалуй, ничего более действенного я не смогу посоветовать…


^

Определение количества вызовов


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

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

Часто вызываемые функции в большинстве случаев имеет смысл инлайнить (от английского in-line), т.е. непосредственно вставить их код в тело вызываемых функций, что сэкономит какое-то количество времени.

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


^

Определение степени покрытия


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

Итак, покрытие – это процент реально выполненного кода программы в процессе его профилировки. Кому нужна такая информация? Ну, в первую очередь, тестерам, – должны же они убедиться, что весь код приложения протестирован целиком и в нем не осталось никаких "темных" мест.

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

Рассмотрим, например, как может выглядеть протокол покрытия функций, сгенерированный профилировщиком profile.exe для нашего тестового примера pswd.exe (о самом тестовом примере см. "Практический сеанс профилировки с VTune")
Program Statistics ; Статистика по программе

------------------

Command line at 2002 Aug 20 03:36: pswd ; командная строка

Call depth: 2 ; глубина вызовов: 2

Total functions: 5 ; всего функций: 5

Function coverage: 60,0% ; покрыто функций: 60%
Module Statistics for pswd.exe ; статистика по модулю pswd

------------------------------

Functions in module: 5 ; функций в модуле: 5

Module function coverage: 60,0% ; функций прокрыто: 60%
Covered Function ; порытые функции

----------------

. _DeCrypt (pswd.obj)

. __real@4@4008fa00000000000000 (pswd.obj)

* _gen_pswd (pswd.obj)

* _main (pswd.obj)

* _print_dot (pswd.obj)
Тут на чистейшем английском языке написано, что лишь 60% функций получили управление, а остальные 40% не были вызваны ни разу! Разумно убедиться: а вызываются ли эти функции когда ни будь вообще или представляют собой "мертвый" код, который можно безболезненно удалить из программы, практически на половину уменьшив ее в размерах?

Если же эти функции при каких-то определенных обстоятельствах все же получают управление, нам необходимо проанализировать исходный код, чтобы разобраться: что же это за обстоятельства и воссоздать их, чтобы профилировщик смог прогнать и остальные участки программы. Имена покрытых и непокрытых функций перечислены в секции Cover Function. Покрытые отмечаются знаком "*", а непокрытые – "."

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


1   2   3   4   5   6   7   8   9

Похожие:

Tempora mutantur, et nos mutamur in illis iconНовикова Михаила Петровича Gaudeamus tffttur Juvenes dum sunuts!...
Учебное пособие предназначено для студентов вузов и учащихся колледжей, гимназий, школ

Tempora mutantur, et nos mutamur in illis iconРеферат скачан с сайта allreferat wow ua
Возжелавшие ауспиций: «другие семьи» 7 Перспективы 8Раздел II. 10 “O tempora! O mores!” 10 Биология открытого брака 12 Моногамия...

Вы можете разместить ссылку на наш сайт:
Школьные материалы


При копировании материала укажите ссылку © 2013
контакты
uchebilka.ru
Главная страница


<