RAMDisk. Ускоряем сборку Gradle проектов

от
Soft   ramdisk, gradle

Хочу поделиться способом, который ускорит сборку Gradle проектов путём переноса папки build в оперативную память.

Достоинства. Папка build не будет занимать место на диске, что сэкономит память на SSD. Сборка будет проводиться в 1.2...1.8 раз быстрее, чем на HDD. На SSD будет меньше циклов перезаписи. Не понадобится много оперативной памяти. Не нужно настраивать каждый проект отдельно, всё делается глобально.

Недостатки. Будет использована часть объёма оперативной памяти. Если у проекта папка сборки занимает 2 Гб, то потребуется выделить именно столько места. Но если проект занимает не более 200 Мб, то такой объём вполне возможно выделить, даже если у вас 6Гб ОЗУ. Также, все данные будут удалены при перезагрузке, а значит, первая инкрементальная сборка после старта системы будет медленной.
Содержание


Создаём RAMDisk
Windows
Существует несколько программ для создания рамдиска: ImDisk Toolkit, AMD Radeon RAMDisk, OSFMount. Я воспользуюсь первой.
Качаем архив с официального сайта https://sourceforge.net/projects/imdisk-toolkit/, распаковываем и устанавливаем.

image-20201101131120131.png
Запускаем RamDisk Configuration.

image-20201101131232806.png
Размер задаём в зависимости от того, с какими проектами будем работать. Например, размер папки build у проекта RxJava не превышает 15 Мб, поэтому тут хватило бы и 30-50 Мб, а вот Android проект может занимать и 150 Мб. Я поставил 800 Мб на своём ноутбуке с 8Гб ОЗУ, потому что использую рамдиск ещё и как кэш для Firefox.

Выбираем любую понравившуюся букву для раздела и файловую систему NTFS. Также поставьте две галочки для автозапуска при старте системы и создания временной папки. Опционально, можно переназначить переменную окружения TEMP:
image-20201101131620286.png
Но имейте в виду, что некоторые программы начнут записывать туда файлы. Например, архиватор 7zip складывает туда файлы перед распаковкой при Drag'n'Drop.

Если всё сделано успешно, появится новый диск:
image-20201101132907556.png

Linux
На линуксе, скорее всего, уже всё будет сделано системой. Проверяем командой df:
  1. > df /tmp
  2. Filesystem 1K-blocks Used Available Use% Mounted on
  3. tmpfs        3992540    0   3992540   0% /tmp
  4. > df /dev/shm
  5. Filesystem 1K-blocks Used Available Use% Mounted on
  6. tmpfs        3992540 4072   3988468   1% /dev/shm
Файловая система tmpfs это и есть рамдиск.


Переносим папку сборки Gradle
У Gradle есть возможность задать глобальный скрипт инициализации, в котором можно переопределить какие-либо параметры, задать обработчики событий или добавить глобальные задачи. Для этого в домашней директории Gradle нужно создать файл init.gradle. По умолчанию, пути находятся в папке .gradle в домашней директории:

Windows: C:\Users\ИмяПользователя\.gradle\init.gradle
Linux: ~/.gradle/init.gradle

Если же вы переопределяли домашнюю директорию Gradle, задав переменной окружения GRADLE_USER_HOME путь к папке, тогда файл нужно создать в %GRADLE_USER_HOME%\init.gradle для Windows и $GRADLE_USER_HOME/init.gradle для Linux.

В init.gradle задаём обработчик события gradle.projectsLoaded и для всех проектов корневого проекта в buildDir указываем путь к папке на рамдиске:
  1. gradle.projectsLoaded {
  2.     rootProject.allprojects {
  3.         // Windows
  4.         buildDir = "R:/build/${rootProject.name}/${project.name}"
  5.         // Linux
  6.         // buildDir = "/dev/shm/build/${rootProject.name}/${project.name}"
  7.     }
  8. }


Собираем проект
Для примера я возьму проект RxJava и склонирую его на HDD.
image-20201101141737401.png

HDD
Сперва соберу без init.gradle, то есть папка build будет привычно находиться внутри проекта.
  1. > killall java
  2. > ./gradlew clean
Убиваем все процессы Java, чтобы градл демон, который мог что-то закешировать, не мешал замеру времени. Затем очищаем проект, чтобы запустился градл демон, а существующие файлы сборки не переиспользовались.

Наконец, запускаем сборку
  1. > ./gradlew jar
  2. BUILD SUCCESSFUL in 1m 7s
Сборка на HDD заняла 67 секунд.

RAM
Теперь соберу проект с init.gradle, в котором buildDir будет указывать на рамдиск. Сам проект при этом остаётся на HDD.
  1. > killall java
  2. > ./gradlew clean
Снова убиваем процессы Java и очищаем папку сборки. Обратите внимание, что в данном случае папка build внутри проекта, которая создалась на предыдущем этапе, осталась.
  1. > ls build
  2. classes  generated  libs  resources  tmp
  3. > du -hs build
  4. 15M build
Всё потому, что Gradle теперь о ней ничего не знает. Для него папка build теперь находится на рамдиске, ls /dev/shm/build ничего не выведет, потому что после очистки ещё не было сборки проекта.
  1. > ./gradlew jar
  2. BUILD SUCCESSFUL in 55s
Сборка на RAM заняла 55 секунд, что в 1.2 раза быстрее, чем в случае HDD.

SSD
Не будет лишним замерить скорость сборки на SSD. В init.gradle я теперь задаю новый путь для buildDir.
  1. > killall java
  2. > ./gradlew clean
  3. > ./gradlew jar
  4. BUILD SUCCESSFUL in 53s
Сборка на SSD заняла 53 секунды, что в 1.25 раз быстрее, чем HDD. К сожалению, при этом расходуется ресурс диска.


Инкрементальная сборка
При первой сборке в каждом из предыдущих способов, Gradle видел, что папки build ещё нет, либо она пуста и запускал полную сборку. Когда мы собирали проект на разных дисках для build, отличалось лишь время записи файлов, поэтому и прирост скорости был невелик.
Теперь же соберём проект с присутствующей папкой build. В этом случае Gradle уже будет читать существующие файлы и перезаписывать старые, что должно ускорить сборку на RAM и SSD. Проверим.

Gradle при этом тоже будем переиспользовать существующий.

Убираем из init.gradle переопределение buildDir, чтобы проект собрался на HDD.
  1. # HDD
  2. > pwd
  3. /run/media/annimon/Disc_D/hdd/RxJava
  4. > ls build
  5. classes  generated  libs  resources  tmp
  6. > ./gradlew jar
  7. BUILD SUCCESSFUL in 38s
Сборка на HDD заняла 38 секунд.

Теперь меняем путь buildDir на рамдиск.
  1. # RAM
  2. > ls /dev/shm/build/rxjava/rxjava
  3. classes  generated  libs  resources  tmp
  4. > ./gradlew jar
  5. BUILD SUCCESSFUL in 22s
Сборка на RAM заняла 22 секунды, что в 1.72 раза быстрее, чем на HDD.

Наконец, SSD:
  1. # SSD
  2. > ls /home/annimon/build/rxjava/rxjava
  3. classes  generated  libs  resources  tmp
  4. > ./gradlew jar
  5. BUILD SUCCESSFUL in 25s
Сборка на SSD заняла теперь 25 секунд, что в 1.52 раза быстрее, чем на HDD.


Заключение
Создание рамдиска и перенос на него папки build помогает ускорить сборку проекта как на HDD, так и на SSD. В случае с SSD, к тому же, меньше тратится место и меньше износится дисковый ресурс.

Если захотите попробовать этот способ, напишите в комментариях, какой прирост скорости вы получили на своих проектах. Особенно интересует Android.
+6   6   0
219