提高 Burst 检查器的搜索性能

我叫 Jonas Reholt,是 Burst 团队的一名学生。我在博客上分享了我的优化历程,正是这些优化使 Burst 检查器最近的性能变化成为可能。Burst Inspector 的搜索速度现在提高了 13 倍,使开发人员在优化项目时能更快地专注于他们关心的代码。
继续阅读,了解如何使用 Unity Profiler 调查程序中的性能瓶颈以及如何修复它们。
Unity Burst 编译器可将 C# 代码转换为高度优化的汇编代码。Burst 检查器可让您直接在 Unity 编辑器中检查该汇编代码,因此您无需使用外部工具来进行简单的代码检查。
首次打开 Burst 检查器并选择要显示的目标作业时,会看到一个类似下图的窗口。

如您所见,Burst 检查器提供语法高亮显示、分支流箭头等功能。
检查器会尝试滚动到执行所选目标功能的装配体,但也可以在装配体视图中搜索具体说明、注释等。这就是本博文的主题。
要执行搜索,检查器必须搜索原始装配输出,并将这些索引转换为检查器视图中的位置。最初的搜索功能遵循下图所示的模式,并在很大程度上依赖于System.String.IndexOf(*) 的实现。
while (assemblyCode.IndexOf(key, accIdx) >= 0) {
// ...
// Do logic for handling search hits
// ...
}
在 135,582 行汇编代码上运行上述搜索,进行一次普通搜索命中(共 21,769 次命中),第一次搜索的执行时间约为 12 秒,后续搜索的执行时间约为 5 秒。对于 GUI 事件来说,这并不是一个理想的等待时间,所以我们必须做点什么。通过 Unity Profiler 运行搜索发现,37.3% 的执行时间花在IndexOf(*) 上,如下所示。

合理的优化必须解决对该函数的依赖问题,要么是定制实现,要么是完全改变算法。无论使用哪种算法,都需要步进整个字符串。因此,需要定制一些用于查找匹配项的实现方法。有鉴于此,开始优化时保留原有算法,但创建一个自定义IndexOf函数似乎是合适的。
LongTextArea.GetFragNrFromBlockIdx()耗时 3.34 秒,是因为要检索未着色的程序集代码。用于执行搜索。Burst 检查器目前会保存两次程序集代码,一次是格式化后的渲染代码,另一次是未格式化的代码。
编写自定义函数还有一个很好的副作用,就是减少了调用次数,因为目前每次搜索命中都要调用一次,外加一次。
IndexOf(*)的源代码揭示了一个强大的通用实现所需的许多安全检查。不过,就我们的情况而言,我们可以有把握地假设这些检查大部分都是正确的。为了尽量提高性能,您需要创建一个类似 C 语言的函数,以避免边界检查等问题。
您可以按照下面的伪代码编写函数,其中IsKeyMatch(*)只是检查键是否匹配。
List<int> Search(string assemblyCode, string key, int accIdx) {
var hits = new List<int>();
for (i = accIdx; i < assemblyCode.len - key.len; i++) {
if (IsKeyMatch(assemblyCode, key, i)) {
hits.add(i);
i += key.len-1;
}
}
return hits;
}
不过,由于 C# 是托管语言,这个类似于 C 语言的功能需要您将使用的托管 Objective-C 钉住,这样垃圾回收器就不会重新定位内存地址。以下是模板代码:
unsafe {
fixed (char* source = assemblyCode) {
fixed (char* needle = key) {
CustomIndexOf(source, key)
}
}
}
把这些东西放在一起,就能把原来的while循环分离成对索引查找器的单次调用和处理搜索命中的逻辑:
matches = FindAllMathces(text, key)
foreach match {
...
Do logic for handling search hits
...
}
收获是什么?以之前的小例子为例,对代码的这一改动使首次调用的速度提高了 6.6 倍,后续调用的速度提高了 13.2 倍(以新/旧值衡量)。初始搜索速度较低的原因是,为了避免在颜色字符串中找到匹配项,需要加载未格式化的程序集。

有了这些改进,现在,点击量略低于 22,000 次的重载搜索,首次搜索耗时约为 1.8 秒,后续搜索耗时约为 0.4 秒。这使得 Burst 检查器更适用于大型装配,因为每次搜索时不再有足够的时间来泡一杯茶。
您现在就可以通过 Burst 1.8.7 软件包利用这一性能改进。
想了解 Burst 的更多信息?在Burst论坛与我们联系。作为Tech from the Trenches系列的一部分,请务必关注来自其他 Unity 开发人员的更多新技术博客。