【问题标题】:Impact of binary code length on performance of CUDA program二进制码长对CUDA程序性能的影响
【发布时间】:2012-11-23 06:09:23
【问题描述】:

我编写了一个包含多个子例程的 CUDA 程序。当我禁用子例程 A 时,运行时间会提高 a 量。当我禁用子例程 B 时,运行时间会提高 b 量。当我禁用子例程 A 和 B 时,运行时间会提高 c > a + b。两个子程序完全相互独立。

下一部分可能是一种幼稚的分析方法,但这是我所做的:我编译了每个版本的代码并为每个二进制文件运行 cuobjdump --dump-sass。结果输出是完整的二进制文件大约 1350 行,每个二进制文件大约 1100 行,其中一个子程序被禁用。如果我禁用这两个子程序,我会得到 850 行。看来我需要前三个每行 3.1 us 和 2.4 us 来禁用两个子例程。

由于 A 和 B 不包含任何复杂的内容或比其他代码更密集地使用内存,我不认为这是由于注释掉所有时间密集型操作并让简单操作保持活动状态造成的。我的猜测是,禁用 A 和 B 的程序代码仍然适合流式多处理器的指令缓存,而其他版本太大。这可能会导致全局内存访问,以便可以加载更多程序代码,而延迟会导致这种差异。不幸的是,我找不到有关指令缓存大小的任何信息。

谁能帮我解释一下这些结果?

【问题讨论】:

  • 您在进行此类分析时需要非常小心。 GPU 编译器和汇编器具有非常激进的“死代码删除”优化。如果编译器可以确定一个代码段对写入全局内存的结果没有贡献,它只会从内核中删除整个代码段。
  • 是的,但这不应该在我运行 cuobjdump --dump-sass 时已经发生吗?我想知道运行时间的下降以及这是否与二进制代码的长度有关。
  • 当前版本的 CUDA 分析器不显示指令缓存统计信息。 Nsight Visual Studio Edition CUDA Profiler 确实显示了停顿的原因。如果主要的停顿原因是 Fetch,那么内核可能会破坏 icache,或者您有很多跳转。进一步的解释需要分析报告和代码审查。
  • 您检查过寄存器使用情况吗?可能是 A 或 B 需要的寄存器比 A 或 B 都多。减少的寄存器数量可能会提高占用率,从而提高性能。
  • 每个流式多处理器的块数受共享内存使用限制为 8 个,并且每个块使用的寄存器少于 40 个。所以那里的入住率没有增加。

标签: performance cuda


【解决方案1】:

可能有几件事会导致您的结果。一些可能包括:

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

  • 优化器发现 A 中的某些代码也存在于 B 中(A 和 B 可能仍然是独立的)。因此,同时拥有 A 和 B 比拥有单独的 A 和单独的 B 减慢程序的速度。

  • 在读取剩余代码中的数据时,只有 A 或 B(或两者都没有)会导致更好的内存访问模式或更多的缓存命中。 (我说的是数据,不是程序代码)

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

我非常怀疑指令缓存可能是问题所在。即使需要全局内存读取,它也永远不会“错位”,因为 warp 总是只需要一条指令。我的猜测是他们使用一些专用硬件来执行指令。

【讨论】:

  • 我想所有这些都是可能的。我认为第一个案例适合我的程序。我对在一个版本中展开而不在另一个版本中展开的循环进行了一些实验。由此产生的更大的二进制代码不会导致运行时间的显着差异,增加重复次数只会线性增加运行时间,正如预期的那样。虽然 cuobjdump --dump-sass 的输出大小有时很奇怪,但这似乎不会影响运行时,这让我想知道“死”代码是否有时会在优化器中幸存下来。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-02
  • 1970-01-01
  • 2021-12-11
  • 2017-05-13
  • 2023-03-26
  • 1970-01-01
相关资源
最近更新 更多