УМНЫЙ КОМПИЛЯТОР В JAVA 9: НАСКОЛЬКО ОН УМЁН? Сергей Петунин
«Глупый» javac: что с ним не так? Каждый раз стартует JVM Каждый раз начинает с чистого листа Не особо использует многоядерность
«Умный» sjavac: что он умеет? Держит javac в памяти Инкрементальный Многопоточный
Но ведь уже есть… maven-compiler-plugin 3.1+: useIncrementalCompilation=true …или false? Параллельная сборка модулей
import dao.Dao; public class Service { private Dao dao = new Dao(); } package dao; public class Dao { public Dao {} } Но ведь уже есть… maven-compiler-plugin 3.1+: useIncrementalCompilation=true
package dao; public class Dao { public Dao throws Exception{} } Но ведь уже есть… maven-compiler-plugin 3.1+: useIncrementalCompilation=true import dao.Dao; public class Service { private Dao dao = new Dao(); }
Gradle 2.1+: options.incremental = true Кроме временных меток и байт-кода, анализирует исходники До сих пор в статусе «incubating» public class Constants { public static final int ANSWER = 42; } Но ведь уже есть…
ECJ Eclipse Compiler for Java Изначально инкрементальный Используется в Apache Tomcat, Liferay, IntelliJ IDEA Для инкрементальности нужна обвязка в виде IDE или системы сборки Java 8 март 2014, ECJ 4.4 июнь 2014 Но ведь уже есть…
Не заменяют Java Specification Requests (JSR) Развитие инфраструктуры JDK Обкатка идей перед включением в JSR JDK Enhancement Proposals
JEP-139 Обёртка над javac Использование серверного процесса Использование множества ядер Отслеживание изменений в пакетах и зависимостях Инкрементальная компиляция
JEP-139
JEP-199: sjavac, phase two
sjavac: начало : Add internal smart javac wrapper to solve JEP 193ohrstrom
Fredrik Öhrström's blog
Клиент стартует каждый раз при вызове sjavac Сервер стартует один раз и висит в памяти до определённого периода бездействия Клиент и сервер находят друг друга через порт-файл Клиент и сервер должны быть на одной машине Клиент-серверная архитектура
5-ddest-sourcepathsrc-implicit:none SjavacClient STDOUT:Compiling STDOUT:Invoking STDERR:Error… RC:-1 SjavacServer Протокол обмена
socket javac IdleResetSjavac PooledSjavac SjavacImpl Архитектура сервера
package demo; import demo.dao.Dao; public class Service { private Dao dao = new Dao(); } package demo.dao; public class Dao {} package demo.utils; public class Utils {} Зависимости и публичный API
M :demo P :demo S C src/demo/Service.java D S demo.Service -> demo.Service D S demo.Service -> demo.dao.Dao I TYPE public demo.Service I METHOD public void () A sjavac_dest/demo/Service.class Timestamp класса Публичный API Зависимости Timestamp исходника Модуль Пакет База данных компилятора javac_state
Корректно обрабатывает ситуации: Инкрементальная компиляция package dao; public class Dao { public Dao throws Exception{} } import dao.Dao; public class Service { private Dao dao = new Dao(); } public class Constants { public static final int ANSWER = 42; }
Не более 3 параллельных задач компиляции 8800 классов в JDK 1.5 ГБ для 64-bit JDK -> 175 кб/класс 1 ГБ для 32-bit JDK -> 119 кб/класс Если не уместились запускаем компиляцию в одном потоке Разбиваем код на чанки по числу параллельных компиляций Сортируем чанки по числу зависимостей -implicit=none Распараллеливание и эвристика
Компиляция: Dao.java Service.java Компиляция: Dao.java Компиляция: Utils.java Запись: Service.class Запись: Dao.class Запись: Utils.class Chunk 3 Utils.java Chunk 2 Dao.java Chunk 1 Service.java -implicit:none
src out javac_statejavac_server sjavac SjavacClientSjavacServer Ресурсы умного компилятора
-tr.properties=com.centreit.demo.PropertiesTransformer,debug=true ключ расширение класс-трансформерextra Трансформеры
public interface Transformer { boolean transform(CompilationService sjavac, Map > pkgSrcs, Set visibleSources, Map > oldPackageDependencies, URI destRoot, Map > packageArtifacts, Map >> packageDependencies, Map >> packageCpDependencies, Map packagePublicApis, Map dependencyApis, int debugLevel, boolean incremental, int numCores); void setExtra(String e); void setExtra(Options args); } Трансформеры
Javac: $ find src -name "*.java" > sources.txt $ Sjavac: $ sjavac -d out src Рекурсивный обход папок
Держит javac в памяти, но: не рассчитан на работу в качестве полноценного сервера Инкреметальный, но: берёт на себя задачи системы сборки необходима интеграция Многопоточный, но: эвристика построена на исходниках JDK пока ещё много «двойной работы» «Умный» sjavac: итоги
Компиляторrealusersys javac Sjavac, с нуля, не «прогретый» Sjavac, без изменений ,042 Sjavac, с нуля, «прогретый» Цифры: компиляция langtools
Когда уже?
проект OpenJDK 9 JEP 139: Enhance javac to Improve Build Speed JEP 199: Smart Java Compilation, Phase Two Fredrik Öhrström's blog Ссылки
Спасибо за внимание! Сергей Петунин руководитель отдела forketyfork