二进制代码长度对CUDA程序性能的影响

4
我写了一个CUDA程序,其中包含多个子程序。当我禁用子程序A时,运行时间提高了a数量级。当我禁用子程序B时,运行时间提高了b数量级。当我禁用子程序A和B时,运行时间提高了c数量级,且c>a+b。两个子程序是完全独立的。
下面这部分可能是一种天真的分析方法,但这是我所做的:我编译了每个版本的代码,并对每个二进制文件运行了"cuobjdump --dump-sass"。完整二进制文件的输出结果约为1350行,而禁用一个子程序的二进制文件的输出结果约为1100行。如果我同时禁用两个子程序,输出结果为850行。似乎我需要3.1微秒才能处理前三个版本的每一行,而禁用两个子程序后,我只需要2.4微秒。
由于A和B不包含任何复杂的内容,也不比代码中其他部分更密集地使用内存,因此我认为这不是通过注释掉所有耗时操作并保留简单操作来实现的。我的猜测是,禁用A和B的程序代码仍适合于流多处理器的指令缓存,而其他版本过大。这可能导致全局内存访问,以便可以加载更多的程序代码,而延迟导致了这种差异。不幸的是,我找不到任何有关指令缓存大小的信息。
请问是否有人可以帮助我解释这些结果?

3
进行此类分析时需要非常小心。GPU编译器和汇编器具有非常激进的“死代码删除”优化功能。如果编译器能够确定某个代码部分对写入全局内存的结果没有贡献,它将从内核中完全删除整个代码段。 - talonmies
是的,但当我运行<em>cuobjdump --dump-sass</em>时,这不应该已经发生了吗?我想知道运行时间的下降是否与二进制代码的长度有关。 - volker
1
目前的CUDA分析工具版本不显示指令缓存统计信息。Nsight Visual Studio Edition CUDA分析工具可以显示停顿原因。如果主要停顿原因是Fetch,则内核很可能正在抢占icache或者有很多跳转。进一步的解释需要分析报告和代码审查。 - Greg Smith
你有检查寄存器的使用情况吗?可能是因为要使用A或B中的任意一个需要比不使用A和B更多的寄存器。减少寄存器数量可能会提高占用率和性能。 - Matt
每个流多处理器的块数由共享内存使用限制为8,并且每个块使用的寄存器少于40个。因此,在那里没有增加占用率。 - volker
1个回答

0

导致您的结果可能有几个原因,其中一些可能包括:

  • 缺少 A 和 B 可能会导致剩余代码的某些额外优化。生成的代码可能不会更短,但可能仍然执行得更快。

  • 优化器发现 A 中的某些代码也存在于 B 中(A 和 B 可能仍然是独立的)。因此,同时具有 A 和 B 比分别具有 A 和 B 的效果更好。

  • 仅具有 A 或 B(或两者都没有)可以在读取剩余代码中的数据时获得更好的内存访问模式或更多的缓存命中。 (我谈论的是数据,而不是程序代码)

  • 缺少 A 和 B 可能会导致更好的占用率,允许更多线程同时运行。

我非常怀疑指令高速缓存可能是问题所在。即使需要全局内存读取,它也永远不会“未对齐”,因为每个warp始终只需要一条指令。我的猜测是他们在使用一些专用硬件来处理指令。


我猜这些都是可能的。我认为第一种情况适合我的程序。我进行了一些实验,其中一个版本中展开了一个循环,而另一个版本没有展开。结果更大的二进制代码并没有导致运行时的显着差异,增加重复次数只会按预期线性地增加运行时间。虽然_cuobjdump --dump-sass_的输出大小有时很奇怪,但这似乎不会影响运行时间,这让我想知道“死”代码是否有时会幸存于优化器中。 - volker

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