ТЕХНИКА ОПТИМИЗАЦИИ ПРОГРАММ

       

Влияние размера исполняемого кода на производительность


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

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

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

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

В результате, у нас получится следующее:

; CODE_SIZE EQU      ?      ; // Макрос CODE_SIZE автоматически генерируется

                           ; // пакетным файлом-транслятором

; /*--------------------------------------------------------------------------

;  *

;  *          МАКРОС, ГЕНЕРИРУЩИЙ N машинных команд "NOP

;  *

;  *                       (команда NOP буквально обозначает "нет операции"

;  *                       и занимает  ровно один байт, т.е. N команд NOP



;  *                       дают N байт исполняемого кода)

;  *

;  -------------------------------------------------------------------------*/


NOPING MACRO N                    ; // НАЧАЛО МАКРОСА //

       _N = N               ; _N := N (получаем переданный макросу аргумент)

       _A = 0               ; _A -- переменная-счетчик цикла

       WHILE _A NE _N             ; while(_A <= _N){

              NOP           ; вставляем в исходный текст "NOP"

              _A = _A + 1   ; _A++;

       ENDM                 ; }

ENDM                       ; // КОНЕЦ МАКРОСА //

; /*--------------------------------------------------------------------------

;  *

;  *          ВЫЗОВ МАКРОСА ДЛЯ СОЗДАНИЯ БЛОКА ИЗ CODE_SIZE KB команд NOP

;  *

; --------------------------------------------------------------------------*/

NOPING CODE_SIZE*1024

Листинг 2 [Cache/ code.cache.size.xm] Ассемблерный листинг программы, генерирующей произвольное количество машинных операций NOP

#include

"code.cache.size.h"             ; ßэтот файл формируется пакетным транслятором

                                  ; и содержит определение CODE_SIZE

#include <DoCPU.h>

main()

{

       int a;

       A_BEGIN(1);                ; ß начало замера времени выполнения

              DoCPU(&a);           ; выполняем блок из CODE_SIZE команд NOP

       A_END(1);                  ; ß конец замера времени выполнения

      

       // вывод результатов замера на экран

       printf("%03d\t %d\n", CODE_SIZE, Ax_GET(1));

}

Листинг 3 [Cache/code.cache.size.c] Пример, демонстрирующий последствия выхода за кэш перового (второго) уровня

@ECHO OFF

IF #%1#==#MAKE_FOR# GOTO make_it

REM MAKE ALL

ECHO

= = = СБОРКА ПРИМЕРА, ДЕМОНСТРУЮЩЕГО ОПРЕДЕЛЕНИЕ РАЗМЕРА КОДОВОГО КЭША = = =

ECHO

Утилита к книге \"Техника  оптимизации  программ"  /* название рабочее */

ECHO @ECHO OFF                                              >  CODE.CACHE.SIZE.RUN.BAT

ECHO ECHO

= = демонстрация определения размера кэша = =     >> CODE.CACHE.SIZE.RUN.BAT



ECHO ECHO

Утилита к книге "Техника  оптимизации  программ"  >> CODE.CACHE.SIZE.RUN.BAT

ECHO ECHO N NOP     ...CLOCK...                             >> CODE.CACHE.SIZE.RUN.BAT

ECHO ECHO ------------------------------------------------- >> CODE.CACHE.SIZE.RUN.BAT

FOR %%A IN (2,4,8,16,32,64,128,256,512,1024,2048) DO CALL  %0 MAKE_FOR %%A

ECHO DEL %%0                                                >> CODE.CACHE.SIZE.RUN.BAT

GOTO end

:make_it

ECHO /%0/%1/%2 *

SHIFT

ECHO CODE_SIZE EQU %1                                       >  CODE.CACHE.SIZE.MOD

ECHO #define CODE_SIZE %1                                   >  CODE.CACHE.SIZE.H

TYPE CODE.CACHE.SIZE.XM                                     >> CODE.CACHE.SIZE.MOD

CALL CLOCK.MAKE.BAT   CODE.CACHE.SIZE.C                     > NUL

DEL  CODE.CACHE.SIZE.MOD

DEL  CODE.CACHE.SIZE.H

IF   NOT EXIST CODE.CACHE.SIZE.EXE  GOTO err

IF   EXIST CODE.CACHE.SIZE.%1.EXE   DEL CODE.CACHE.SIZE.%1.EXE

REN  CODE.CACHE.SIZE.EXE CODE.CACHE.SIZE.%1.EXE

ECHO CODE.CACHE.SIZE.%1.EXE                                 >> CODE.CACHE.SIZE.RUN.BAT

ECHO DEL CODE.CACHE.SIZE.%1.EXE                             >> CODE.CACHE.SIZE.RUN.BAT

GOTO end

:err

ECHO -ERR ошибка

компиляции! подробнее см. CODE.CACHE.SIZE.ERR

TYPE CODE.CACHE.SIZE.ERR

EXIT

:end

Листинг 4 [Cache/code.cache.size.make.bat] Пакетный файл, выполняющий трансляцию тестовой программы


Содержание раздела