我们现在可以使用在 Instrument 的“兴趣点”中捕获的以编程方式插入的路标,而不是使用标志。
在 iOS 13 和 macOS 10.15 中,我们可以使用os_signpost。这在 WWDC 2019 视频Getting Started with Instruments 中有说明。
例如,在 Swift 中:
-
导入统一的日志框架:
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")
或者在 Objective-C 中:
-
导入统一的日志记录路标框架:
@import os.signpost;
-
为兴趣点创建OSLog:
os_log_t log = os_log_create("ViewController", OS_LOG_CATEGORY_POINTS_OF_INTEREST);
-
当你想开始一个兴趣点范围时,你可以.begin一个兴趣点:
os_signpost_id_t identifier = os_signpost_id_generate(log);
os_signpost_interval_begin(log, identifier, "Download", "Started %d", index);
-
当你想结束一个兴趣点范围时,你可以.end它:
os_signpost_interval_end(log, identifier, "Download", "Finished %d", index);
-
如果您对某个时间范围不感兴趣,而对单个路标感兴趣,则可以发布.event:
os_signpost_event_emit(log, OS_SIGNPOST_ID_EXCLUSIVE, "Done");
无论如何,“兴趣点”工具现在可以在 Instruments 中以图形方式表示一系列下载和解析操作(每个队列限制为每个队列两个并发操作):
请注意,name 值(一组我使用了名称Download,另一组我使用了Parse)在兴趣点工具中很好地分成了不同的泳道。而且因为我使用了可选的格式字符串,我实际上可以看到消息,我可以清楚地将每个下载和解析操作与我的应用程序中的特定任务相关联。
上面我使用了可选的OSSignpostID 参数,因为我有多个重叠的范围,我想避免将特定的.end 与相应的.begin 相关联的任何混淆。如果您不使用兴趣点范围或没有重叠范围,则在不可能存在歧义的情况下,从技术上讲,您不需要使用此可选参数。 (即使您使用这些路标标识符,请确保关联的.begin 和.end 路标的name 也匹配,否则仪器不会将它们识别为同一兴趣点范围的开始和结束,即使使用相同的路标 ID。)
无论如何,既然您已经拥有填充了信息的“兴趣点”工具,您可以双击一个范围来选择它,或者三次单击它来设置您的检查范围。
在 iOS 10 和 macOS 10.12 中,我们使用了kdebug_signpost。这在 WWDC 2016 视频System Trace in Depth 中有说明。
对于那些花费离散时间的进程,我们可以使用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)
第一个参数只是一些唯一的数字代码,对应于我们将在 Instruments 中使用的“路标代码名称”。你可以使用任何你想要的值(介于 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 调用,我将使用最后一个参数在 Instruments 中对我的区域进行颜色编码:
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
}
完成此操作后,您可以在 Instruments 中配置应用程序,单击 Instruments 工具栏右侧的“+”按钮,然后添加“Points of Interest”。通过配置“路标代码名称”以匹配我作为第一个参数传递给路标的数值,仪器实际上会为我翻译这些代码。一旦我对应用进行了概要分析,我现在就可以清楚地突出显示我的兴趣点:
在此快照中,我分析了七个下载操作(橙色)和七个解析操作(绿色),一次限制为两个。当他们完成后,我张贴了一个“完成”路标(红色针脚)。但是这个演示应用程序的细节并不重要,而这只是说明了如何在 Instruments 的“兴趣点”中呈现单个路标和开始/结束路标。
主要问题是我现在在我的代码中的事件和我在 Instruments 中看到的事件之间有了明确的对应关系。如果需要,我可以控制-单击路标范围列表中的条目并告诉仪器“设置时间过滤器”,这样当我回到我的其他仪器(分配或时间探查器或其他),检查范围被过滤到我的应用程序中的相关兴趣点。
注意,以上是 Swift。在 Objective-C 中,kdebug_signpost API 是类似的,但你必须包括:
#import <sys/kdebug_signpost.h>
显然,您为代码定义枚举的方式也会发生变化。
注意,这个kdebug_signpost API 是在 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,则必须导入 <sys/kdebug.h>:
#import <sys/kdebug.h>
另外,我在任何标题中都找不到SYS_kdebug_trace 的声明,但偶然发现了网上的参考资料,上面说这个值为180,我凭经验验证了这一点:
#ifndef SYS_kdebug_trace
#define SYS_kdebug_trace 180
#endif