Пользовательский профилировщик производительности для Objective C - PullRequest
2 голосов
/ 19 марта 2012

Я хочу создать простую в использовании и облегченную структуру профиля производительности для Objective C. Моя цель - измерить узкие места моего приложения.

Просто упомяну, что я не новичок и мне известны инструменты / Time Profiler.Это не то, что я ищу.Time Profiler - отличный инструмент, но он слишком ориентирован на разработчиков.Мне нужна среда, которая может собирать данные о производительности от пользователей QA или опытных пользователей и даже использовать их в реальной производственной среде для сбора реальных данных.

Основная часть этой среды - это возможность измерять, сколько временибыло потрачено в сообщении Objective C (я собираюсь профилировать только сообщения Objective C).

Самый простой способ - запустить таймер в начале сообщения и остановить его в конце.Это самый простой способ, но его недостатком является то, что он утомителен и подвержен ошибкам - если какое-либо сообщение имеет более 1 пути возврата, то потребуется добавлять код «таймера остановки» перед каждым возвратом.

IЯ думаю о том, чтобы использовать метод Swizzling (просто заметьте, что я знаю, что Apple недовольна методом Swizzling, но эти профилированные сборки будут использоваться только для внутреннего использования - не будут загружены в App Store).

Моя идеячтобы пометить каждое сообщение, которое я хочу профилировать, и автоматически сгенерировать код для метода swizzling (возможно, с помощью макросов).При запуске приложение будет переключаться между исходным селектором и сгенерированным.Сгенерированный просто запустит таймер, вызовет оригинальный метод и затем остановит таймер.Так что в общем метод swizzled будет просто оберткой оригинального.

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

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

Также буду очень признателен, если у вас есть какая-либо другая идея (помимо метода метания), как измерить производительность.

1 Ответ

1 голос
/ 18 июля 2012

Я нашел решение, которое работает для меня довольно хорошо.Сначала просто уточнить, что я не смог найти простой (и быстрый по быстродействию) способ автоматической генерации подходящих методов swizzled для произвольных селекторов (то есть с произвольными аргументами и возвращаемым значением), используя только имя селектора.Поэтому мне пришлось добавить типы аргументов и возвращаемое значение для каждого селектора, а не только имя селектора.В действительности должно быть относительно легко создать небольшой инструмент, который сможет анализировать все исходные файлы и автоматически определять типы аргументов и возвращаемое значение селектора, который мы хотим профилировать (и подготовить методы swizzled), но правильнотеперь мне не нужно такое автоматизированное решение.

Так что сейчас мое решение включает в себя вышеупомянутые идеи для метода swizzling, некоторый код C ++ и макросы для автоматизации и минимизации некоторого кодирования.

Сначала здесьпростой класс C ++, который измеряет время

class PerfTimer
{    
public:
    PerfTimer(PerfProfiledDataCounter* perfProfiledDataCounter);
    ~PerfTimer();

private:
    uint64_t _startTime;

    PerfProfiledDataCounter* _perfProfiledDataCounter;
};

Я использую C ++, чтобы использовать этот деструктор, когда объект выйдет из текущей области видимости.Идея состоит в том, чтобы создать PerfTimer в начале каждого метода Swizzled, и он позаботится об измерении истекшего времени для этого метода

PerfProfiledDataCounter - это простая структура, которая подсчитывает количество выполнения и все затраченное время (поэтому он может узнать, сколько времени в среднем уходит).

Кроме того, я создаю для каждого класса, который мне нужен профиль, категорию с именем "__Performance_Profiler_Category" и соответствует протоколу "__Performance_Profiler_Marker".Для облегчения создания я использую некоторые макросы, которые автоматически создают такие категории.Также у меня есть набор макросов, которые принимают имя селектора, тип возвращаемого значения и тип аргумента и создают селекторы для каждого имени селектора.

Для всех вышеперечисленных задач я создал набор макросов, чтобы помочь мне.Также у меня есть один файл с расширением .mm для регистрации всех классов и всех селекторов, которые я хотел бы профилировать.При запуске приложения я использую среду выполнения для извлечения всех классов, соответствующих протоколу "__Performance_Profiler_Marker" (то есть зарегистрированных), и поиска селекторов, помеченных для профилирования (эти селекторы начинаются с предопределенного префикса).Обратите внимание, что этот файл .mm является единственным файлом, для которого требуется расширение .mm, и нет необходимости изменять расширение файла для каждого класса, который я хочу профилировать.

После этого код превращает оригинальные селекторы в профилированные.В каждом профилированном я просто создаю PerfTimer и вызываю метод swizzled.

Вкратце, это моя идея, которая сработала довольно гладко.

...