Profile-guided optimization
Profile-guided optimization (PGO) - техника оптимизации программы компилятором, нацеленная на увеличение производительности выполнения программы. В отличии от традиционных способов оптимизации анализирующих исключительно исходные коды, PGO использует результаты измерений тестовых запусков оптимизируемой программы для генерации оптимального кода.Тестовые запуски выявляют какие части программы исполняются чаще, а какие реже. Преимущество такого подхода в том что компилятор не строит предположений при выборе способа оптимизации, а базируется на реальных данных, собранных во время выполнения программы. Необходимо учитывать то, что тестовые запуски программы должны выполнятся по наиболее типичному сценарию, что бы статистика была репрезентативной, иначе производительность программы может даже уменьшиться.
PGO может включать следующие типы оптимизаций [1]:
- Inlining – например, если функция A часто вызывает функцию B, и функция B достаточна мала, тогда функция B встраивается в A. Это делается на основе реальной статистике запусков программы.
- Virtual Call Speculation – если виртуальный вызов, или вызов через функцию указатель часто указывает на конкретную функцию, то он может быть заменён на условно-прямой (срабатывающий при выполнении условия) вызов конкретной функции, и даже функция может быть встроена (inline).
- Register Allocation – оптимизация распределения регистров на основе собранных данных.
- Basic Block Optimization – эта оптимизация позволяет поместить совместно вызываемые блоки кода в общую страницу памяти, что минимизирует количество используемых страниц и перерасход памяти.
- Size/Speed Optimization – функции в которых программа тратит значительную часть времени могут быть оптимизированы по скорости выполнения.
- Function Layout – на основе графа вызовов, функции которые принадлежат одной цепочки исполнения будут помещены в одну и ту же секцию.
- Conditional Branch Optimization – оптимизация ветвлений и switch выражений. На основе тестовых запусков, PGO помогает определить какие условия в switch выражении выполняются чаще других. Эти значения затем могут быть вынесены из switch выражения. То же самое относится к if/else - компилятор может упорядочить ветви на основе того какая из них вызывается чаще.
- Dead Code Separation – код который не вызывался во время тестовых запусков может быть перемещён в специальную секцию, что бы исключить его попадание в часто используемые страницы памяти.
- EH Code Separation – код обработки исключения, выполняющийся в исключительных случаях, может быть перенесён в отдельную секцию, если возможно определить что исключения срабатывают в конкретно определённых условиях.
- Memory Intrinsics – (затрудняюсь правильно перевести, привожу оригинал) The expansion of intrinsics can be decided better if it can be determined if an intrinsic is called frequently. An intrinsic can also be optimized based on the block size of moves or copies.
Реализации
Техники оптимизации PGO реализованы компиляторами: Intel C++ Compiler and Fortran compilers, GNU Compiler Collection compilers, Sun Studio, and the Microsoft Visual C++ Compiler.