当 运行 在不同的设备上(CPU vs GPU)时,OpenCL 内核函数产生不同的结果

OpenCL kernel function yields different results when running on different devices (CPU vs GPU)

我正在尝试理解我的 OpenCL 内核函数中发生的奇怪行为。我基本上是在尝试将包含十六进制的字符串转换为包含其十进制表示形式的字符串,但是由于我无法理解的原因,运行 使用 GPU 和 CPU 产生不同的结果。

内核如下所示:

 // yes, there's no result defined for the moment
__kernel void testKernel(__global uint message_length, __global char *message) {

  size_t converted_message_length = message_length / 2;
  char converted_message[converted_message_length];

  // (1) hex to decimal conversion 
  for (size_t idx = 0, j = 0; idx < converted_message_length; idx++, j++) {
    converted_message[idx] = (message[j] & '@' ? message[j] + 9 : message[j]) << 4;
    j++;
    converted_message[idx] |= (message[j] & '@' ? message[j] + 9 : message[j]) & 0xF;
    printf("converted '%c%c' into '%i'\n", message[j - 1], message[j], converted_message[idx]);
  }

  // (2) this should be redundant, since I already print the content...
  // but actually behaves differently with different device (CPU/GPU)
  for (size_t idx = 0, j = 0; idx < converted_message_length; idx++, j++) {
    printf("converted_message[%i]: '%i'\n", idx, converted_message[idx]);
  }

现在,如果我将长度 4 作为 testKernel 函数的参数传递,并输入包含十六进制值的字符串 3e2b,我希望它们被转换为小数 6243see this table 用于十六进制 -> 十进制转换)。

而且,如果我 运行 内核使用我的 CPU(Intel(R) Core(TM) i9-9880H),我确实可以看到发生以下转换:

converted '3e' into '62'
converted '2b' into '43'
converted_message[0]: '62'
converted_message[1]: '43'

但是,如果我 运行 使用我的 GPU (AMD Radeon Pro 5500M) 这个完全相同的内核,我会看到以下结果:

converted '3e' into '62'
converted '2b' into '43'
converted_message[0]: '0'  <-- why it is 0 ???
converted_message[1]: '0'  <-- why it is 0 ???

似乎 converted_message 已成功写入循环 (1) 内,但当我进入 (2) 循环时其值丢失。这怎么可能?是 OpenCL 在幕后执行了一些奇怪的优化,只有在 GPU 中 运行 时才会表现出来吗?

char converted_message[converted_message_length];

这是一个变长数组not supported in standard OpenCL。它可能作为扩展在某些 OpenCL 实现上工作,但不可移植。

为数组指定固定大小或在主机上分配缓冲区。