Хабрахабр

[Перевод] MetricKit. Анализ производительности iOS приложений

image

Новая игрушка

Мы продолжаем знакомится с новым материалом от Apple, представленным на WWDC. На этот раз рассмотрим MetricKit, это абсолютно новый фреймворк, который служит инструментом для мониторинга производительности приложений.

Xcode показывает количество используемой оперативной памяти и загруженность процессора, вы можете подключиться с помощью Instruments к симулятору или тестируемому устройству и даже написать собственные инструменты (более подробно об этом смотрите наши статьи о пользовательских пакетах инструментов: часть 1/часть 2). Все знают, что измерение производительности приложения во время разработки — это просто. Но все стает более сложным, когда мы говорим о AppStore, если разрабатываемое приложение предназначается для реальных пользователей. Только лишь понимание важности настройки производительности не позволяет измерить практически все, что выполняет приложение. Конечно, существует множество инструментов для сбора различных параметров, но большинство из них ограничены iOS SDK, а также влиянием фактического мониторинга на поведение приложений. Независимо от того, насколько тщательно вы тестируете свое приложение, в реальных условиях всегда появится куча сюрпризов, которые повлияют на производительность и пользовательский опыт.

Они анонсировали MetricKit (фреймворк, который предоставляет доступ к параметрам, которые предоставляет OS) отдельной вкладки в органайзере Xcode 11, где можно найти параметры приложений. В этом году Apple решила заполнить этот пробел и предоставила разработчикам инструмент, который помогает им собирать и анализировать показатели производительности приложений в реальной среде. Сделаем паузу в MetricKit, потому что отображение параметров в XCode будет работать только с приложениями, которые уже опубликованные в AppStore.

image

MXMetricManager

Архитектура фреймворка довольно проста и понятна. Центральную часть занимает класс MXMetricManager, представляющий собой одно-элементную структуру, которая предоставляет разработчику большой набор APIs фреймворка.

В общем, рабочий процесс состоит из 3-х основных этапов:

  1. Вы инициализируете MXMetricMnager и назначаете для него наблюдателя.
  2. При желании вы можете реализовать собственные метрики в своем приложении, используя API Signpost
  3. И, наконец, теперь мы имеем дело с полученными данными в методе didReceivePayloads, т.е. отправляем их в свой бэкэнд для дальнейшего анализа.

Параметры приходят в виде массива экземпляров MXMetricPayload. Полезная нагрузка инкапсулирует наборы метаданных и временные метки. Metric payload — это простая оболочка для подкласса MXMetric. Для каждого типа параметров она отдельная.

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

Внутренние компоненты MetricKit.

Снаружи MetricKit выглядит довольно просто. Но всегда интересно увидеть, как все работает изнутри. Погружение во что-то более глубокое является всегда интригой, если перед вами стоит конкретная задача. Поэтому я решил, что хочу передать параметры с метками MetricKit, а затем заставить их предоставлять мне обновленные метрики в любое время. Конечно, вы можете использовать `Debug -> Simulate MetricKit Payloads` в Xcode, но id не позволяет отображать собственные данные. Правда, это не очень полезная команда, но она дает вам направление в ваших исследованиях, и это выглядит весьма забавно 😉

Можно подумать, что получить бинарный файл для фреймворка легко, потому что Xcode показывает его в списке фреймворков, как только вы добавите его через диалог «связать бинарный файл с библиотеками». Чтобы начать выполнение задачи, нам, очевидно, необходим сам MetricKit. Потому что если вы откроете MetricKit.framework, вы увидите файл MetricKit.tbd. Это весьма оптимистичная мысль. Очевидно, это не то, что мы ищем. Его размер всего 4кб.

Так что же на самом деле здесь происходит?

Связывание с файлами tbd уменьшает размер двоичного файла. TBD расшифровывается как «text-based dylib stub» и фактически является файлом YAML с описанием dylib, экспортирующим символы и путем к двоичному файлу dylib. Вот как выглядит файл, когда вы открываете его в Xcode: Позже, во время выполнения, настоящий бинарный файл dylib будет загружен из OS по пути, указанному в файле tbd.

image

Используя путь из файла tbd, можно легко получить двоичный файл MetricKit для дальнейшего исследования, но существует еще более простой метод.

Эту информацию легко получить с помощью инструмента, используя флаг -l. Наш двоичный файл приложения содержит путь к каждой динамически связанной библиотеке в разделе заголовка Mach-O.

Вот вывод для тестового проекта, который я создал:

→ otool -l ./Metrics | grep -i metrickit
name /System/Library/Frameworks/MetricKit.framework/MetricKit (offset 24)

Имея бинарный файл фреймворка, можно взглянуть на внутренние элементы. Можно увидеть тот же путь, который мы видели ранее в файле tbd. Он простой в использовании, но очень мощный инструмент для внимательного исследования двоичных файлов. Для этого я обычно использую Hopper Disassemble.

Здесь можно увидеть все экспортированные символы. Как только откроется бинарный файл MetricKit — перейдем к вкладке ‘Proc.’ и развернем список ’Tags’. Выбрав один из них (например, MXMetricManager), увидим все его методы и, выбрав метод, увидим его содержимое в правой части:

image

Похоже, это то, что необходимо вызвать, чтобы заставить MetricKit доставлять обновления подписчикам. При просмотре списка методов MXMetricManager [ https://gist.github.com/deszip/88a258ae21d33dc75d7cbac9569c6ec1 ] весьма легко заметить метод _checkAndDeliverMetricReports.

Рассматривая реализацию метода, заметим несколько интересных вещей: он выполняет перебор содержимого каталога /Library/Caches/MetricKit/Reports. К сожалению, попытка вызвать его не привела к вызову абонента, что, вероятно, означает то, что данные параметры не будут доставлены.

И, наконец, он перебирает зарегистрированных подписчиков и вызывает метод didReceive со списком данных. Затем он пытается разархивировать экземпляр MXMetricPayload для каждого элемента на диске.

Итак, давайте создадим их и поместим на диск перед вызовом ‘_checkAndDeliverMetricReports’. Проблема, вероятно, в том, что в /Library/Caches/MetricKit/Reports нет данных, но известно то, что нам необходимы некоторые заархивированные экземпляры MXMetricPayload. После всего вызвать метод ‘_checkAndDeliverMetricReports’, это должно привести к вызову нашего подписчика с stub в качестве аргумента. Опять же, план состоит в том, чтобы создать экземпляр MXMetricPayload, затем создать и добавить в него любой тип MXMetric, а затем заархивировать экземпляр данных на диске.

Итак, каким же образом возможно создать экземпляр класса? Просматривая документы Apple по payload и метрикам, вы можете заметить, что у них нет общедоступных инициализаторов, и большинство свойств доступны только для чтения.

Снова вернемся к Hopper, чтобы посмотреть список методов MXMetricPayload:

image

Вызывать закрытые методы легко, с помощью класса NSInvocation и метода ‘performSelector’ из-за динамической природы Objective-C. Здесь видно его инициализаторы и методы для присваивания параметров.

Используя данную ссылку, можно найти полный фрагмент кода: [ https://gist.github.com/deszip/a0cf877b07cc2877129e0aaef2fed1e4 ]. В качестве примера мы создадим метрики для CPU и добавим их в payload.

И в завершение архивируем все что мы создали и записываем данные в каталог /Library/Caches/MetricKit/Reports.

На этот раз в качестве аргумента передаем данные с stubbed payload в качестве аргумента. Теперь пришло время вызвать метод '_checkAndDeliverMetricReports', что в итоге должно привести к вызову абонента.

Откуда берутся метрики

Получение отчетов довольно просто реализовать посредством MetricKit, но вам, вероятно, интересно узнать, как отчеты появляются в каталоге app/Library. Вот как.

Проверка его реализации проясняет ситуацию — он строит NSXPCConnection для обслуживания с именем com.apple.metrickit.xpc и двумя интерфейсами MXXPCServer и MXXPCClient для клиентской и серверной сторон. Копая внутри двоичного файла MetricKit, я заметил этот метод: ' _createXPCConnection’. Если посмотреть на описание протокола:

image

Заключение

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

К сожалению, в настоящее время невозможно взглянуть на пользовательский интерфейс ‘Metric’ в Xcode, за исключением того, что было показано во время демонстрации на сессии WWDC.

image

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

Один недостаток, который я вижу сейчас в данном инструменте — это отсутствие подробностей для каждого типа: только разделение — это версия приложения, и вы не можете видеть какие-либо метрики для определенной группы устройств/версий OS/регионов и т.д.

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

Оставаться в курсе событий!

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть