• mobile

Профилирование без боли: как в Яндексе появился Demeter — open source инструмент для выявления просадок в Android-коде

Как найти бутылочное горлышко в Android-приложении, если даже Perfetto не даёт внятного ответа? Как отловить тяжёлую зависимость в DI-графе, не закопавшись в ручной трейсинг? Как понять, почему Compose-рекомпозиции происходят слишком часто — и где именно всё начинает тормозить? Теперь в Яндексе на эти вопросы отвечает Demeter — инструмент, который встроился в сборку и начал показывать, что на самом деле происходит внутри приложения. Мы поговорили с автором библиотеки Вадимом Мезенцевым о том, как родилась идея создать такой инструмент, почему Demeter стал open source, как он помогает ускорять реальные фичи — и как влияет на архитектуру. Получилось честное, подробное интервью с практикой и кейсами.

01 (4).png

Предыстория

Как вообще появилась идея создать Demeter? Что именно натолкнуло на мысль сделать собственный продукт, а не использовать что-то уже существующее?

Идея Demeter родилась из очень прикладной боли — мы пытались разобраться, почему наше Android-приложение запускается медленно и фризит. Особенно много вопросов было к графу зависимостей Dagger 2: какие объекты создаются, в какой момент, почему это происходит на главном потоке и откуда берутся задержки. Хотелось получить простую и понятную картину — что именно тормозит приложение, где тратится время и как это можно ускорить.

Мы смотрели сторонние решения на GitHub, в том числе на основе AspectJ. Но быстро поняли, что полагаться на них нельзя: нестабильность, проблемы с поддержкой, конфликты после обновлений зависимостей. Было ощущение, что проще сделать инструмент под себя — такой, который мы полностью контролируем, и который не рассыпается на ровном месте.

До появления Demeter мы, как и многие, пользовались разрозненными инструментами — Android Profiler, Perfetto, ручными логами. Всё это требовало времени, внимания и большого количества ручного труда. Мы понимали: если хотим ускорить разработку и действительно влиять на производительность, нужен новый подход. Так и началась работа над Demeter — профилировщиком, который встраивается в приложение, автоматически замеряет нужные метрики и показывает реальную картину исполнения кода.

Специфика работы

В чём специфика работы Demeter? Он помогает получать какие-то специфические метрики и данные, которые нельзя получить с помощью других инструментов, или он делает что-то похожее, но лучше или быстрее?

Demeter — это инструмент, который глубоко встраивается в процесс сборки и работает на уровне байткода. Его основная задача — автоматически измерять время выполнения методов и точно показывать, где тратятся ресурсы, без ручного вмешательства. Мы используем ASM — это позволяет вставлять таймеры прямо в байткод, не трогая исходный код. Благодаря этому Demeter работает стабильно, не зависит от стиля кода и охватывает не только собственные классы, но и сторонние библиотеки.

В отличие от стандартных инструментов, таких как Android Profiler или Perfetto, Demeter показывает реальное время исполнения каждого метода — с привязкой к потоку. Это значит, что можно сразу понять, какие тяжёлые вызовы выполняются на главном потоке, а какие — в фоне. Помимо этого, библиотека отслеживает рекомпозиции в Jetpack Compose, фиксируя, что именно стало их причиной — изменение StateObject, mutableStateOf и так далее.

По сути, Demeter собирает те же классы метрик, что и другие инструменты, но делает это быстрее, глубже и с меньшими затратами. Он не заменяет Firebase или Perfetto, но отлично их дополняет — особенно в ситуациях, где нужна высокая точность, прозрачность и минимальные накладные расходы. Это особенно важно в больших проектах с десятками модулей и сложной архитектурой.

Как с помощью Demeter можно ускорить конкретные экраны и фичи?

Demeter помогает ускорить работу конкретных экранов и пользовательских сценариев за счёт прицельного анализа времени исполнения каждого метода, включая сторонние зависимости, DI-фреймворки и SDK, которые участвуют в старте или отрисовке.

02 (5).png

Процесс обычно строится в три шага:

1. Подключение и выбор сценария. После интеграции Demeter в проект через Gradle-плагины и конфигурацию demeterConfig, запускается обычная отладочная сборка. Разработчик выполняет нужный сценарий — например, открытие конкретного экрана, переход между экранами, взаимодействие с UI. Demeter в этот момент автоматически начинает сбор информации по всем вызванным методам, включая код приложения, библиотеки и внутренние фреймворки.

2. Формирование отчёта. На выходе получается отчёт, в котором все методы отсортированы по нескольким признакам:

  • по времени исполнения в миллисекундах;
  • по потоку: главный или фоновый;
  • по частоте вызова.

Это сразу показывает, какие участки кода нагружают главный поток, какие зависимости создаются слишком долго, какие методы вызываются избыточно. Особенно полезно, что фиксируются вызовы не только из пользовательского кода, но и из сторонних SDK.

3. Оптимизация. Получив отчёт, разработчик может:

  • вынести тяжёлые вызовы с главного потока на фон;
  • отложить или распараллелить инициализацию зависимостей;
  • переписать рекомпозиции в Jetpack Compose, устранив лишние StateObject, mutableStateOf или observeForever;
  • заменить медленные конструкции, такие как блокирующий I/O или неочевидные вызовы в UI-слое.

Эта схема позволяет не просто «почистить» код, а увидеть реальные причины деградации производительности. В сложных проектах с большим количеством модулей, глубоким DI-графом и активным использованием Compose — это особенно критично. Там, где раньше приходилось вручную собирать трейс в Perfetto или гадать, что именно тормозит, теперь всё видно сразу: от первого до последнего вызова, включая сторонние библиотеки.

Благодаря этому Demeter помогает экономить часы и дни разработки, особенно на задачах, где производительность критична: холодный старт, рендер сложных экранов, анимации и сценарии с большим количеством recomposition.

Влияет ли Demeter на качество кода в долгосрочной перспективе?

Да, и довольно сильно. Когда в команде постоянно есть инструмент, который показывает реальное время исполнения методов и подчёркивает проблемные вызовы на главном потоке — это меняет подход к проектированию. Разработчики начинают по-другому относиться к производительности: ещё на этапе написания фичи задумываются, какая логика может быть асинхронной, где нужны ленивые инициализации, а что вообще стоит вынести из критического пути.

Это напрямую влияет на архитектуру. Например, если Demeter показывает, что создание объекта занимает 500 мс из-за 10 вложенных зависимостей — появляется факт, на который можно опереться при пересмотре DI-графа. Такие замеры дают основание для выноса логики в фон, внедрения кэширования или даже полной переработки структуры компонентов.

Снижается и технический долг. Demeter позволяет отслеживать «скрытую тяжесть» кода — например, когда метод вроде бы безобиден, но на деле грузит главный поток. Раньше такие вещи выявлялись либо на проде, либо при ручном профилировании. Теперь это видно сразу, без дополнительной настройки и логирования.

Кроме того, регулярная работа с отчётами Demeter повышает дисциплину в команде: становится проще договориться о стандартах работы с потоками, подходах к инициализации, разделению логики по уровням ответственности. Постепенно производительность перестаёт быть точечной задачей и становится системной частью разработки. Это снижает стоимость поддержки, ускоряет масштабирование продукта и делает код предсказуемо стабильным с точки зрения исполнения.

Практика и кейсы

Какие самые неожиданные или запоминающиеся проблемы удалось выявить с помощью Demeter? Помню, что был какой-то кейс, когда проблему ничем, кроме Demeter, не смогли бы выявить.

Одним из самых показательных случаев стала работа с DI-графом. Когда в приложении используется Dagger и создаются сотни или даже тысячи зависимостей, становится почти невозможно вручную отследить, какая из них инициализируется дольше всего и как это влияет на startup. При обновлении библиотеки может незаметно добавиться тяжёлая зависимость, и в итоге цепочка инициализаций начинает тормозить запуск приложения. Именно такие случаи Demeter помогает ловить максимально точно и быстро.

Например, однажды нам нужно было поднять версию библиотеки, которая тянула за собой стороннюю зависимость — неочевидную, но очень «тяжёлую». На проде это вылилось бы в замедление cold start. С помощью отчёта Demeter мы сразу заметили, что новый компонент инициализируется дольше остальных и грузит главный поток. Без автоматических замеров и встроенного байткод-анализа найти это место было бы крайне сложно — ни Firebase, ни Perfetto не дали бы такой же степени детализации.

03 (4).png

Расскажи про пару кейсов, когда внедрение Demeter позволило серьёзно сократить время и ресурсы на разработку и отладку. Какие ещё команды и сервисы начали использовать у себя Demeter? Есть какой-то фидбек от них?

Сокращение времени отладки — это одна из самых заметных сторон эффекта от Demeter. Раньше на локализацию проблемы с производительностью могло уходить два дня: нужно было собрать Perfetto-трейс, воспроизвести сценарий, проанализировать stacktrace и всё это — вручную. Сейчас мы запускаем сценарий с Demeter, получаем отчёт, и уже через пару часов можно принять архитектурное решение или внести нужные изменения. Это особенно критично при работе с Compose, сложными экранами и графами зависимостей.

Что касается распространения, Demeter уже используют не только в нашей команде. Инструментом заинтересовались коллеги из Доставки, Музыки, Диска, а недавно приходили разработчики из Умной камеры. Фидбек пока только положительный: люди рассказывают, как у них сразу всплыли «невидимые» проблемы, и как удалось быстро на них отреагировать. Сейчас мы ждём обратной связи по новому функционалу и запросы на развитие — хочется, чтобы инструмент был полезен в самых разных командах.

Open source

Почему решили сделать Demeter именно open source, а не просто ещё одним внутренним инструментом? Чего ожидали от такого шага?

Мы изначально делали Demeter как внутренний инструмент, чтобы решать конкретные задачи команды: ускорение старта приложения, выявление тяжёлых зависимостей, оптимизация рекомпозиций. Но довольно быстро стало понятно, что такие задачи стоят не только перед нами — производительность остаётся системной проблемой для всей индустрии. Многие разработчики, особенно в больших проектах, сталкиваются с тем же: сложные DI-графы, непредсказуемое поведение Compose, тяжёлые сторонние SDK. При этом существующие инструменты либо слишком низкоуровневые, как Perfetto; либо требуют сложной настройки, как Simpleperf; либо недостаточно гибкие как Firebase.

Решение выложить Demeter в open source стало логичным шагом. Мы хотели не просто поделиться кодом, а внести вклад в культуру профилирования Android-приложений. Сейчас, когда проект уже доказал свою эффективность внутри компании, у нас есть возможность помочь другим командам — в том числе тем, кто раньше не имел опыта с такими инструментами или не мог их себе позволить. Мы рассчитываем, что открытый исходный код привлечёт внимание сообщества, появятся предложения, фичи и, возможно, контрибьюторы. В идеале хочется, чтобы Demeter развивался не только усилиями нашей команды, а стал по-настоящему живым и полезным инструментом в экосистеме Android.

Насколько просто разработчикам интегрировать Demeter в уже существующие проекты? Сколько времени занимает установка и первичная настройка?

Одна из целей при разработке Demeter была — сделать его максимально простым в интеграции. И это получилось: чтобы начать использовать библиотеку, достаточно добавить нужные зависимости и плагины в Gradle.

Никакого дополнительного кода в приложение вносить не нужно — все измерения происходят автоматически на уровне байткода. Это значит, что разработчик может буквально за час подключить Demeter к существующему проекту и уже в этот же день получить первую полезную метрику. Такой быстрый старт особенно важен в больших командах, где сложно внедрять тяжёлые и инвазивные инструменты. Demeter просто подключается, работает из коробки и не требует изменений в логике приложения.

Какой вклад в развитие Demeter могут внести сторонние разработчики?

Первое и самое очевидное — поддержка новых платформ. Например, Kotlin Multiplatform. Сейчас Demeter работает только с Android, но похожую механику можно реализовать и для KMP-модулей — через IR-плагины или KSP. Это дало бы возможность анализировать производительность в кроссплатформенных проектах. Ещё одно большое направление — iOS. Там невозможно использовать ASM, поэтому придётся переосмыслить архитектуру: возможно, через LLVM-плагины или runtime-хуки. Это технически сложная задача, но она открывает Demeter дорогу за пределы Android.

04 (4).png

Второе направление — расширение системы плагинов и модулей. Уже сейчас можно представить модули для анализа WorkManager, фоновых задач, Navigation или Navigation Compose. Это позволит разработчикам глубже исследовать поведение приложения на всех уровнях — от запуска задач до переходов между экранами.

Отдельный большой блок — улучшение работы с корутинами. Например, выделение «чистого» времени исполнения suspend-функций, без учёта переключений потоков и времени ожидания. Также интересна возможность трекать Job, Flow, StateFlow — чтобы точно понимать, где проходит граница между активной логикой и idle-временем.

Третье направление — улучшение визуализации отчётов. Сейчас отчёты представлены в текстовом виде, но есть спрос на более удобные способы анализа. Можно сделать web-интерфейс или desktop-приложение для просмотра результатов, а также реализовать сравнение отчётов между сборками — например, чтобы отслеживать деградации по метрикам, сравнивать recomposition или изменения времени старта.

Наконец, важная зона роста — интеграция с внешними системами. Например, с Firebase, AppMetrica или Sentry. Это позволит автоматически связывать данные профилирования с аналитикой, крашами или пользовательскими сессиями — и таким образом дать ещё более полную картину происходящего в приложении.

Все эти направления открыты для сообщества. Мы будем рады любым pull request’ам, предложениям, обсуждениям и фичам — у Demeter есть все шансы стать мощным и гибким инструментом на уровне всей Android-индустрии.

Личный опыт

Какой самый интересный фидбек вы получили от разработчиков, которые попробовали Demeter?

Один из самых запомнившихся отзывов пришёл от бывшего коллеги. Мы когда-то работали вместе, а потом наши пути разошлись — он ушёл в другую компанию. Спустя время он случайно наткнулся на Demeter в open source, попробовал внедрить у себя — и почти сразу получил результат. Они быстро нашли у себя множество проблем с производительностью, о которых даже не подозревали, и пересмотрели подход к профилированию. Фидбек был очень тёплый: он рассказал, что теперь команда регулярно закладывает время на анализ и устранение таких проблем, а не отодвигает это в бэклог. Было приятно узнать, что библиотека действительно помогает — не только внутри Яндекса, но и в других продуктах.

Если бы Demeter существовал 5 лет назад, как бы это повлияло на вашу работу? Каких ошибок или проблем удалось бы избежать?

Если бы такой инструмент был доступен раньше, многое в работе действительно было бы проще. Раньше профилирование всегда было трудозатратным процессом: запускали Perfetto или Simpleperf, собирали логи, долго разбирались в stacktrace. Любое исследование занимало часы, а то и дни. А с Demeter нужный сценарий можно воспроизвести за пару минут, получить автоматический отчёт и сразу увидеть, где просадка.

Кроме того, многие ошибки закладываются ещё на этапе проектирования: тяжёлые зависимости в Application.onCreate(), блокирующие вызовы в UI, логика, не вынесенная из главного потока. Если бы тогда был Demeter, мы бы сразу видели такие узкие места, и архитектура экранов или фич выглядела бы иначе. Производительность стала бы частью процесса — не реакцией на проблемы, а опережающей мерой. И, скорее всего, поддержка старых фич тоже обходилась бы дешевле.

Планы на будущее

Какие планы по развитию библиотеки? Есть ли мысли о дополнительных функциях?

В ближайших планах — углублённый анализ Jetpack Compose и более точная работа с корутинами. Мы продолжаем развивать Compose-анализатор: хотим глубже отслеживать, что именно вызывает рекомпозиции. Сейчас фиксируются изменения StateObject, но мы хотим выйти на следующий уровень — понимать не только сам факт рекомпозиции, но и причину её возникновения, а также частоту, с которой это происходит. В перспективе планируем добавить возможность сравнивать эти метрики между сборками — чтобы отслеживать деградации или, наоборот, улучшения производительности.

Вторая важная задача — поддержка анализа suspend-функций. Здесь цель — измерять именно «чистое» время их выполнения: исключить idle-time, переключения между потоками и моменты ожидания. Это позволит точнее понять, где действительно работает бизнес-логика, а где просто «висит» ожидание. Также хотим научиться трекать корутины как объекты (Job, Flow, StateFlow), чтобы получить более полное представление о поведении асинхронного кода.

Наконец, мы хотим реализовать механизм сравнения отчётов между сборками. Это позволит автоматизировано видеть, какие методы стали медленнее, какие участки кода появились или исчезли, и как это повлияло на производительность в конкретных сценариях.

05 (1).png

Возможно ли расширение Demeter за пределы Android-разработки?

Технически — да, но это требует серьёзных архитектурных изменений. Сейчас ядро Demeter основано на ASM Visitor Factory и работает строго на этапе упаковки .dex-файлов. Это позволяет вставлять замеры в байткод максимально точно и при этом не трогать исходный код. Такой подход хорошо работает именно в Android-сборках, где .dex — стандартный формат.

Тем не менее, мы рассматриваем эти направления как потенциальные. Если появится интерес со стороны сообщества или появятся контрибьюторы с опытом в этих областях, мы будем готовы двигаться в сторону расширения — шаг за шагом, с сохранением точности и прозрачности, за которые ценят Demeter.

  • mobile