opt-sanitizer: Инструмент детектирования неточностей в работе оптимизаций компилятора LCC¶
Описание инструмента¶
opt-sanitizer - это инструмент отслеживания неточностей в работе оптимизаций в компиляторе LCC для архитектуры “Эльбрус”. Он имеет в составе модуль в компиляторе для инструментирования кода, библиотеку поддержки и анализатор отчётов.
С помощью данного инструмента программист сможет обнаружить неточности в работе эвристик компиляторных оптимизаций. В процессе своей работы, инструмент выдаёт подсказки для расстановки в коде (или опции сборки). Программист, расставив подсказки от инструмента, в большинстве случаев сможет ускорить работу своей программы.
При работе с большими кодовыми базами программист, как правило, может самостоятельно отследить проблемы в горячих участках кода. Однако просмотреть весь код на предмет неоптимальной работы оптимизаций может занять огромное количество времени. Например, в компиляторе LCC ~20000 циклов. Проверить оптимальность применения оптимизаций в таком случае займёт большое количество даже силами целой команды разработчиков. Санитайзер оптимизаций призван взять на себя часть такой работы и в автоматическом режиме указать на важные в коде места, где оптимизации могли примениться неоптимально.
Схема работы с инструментом следующая:
Необходимо скомпилировать все модули программы с опциями
-fsanitize=opt -fosan-analyze=<тип анализа> -fosan-report-dir=<директория для отчётов>;Запустить исполнение программы на репрезентативных данных;
Прочитать полученный от санитайзера отчёт. Он имеет вид
<номер отчёта>_<анализ>_<имя программы>_<суффикс>.report;Самостоятельно расставить предложенные подсказки в коде;
Скомпилировать повторно программу;
Запустить исполнение программы и сравнить время.
В общем случае, данный процесс является итеративным, так как оптимизации создают сложный контекст друг для друга и эффект от точечного отключения/включения оптимизаций также может потребовать дальнейшего анализа.
На данный момент в инструменте поддержан анализ работы следующих оптимизаций:
-fosan-analyze=inline- оптимизация подстановки тела функции в точку вызова.-fosan-analyze=loops- цикловые оптимизации. Список анализируемых оптимзаций следующий:overlap - конвейеризация циклов с аппаратной поддержкой.
APB - асинхронная подкачка данных.
nesting - вынос участков цикла с малой вероятностью исполнения в создаваемый охватывающий цикл.
vect - замена скалярных вычислений векторными в циклах.
RTMD (runtime memory disambiguation) - динамический разрыв зависимостей по данным.
Работа с инструментом¶
Оптимизация inline¶
Оптимизация подстановки функции является одной из самых важных оптимизаций для процессоров с VLIW архитектурой. Оптимизация обладает рядом положительных эффектов:
устраняет передачу аргументов вызова;
устраняет подготовку перехода;
устраняет операцию подготовленного перехода;
устраняет необходимость возврата значения;
создаёт контекст для работы последующих оптимизаций.
Компилятор при однофазной компиляции не знает точного профиля программы. Также эвристики работы оптимизации компилятора могут работать неоптимально в каком-то частном случае.
Для анализа проблем в работе оптимизации inline необходимо провести следующие действия:
Необходимо скомпилировать все модули программы с опциями
-fsanitize=opt -fosan-analyze=inline -fosan-report-dir=<директория для отчётов>;Запустить исполнение программы на репрезентативных данных;
Прочитать полученный от санитайзера отчёт. Он имеет вид
<номер отчёта>_inline_<имя программы>_<суффикс>.report;
Пример отчёта:
Function name: "addlist"
Function size: 136
Total rate: 24145855.00 (sum calls: 16419193) (46.78 %)
Called from:
Function name: "upldrflags"
Func size: 108
Rate: 13557269.00 (num calls: 9218943) (26.26 %)
Src: ./src/g22.c 262
Inline fail kind: (3) Heuristic desided inline unprofitable
__attribute__((always_inline))
Function name: "pointeyes"
Func size: 150
Rate: 768022.00 (num calls: 522255) (1.49 %)
Src: ./src/g25.c 1005
Inline fail kind: (3) Heuristic desided inline unprofitable.
To inline function use __attribute__((always_inline))
...
Отчёт по оптимизации inline разбит следующим образом:
Имя вызываемой функции. Для С++ манглированное и необходимо использовать
c++filt <путь до отчёта>для получения человекочитаемых имён;Размер вызываемой функции в количестве операций.
Вес функции, количество вызовов функции и отношение к весу всех вызовов в программе. Вес показывает насколько “важным” является вызов функции в данной точке вызова. Его тяжело трактовать как абсолютную характеристику. Намного более наглядным является отношение веса вызовов функции (или отдельной точки) к общему весу всех вызовов в программе. В большинстве случаев, если точки вызовов функции занимают 1% и более от общего веса всех вызовов, то это является поводом для детального анализа.
Далее идут точки вызова данной функции:
Точки вызова с привязкой к исходнику
Веса в конкретной точке вызова
Размер вызывающей функции
Причины, по которой не применилась оптимизация подстановки функций.
Рядом с причиной не подстановки указывается подсказка, которая может помочь ускорить программу.
Далее программист на основаниии отчёта должен расставить подсказки в коде программу (или опций сборки).
Пример анализа работы оптимизации inline¶
Рассмотрим бенчмарк Coremark 1.0.1. Соберём его сначала с базовыми опциями и запустим на исполнение:
$ lcc_i -O4 -fwhole -ffast -ffast-math -mtune=elbrus-2c3\
-fno-swp-ext -frestrict-params -fprofile-use -Ie2k -I.\
-DFLAGS_STR=\"" -O4 -fwhole -ffast -ffast-math -mtune=elbrus-2c3\
-fno-swp-ext -frestrict-params -fprofile-use -lrt"\" -DITERATIONS=0\
core_list_join.c core_main.c core_matrix.c core_state.c core_util.c\
e2k/core_portme.c -o ./coremark.exe -lrt
$ ./coremark_1_thread.exe
...
CoreMark 1.0 : 6915.194568 / GCC11.3 -O4 -fwhole -ffast -ffast-math -mtune=elbrus-2c3 -fno-swp-ext -frestrict-params -fprofile-use -lrt / Heap
...
Теперь добавляем пиковую опцию -ffinite-state-machine-transform. Эта опция обнаруживает машины состояний в коде и упрощает поток управления в них, что должно сильно ускорить тест:
$ lcc_i -O4 -fwhole -ffast -ffast-math -mtune=elbrus-2c3\
-fno-swp-ext -frestrict-params -fprofile-use -ffinite-state-machine-transform -Ie2k -I.\
-DFLAGS_STR=\"" -O4 -fwhole -ffast -ffast-math -mtune=elbrus-2c3\
-fno-swp-ext -frestrict-params -fprofile-use -lrt"\" -DITERATIONS=0\
core_list_join.c core_main.c core_matrix.c core_state.c core_util.c\
e2k/core_portme.c -o ./coremark.exe -lrt
$ ./coremark_1_thread.exe
...
CoreMark 1.0 : 8558.979147 / GCC11.3 -O4 -fwhole -ffast -ffast-math -mtune=elbrus-2c3 -fno-swp-ext -frestrict-params -fprofile-use -ffinite-state-machine-transform -lrt / Heap
...
Соберём теперь с санитайзером и получим отчёт для оптимизации inline :
$ lcc_i -O4 -fwhole -ffast -ffast-math -mtune=elbrus-2c3\
-fno-swp-ext -frestrict-params -fprofile-use -ffinite-state-machine-transform\
-fsanitize=opt -fosan-report-dir=. -fosan-analyze=inline -Ie2k -I.\
-DFLAGS_STR=\"" -O4 -fwhole -ffast -ffast-math -mtune=elbrus-2c3\
-fno-swp-ext -frestrict-params -fprofile-use -lrt"\" -DITERATIONS=0\
core_list_join.c core_main.c core_matrix.c core_state.c core_util.c\
e2k/core_portme.c -o ./coremark.exe -lrt
$ ./coremark_1_thread.exe
Посмотрим на отчёт:
Function name: "core_bench_state"
Function size: 177
Total rate: 547389.00 (sum calls: 484440) (100.00 %)
Called from:
Function name: "calc_func"
Func size: 141
Rate: 547389.00 (num calls: 484440) (100.00 %)
Src: core_list_join.c 77
Inline fail kind: (31) Heuristic desided inline unprofitable
To inline function use __attribute__((always_inline))
Видим, что в программе осталось всего несколько неподставленных функций.
Одна из них оказалась целью для оптимизации машины состояний и имеет большое
число вызовов, а размер её меньше размера вызывающей функции.
Однако компилятор посчитал подстановку не выгодной.
Попробуем использовать предложенную подсказку __attribute__((always_inline)),
чтобы подставить функцию безусловно:
enum CORE_STATE __attribute__((always_inline)) core_state_transition( ee_u8 **instr , ee_u32 *transition_count) {
Компилируем теперь уже исходный код с подсказками и снова запускаем тест:
$ lcc_i -O4 -fwhole -ffast -ffast-math -mtune=elbrus-2c3\
-fno-swp-ext -frestrict-params -fprofile-use -ffinite-state-machine-transform -Ie2k -I.\
-DFLAGS_STR=\"" -O4 -fwhole -ffast -ffast-math -mtune=elbrus-2c3\
-fno-swp-ext -frestrict-params -fprofile-use -lrt"\" -DITERATIONS=0\
core_list_join.c core_main.c core_matrix.c core_state.c core_util.c\
e2k/core_portme.c -o ./coremark.exe -lrt
$ ./coremark_1_thread.exe
...
CoreMark 1.0 : 9724.186704 / GCC11.3 -O4 -fwhole -ffast -ffast-math -mtune=elbrus-2c3 -fno-swp-ext -frestrict-params -fprofile-use -ffinite-state-machine-transform -lrt / Heap
...
Как видно, инструмент позволил найти ресурс для ускорения теста Coremark 1.0.1 ещё на 13.6%.
Цикловые оптимизации¶
Для анализа проблем в работе цикловых оптимизаций необходимо провести следующие действия:
Необходимо скомпилировать все модули программы с опциями
-fsanitize=opt -fosan-analyze=loops -fosan-report-dir=<директория для отчётов>;Запустить исполнение программы на репрезентативных данных;
Прочитать полученный от санитайзера отчёт. Он имеет вид
<номер отчёта>_loops_<имя программы>_<суффикс>.report;
В отчёте по цикловым оптимизациям могут встретиться два типа дескрипторов:
Дескриптор одного цикла:
Пример единичного цикла приведён ниже:
12. weight: 447811.00 (0.12% of function, 0.01% overall)
| src: | reload.c 3145-3152 |
| head counter: | 10966 |
| body counter: | 24989 |
| predicted iterations: | 16.00 |
| average iterations: | 2.28 |
| average loop exec time: | 40.84 |
| has dependencies: | false |
[------------------------------------- Overlap -------------------------------------]
Tpre = 29.00, Tpost = 2.00
II = 3 OVL = 2
exec time: 40.84
OVERLAP APPLIED
Twin loop info:
Tpre = 10.00, Tpost = 2.00, Tloop = 6.00
exec time: 25.67
[SUGGESTION] exec time of overlapped loop
is bigger than not overlapped one more by 25%.
Use "#pragma noswp" to disable overlap optimization.
[------------------------------------------------------------------------------------]
3. weight: 7402396.54 (7.98% of function, 0.24% overall)
| src: | global.c 638-651 |
| head counter: | 7696 |
| body counter: | 244146 |
| predicted iterations: | 5.00 |
| average iterations: | 31.72 |
| average loop exec time: | 961.85 |
| has dependencies: | false |
[------------------------------------- Overlap -------------------------------------]
Tpre = 0.00, Tpost = 0.00, Tloop = 30.32
OVERLAP DIDN'T APPLY
[SUGGESTION] because of low predicted iterations num 5
overlap optimization didn't apply.
To apply overlap optimization try "#pragma loop count(N)"
Suggested N: 32
[------------------------------------------------------------------------------------]
Для цикла здесь приведена следующая информация:
расположение цикла в исходном файле;
количество заходов в предцикл;
количество итераций тела цикла;
предсказанное среднее число итераций;
реальное среднее число итераций;
среднее время исполнения цикла;
наличие зависимостей между операциями LD/ST;
информация о работе оптимизаций.
Здесь приведён пример, где инструмент нашёл неточности в работе оптимизации overlap, т.к. предсказанное число итераций в цикле отличается от реального и накладные расходы перевешивают положительный эффект.
Дескриптор группы циклов
Пример отчёта для оптимизации векторизации:
9. Loops group weight: 595890.00 (0.64% of function, 0.02% overall)
src: global.c 1243-1244, inlined into global.c 658
| N | Weight | Overall | RTMD | Vect | Suggestions |
| 1 | 0.00 | 0.00% | not applied | good loop | - |
| 2 | 595890.00 | 0.02% | not applied | bad loop | no swp |
[--------------------------------------- Vect ---------------------------------------]
Number of good loops: 0 with overall weight: 0.00
Number of bad loops: 1 with overall weight: 595890.00
[------------------------------------------------------------------------------------]
[--------------------------------------- RTMD ---------------------------------------]
Number of good loops: 0 with overall cnt: 0
Number of bad loops: 0 with overall cnt: 0
[------------------------------------------------------------------------------------]
[--------------------------------------- Vect ---------------------------------------]
[SUGGESTION] Vect seems unprofitable.
Try to use "#pragma novector"
[------------------------------------------------------------------------------------]
[------------------------------------- Overlap --------------------------------------]
[SUGGESTION] exec time of overlapped loops
are bigger than not overlapped ones more by 25%.
Use "#pragma noswp" to disable overlap optimization
for whole vector group
[------------------------------------------------------------------------------------]
Группа циклов формируется, когда компилятор создаёт копии циклов перед векторизацией для различных динамических проверок. Например, выравнивание адресов массивов, количества итераций, отсутствия зависимостей и т.д.
Здесь приведена следующая информация:
Вес группы циклов, а также отношение к суммарному весу всех циклов;
Положение в исходном коде;
Таблица циклов, которые входят в группу с указанием веса отдельного цикла, статуса оптимизаций RTMD и векторизации и есть ли подсказки к каждому циклу;
Общая статистика о работе оптимизаций векторизации и RTMD с подсказками к каждой оптимизации;
Подсказки к векторной группе по оптимизациям overlap, nesting и APB.
Пример анализа работы цикловых оптимизаций¶
Для примера возьмём задачу 531.deepsjeng из набора бенчмарков SPEC CPU 2017 rate
Для сравнения времени исполнения сначала соберём задачу в обычном режиме
$ lcc -O3 -fwhole -ffast -static $SRC\
-w -fno-ident -fno-verbose-asm -faligned-check -march=elbrus-v5\
-o 531.deepsjeng -lm
Запустим её и замеряем время:
$ time ./531.deepsjeng ref.txt
832 s
Далее собираем задачу с инструментированием:
$ lcc -O3 -fwhole -ffast -static $SRC\
-w -fno-ident -fno-verbose-asm -faligned-check -march=elbrus-v5\
-fsanitize=opt -fosan-report-dir=/home/user/reports\
-fosan-analyze=loops -losan -o 531.deepsjeng -lm
Далее исполнение задачи на репрезентативных данных для получения отчёта
$ ./531.deepsjeng ref.txt
Откроем полученный отчёт и посмотрим на предложения инструмента. Здесь видно, что инструмент предложил следующие подсказки:
neval.cpp 663-671
#pragma loop count(1)neval.cpp 675-683
#pragma loop count(1)generate.cpp 549-551
#pragma loop count(1)generate.cpp 564-566
#pragma loop count(1)search.cpp 378-381
#pragma prefetchsearch.cpp 567-632
#pragma loop count(29)search.cpp 378-381, inlined into search.cpp 567
#pragma loop count(5)search.cpp 378-381, inlined into search.cpp 567
#pragma prefetch
Здесь необходимо обратить внимание на три последние подсказки, так как в исходном коде конструкция вида:
while( function(arg1, arg2))
В итоге, после подстановки, несколько циклов получили одинаковую строку в исходном файле.
Здесь необходимо разделить их и запустить инструментирование заново,
так как не ясно к какому циклу ставить подсказку.
Также видно, что после подстановки отработали другие оптимизации,
которые клонировали цикл.
Отследить вторую копию можно через режим -fopt-report=5, но подсказку
поставить можно только к одному циклу. Предпочтительно выбирать тот, у которого больше вес.
Предложенные подсказки расставляем в коде, после чего компилируем программу заново и запускаем на исполнение с измерением времени. Получаем 781 s, что даёт ускорение 6.5%.
Опции компиляции¶
Опция |
Описание |
|---|---|
-fsanitize=opt |
включить режим поиска неточностей в работе оптимизаций |
-fosan-analyzes= |
обязательная опция. Выбрать анализ для проведения. Доступные опции loops и inline. |
-fosan-report-dir= |
обязательная опция. Указать директорию, куда будут сохранены отчёты. |
Переменные окружения¶
Опция |
Описание |
|---|---|
OSAN_REPORT_NUM_PRINTS |
указать количество дескрипторов для вывода на печать |
OSAN_REPORT_THRESHOLD_RATE |
отбросить дескрипторы, чей вес меньше максимального веса дескриптора умноженного на указанный коэффициент. Может быть в диапазоне от 0 до 1 |
OSAN_REPORT_FILE_SUFFIX |
указать суффикс, который будет печататься в конце имени отчёта |
OSAN_REPORT_MIN_OVERALL_RATE |
отбросить дескрипторы, у которых отношение их веса к суммарному весу всех дескрипторов в программе меньше указанного отношения. Может быть в диапазоне от 0 до 1 |
Анализатор отчётов¶
В процессе работы программы может возникнуть ситуация, когда в программе есть
несколько горячих путей исполнения, которые зависят от входных данных.
При работе инструмента получится по одному отчёту на каждый вариант входных данных.
Анализировать “глазами” несколько отчётов, которые могут быть ещё и очень длинными может быть неудобно и есть риск упустить важную подсказку.
Для автоматизации решения этой задачи в составе санитайзера оптимизаций поставляется
анализатор отчётов osan_report_analyzer, который является программой для анализа нескольких отчётов для
разных входных данных и определения средневзвешенной подсказки.
Опции анализатора отчётов¶
Опция |
Описание |
|---|---|
-a/–analyze |
выбрать тип анализа отчётов loops/inline |
-d/–dir |
указать директорию с отчётами |
-f/–file |
указать конкретные файлы в директории. Если не указано, то будут анализироваться все файлы в директории |
–summary-path |
указать директорию, куда сохранить суммарный отчёт |
-r/–recursive |
указать, что в указанной директории необходимо обойти все поддиректории рекурсивно |
–demangle |
ищет c++filt и если есть, то деманглирует имена функций |
–skip-descriptors-without-suggestions |
пропустить дескрипторы, у которых нет подсказок. |
–skip-descriptors-with-low-weight |
пропустить дескрипторы, у которых отношение веса к сумме всех весов в программе меньше указанного отношения |
Пример использования¶
После работы санитайзера на задаче 126.gcc при анализе оптимизации inline мы получаем 14 отчётов вида:
00000000_inline_126.gcc.report
...
00000013_inline_126.gcc.report
Будем считать, что все отчёты находятся в директории /home/user/reports. Тогда для анализатора не обязательно указывать имена всех файлов, которых может быть очень много. Если же нужно указать конкретные имена файлов, то можно использовать опцию -f. В нашем случае достаточно указать только директорию:
$ osan-report-analyzer -a inline\
-d /home/user/reports\
--summary-path /home/user/\
--demangle\
--skip-descriptors-without-suggestions\
--skip-descriptors-with-low-weight 0.01
[INFO] Analyzing dir "/home/user/reports"
[INFO] Parsing "00000000_inline_126.gcc.report" file
[INFO] Parsing "00000001_inline_126.gcc.report" file
[INFO] Parsing "00000002_inline_126.gcc.report" file
[INFO] Parsing "00000003_inline_126.gcc.report" file
[INFO] Parsing "00000004_inline_126.gcc.report" file
[INFO] Parsing "00000005_inline_126.gcc.report" file
[INFO] Parsing "00000006_inline_126.gcc.report" file
[INFO] Parsing "00000007_inline_126.gcc.report" file
[INFO] Parsing "00000008_inline_126.gcc.report" file
[INFO] Parsing "00000009_inline_126.gcc.report" file
[INFO] Parsing "00000010_inline_126.gcc.report" file
[INFO] Parsing "00000011_inline_126.gcc.report" file
[INFO] Parsing "00000012_inline_126.gcc.report" file
[INFO] Parsing "00000013_inline_126.gcc.report" file
[INFO] Performing an analysis
[INFO] Saving summary to "/home/user/inline_summary.txt"
[SUCCESS]
Тогда в /home/user появится файл inline_summary.txt, где будет находиться информация со всех запусков. Посмотрим на один из блоков суммарного отчёта:
Name: "register_operand" with weight 2762166.00 (overall 8.15%)
Size: 36
Calls number: 497195
| Overall weight % | Inline fail call site | Source file and line | Calling func size | Fail kind |
| 3.94 | reg_or_nonsymb_mem_operand | ./src/aux-output.c 210 | 34 | Heuristic desided inline unprofitable |
| 3.71 | move_operand | ./src/aux-output.c 249 | 79 | Heuristic desided inline unprofitable |
| 0.27 | arith_operand | ./src/aux-output.c 387 | 14 | Heuristic desided inline unprofitable |
| 0.12 | move_operand | ./src/aux-output.c 262 | 79 | Heuristic desided inline unprofitable |
| 0.05 | reg_or_0_operand | ./src/aux-output.c 100 | 42 | Heuristic desided inline unprofitable |
| 0.04 | sparc_operand | ./src/aux-output.c 224 | 66 | Heuristic desided inline unprofitable |
| 0.02 | shift_operand | ./src/aux-output.c 422 | 13 | Heuristic desided inline unprofitable |
Heuristic desided inline unprofitable: 8.15%
[SUGGESTION] use attribute "always_inline".
Also you can use options "-finline-level=" and "-finline-scale="
В суммарном отчёте для каждого дескриптора выводится та же информация, что и в единичном отчёте, но уже просуммированная по всем отчётам с вычислением средневзвешенной подсказки.
Для цикловых оптимизаций, рядом с каждым отчётом формата .report создаётся файл формата .json и в режиме анализа цикловых оптимизаций анализатор ищет файлы с этим форматом.
После работы санитайзера на задаче 126.gcc при анализе цикловых оптимизаций мы так же получаем 14 отчётов вида:
00000000_loops_126.gcc.json
...
00000013_loops_126.gcc.json
Аналогично считаем, что все отчёты лежат в одной директории /home/user/reports:
$ osan-report-analyzer -a loops\
-d /home/user/reports\
--summary-path /home/user/\
--demangle\
--skip-descriptors-without-suggestions\
--skip-descriptors-with-low-weight 0.01
[INFO] Analyzing dir "/home/user/reports"
[INFO] Parsing "00000000_loops_126.gcc.json" file
[INFO] Parsing "00000001_loops_126.gcc.json" file
[INFO] Parsing "00000002_loops_126.gcc.json" file
[INFO] Parsing "00000003_loops_126.gcc.json" file
[INFO] Parsing "00000004_loops_126.gcc.json" file
[INFO] Parsing "00000005_loops_126.gcc.json" file
[INFO] Parsing "00000006_loops_126.gcc.json" file
[INFO] Parsing "00000007_loops_126.gcc.json" file
[INFO] Parsing "00000008_loops_126.gcc.json" file
[INFO] Parsing "00000009_loops_126.gcc.json" file
[INFO] Parsing "00000010_loops_126.gcc.json" file
[INFO] Parsing "00000011_loops_126.gcc.json" file
[INFO] Parsing "00000012_loops_126.gcc.json" file
[INFO] Parsing "00000013_loops_126.gcc.json" file
[INFO] Performing an analysis
[INFO] Saving summary to "/home/user/loops_summary.txt"
[SUCCESS]
В директории /home/user появится файл loops_summary.txt, где будет находиться информация со всех запусков. Посмотрим на один из блоков суммарного отчёта:
5. loop descriptor weight: 28567401.00 (overall 0.11%)
Src: flow.c 1498-1501
ID: 3226
Tpre: 41.0, Tpost: 9.0, Tloop: 0.0
Predicted avg. cnt: 16.0
| Filename | Weight | Avg. cnt | Overlap | APB | Nesting |
| 00000003_loops_126.gcc.json | 3987467.00 | 16.16 | #pragma noswp | - | - |
| 00000002_loops_126.gcc.json | 3576166.00 | 14.72 | #pragma noswp | - | - |
| 00000000_loops_126.gcc.json | 3369567.00 | 12.76 | #pragma noswp | - | - |
| 00000001_loops_126.gcc.json | 3369567.00 | 12.76 | #pragma noswp | - | - |
| 00000006_loops_126.gcc.json | 2947055.00 | 11.05 | #pragma noswp | - | - |
| 00000012_loops_126.gcc.json | 2883216.00 | 10.52 | #pragma noswp | - | - |
| 00000011_loops_126.gcc.json | 2256380.00 | 21.01 | - | #pragma prefetch | - |
| 00000013_loops_126.gcc.json | 1530148.00 | 10.74 | #pragma noswp | - | - |
| 00000009_loops_126.gcc.json | 1412503.00 | 9.90 | #pragma noswp | - | - |
| 00000007_loops_126.gcc.json | 1228759.00 | 6.69 | #pragma noswp | - | - |
| 00000008_loops_126.gcc.json | 620620.00 | 12.44 | #pragma noswp | - | - |
| 00000010_loops_126.gcc.json | 607933.00 | 9.87 | #pragma noswp | - | - |
| 00000004_loops_126.gcc.json | 407003.00 | 9.07 | #pragma noswp | - | - |
| 00000005_loops_126.gcc.json | 371017.00 | 8.10 | #pragma noswp | - | - |
[SUGGESTIONS]:
#pragma noswp: 92.10%
Здесь видно, что для большинства входных данных оптимзация overlap оказалась вредной и санитайзер предлагает её отключить. Однако нашёлся один запуск, где оптимизация оказалась полезной и более того, санитайзер предлагает добавить тут оптимизацию APB. Однако относительный вес этого случая 2256380/28567401*100% = 7.9%, что не является горячим участком. Если есть выделенный случай, вес которого занимает >25%, то необходимо подумать о версионировании цикла, где одна из копий будет с одной подсказкой, а другая с другой.
Для примера выше можно было бы постоить такое версионирование:
if (N < 18)
{
#pragma noswp
for(...){...}
} else
{
#pragma prefetch
for(...){...}
}
Известные ограничения инструмента¶
- Невозможно поставить подсказку к циклам, которые сгенерированы компилятором. Например:
Если цикл появился в результате работы оптимизации слияния нескольких циклов в один.
Если цикл появился в результате преобразования хвостовой рекурсии в цикл.
- Невозможно поставить подсказку к циклам, которые образованы путём раскрытия языковой конструкции. Например:
Если циклы образованы путём раскрытием среза в Fortran. По каждому измерению строится свой цикл, которого не было в исходном файле.
Если цикл образован с помощью конструкции goto.
Невозможно поставить подсказку к циклу, который пришёл из макроса. Дополнительно эта проблема усложняется, если в макросе содержалось несколько циклов. Тогда они получат одинаковое положение в исходном файле. В качестве решения рекомендуется вставить цикл руками в место вызова и сделать повторное инструментирование. После чего цикл появится физически в нужном месте, положение в исходном файле будет определено и для него можно будет поставить подсказку.
Для шаблонных функций, где необходимо поставить подсказки к циклам лучше всего сделать специализацию шаблона для конкретного типа для которого цикл является горячим.
Нет инструментирования несводимых циклов.
В ситуации, где отработала оптимизация подстановки функции и в одном месте цикл является горячим, а во втором холодным, имеет смысл клонировать функцию, и выставить в двух местах разные подсказки.
В ситуации, где в зависимости от входных данных цикл может быть как горячим, так и холодным, имеет смысл сделать версионирование цикла по количеству итераций.
Если в цикле есть вызов функции и отработала оптимизация подстановки функции, то выставление слишком большой подсказки
#pragma loop countциклу может сильно изменить поведение оптимизации подстановки и даже замедлить задачу при ускорении конкретного цикла.
