Удельное время выполнения
Если время выполнения некоторой точки программы не постоянно, а варьируется в тех или иных пределах (например, в зависимости от рода обрабатываемых данных), то трактовка результатов профилировки становится неоднозначной, а сам результат – ненадежным. Для более достоверного анализа требуется: а) действительно ли в программе присутствуют подобные "плавающие" точки и если да, то: б) определить время их исполнения в лучшем, худшем и среднем случаях.
Очень немногие профилировщики могут похвастаться способностью засекать удельное время выполнения машинных команд (еще называемое растактовкой). К счастью, 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, время выполнения всех остальных команд строго постоянно и не меняется от случая к случаю. Наша же "подопечная" в зависимости от еще не выясненных обстоятельств, может отъедать аж восемьдесят тактов, что на время делает ее самой горячей точкой данного фрагмента программы. Восемьдесят тактов – это вообще полный беспредел! И пускай среднеарифметическое время ее выполнения составляет всего лишь семь тактов, а минимальное – и вовсе ноль, мы не успокоимся пока не выясним: на что и при каких именно обстоятельствах уходит такое количество тактов?