Site icon AppTractor

Как 5 приложений для iOS могут сократить время запуска в среднем на 28%

Миллисекунды имеют значение

Время запуска — важная метрика приложения, которую следует постоянно отслеживать и улучшать. A/B-тесты в ведущих компаниях, занимающихся мобильными приложениями, постоянно показывают, что добавление всего лишь доли секунды может значительно повредить основным показателям использования, таким как количество активных пользователей в день и время, затрачиваемое на приложение на пользователя в день.

Lyft сообщил об увеличении количества пользовательских сеансов на 5% благодаря сокращению времени запуска их приложения для водителей на 21%. Apple сделала время запуска предметом многочисленных презентаций WWDC (1, 2, 3).

Вместо высокоуровневых заявлений о том, что меньшее время запуска лучше большего и о том, что надо избегать распространенных анти-шаблонов, в этой статье будет использоваться конкретный продукт для анализа производительности — Performance Analysis от Emerge — для диагностики конкретных проблем запуска конкретных приложений и предложения улучшений. Этот пост будет посвящен приложениям для iOS, однако инструменты Emerge полностью идентичны как для Android, так и для iOS.

Это настоящие оптимизации, которые применяются к общедоступным сборкам App Store без участия разработчиков.

Как мы измеряли время запуска

Поскольку проанализированные здесь приложения взяты из App Store без какой-либо отладочной информации или исходного кода, мы решили просто определить «время запуска» как самую раннюю точку от запуска приложения до конца applicationDidBecomeActive(_:).

Для команд мобильных приложений, работающих с Emerge, определения времени запуска полностью настраиваются разработчиком. Распространенным вариантом использования будет определение конечных точек после applicationDidBecomeActive(_:) для измерения времени, до которого пользователь может осмысленно взаимодействовать с приложением. Это означает, что измерения времени запуска, показанные ниже, вероятно, являются консервативными оценками по сравнению с тем, что разработчик в компании может считать запуском.

Из-за отсутствия каких-либо символов отладки мы не можем полностью расшифровать многие имена функций. Приложения, которые являются частью интеграции Emerge CI с включенными символами отладки, дадут гораздо более подробные и понятные диаграммы.

Emerge использует современную ферму физических устройств, чтобы обеспечить максимально точные измерения производительности. Следующие измерения основных потоков были проведены на iPhone SE (2020 г.) под управлением iOS 15.4.1.

Важно отметить, что единственное измерение времени запуска приложения — это именно то, что нужно, и его не обязательно экстраполировать для представления большего размера выборки. Контроль дисперсии сродни приручению дикого зверя — все, от приложений, в которые вы вошли и недавно запускали, до типа или даже температуры устройства, может сильно повлиять на результаты.

United Airlines

Время запуска: 2.05 с
Вероятно можно сэкономить: 40% (0.83 с)
Интерактивный граф запуска

Приложение United уже подробно обсуждалось другими из-за проблем с размером приложения, но время его запуска также имеет много возможностей для улучшения. Сразу бросаются в глаза три вещи:

Chipotle

Время запуска: 0.57 с
Вероятно можно сэкономить: 33% (0.19 с)

Интерактивный граф запуска

Curb

Время запуска: 0.8 с
Вероятно можно сэкономить: 22% (0.18 с)
Интерактивный граф запуска

Curb — единственное приложение, которое мы анализируем здесь и которое использует Salesforce Service Cloud SDK. Этот SDK предоставляет API и пользовательские интерфейсы для инструментов управления взаимоотношениями с клиентами, таких как чат поддержки. Как и в случае с LPMessagingSDK, Salesforce Service Cloud SDK выполняет очень дорогостоящую загрузку пакетов. В частности, он тратит 83 мс на Bundle.allFrameworks, а затем еще 93 мс на NSArray.filtered(using:) сразу после этого. Эти вызовы методов находятся в самом начале запуска (или, по крайней мере, в той части, которую мы можем записать), что позволяет предположить, что они являются инициализаторами. Инициализаторы — это специальные функции, которые неявно запускаются во время начала запуска, например, во время методов NSObject.load().

Если мы переключим «Свернуть системные вызовы» в пользовательском интерфейсе, то увидим, что они действительно являются инициализаторами, которые запускаются не кодом приложения, а вместо этого dyld4::Loader::findAndRunAllInitializers. После декомпиляции этой библиотеки с помощью Hopper мы обнаружим, что последующая функция вызывает Bundle.allFrameworks и делает по существу следующее:

var frameworksList: [Bundle]?
...
func initializeFrameworkBundles() {
  ...
  let allFrameworks = NSBundle.allFrameworks
  let predicate = Predicate(format:"bundleIdentifier BEGINSWITH %@", "com.salesforce")
  frameworksList = allFrameworks.filteredArray(predicate:predicate)
  ...
}

NSBundle.allFrameworks стоит дорого, поскольку выполняет некоторую первоначальную настройку и/или выборку из кеша для каждого отдельного фреймворка. Это включает в себя как предоставленные пользователями фреймворки, так и системные Apple. Вызов NSArray.filteredArrayUsingPredicate(using:) дорог по той же причине: он вызывает NSBundle.bundleIdentifier для каждого отдельного пакета фреймворка. Это означает, что помимо первоначальной настройки, выполненной в NSBundle.allFrameworks, теперь необходимо прочитать Info.plist для каждой платформы и получить значение CFBundleIdentifier. Хотя это может ускориться при дальнейших запусках из-за заполнения кеша, это все равно займет нетривиальное количество времени, и холодный запуск остается критическим случаем.

В Salesforce могли бы избежать всего этого, сократив поиск только до пользовательских фреймворков в *bundle path*/Frameworks, или, что еще лучше, поиска фреймворков по имени, которое, как известно, может быть предоставлено Salesforce. Для разработчика приложений, который использует Salesforce, это сложнее обойти. В отличие от LPMessagingSDK, где разработчик может контролировать, когда происходит инициализация, и полностью удалить ее из пути запуска, у разработчика нет такой опции для функции инициализации, которая автоматически запускается системой.

Разработчикам SDK: пожалуйста, не используйте функции инициализации. Их влияние на запуск гораздо сложнее измерить, как и предотвратить/отложить в запуске. Они могут повредить не только производительности, но и стабильности, как я думаю, мы все помним фиаско Facebook SDK.

Имея это в виду, вот несколько подходов к смягчению последствий:

Помимо проблем, упомянутых выше, Salesforce Service Cloud SDK тратит 67 мс на выполнение class_conformsToProtocol и objc_copyClassList (возможно, перебирая все классы, чтобы определить, какие из них соответствуют какому-либо протоколу) в настройке без инициализатора. Всю эту настройку, скорее всего, можно вынести из загрузки приложения.

Что касается других SDK, мы видим, что NewRelic занимает 4% при запуске из-за Method Swizzling, LeanPlum — 3% из-за Method Swizzling, а Realm — 1% для objc_copyClassList (вероятно, только 1%, потому что Service Cloud SDK разогревает кэши, вызывая это функция в первую очередь). Хотя Realm может быть неотъемлемой частью запуска, кажется, что два других SDK могут, по крайней мере, немного задерживаться, чтобы позволить отображать экран запуска, прежде чем блокировать основной поток.

Walmart

Время запуска: 0.67 с
Вероятно можно сэкономить: 33% (0.22 с)
Интерактивный граф запуска

Zoom

Время запуска: 0.27 с
Вероятно можно сэкономить: 15% (0.04 с)
Интерактивный граф запуска

Вывод

Даже в самом крупном масштабе управление производительностью мобильного приложения является чрезвычайно сложной задачей. Время запуска — одна из наиболее распространенных и доступных метрик производительности, но достижение точных измерений в процессе разработки — серьезное препятствие.

Используя продукт Emerge Performance Analysis, мы смогли проанализировать и предложить улучшения времени запуска для пяти популярных iOS-приложений, загруженных непосредственно из App Store. Многие идеи, предлагаемые в этом сообщении в блоге, являются автоматическими выводами продукта Emerge Performance Analysis, который автоматически определяет и предлагает улучшения производительности.

После интеграции в CI разработчик может вносить изменения и сразу же видеть, снизила ли эта функция производительность приложения или улучшила ее, непосредственно в пул-реквесте.

Удачи всем, кто работает над улучшением времени запуска и производительности приложений, и, пожалуйста, дайте нам знать, если у вас есть какие-либо вопросы!

Источник

Exit mobile version