Ответ более вероятен: никто не сделал больше, чем PGO для C ++, потому что преимущества, вероятно, незаметны.
Позвольте мне уточнить: JIT Движки / среды исполнения имеют как преимущества, так и недостатки с точки зрения их разработчика: у них больше информации во время выполнения, но много времени для анализа.
Некоторые оптимизации действительно дороги, и вы вряд ли увидите, что без огромного влияния на время запуска вы увидите такие, как: развертывание цикла, автоматическая векторизация (которая в большинстве случаев также основана на развертывании цикла), выбор инструкций (для использования SSE4.1 для ЦП, использующий SSE4.1) в сочетании с планированием и переупорядочением команд (для использования более суперскалярных ЦП). Этот вид оптимизации прекрасно сочетается с C-подобным кодом (который доступен из C ++).
Единственная полноценная архитектура компилятора для продвинутой компиляции (насколько мне известно) - это компиляция Java Hotspot и архитектуры с аналогичными принципами с использованием многоуровневой компиляции (Java Azul ' Системы, популярные на сегодняшний день JaegerMonkey JS engine).
Но одной из самых больших оптимизаций во время выполнения является следующее:
Полиморфное встроенное кэширование (это означает, что если вы запустите первый цикл с некоторыми типами, во второй раз, код цикла будет специализированным типом, который был из предыдущего цикла, и JIT установит охрану и установит в качестве ветви по умолчанию встроенные типы, и на основе этого из этой специализированной формы, использующей механизм на основе SSA , будет применяться постоянное свертывание / распространение, встраивание, мертвая Оптимизация устранения кода и в зависимости от того, насколько «продвинутым» является JIT , сделает улучшенное или менее улучшенное назначение регистров ЦП.)
Как вы можете заметить, JIT (горячие точки) улучшит в основном ветвистый код, и с течением времени информация станет лучше, чем код C ++, но статический компилятор, имеющий время для анализа, переупорядочение команд для простых циклов, скорее всего, даст чуть лучшую производительность. Также, как правило, код C ++, области, которые должны быть быстрыми, обычно не является ООП, поэтому информация об оптимизации JIT не принесет такого удивительного улучшения.
Еще одним преимуществом JIT является то, что JIT работает на кросс-сборках, поэтому у него больше информации, если он хочет выполнить встраивание.
Позвольте мне уточнить: допустим, у вас есть базовый класс A, и у вас есть только одна его реализация, а именно B, в другом пакете / сборке / gem / и т.д. и загружается динамически.
JIT , поскольку он видит, что B является единственной реализацией A, он может заменить во всем своем внутреннем представлении вызовы A на коды B, и вызовы методов не будут выполнять диспетчеризацию (см. vtable) но будут прямые звонки. Эти прямые звонки также могут быть встроены. Например, этот B имеет метод: getLength()
, который возвращает 2, все вызовы getLength()
могут быть уменьшены до постоянной 2 во всем. В конце код C ++ не сможет пропустить виртуальный вызов B из другой библиотеки DLL.
Некоторые реализации C ++ не поддерживают оптимизацию большего количества файлов .cpp (даже сегодня в последних версиях GCC есть флаг -lto, который делает это возможным). Но если вы являетесь разработчиком C ++ и беспокоитесь о скорости, вы, скорее всего, поместите все чувствительные классы в одну статическую библиотеку или даже в один и тот же файл, поэтому компилятор может легко встроить его, создавая дополнительную информацию, которая есть у JIT. , предоставляется самим разработчиком, поэтому без потери производительности.