Альтернатива DTSendSignalFlag для определения ключевых событий в Инструментах?

Раньше был хороший инструмент, DTSendSignalFlag, часть рамки DTPerformanceSession, благодаря которой вы могли программно вставлять флаги в Инструменты (см. Сравнение трассировки Xcode Instruments). Эта функция перестала работать в iOS 7.

Кто-нибудь преуспел в том, чтобы DTSendSignalFlag работать в iOS 7? Сигнальные флаги являются (были?) Полезным способом программно размещать флаги в Инструментах по коду (очень полезно при диагностировании сложных приложений в Инструментах), но я не вижу свои программно созданные флаги в Инструментах, когда я запускаю симулятор iOS 7 ( но он работает, когда у меня есть Xcode 5 для симулятора iOS 6).

Ответы

Ответ 1

Вместо использования флагов мы можем теперь использовать программно вставленные указатели, которые фиксируются в инструменте "Достопримечательности".

В iOS 13 и macOS 10.15 мы можем использовать os_signpost. Это показано в видео WWDC 2019 Начало работы с инструментами.

  • Импортируйте единую структуру ведения журнала:

    import os.log
    
  • Создайте OSLog для достопримечательностей:

    private let pointsOfInterest = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: .pointsOfInterest)
    
  • Если вы хотите начать диапазон точек интереса, вы можете. .begin точку интереса:

    let id = OSSignpostID(log: pointsOfInterest)
    os_signpost(.begin, log: pointsOfInterest, name: "Download", signpostID: id, "Download %d", index)
    
  • Если вы хотите, чтобы закончить точки диапазона интереса, вы можете .end его:

    os_signpost(.end, log: pointsOfInterest, name: "Download", signpostID: id, "Download %d", index)
    
  • Если вы не заинтересованы в определенном интервале времени, а предпочитаете один указатель, вы можете просто опубликовать .event:

    os_signpost(.event, log: pointsOfInterest, name: "Done", "All done")
    

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

enter image description here

Обратите внимание, что значения name (в одном наборе я использовал имя Download а в другом - Parse) красиво разделены на разные дорожки в инструменте Points of Interest. И поскольку я использовал необязательные строки формата, я на самом деле могу видеть сообщения, в которых я могу четко соотнести каждую операцию загрузки и анализа с конкретной задачей в моем приложении.

Выше я использовал необязательные параметры OSSignpostID потому что у меня было несколько перекрывающихся диапазонов, и я хотел избежать путаницы, связывающей конкретный .end с соответствующим .begin. Если вы либо не используете диапазоны точек интереса, либо у вас нет перекрывающихся диапазонов, вам не нужно использовать этот необязательный параметр. Например, вы можете просто сделать:

os_signpost(.begin, log: pointsOfInterest, name: "SomeTask")
asynchronousMethod {
    os_signpost(.end, log: pointsOfInterest, name: "SomeTask")
}

В любом случае, теперь, когда у вас есть инструмент "Достопримечательности", заполненный информацией, вы можете удвоить -click в диапазоне, чтобы выбрать его, или в три раза -click, чтобы также установить свой диапазон проверки.


В iOS 10 и macOS 10.12 мы использовали kdebug_signpost. Это проиллюстрировано на трассе видеосистемы WWDC 2016 в глубине.

Для тех процессов, которые занимают определенное количество времени, мы можем использовать kdebug_signpost_start и kdebug_signpost_end. Например:

kdebug_signpost_start(SignPostCode.download.rawValue, UInt(index), 0, 0, SignPostColor.orange.rawValue)
performDownload {
    kdebug_signpost_end(SignPostCode.download.rawValue, UInt(index), 0, 0, SignPostColor.orange.rawValue)
}

Чтобы отметить один момент времени, мы можем просто использовать kdebug_signpost:

kdebug_signpost(SignPostCode.done.rawValue, 0, 0, 0, SignPostColor.red.rawValue)

Первый параметр - это просто некоторый уникальный числовой код, который соответствует "кодовому имени указателя", которое мы будем использовать в инструментах. Вы можете использовать любые значения (от 0 до 16383), но я использую то, что обозначает тип задачи:

enum SignPostCode: UInt32 {   // some custom constants that I'll reference in Instruments
    case download = 0
    case parse = 1
    case done = 2
}

Остальные параметры могут быть любыми значениями UInt вы хотите, но в моем примере я буду использовать второй параметр в качестве уникального идентификатора для сопоставления повторяющихся start и end вызовов, и я буду использовать последний параметр для цветовой кодировки моих регионов в инструментах:

enum SignPostColor: UInt {    // standard color scheme for signposts in Instruments
    case blue = 0
    case green = 1
    case purple = 2
    case orange = 3
    case red = 4
}

Сделав это, вы можете затем профилировать приложение в разделе "Инструменты", нажать кнопку "+" в правой части панели инструментов и добавить "Точки интереса". Сконфигурировав "Имена кодов указателей", чтобы они соответствовали числовым значениям, которые я передал в качестве первого параметра моим указателям, Инструменты фактически переведут эти коды для меня. После того, как я профилировал приложение, и теперь у меня есть четко обозначенные пункты интереса:

enter image description here

В этом снимке я профилировал семь операций загрузки (оранжевым цветом) и семь операций синтаксического анализа (зеленым цветом), ограничив их до двух одновременно. И когда они были сделаны, я разместил единый указатель "сделано" (красный). Но детали этого демонстрационного приложения не являются критическими, а скорее всего лишь иллюстрируют, как единичные указатели и начальные/конечные указатели отображаются в "точках интереса" инструментов.

Основная проблема заключается в том, что теперь у меня есть четкое соответствие между событиями в моем коде и тем, что я вижу в инструментах. И я могу control -click на записи в списке диапазонов указателей и сказать инструментам "Установить фильтр времени", если я хочу, чтобы, когда я возвращаюсь к другим своим инструментам (распределению или профайлеру времени или как угодно), диапазон проверки отфильтрован до соответствующих точек интереса в моем приложении.


Обратите внимание, что выше Swift. В Objective-C API kdebug_signpost похож, но вы должны включить:

#import <sys/kdebug_signpost.h>

Очевидно, что и то, как вы определяете свои перечисления для ваших кодов, тоже изменится.

Обратите внимание, этот API kdebug_signpost был представлен в iOS 10/macOS 10.12. Заголовки говорят нам, что более ранние версии ОС могли использовать syscall:

В предыдущих версиях операционной системы приложения могли использовать:

syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, <your event code>) | DBG_FUNC_<type>, arg1, arg2, arg3, arg4);

для записи событий, которые будут отображаться с помощью инструментов. syscall(2) теперь устарела, и этот интерфейс заменяет вышеуказанный вызов.

Примечание. Если вам syscall использовать syscall в более ранней версии ОС, вам придется импортировать <sys/kdebug.h>:

#import <sys/kdebug.h>

Кроме того, я не смог найти объявление SYS_kdebug_trace ни в одном из заголовков, но наткнулся на ссылку в Интернете, в которой говорилось, что это значение равно 180, что я проверял эмпирически:

#ifndef SYS_kdebug_trace
#define SYS_kdebug_trace 180
#endif