【问题标题】:Cuda signed 128-bit multiplication errorCuda 签名 128 位乘法错误
【发布时间】:2016-02-13 22:53:41
【问题描述】:

我想我在使用有符号整数在 cuda PTX 中进行 128 位有符号乘法时发现了一个问题。 这是我的示例代码:

long long result_lo, result_hi;
asm(" mul.lo.s64 %0, 0, -1;     \n\t" // 0 * -1 = 0
    " mul.hi.s64 %1, 0, -1;     \n\t"
    : "=l"(result_lo), "=l"(result_hi));

这应该会产生结果result_lo = 0x0, result_hi = 0x0。然而,这会产生结果:result_lo = 0x0, result_hi = 0xFFFFFFFFFFFFFFFF 如果我没有记错并且显然不是零,这实际上是值 2^127 - (2^126 - 1)

首先,我想确保我的理解是正确的,但是,有没有办法解决这个问题?

更新Debug mod 更改为Release 模式修复了这个问题,仍然想知道这是否是 cuda 中的错误?

更新 2 将此错误报告给 NVIDIA

在 Visual Studio 2013 中使用了 Cuda 工具包 7.5。x64 Debugsm_52compute_52

【问题讨论】:

  • 这可能是sm_52 的调试模式下的错误。我可以在sm_52 调试模式下重现它,但不能在sm_35sm_20 上重现。请注意,maxwell 设备没有原生 64 位整数乘法运算;编译器生成 32 位操作序列。因此this 可能会引起人们的兴趣。
  • @RobertCrovella 由于 sm_5x(相对于 sm_2x,sm_3x)在硬件中甚至没有 32 位整数乘法器,所以 sm_5x 上 64 位整数乘法的仿真序列必然与仿真不同用于 sm_2x、sm_3x 的序列。一个特定于 sm_5x 的错误报告似乎是有序的。
  • 是的,我已经提交了一个错误。
  • 作为一种解决方法,您需要确保 PTXAS 优化级别至少为 -O1。在 PTXAS 优化级别 -O0(用于调试构建),正在为 sm_5x 目标发出错误的仿真序列(FWIW,这个仿真序列看起来不像我期望的那样)。所以尝试使用-Xptxas -O1 或更高版本进行构建。
  • @njuffa:如果您愿意添加它,那将是一个完美的答案。

标签: cuda ptx


【解决方案1】:

TL;DR 这似乎是模拟 PTX 指令 mul.hi.s64 中的一个错误,该指令特定于 sm_5x 平台,因此建议向 NVIDIA 提交错误报告行动。

通常,NVIDIA GPU 是 32 位架构,因此所有 64 位整数指令都需要仿真序列。在 64 位整数乘法的特定情况下,对于sm_2xsm_3x 平台,这些是从机器代码指令IMAD.U32 构造的,它是一个32 位整数乘加指令。

对于 Maxwell 架构(即 sm_5x),引入了高吞吐量但宽度较低的整数乘加指令 XMAD,尽管低吞吐量的传统 32 位整数乘法 @987654328 @ 显然被保留了。检查由带有cuobjdump --dumpsass 的CUDA 7.5 工具链为sm_5x 生成的反汇编机器代码表明,对于ptxas 优化级别-O0(用于调试构建),64 位乘法用@987654333 模拟@ 指令,而对于优化级别 -O1 和更高的 XMAD 被使用。我想不出为什么要使用两种完全不同的仿真序列。

事实证明,基于IMULmul.hi.s64sm_5x 的仿真被破坏,而基于XMAD 的仿真工作正常。因此,一种可能的解决方法是通过在nvcc 命令行上指定-Xptxas -O1,为ptxas 使用至少-O1 的优化级别。请注意,发布版本默认使用-Xptxas -O3,因此发布版本无需采取任何纠正措施。

从代码分析来看,mul.hi.s64 的仿真是作为mul.hi.u64 仿真的包装器实现的,后一种仿真似乎在包括sm_5x 在内的所有平台上都能正常工作。因此,另一种可能的解决方法是使用我们自己的 mul.hi.u64 包装器。在这种情况下,不需要使用内联 PTX 进行编码,因为可以通过设备内部函数 __mul64hi()__umul64hi() 访问 mul.hi.s64mul.hi.u64。从下面的代码可以看出,将结果从无符号乘法转换为有符号乘法的调整非常简单。

    long long int m1, m2, result;
#if 0 // broken on sm_5x at optimization level -O0
    asm(" mul.hi.s64 %0, %1, %2;     \n\t"
        : "=l"(result)
        : "l"(m1), "l"(m2));
#else
    result = __umul64hi (m1, m2);
    if (m1 < 0LL) result -= m2;
    if (m2 < 0LL) result -= m1;
#endif

【讨论】:

    猜你喜欢
    • 2015-05-02
    • 2015-11-28
    • 1970-01-01
    • 2012-03-03
    • 1970-01-01
    • 2011-09-03
    • 2016-05-22
    • 1970-01-01
    相关资源
    最近更新 更多