Компиляция точно в срок
Выполнение программы |
---|
Общие понятия |
Типы кода |
Стратегии составления |
Известное время выполнения |
|
Известные компиляторы и наборы инструментов |
|
В вычислениях JIT компиляция - ( компиляция во также динамическая трансляция или время выполнения ). [1] — это компиляция ( компьютерного кода ) во время выполнения программы (во время выполнения ), а не перед выполнением. [2] Это может состоять из перевода исходного кода , но чаще всего это перевод байт-кода в машинный код , который затем выполняется напрямую. Система, реализующая JIT-компилятор, обычно постоянно анализирует исполняемый код и определяет части кода, в которых ускорение, полученное от компиляции или перекомпиляции, перевешивает накладные расходы на компиляцию этого кода.
JIT-компиляция представляет собой комбинацию двух традиционных подходов к трансляции в машинный код — компиляцию с опережением времени (AOT) и интерпретацию — и сочетает в себе некоторые преимущества и недостатки обоих. [2] Грубо говоря, JIT-компиляция сочетает в себе скорость скомпилированного кода с гибкостью интерпретации, с накладными расходами интерпретатора и дополнительными накладными расходами на компиляцию и компоновку (а не только интерпретацию). JIT-компиляция — это форма динамической компиляции , которая обеспечивает адаптивную оптимизацию, такую как динамическая перекомпиляция и ускорение, зависящее от микроархитектуры . [номер 1] [3] Интерпретация и JIT-компиляция особенно подходят для динамических языков программирования , поскольку система времени выполнения может обрабатывать типы данных с поздней привязкой и обеспечивать гарантии безопасности.
История
[ редактировать ]Самый ранний опубликованный JIT-компилятор обычно приписывают работе над LISP Джоном Маккарти в 1960 году. [4] В своей основополагающей статье « Рекурсивные функции символических выражений и их машинное вычисление», часть I , он упоминает функции, которые транслируются во время выполнения, тем самым избавляя от необходимости сохранять выходные данные компилятора на перфокартах. [5] (хотя точнее это было бы называть « системой компиляции и запуска »). Другой ранний пример принадлежит Кену Томпсону , который в 1968 году предложил одно из первых применений регулярных выражений , в данном случае для сопоставления с образцом в текстовом редакторе QED . [6] Для ускорения Томпсон реализовал сопоставление регулярных выражений путем JIT-компиляции с кодом IBM 7094 в совместимой системе разделения времени . [4] Влиятельная техника получения скомпилированного кода из интерпретации была впервые предложена Джеймсом Г. Митчеллом в 1970 году и реализована для экспериментального языка LC² . [7] [8]
Smalltalk (около 1983 г.) стал пионером в новых аспектах JIT-компиляции. Например, трансляция в машинный код выполнялась по требованию, а результат кэшировался для последующего использования. Когда памяти становилось недостаточно, система удаляла часть этого кода и восстанавливала его, когда он снова требовался. [2] [9] Язык Sun Self значительно усовершенствовал эти методы и в какой-то момент был самой быстрой системой Smalltalk в мире, достигая половины скорости оптимизированного C. [10] но с полностью объектно-ориентированным языком.
Компания Sun отказалась от Self, но исследования перешли к языку Java. Термин «компиляция точно в срок» был заимствован из производственного термина « точно в срок » и популяризирован Java, а Джеймс Гослинг использовал этот термин с 1993 года. [11] В настоящее время JITing используется в большинстве реализаций виртуальной машины Java , поскольку HotSpot основывается на этой исследовательской базе и широко использует ее.
Проект HP Dynamo представлял собой экспериментальный JIT-компилятор, в котором формат «байт-кода» и формат машинного кода были одинаковыми; система оптимизировала машинный код PA-8000 . [12] Как это ни странно, это привело к увеличению скорости, в некоторых случаях на 30 %, поскольку это позволило провести оптимизацию на уровне машинного кода, например, встроить код для лучшего использования кэша, оптимизировать вызовы динамических библиотек и многие другие оптимизации во время выполнения, которые традиционные компиляторы не могут попытаться. [13] [14]
В ноябре 2020 года в PHP 8.0 появился JIT-компилятор. [15]
Дизайн
[ редактировать ]В системе, скомпилированной с помощью байт-кода, исходный код преобразуется в промежуточное представление, известное как байт-код . Байт-код не является машинным кодом для какого-либо конкретного компьютера и может переноситься между компьютерными архитектурами. Затем байт-код может быть интерпретирован или запущен на виртуальной машине . JIT-компилятор считывает байт-коды во многих разделах (или полностью, в редких случаях) и динамически компилирует их в машинный код, чтобы программа могла работать быстрее. Это можно сделать для каждого файла, для каждой функции или даже для любого произвольного фрагмента кода; код можно скомпилировать перед его выполнением (отсюда и название «точно в срок»), а затем кэшировать и повторно использовать позже без необходимости перекомпиляции.
Напротив, традиционная интерпретируемая виртуальная машина будет просто интерпретировать байт-код, как правило, с гораздо меньшей производительностью. Некоторые интерпретаторы даже интерпретируют исходный код без предварительной компиляции в байт-код, что приводит к еще худшей производительности. Статически скомпилированный код или собственный код компилируется перед развертыванием. Среда динамической компиляции — это среда, в которой компилятор может использоваться во время выполнения. Общая цель использования методов JIT — достичь или превзойти производительность статической компиляции , сохраняя при этом преимущества интерпретации байт-кода: большая часть «тяжелой работы» по синтаксическому анализу исходного исходного кода и выполнению базовой оптимизации часто выполняется во время компиляции. перед развертыванием: компиляция из байт-кода в машинный код происходит намного быстрее, чем компиляция из исходного кода. Развернутый байт-код является переносимым, в отличие от собственного кода. Поскольку среда выполнения контролирует компиляцию, как и интерпретируемый байт-код, она может работать в безопасной изолированной программной среде. Компиляторы из байт-кода в машинный код писать легче, поскольку портативный компилятор байт-кода уже выполнил большую часть работы.
JIT-код обычно обеспечивает гораздо лучшую производительность, чем интерпретаторы. Кроме того, в некоторых случаях она может обеспечить более высокую производительность, чем статическая компиляция, поскольку многие оптимизации возможны только во время выполнения: [16] [17]
- Компиляцию можно оптимизировать для целевого процессора и модели операционной системы, в которой работает приложение. Например, JIT может выбирать векторные инструкции ЦП SSE2 , когда обнаруживает, что ЦП их поддерживает. Чтобы получить этот уровень специфичности оптимизации с помощью статического компилятора, необходимо либо скомпилировать двоичный файл для каждой предполагаемой платформы/архитектуры, либо включить несколько версий частей кода в один двоичный файл.
- Система способна собирать статистику о том, как программа фактически работает в той среде, в которой она находится, а также переупорядочивать и перекомпилировать ее для достижения оптимальной производительности. Однако некоторые статические компиляторы также могут принимать информацию профиля в качестве входных данных.
- Система может выполнять глобальную оптимизацию кода (например, встраивание библиотечных функций), не теряя преимуществ динамического связывания и без накладных расходов, присущих статическим компиляторам и компоновщикам. В частности, при выполнении глобальных встроенных замен процессу статической компиляции могут потребоваться проверки во время выполнения и гарантировать, что виртуальный вызов произойдет, если фактический класс объекта переопределяет встроенный метод, а также может потребоваться обработка проверок граничных условий при доступе к массиву. внутри циклов. При своевременной компиляции во многих случаях эту обработку можно вынести за пределы циклов, что часто приводит к значительному увеличению скорости.
- Хотя это возможно при использовании статически скомпилированных языков со сборкой мусора, система байт-кода может легче переупорядочить исполняемый код для лучшего использования кэша.
Поскольку JIT должен отображать и выполнять собственное двоичное изображение во время выполнения, настоящие JIT-компьютеры с машинным кодом требуют платформ, которые позволяют выполнять данные во время выполнения, что делает гарвардской архитектурой невозможным использование таких JIT-компиляторов на машине с ; то же самое можно сказать и о некоторых операционных системах и виртуальных машинах. Однако специальный тип «JIT» потенциально может быть нацелен не на архитектуру ЦП физической машины, а скорее на оптимизированный байт-код виртуальной машины, где преобладают ограничения на необработанный машинный код, особенно там, где виртуальная машина этого байт-кода в конечном итоге использует JIT для собственного кода. [18]
Производительность
[ редактировать ]JIT вызывает небольшую или заметную задержку при первоначальном выполнении приложения из-за времени, затрачиваемого на загрузку и компиляцию входного кода. Иногда эту задержку называют «задержкой времени запуска» или «временем прогрева». В общем, чем больше оптимизации выполняет JIT, тем лучше будет сгенерированный код, но и начальная задержка также будет увеличиваться. Поэтому JIT-компилятору приходится искать компромисс между временем компиляции и качеством кода, который он надеется сгенерировать. Время запуска может включать в себя увеличение операций ввода-вывода в дополнение к JIT-компиляции: например, файл данных класса rt.jar для виртуальной машины Java (JVM) составляет 40 МБ, и JVM должна искать много данных в этом контекстно огромном файле. . [19]
Одной из возможных оптимизаций, используемой виртуальной машиной Sun HotSpot Java, является объединение интерпретации и JIT-компиляции. Код приложения изначально интерпретируется, но JVM отслеживает, какие последовательности байт-кода выполняются чаще, и преобразует их в машинный код для непосредственного выполнения на оборудовании. Для байт-кода, который выполняется всего несколько раз, это экономит время компиляции и уменьшает начальную задержку; для часто выполняемого байт-кода JIT-компиляция используется для работы на высокой скорости после начальной фазы медленной интерпретации. Кроме того, поскольку программа тратит большую часть времени на выполнение меньшей части своего кода, сокращение времени компиляции является значительным. Наконец, во время первоначальной интерпретации кода можно собрать статистику выполнения перед компиляцией, что помогает лучше оптимизировать. [20]
Правильный компромисс может варьироваться в зависимости от обстоятельств. Например, виртуальная машина Java компании Sun имеет два основных режима — клиентский и серверный. В клиентском режиме выполняется минимальная компиляция и оптимизация для сокращения времени запуска. В режиме сервера выполняется обширная компиляция и оптимизация, чтобы максимизировать производительность после запуска приложения за счет сокращения времени запуска. Другие JIT-компиляторы Java использовали измерение количества выполнений метода во время выполнения в сочетании с размером байт-кода метода в качестве эвристики для принятия решения о том, когда компилировать. [21] Третий использует количество выполнений в сочетании с обнаружением циклов. [22] В общем, гораздо сложнее точно предсказать, какие методы оптимизировать в кратковременных приложениях, чем в долговыполняющихся. [23]
Native Image Generator (Ngen) от Microsoft — это еще один подход к уменьшению начальной задержки. [24] Ngen предварительно компилирует (или «предварительно-JIT») байт-код из образа Common Intermediate Language в машинный код. В результате компиляция во время выполнения не требуется. .NET Framework 2.0, поставляемый с Visual Studio 2005, запускает Ngen во всех библиотеках Microsoft DLL сразу после установки. Предварительная синхронизация позволяет сократить время запуска. Однако качество генерируемого им кода может быть не таким хорошим, как код, скомпилированный JIT, по тем же причинам, по которым код, скомпилированный статически, без оптимизации на основе профиля , не может быть таким же хорошим, как код, скомпилированный JIT, в крайнем случае: отсутствие профилирования данных для управления, например, встроенным кэшированием. [25]
Также существуют реализации Java, которые сочетают в себе компилятор AOT (предварительный) либо с JIT-компилятором ( Excelsior JET ), либо с интерпретатором ( компилятор GNU для Java ).
JIT-компиляция может не достичь своей цели, а именно перехода в устойчивое состояние повышенной производительности после короткого начального периода прогрева. [26] [27] На восьми разных виртуальных машинах Барретт и др. (2017) измерили шесть широко используемых микротестов , которые обычно используются разработчиками виртуальных машин в качестве целей оптимизации, многократно запуская их в рамках одного выполнения процесса. [28] В Linux они обнаружили, что от 8,7% до 9,6% выполнений процессов не смогли достичь устойчивого состояния производительности, от 16,7% до 17,9% перешли в устойчивое состояние снижения производительности после периода прогрева и 56,5% пар конкретной виртуальной машины работали. конкретный тест не смог последовательно увидеть устойчивое отсутствие ухудшения производительности при нескольких выполнениях (т. е. по крайней мере одно выполнение не смогло достичь устойчивого состояния или привело к снижению производительности в устойчивом состоянии). Даже там, где достигалось улучшенное устойчивое состояние, иногда требовались многие сотни итераций. [29] Трайни и др. (2022) вместо этого сосредоточились на виртуальной машине HotSpot, но с гораздо более широким набором тестов, [30] обнаружили, что 10,9% выполнений процессов не смогли достичь устойчивого состояния производительности, а 43,5% тестов не смогли последовательно достичь устойчивого состояния при нескольких выполнениях. [31]
Безопасность
[ редактировать ]JIT-компиляция в основном использует исполняемые данные и, таким образом, создает проблемы безопасности и возможные эксплойты.
Реализация JIT-компиляции состоит из компиляции исходного кода или байт-кода в машинный код и его выполнения. Обычно это делается непосредственно в памяти: JIT-компилятор выводит машинный код непосредственно в память и немедленно выполняет его, вместо того, чтобы выводить его на диск и затем вызывать код как отдельную программу, как при обычной предварительной компиляции. В современных архитектурах это сталкивается с проблемой из-за защиты исполняемого пространства : произвольная память не может быть выполнена, так как в противном случае существует потенциальная дыра в безопасности. Таким образом, память должна быть помечена как исполняемая; по соображениям безопасности это следует делать после того, как код записан в память и помечен как доступный только для чтения, поскольку записываемая/исполняемая память является дырой в безопасности (см. W^X ). [32] Например, JIT-компилятор Firefox для Javascript представил эту защиту в версии Firefox 46. [33]
JIT-распыление — это класс эксплойтов компьютерной безопасности , которые используют JIT-компиляцию для распыления кучи : полученная память затем становится исполняемой, что позволяет использовать эксплойт, если выполнение может быть перенесено в кучу.
Использование
[ редактировать ]JIT-компиляция может применяться к некоторым программам или может использоваться для определенных возможностей, особенно для динамических возможностей, таких как регулярные выражения . Например, текстовый редактор может скомпилировать регулярное выражение, предоставленное во время выполнения, в машинный код, чтобы обеспечить более быстрое сопоставление: этого нельзя сделать заранее, поскольку шаблон предоставляется только во время выполнения. Некоторые современные среды выполнения полагаются на JIT-компиляцию для высокоскоростного выполнения кода, включая большинство реализаций вместе с Microsoft .NET Java . Аналогично, многие библиотеки регулярных выражений поддерживают JIT-компиляцию регулярных выражений либо в байт-код, либо в машинный код. JIT-компиляция также используется в некоторых эмуляторах для перевода машинного кода из одной архитектуры ЦП в другую.
Обычной реализацией JIT-компиляции является сначала компиляция AOT в байт-код ( виртуальной машины код ), известная как компиляция байт-кода , а затем JIT-компиляция в машинный код (динамическая компиляция), а не интерпретация байт-кода. Это повышает производительность во время выполнения по сравнению с интерпретацией за счет задержки из-за компиляции. JIT-компиляторы транслируют непрерывно, как и интерпретаторы, но кэширование скомпилированного кода сводит к минимуму задержку при будущем выполнении того же кода во время данного запуска. Поскольку компилируется только часть программы, задержка значительно меньше, чем если бы перед выполнением компилировалась вся программа.
См. также
[ редактировать ]- Двоичный перевод
- Общеязыковая среда выполнения
- Копирование и исправление
- Динамическая компиляция
- ГНУ молния
- ЛЛВМ
- ОВПсим
- Самомодифицирующийся код
- Отслеживание своевременной компиляции
- Трансмутационный Крузо
Примечания
[ редактировать ]- ^ Компиляторы Ahead-of-Time также могут ориентироваться на определенные микроархитектуры, но разница между AOT и JIT в этом вопросе заключается в переносимости. JIT может отображать код, адаптированный к текущему процессору во время выполнения, тогда как AOT вместо оптимизации для обобщенного подмножества uarches должен заранее знать целевой процессор: такой код может не только быть непроизводительным на других типах процессоров, но может быть совершенно нестабильным.
Ссылки
[ редактировать ]- ^ Языки, компиляторы и системы выполнения , Мичиганский университет, факультет компьютерных наук и инженерии , получено 15 марта 2018 г.
- ^ Jump up to: а б с Эйкок 2003 .
- ^ «Использует ли JIT преимущества моего процессора?» . Веб-журнал Дэвида Нотарио . Проверено 03 декабря 2018 г.
- ^ Jump up to: а б Эйкок 2003 , 2. Методы JIT-компиляции, 2.1 Бытие, с. 98.
- ^ Маккарти, Дж. (апрель 1960 г.). «Рекурсивные функции символьных выражений и их машинное вычисление, Часть I». Коммуникации АКМ . 3 (4): 184–195. CiteSeerX 10.1.1.111.8833 . дои : 10.1145/367177.367199 . S2CID 1489409 .
- ^ Томпсон 1968 .
- ^ Эйкок 2003 , 2. Методы JIT-компиляции, 2.2 LC², стр. 98–99.
- ^ Митчелл, Дж. Г. (1970). «Проектирование и построение гибких и эффективных систем интерактивного программирования».
{{cite journal}}
: Для цитирования журнала требуется|journal=
( помощь ) - ^ Дойч, ЛП; Шиффман, AM (1984). «Эффективное внедрение системы smalltalk-80» (PDF) . Материалы 11-го симпозиума ACM SIGACT-SIGPLAN по принципам языков программирования — POPL '84 . стр. 297–302. дои : 10.1145/800017.800542 . ISBN 0-89791-125-3 . S2CID 3045432 . Архивировано из оригинала (PDF) 18 июня 2004 г.
- ^ "97-пеп.пс" . www.research.sun.com . Архивировано из оригинала 24 ноября 2006 года . Проверено 15 января 2022 г.
- ^ Эйкок 2003 , 2.14 Java, с. 107, сноска 13.
- ^ «Динамо: прозрачная система динамической оптимизации» . Васант Бала, Эвелин Дюстервальд, Санджив Банерджиа. PLDI '00 Материалы конференции ACM SIGPLAN 2000 по проектированию и реализации языков программирования. страницы с 1 по 12. DOI 10.1145/349299.349303. Проверено 28 марта 2012 г.
- ^ Джон Джаннотти. «Динамо HP» . Арс Техника . Проверено 5 июля 2013 г.
- ^ «Проект HP Dynamo» . Архивировано из оригинала 19 октября 2002 года . Проверено 12 апреля 2016 г.
{{cite web}}
: CS1 maint: неподходящий URL ( ссылка ) - ^ Тунг, Лиам (27 ноября 2020 г.). «Вышел язык программирования PHP 8: этот новый JIT-компилятор обеспечивает лучшую производительность» . ЗДНет . Проверено 28 ноября 2020 г. .
- ^ Кроче, Луи. «Подборка точно в срок» (PDF) . Колумбийский университет . Архивировано из оригинала (PDF) 3 мая 2018 г.
- ^ «Каковы преимущества JIT-компиляции по сравнению с AOT-компиляцией» . Переполнение стека . 21 января 2010 г.
- ^ «Компилировать язык на основе JIT в Webassembly» . Переполнение стека . Проверено 4 декабря 2018 г.
- ^ Хаазе, Чет (май 2007 г.). «Потребительская JRE: более экономичная, более эффективная технология Java» . Сан Микросистемс . Проверено 27 июля 2007 г.
- ^ «Архитектура механизма производительности Java HotSpot» . Oracle.com . Проверено 5 июля 2013 г.
- ^ Шиллинг, Джонатан Л. (февраль 2003 г.). «Самая простая эвристика может быть лучшей в JIT-компиляторах Java» (PDF) . Уведомления SIGPLAN . 38 (2): 36–46. дои : 10.1145/772970.772975 . S2CID 15117148 . Архивировано из оригинала (PDF) 24 сентября 2015 г.
- ^ Тошио Суганума, Тошиаки Ясуэ, Мотохиро Кавахито, Хидеаки Комацу, Тошио Накатани, «Среда динамической оптимизации для JIT-компилятора», Материалы 16-й конференции ACM SIGPLAN по объектно-ориентированному программированию, системам, языкам и приложения (OOPSLA '01), стр. 180–195, 14–18 октября 2001 г.
- ^ Мэтью Арнольд, Майкл Хинд, Барбара Г. Райдер, «Эмпирическое исследование выборочной оптимизации», Труды 13-го международного семинара по языкам и компиляторам для параллельных вычислений, пересмотренные статьи , стр. 49–67, 10–12 августа 2000 г. .
- ^ «Собственный генератор изображений (Ngen.exe)» . Msdn2.microsoft.com. 5 декабря 2006 года . Проверено 5 июля 2013 г.
- ^ Суини, Арнольд (февраль 2005 г.). «Обзор адаптивной оптимизации виртуальных машин» (PDF) . Труды IEEE . 92 (2): 449–466. Архивировано из оригинала (PDF) 29 июня 2016 г.
- ^ Барретт и др. 2017 , с. 3.
- ^ Трайни и др. 2022 , с. 1.
- ^ Барретт и др. 2017 , с. 5-6
- ^ Барретт и др. 2017 , с. 12-13.
- ^ Трайни и др. 2022 , с. 17-23.
- ^ Трайни и др. 2022 , с. 26-29.
- ^ «Как JIT – введение», Эли Бендерский, 5 ноября 2013 г., 5:59.
- ^ Де Муидж, Ян. «JIT-код W^X включен в Firefox» . Ян Де Муидж . Проверено 11 мая 2016 г.
Библиография
[ редактировать ]- Барретт, Эд; Больц-Терайк, Карл Фридрих; Киллик, Ребекка; Маунт, Сара; Тратт, Лоуренс (12 октября 2017 г.). «Прогрев виртуальной машины то горяч, то холоден». Учеб. Программа АКМ. Ланг. 1 :1–27. arXiv : 1602.00602 . дои : 10.1145/3133876 . S2CID 1036324 .
- Трайни, Лука; Кортеллесса, Витторио; Ди Помпео, Даниэле; Туччи, Микеле (30 сентября 2022 г.). «На пути к эффективной оценке устойчивой производительности программного обеспечения Java: мы уже там?». Эмпирическая программная инженерия . 28 . arXiv : 2209.15369 . дои : 10.1007/s10664-022-10247-x . S2CID 252668652 .
- Эйкок, Дж. (июнь 2003 г.). «Краткая история системы «точно в срок». Обзоры вычислительной техники ACM . 35 (2): 97–113. CiteSeerX 10.1.1.97.3985 . дои : 10.1145/857076.857077 . S2CID 15345671 .
- Томпсон, К. (1968). «Техника программирования: Алгоритм поиска по регулярным выражениям» . Коммуникации АКМ . 11 (6): 419–422. дои : 10.1145/363347.363387 . S2CID 21260384 .
Внешние ссылки
[ редактировать ]- Бесплатный онлайн-словарь по информатике
- Mozilla Nanojit. Архивировано 9 мая 2012 г. на Wayback Machine : небольшая кроссплатформенная библиотека C++, генерирующая машинный код. Он используется в качестве JIT для движков Javascript Mozilla Tamarin и SpiderMonkey .
- Профилирование сгенерированного и интерпретированного кода во время выполнения с помощью анализатора производительности VTune