- app/src/main/baseline-prof.txt: 29 641 правило (4 344 — код приложения), записано на эмуляторе по обходу Главной, Серверов, Маршрутов и Настроек; AGP сам кладёт его в assets/dexopt/baseline.prof и переносит через R8. - scripts/generate-baseline-profile.sh: сборка build type profileGen (release без R8, подпись одноразовым ключом), обход UI через uiautomator/input, сброс профиля SIGUSR1, profman -> отсортированный HRF. - scripts/measure-startup-frames.sh: холодный старт и gfxinfo до/после, docs/PERFORMANCE.md с методом и честными цифрами (эмулятор, не телефон). - verify-project.sh проверяет файл профиля, verify-release-candidate.sh требует baseline.prof(m) в релизном APK; release build type не менялся. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8.5 KiB
Zapret KVN — Baseline Profile и замеры скорости
| Поле | Значение |
|---|---|
| Файл правил | app/src/main/baseline-prof.txt (формат HRF, отсортирован, 29 641 правило, из них 4 344 — код приложения) |
| Генерация | scripts/generate-baseline-profile.sh |
| Замеры | scripts/measure-startup-frames.sh |
| Дата записи профиля и замеров | 14 октября 2026 года, эмулятор API 37 x86_64 (google_apis) |
AGP сам компилирует baseline-prof.txt в assets/dexopt/baseline.prof(m) релизного APK и при R8
переносит исходные имена на обфусцированные. Профили библиотек (Compose и др.) в APK были и раньше:
файл приложения добавляется к ним. Плагины baselineprofile/macrobenchmark не подключены
(gradle/verification-metadata.xml строгий), поэтому профиль пишется скриптом.
Как обновлять профиль
# эмулятор google_apis (нужен `adb root`), только adb из SDK, не `adb` из PATH
$ANDROID_HOME/emulator/emulator -avd zapret_api37 -port 5560 -no-window -no-audio -no-snapshot-save &
scripts/generate-baseline-profile.sh --serial emulator-5560
Что делает скрипт:
- Собирает
:app:assembleProfileGen— тот же release, но без R8 (isMinifyEnabled = false), чтобы записанный профиль содержал исходные имена классов. Сборка подписана одноразовым ключом (keytoolво временной папке, исчезает после работы); боевой JKS не используется, build typereleaseи выпускные скрипты не менялись. - Убирает из APK встроенный
assets/dexopt/baseline.prof*и подписывает заново, иначе прошлые правила «самоподтвердятся» в новом файле. - Ставит APK, делает
cmd package compile --reset, импортирует 60 выдуманных ссылок VLESS черезVIEW file://(длинный список серверов; VPN не запускается и сеть серверов не нужна). - Три круга: холодный старт и обход Главной, Серверов (прокрутка, сортировка, поиск, смена
профиля), Маршрутов (выбор приложений, режим, правило, исходный JSON профиля) и страниц
Настроек. Узлы находятся по тексту через
uiautomator dump, прокрутка и вкладки —input. После каждого кругаkillall -s SIGUSR1заставляет ART сохранить профиль. profman --dump-classes-and-methodsдаёт текст с флагами H/S/P; остаются пакетыio/github/zapretkvn,io/nekohasekai,androidx,kotlinx,kotlin,com/journeyapps, результатLC_ALL=C sort -uпишется вbaseline-prof.txt.
scripts/verify-project.sh проверяет, что файл существует, отсортирован, состоит только из правил HRF
и содержит не менее 500 правил приложения, а profileGen не упомянут в выпускных скриптах.
scripts/verify-release-candidate.sh требует, чтобы в релизном APK был assets/dexopt/baseline.prof
и .profm. Профиль нужно перезаписывать после крупных правок экранов: правила для переименованных
классов просто не сработают, но и не вредят.
Метод замеров
scripts/measure-startup-frames.sh --before A.apk --after B.apk сравнивает два release-APK (x86_64,
R8, одноразовая подпись одним ключом), собранных из одного коммита:
before— без правил приложения (baseline-prof.txtубран; остались профили библиотек, то есть то, что было в выпусках до этого);after— сbaseline-prof.txt;noprofile(--verify-baseline, тот же APK, чтоafter) —cmd package compile -m verify -f, то есть без AOT вообще.
Для before и after профиль применяется так же, как в Macrobenchmark: широковещательная команда
androidx.profileinstaller.action.INSTALL_PROFILE (результат 1 — успех), затем
cmd package compile -m speed-profile -f. Перед каждым состоянием приложение ставится заново,
импортируются те же 60 серверов. Раундов два, порядок состояний чередуется.
- Холодный старт:
am start -W -S, полеTotalTime; перед каждым запускомforce-stopиecho 3 > /proc/sys/vm/drop_caches; один прогревочный запуск не считается; 10 запусков на раунд. - Кадры:
dumpsys gfxinfo <пакет> reset, затем скрипт изinput swipe/input tap— три раза по 6 прокруток списка Серверов вниз и вверх и три раза обход вкладок с прокруткой Настроек; после этогоdumpsys gfxinfo. Три прогона на раунд.
Результаты
Эмулятор API 37, x86_64 с KVM, headless; хост в это время был загружен чужими задачами (load average 13–23 на 32 ядрах). Это не телефон: ядра быстрые, JIT догоняет за секунды, GPU программный. Цифры показывают направление и порядок величин, но не обещание для реальных устройств.
| Метрика | before | after | noprofile (verify) |
|---|---|---|---|
| Холодный старт, медиана 20 запусков, мс | 694 | 652 | 686 |
| Холодный старт, min–max, мс | 587–1747 | 572–745 | 628–857 |
| Медианы по раундам (1 / 2), мс | 798 / 632 | 660 / 622 | 671 / 703 |
| Кадров всего | 6 988 | 7 108 | 7 112 |
| Janky-кадры, % | 8,0 | 6,0 | 5,7 |
| p50, мс | 14 | 10 | 9 |
| p90, мс | 23 | 19 | 20 |
| p95, мс | 28 | 26 | 26 |
| p99, мс | 45 | 36 | 44 |
| Записей в профиле на устройстве | 9 945 | 15 374 | — |
Размер base.odex, байт |
5 045 360 | 6 570 616 | 49 920 |
Перцентили — медианы по шести прогонам (gfxinfo считает время кадра в целых миллисекундах).
Что из этого следует:
- Профиль применился: записей в профиле на 55 % больше, скомпилированного кода на 30 % больше.
- Старт
afterна 6 % быстрееbeforeпо общей медиане, но во втором раунде разница 632 против 622 мс, то есть в пределах шума; уbeforeв первом раунде были выбросы 1,2–1,7 с, которые и тянут медиану. - Кадры
afterнемного лучшеbefore(janky 6,0 % против 8,0 %, p99 36 против 45 мс), ноbeforeв первом раунде мерился при самой большой нагрузке на хост (10,1 % против 5,9 % во втором). noprofileна этом эмуляторе не хужеbefore: на быстром хосте JIT и без профиля прогревает приложение почти мгновенно. Значимого выигрыша от Baseline Profile эмулятор не показывает; настоящую проверку нужно делать на физическом устройстве (arm64, слабые ядра, холодный старт после установки), где разница между интерпретатором и AOT обычно заметно больше.