My Authors
Read all threads
По плану сегодня у нас самая холиварная тема из палана, но я задумал ее скипнуть и 80% проголосовавших тут меня поддержали. Поэтому продолжаем говорить про перформанс и я постараюсь рассказать о нашем опыте. Как что делаем, что зашло, а что нет.
Сначала вообще поговорим, как понять что браться оптимизировать. Есть 3 градации оптимизаций: зеленая, желтая и красная. Каждая отличается упоротостью того, что вы делаете. Почитать об этом подробнее можно тут bit.ly/2sEjjHu, но я вкратце тоже расскажу.
В зеленой зоне сидят низковисящие оптимизации. Те самые задержки и дебаунсеры, которые можно просто пофиксить. Проще говоря - места, которые требуют рефакторинга. Тут и код становится красивее и перформанс лучше.
В желтой зоне уже начинается закручивание гаек. То, что ты бы не сделал не гонись за оптимизациями. Код может стать не таким красивым, понимать его посложнее, зато работает быстрее.
А вот в красной зоне уже адок. Это низкоуровневые оптимизации, всякая магия. Она дает мало профита и прибегают к ней только если в этом месте совсем нужен перформанс. Такой код по-хорошему надо сразу же удалять или писать развернутые комменты и тудушки. Он ужасен, но быстр.
Еще можно пользоваться законом Амдала, чтобы понять что оптимизировать. Он отвечает на вопрос, какую задачу стоит браться оптимизировать. Ответ - ту, которая даст больший вклад в общий перформанс. Полная задача в статье выше (bit.ly/2sEjjHu).
Мы все пока еще находимся на этапе, где находим большие просадки в зеленой зоне и это дает много профита. Проблема в том, что такие просадки часто не найдешь обычным профайлером, особенно в асинхронном коде, так как он может показать, что ресурсы не заняты.
Когда мы с этим столкнулись, то поняли, что нужно что-то другое и накрутили в iOS os_signpost'ы на кучу разных типичных операций. Таким образом мы смогли видеть верхнеуровневые таймлайны процессов (даже асинхронных), чтобы понимать куда дальше профайлером смотреть.
На скрине всего-лишь открытие карточки обьявления от тапа до отрисовки. Данных дофига, приходится приноравливаться их парсить. Хорошо, что в Xcode 11 в инструментах групировка метрик более нормальная польехала.
Сайнпосты могут показать, что какой-то процесс идет долго, что CPU профайлер не заметит, так как он - лупа. Вероятно, что это какое-то асинхронное IO (сеть, диск) или дебаунсер, слип. Мы таких мест кучу понаходили, до сих пор находим и вырезаем. Это прям Amazingly stupid!
Так как у нас VIPER и DI, то возникла проблема с тем, что сетевой запрос на экран делается только после создания всего экрана, бывало даже во viewDidAppear. Порой это до 600мс занимало с анимациями. Таких проблем довольно много, так как мы долго упарывались только по архитектуре.
Решили мы их тоже довольно тупо. Делаем запрос с промисом почти прям в ассамблее (на самом деле там легковесный хелпер), пока что-то грузится - собираем наш экран, инжектим промис в интерактор и во viewWillAppear подхватываем готовенькие данные. Короче - грузи раньше!
Вообще много в теме ожидания контента касается именно сететвых запросов. Частая проблема - последовательные запросы, где один другому передает что-то. Пинг-понг между клиентом и сервером. Если они оба нужны для открытия экрана, то приходится идти в бек и мержить их в один.
Если же для открытия экрана нужны не все, то откладываем ненужные до конца отрисовки основного контента, чтобы не замедлять основной флоу.

Бывает еще, что ручки жирные и кучу всего отдают, что экрану не нужно сразу. Тогда наоброт распиливаем и делаем как я только что описал.
Бывают, конечно, и проблемы, когда что-то сделано не оптимально в алгоримтмах, но это редко аффектит сильно перформанс (у нас же не хайлоад, а мобилка) и прям критические места мы просто переделываем. Хз на сколько тут что-то интересное есть.
Из таких мест это только всякие расчеты диффов для коллекций, лейаутов, парсинги данных. Кажется, про это уже куча докладов было. Если не видели - пишите, попробуем найти вместе.
Короче логика на клиенте не прям хардкор и ускорения тоже. Самые большие просадки перформанса случаются из-за глупых ошибок. Уверен, что у вас тоже таких найдется. Поэтому я так топлю просто следить за ним. А как мы следим чуть позже еще поговорю.
Еще мы ускоряли запуск приложения. Про основы рассказывал мой коллега - . Суть - апп большой, много фреймворков, чтобы ускорить старт - за счет меньшей динамической линковки мерджим их в один. Ну и выносим со старта все, что не нужно.
Из последнего - я распарралелил инициализацию DI (он у нас жирный) с инициализаций яндекс карт и фабрика. Жду ускорения в 100мс на iPhone 7.

Суть - имейте ввиду, что инициализация сторонней либы может быть довольно долгой (порядка 200мс).
Давайте поговорим как мы все это меряем и начнем с перформанс тестов. Коротко - они у нас на iOS совсем не зашли, а на вебе прям хорошо. Подход примерно один и тот же, но инструменты и их развитие разное.
Перформанс тестами мы пытаемся мерять скорость открытия аппа, скорость открытия важных экранов и FPS на них. В чем проблема? В том, что ты не можешь один раз сделать прогон и сравнить цифру с прошлым прогоном, данные будут очень разные и несравнимые.
Поэтому во-первых нужно делать 100-1000 прогонов одного теста и смотреть на статистические данные по ним, медианы, сигмы, отклонения, а не просто голые цифры. Плюс нужно запускать на ПР таргет ветку и сорс в одно и то же время, чтобы фаза луны не повлияла на цифры.
Даже когда ты сделаешь все так и даже все замокаешь, то миники, симуляторы и прочая фигня будет вносить тебе огого какие отклонения и ты будешь детектить просадки которых нет и это будет всех бесить.
Поэтому мы начали использовать MDE (Minimal detectable effect) - запускать ночью по около 10000 (цифры отличаются для каждого теста) прогонов каждого теста и смотреть на сколько большие могут быть разбросы, какие просадки мы можем детектить по хитрым математическим формулам.
Число считается для каждого отдельно взятого теста и сохраняется в базу. На обычных прогонах тестов мы берем наши статистики и смотрим, расходятся ли они больше, чем мы должны детектить опираясь на MDE. Если да, то фейлим тест, если нет, то нет.
Число считается для каждого отдельно взятого теста и сохраняется в базу. На обычных прогонах тестов мы берем наши статистики и смотрим, расходятся ли они больше, чем мы должны детектить опираясь на MDE. Если да, то фейлим тест, если нет, то нет.
На вебе эта тема примерно с таким алгоритмом неплохо зашла, а на мобилках и на iOS в большей степени различные флуктуации настолько сильны, что как бы мы не пытались пока чистить данные от выбросов - все равно получаем ложнопозитивные просадки и не можем опираться на такие тесты.
Сил в них было вложено много, но требуют они еще больше. Мы не готовы пока столько вкладывать и отложили эту тему на будущее. Если у кого есть позитивный опыт с перформанс тестами на iOS буду рад пообщаться. А пока знайте, что перформанс тесты - самый дорогой способ замера.
Поэтому мы решили пойти другим путем и сделали мониторинги тех же метрик, кроме FPS с прода. Они хоть и более разбросанные, но тренды на них видеть и даже АБ тесты по перформансу катить оказалось более, чем возможно.
Даже с перформанс тестами метрики с прода вам нужны, так как тксты - это синтетика и не отражают реальную картину у пользователей. Вы можете хоть бесконечность гордиться, что на синтетике все хорошо, пока пользователи будут страдать.
По скорости запуска аппа мы шлем метрики по разным этапам от входа в main, до отрисовки первого экрана и видим что увеличилось, а что уменьшилось. У нас есть разбивка по девайсам, осям, версиям приложения и мы четко видим разницу после изменений кода.
Чуть веселее с метриками открытия экранов. Во-первых их тоже нужно разбить на этапы типа инита экрана и резолвов DI, загрузки контента, парсинга и диффов, отрисовки. Тут плюс-минус понятно.
Но мы хотим трекать время от пользовательского действия. Мы сохраняем таймстемпы всех тапов и когда экран только начинает открываться - он связывает время последнего тапа со своей метрикой. Если тапа нет, то считаем, что экран открылся из вне, например по диплинку.
Там могут быть потенциальные проблемы, что последний тап не затрекался и мы взяли слишком старый, что пользователь ждал и тапал много раз, а мы не померяли все время ожидания, но на практике это выбросы, которые нам совсем не мешают смотреть на метрики и принимать решения.
Делая ускорения какой-то части приложения, на основе всех этих метрик мы можем проводить АБ тесты. Сейчас даже сделано так, что если кто-то другой проводит АБ тесты функционала, но аффектит метрики перформанса, то они прокрашиваются и это повод обсудить тест с нашей командой.
В общем как-то так у нас сейчас устроено. Из ближайших целей - научить команды ускорять свои экраны и передать им знания, которые помогают нам делать Авито быстрым. Так сказать, развивать культуру, чтобы не быть бутылочным горлышком. Но это отдельная история)
В общем, про перформанс у меня все и так дофига вышло прям. К сожалению, нельзя все, что лежит в голове выложить в паре десятков твитов, поэтому сумбурно. Если эта тема тебе близка или вы ты уже ей занимаешься, то пиши мне, буду рад пообщаться.
Напоследок скажу, что та самая культура перформанса должна зарождаться не в рамках какой-то одной компании, а в самом комьюнити, иначе толку будет мало. Поэтому еще раз призыву обсуждать тему и писать мне, если интересно. И не забывай следить за перформансом)
Missing some Tweet in this thread? You can try to force a refresh.

Enjoying this thread?

Keep Current with Мобильный разработчик

Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Follow Us on Twitter!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just three indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3.00/month or $30.00/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!