JIT-компиляторы должны не только оптимизировать код, но и не тратить времени на редко используемые фрагменты.
Аппаратное и программное обеспечение компьютеров все время усложняется, а вот программисты остаются теми же, к тому же их постоянно не хватает. Более совершенные компиляторы, возможно, могут спасти или хотя бы облегчить ситуацию в ближайшие годы.
«Возможности компиляторов меняются коренным образом», — утверждает Эндрю Эйерс, руководитель программы исследований компании InCert Software. Для многих языков программирования, например для Java, используются динамические (just-in-time — JIT) компиляторы. Они преобразуют коды апплетов или какие-либо другие фрагменты кода в машинные команды непосредственно во время исполнения. Но сейчас недостаточно лишь создать эффективный код, как требовалось когда-то, нужно сделать это как можно быстрее.
Исходя из этого требования JIT-компиляторы должны не только хорошо оптимизировать код, но и не тратить при этом времени на редко используемые фрагменты. Осуществить это можно с помощью «профилирования» программы. Обычно это означает отслеживание показателей производительности во время работы и отсылку этой информации компилятору, чтобы в следующий раз он справился со своей задачей быстрее. Однако сегодня профилирование все чаще подразумевает динамическую оптимизацию самой программы в процессе ее работы.
Эйерс, в прошлом эксперт по технологиям компиляции компании Hewlett-Packard, поясняет описанный процесс так: «Сначала Java-программа является оптимизированной в самой незначительной степени. JIT-компилятор внедряет в нее небольшие «зонды» для отслеживания наиболее часто работающих участков, а затем постепенно оптимизирует их сильнее и сильнее. При этом, если поведение программы изменится, уже другие ее части подвергнутся динамической оптимизации».
Компания Transmeta применяет сходный тип профилирования в своей технологии «трансформации кода». В Transmeta утверждают, что разработанный ее инженерами микропроцессор Crusoe, предназначенный для мобильных устройств, потребляет на 70% меньше энергии и выделяет меньше тепла, чем аналог семейства x86 корпорации Intel, благодаря тому что некоторые команды вынесены из его аппаратной части в программную. Сбор статистических данных происходит в процессе работы. При обнаружении часто используемых последовательностей команд архитектуры x86 происходит их динамическая рекомпиляция в оптимизированный код процессора Crusoe.
Еще одной перспективной темой для дальнейших исследований является оптимизация размещения данных или кода в иерархии памяти, включающей жесткий диск, оперативную память и кэш-память процессора различных уровней. Существующие экспериментальные компиляторы способны, анализируя поведение программы, выбирать уровень иерархии для хранения соответствующей порции данных, а затем генерировать команды для перемещения данных вверх или вниз по иерархической памяти.
Тод Маури, адъюнкт-профессор Университета Карнеги-Меллона, работает над технологиями «предварительной выборки», благодаря которой компилятор генерирует команды для передачи данных из оперативной памяти в процессорный кэш еще до того, как она понадобится. Он также работает над методами заблаговременного переноса данных с дисковых накопителей в оперативную память. По словам Маури, при работе с большим приложением, которое постоянно обращается к диску, необходимая информация окажется в оперативной памяти на миллионы циклов раньше обращения к ней.
В то время как методики, подобные профилированию, применяют для динамической оптимизации кода, исследователи Университета Райса из Хьюстона совершенствуют оптимизацию в другом направлении. Кен Кеннеди, руководитель Центра исследований высокопроизводительного программного обеспечения Университета Райса, выделяет две основные фазы компиляции. Первая фаза включает создание языка программирования с высокой степенью оптимизации для выполнения конкретных задач. Например, операций над матрицами для научных приложений или составления запросов к базам данных для программ экономической направленности.
Генератор языка содержит подробные сведения о нужной предметной области и может потратить значительное время на компиляцию и оптимизацию фрагментов исходного кода, часто используемых разработчиками при написании программ данной направленности. При обработке исходного кода реальной программы компилятор второй фазы может заменить его малоэффективные фрагменты на те, которые уже подверглись «глубокой оптимизации».
Кеннеди полагает, что появится множество языков для конкретных пользовательских предметных областей.
«Люди, не знакомые в полной мере с методологией объектно-ориентированного программирования, смогут создавать собственные приложения путем взаимной интеграции компонентов, написанных специалистами по программированию. Это приведет к значительному повышению профессионализма», — говорит он.
Методы оптимизации, применяемые в компиляторах для получения эффективного кода, могут быть также использованы разработчиками для отладки и адаптации приложений. «Компилятор позволяет смоделировать поведение программы, — считает Эйерс. — Но, помимо генерации машинных команд, полученную модель можно использовать и для множества других целей. Люди только начали понимать это».