如何在Xcode Instruments中识别关键事件?

26

以前有一个很好的工具,DTSendSignalFlag,属于DTPerformanceSession框架的一部分,您可以通过编程方式将标记插入到Instruments中。(Xcode Instruments trace comparison解释了我们如何在iOS目标中使用这个macOS诊断工具)。此功能在iOS 7中停止工作。

有人成功地让DTSendSignalFlag在iOS 7中工作吗?信号标记是(曾经是)通过代码在Instruments中编程式地提交标记的有用方法(在诊断复杂的应用程序时非常有用),但是当我在iOS 7模拟器上运行时,我没有看到我通过编程创建的标记在Instruments中显示(但是当我使用Xcode 5构建iOS 6模拟器时可以正常工作)。

不用说,我也在寻找类似的针对macOS目标的工具。


2
我找不到任何关于这个的提及,或者如果它已经消失了,也没有替代品。很想能让类似这样的东西运作起来。 - perezda
2个回答

48
不再使用旗帜,我们现在可以使用以编程方式插入的路标,这些路标可以在Instruments的“兴趣点”工具中捕获。
在iOS 15和macOS 12中,我们可以使用OSSignposter。例如,在Swift中:
导入统一的日志框架: ``` import os.signpost ```
为感兴趣的点创建一个`OSSignposter`: ``` private let pointsOfInterest = OSSignposter(subsystem: Bundle.main.bundleIdentifier!, category: .pointsOfInterest) ```
当您想要开始一个感兴趣的范围时,您可以“开始”一个时间间隔: ``` let id = pointsOfInterest.makeSignpostID() let state = pointsOfInterest.beginInterval("Download", id: id, "\(index)") ```
当您想要结束一个感兴趣的范围时,您可以“结束”它: ``` pointsOfInterest.endInterval(#function, state) ```
如果您对时间范围不感兴趣,而只对单个标记感兴趣,您可以直接发出一个事件: ``` pointsOfInterest.emitEvent("Done") ```
如果您需要支持旧的操作系统版本,在iOS 13和macOS 10.15中,我们可以使用os_signpost,如WWC 2019的入门指南所示。
例如,在Swift中:
导入统一的日志框架: ``` import os.signpost ```
为感兴趣的点创建一个`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"); ```
无论如何,“Points of Interest”工具现在可以在Instruments中以图形方式表示一系列的下载和解析操作(每个队列限制为每个队列两个并发操作)。

enter image description here

请注意,在“Points of Interest”工具中,name值(一个集合中我使用了Download作为名称,另一个集合中我使用了Parse作为名称)被很好地分隔到不同的泳道中。而且,由于我使用了可选的格式字符串,我实际上可以看到消息,可以清楚地将每个下载和解析操作与我的应用程序中的特定任务相关联。
上面我使用了可选的OSSignpostID参数,因为我有多个重叠的范围,并且我想避免将特定的.end与相应的.begin混淆。如果您不使用兴趣点范围,或者您没有重叠的范围,从技术上讲,如果不存在任何可能的歧义,您实际上不需要使用此可选参数。(即使您使用这些标志点标识符,请确保相关的.begin.end标志点的name也匹配,否则Instruments将无法将它们识别为同一兴趣点范围的起始和结束,即使具有相同的标志点ID。)
无论如何,现在您已经在“Points of Interest”工具中填充了信息,您可以双击范围来选择它,或者三击范围来设置您的检查范围。
在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)

第一个参数只是一个唯一的数字代码,对应于我们在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工具栏的右侧点击“+”按钮,然后添加“兴趣点”。通过将“标志代码名称”配置为与我传递给标志的第一个参数相匹配的数字值,Instruments实际上会为我翻译这些代码。一旦我对应用程序进行了分析,我现在可以清楚地看到我的兴趣点已经被突出显示了。

enter image description here

在这个快照中,我对七个下载操作(橙色)和七个解析操作(绿色)进行了分析,分别限制为每次两个。当它们完成时,我发布了一个单独的“完成”标志(红色图钉)。但是这个演示应用程序的细节并不重要,而是展示了Instruments的“兴趣点”如何呈现单个标志和起始/结束标志。
主要问题是我现在清楚地知道了代码中的事件与Instruments中所见的事件之间的对应关系。如果我想要,我可以在标志范围列表中控制-点击一个条目,并告诉Instruments“设置时间过滤器”,这样当我返回到其他仪器(分配或时间分析器等)时,检查范围将被过滤为我应用程序中相关的兴趣点。
注意,上述是Swift。在Objective-C中,kdebug_signpost API类似,但你必须包含以下内容:
#import <sys/kdebug_signpost.h>

显然,你对代码中的枚举定义的方式也会发生变化。
请注意,这个`kdebug_signpost` API是在iOS 10/macOS 10.12中引入的。头文件告诉我们早期的操作系统版本可以使用`syscall`。

In previous versions of the operating system, applications could use:

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

to record events that would be displayed by Instruments. syscall(2) is now deprecated and this interface replaces the above call.

注意:如果你发现自己在早期的操作系统版本上不得不使用syscall,你将需要导入<sys/kdebug.h>
#import <sys/kdebug.h>

此外,我在任何头文件中都找不到关于SYS_kdebug_trace的声明,但在网上偶然发现了一个参考,称该值为180,我进行了实证验证。
#ifndef SYS_kdebug_trace
#define SYS_kdebug_trace 180
#endif

1
有没有办法在Instruments中保存/应用常用的标志配置(例如,帮助调试共享公共代码库的多个应用程序)?是否有任何方法可以直接使用dtrace监视标志事件(而不使用Instruments)?顺便说一句,非常好的答案! - lilinjn
1
@lilinjn - 在Instruments的“文件”菜单中使用“另存为模板…”选项。然后,下次运行Instruments时,不要选择标准工具之一,而是点击“自定义”,您会在那里看到保存的模板。至于dtrace,我不知道。 - Rob
2
我能控制新API中的颜色吗?我真的很想念那个...我知道它可以为我分组,但我无法动态地分配组名——这是什么样的落后API... - Paulius Liekis
2
据我所知,新的API不会公开用于颜色编码的第四个参数。理论上,您可以使用kdebug API并失去lanes,但获得着色,并忽略/抑制弃用警告。但这只是一个短期解决方案。 - Rob
1
@PauliusLiekis 您还可以编写自己的自定义工具,并使用事件概念工程类型来控制颜色(通过引用显式颜色名称或语义“事件概念”值)。例如,请参见https://stackoverflow.com/a/67852179/1271826(其中我正在诊断自定义仪器的特定习惯性功能)。自定义仪器有点复杂,但一旦您克服了如何做到这一点的非微不足道的障碍,对车道进行着色就变得非常简单。 - Rob
显示剩余13条评论

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接