переопределение objc_msgSend () и его братьев и сестер в objc2.0 на iPhone - PullRequest
1 голос
/ 01 июня 2011

Я хочу сделать что-то вроде этого:

#import <sys/time.h>

typedef long long int64;

int64 int64Micro(void)
{
    struct timeval timestruct;
    gettimeofday(&timestruct, NULL);
    return ((int64)timestruct.tv_sec)*((int64)1000000)+(int64)timestruct.tv_usec;
}

int64 lasttime = 0;

id objc_msgSend(id self, SEL op, ...)
{
    int64 starttime = int64Micro();
    va_list argptr;
    va_start(argptr, op);
    id retVal = 0;//objc_msgSendv(self, op, method_getSizeOfArguments(op), argptr);
    va_end(argptr);
    int64 cost = int64Micro()-starttime;
    if(cost > 1000)
        NSLog(@"%@() : %lld µs\n", NSStringFromSelector(op), cost);
    return retVal;
}

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

Как на iPhoneдинамические библиотеки не возможны, нет способа заменить objc_msgSend-реализацию, которая вызывается предварительно скомпилированными фреймворками, без их перекомпиляции, но в моем коде фактически моя реализация вызывается вместо той, что из objc-runtime.

Но эта строка

id retVal = 0;//objc_msgSendv(self, op, method_getSizeOfArguments(op), argptr)

закомментирована, так как она должна работать в objc 1.0, но в objc 2.0 objc_msgSendv () больше не доступна, так же, как method_getSizeOfArguments ().

Итак, есть ли способ сделать это, без необходимости перестраивать среду выполнения objc и без необходимости заново реализовывать исходное поведение objc_msg.Можно ли скопировать и вставить эти тысячи строк кода сборки, зависящих от платформы, из источника среды выполнения objc?

Я уже думал о функции __builtin_apply () GCC, чтобы вызвать оригинальную функцию objc_msgSend (), ноКажется, нет способа узнать размер в байтах параметров переменной, переданных objc_msgSend () для определенного вызова.

1 Ответ

10 голосов
/ 21 июня 2011

Замена objc_msgSend для измерения производительности, как это плохая идея по нескольким причинам.

  1. На самом деле существует несколько вариантов objc_msgSend в зависимости от типов параметров и возвращаемых типов.Вам придется заново реализовать все это.
  2. Производительность вашего приложения может значительно снизиться.Когда вы пытаетесь измерить производительность, это не лучший способ сделать это.
  3. Для определенных селекторов компилятор фактически выдает указатель на функцию objc_msgSend_fixup, который затем динамически оптимизируется впоиск в таблице .Это полностью исключает традиционный objc_msgSend.Вам также придется поймать все это.
  4. objc_msgSend не может быть реализовано в C, так как это на самом деле не функция с переменным числом аргументов и не имеет прототипа, который может быть представлен в C. Из вызывающей стороныв перспективе objc_msgSend - непрозрачный батут;оно будет отправлено методу IMP, который, как ожидается, сам реализует функцию ABI, требуемую вызывающей стороной.

Существуют гораздо лучшие способы измерения производительности.

If Instruments isn 't показывая ваши медленные области, вы можете профилировать только запущенные потоки вместо всех потоков.Используя инструмент Time Profiler, щелкните маленькое «i» рядом с заголовком дорожки и выберите «Все состояния потоков».Это гарантирует, что время, потраченное на ожидание ввода / вывода, будет учтено в ваших измерениях, которые по умолчанию не учитываются.

Profiling all thread states

Если по какой-то причине это все еще неЕсли вы работаете, и вы просто хотите записать жесткий список всех времен выполнения селектора, вы можете добавить зонд DTrace с помощью поставщика DTj objc для записи времени выполнения каждого метода Objective-C.Это не будет записывать статистику для функций C, как это делают Instruments, и не будет организовывать иерархическую структуру, но если Instruments не делает это для вас, это будет.В разделе «Инструменты» выберите Instrument -> Trace Symbol.В появившемся окне введите следующее:

-[* *]

То есть отследите все методы экземпляра (-), вызываемые в любом классе (*) любого имени селектора (*).Затем запишите, и вы получите список времени, затраченного на каждый метод.Кроме того, это не побеждает вручную настроенный ассемблер во встроенном objc_msgSend и полностью поддерживается Apple.Это также не ограничивается только вашим кодом;он также будет профилировать вызовы внутри фреймворков Apple.

К сожалению, датчики DTrace в настоящее время не поддерживаются на устройствах iOS, поэтому вам придется использовать тест DTrace для приложения, работающего в симуляторе.Это явно не идеально.Если у вас действительно есть один метод, служащий горячей точкой, вероятно, он будет отображаться и в симуляторе.

Опять же, инструмент «Профиль времени» гораздо лучше подходит дляработа, и это определенно работает.Включите все состояния потоков, и вы увидите свою проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...