При работе с оптимизациями могут возникать весьма забавные наведённые эффекты. Они не очевидным образом влияют на скорость исполнения программ. Возьмём, например, мой недавний strict-aliasing. Когда я его исследовал столкнулся со следующим явлением:
В таблице приведены опции компиляции теста и замеры при его исполнении. Видно, что применение strict-aliasing просаживает тест на 15%. Во-первых это очень много, а во-вторых совершенно непонятно почему. Ведь strict-aliasing это даже не оптимизация, а анализ, который разрывает зависимости между LOAD/STORE. Как можно замедлить программу разорвав несколько лишних зависимостей? Оказывается легко.
В Эльбрусах есть аппаратная поддержка технологии dam (memory access disambiguation). В двух словах она делает следующее. Если на этапе компиляции невозможно определить ни независимость, ни пересечение операций, а LOAD очень хочется закинуть за STORE, то это можно сделать, и ниже поставить проверку адресов, по которым работают эти операции. Если они не совпадают, то всё хорошо, если совпадают, то уходим на компенсирующий код и делаем всё по-старому.
Так вот, теперь как это связано со strict-aliasing. Внезапно на одном тесте strict-aliasing определил независимость операций, с которыми ранее работал dam. Из-за этого dam'у пришлось применяться к другим операциям, которые по факту оказались зависимыми. Из-за этого много времени ушло на компенсирующий код, и исполнение деградировало. Теперь смотрим без dam:
Видно, что тест более не деградирует, однако исполняется заметно медленнее.
А мораль отсюда такова: даже если в целом оптимизация ведёт себя хорошо - обязательно найдётся тест, который будет работать медленнее.
"-O3" :442.34:real:438.46:user:0.51:sys
"-O3 -fno-strict-aliasing" :376.43:real:374.28:user:0.39:sys
В таблице приведены опции компиляции теста и замеры при его исполнении. Видно, что применение strict-aliasing просаживает тест на 15%. Во-первых это очень много, а во-вторых совершенно непонятно почему. Ведь strict-aliasing это даже не оптимизация, а анализ, который разрывает зависимости между LOAD/STORE. Как можно замедлить программу разорвав несколько лишних зависимостей? Оказывается легко.
В Эльбрусах есть аппаратная поддержка технологии dam (memory access disambiguation). В двух словах она делает следующее. Если на этапе компиляции невозможно определить ни независимость, ни пересечение операций, а LOAD очень хочется закинуть за STORE, то это можно сделать, и ниже поставить проверку адресов, по которым работают эти операции. Если они не совпадают, то всё хорошо, если совпадают, то уходим на компенсирующий код и делаем всё по-старому.
Так вот, теперь как это связано со strict-aliasing. Внезапно на одном тесте strict-aliasing определил независимость операций, с которыми ранее работал dam. Из-за этого dam'у пришлось применяться к другим операциям, которые по факту оказались зависимыми. Из-за этого много времени ушло на компенсирующий код, и исполнение деградировало. Теперь смотрим без dam:
"-O3 -fno-dam" :471.28:real:468.70:user:0.39:sys
"-O3 -fno-dam -fno-strict-aliasing" :473.76:real:470.96:user:0.36:sys
Видно, что тест более не деградирует, однако исполняется заметно медленнее.
А мораль отсюда такова: даже если в целом оптимизация ведёт себя хорошо - обязательно найдётся тест, который будет работать медленнее.