指定 gencode 时 CUB ReduceByKey 结果不正确
Incorrect results with CUB ReduceByKey when specifying gencode
在我的一个项目中,我在使用 CUB 时看到了一些不正确的结果
DeviceReduce::ReduceByKey。但是,使用相同的 inputs/outputs 和 thrust::reduce_by_key 会产生预期的结果。
#include "cub/cub.cuh"
#include <vector>
#include <iostream>
#include <cuda.h>
struct AddFunctor {
__host__ __device__ __forceinline__
float operator()(const float & a, const float & b) const {
return a + b;
}
} reduction_op;
int main() {
int n = 7680;
std::vector < uint64_t > keys_h(n);
for (int i = 0; i < 4000; i++) keys_h[i] = 1;
for (int i = 4000; i < 5000; i++) keys_h[i] = 2;
for (int i = 5000; i < 7680; i++) keys_h[i] = 3;
uint64_t * keys;
cudaMalloc(&keys, sizeof(uint64_t) * n);
cudaMemcpy(keys, &keys_h[0], sizeof(uint64_t) * n, cudaMemcpyDefault);
uint64_t * unique_keys;
cudaMalloc(&unique_keys, sizeof(uint64_t) * n);
std::vector < float > values_h(n);
for (int i = 0; i < n; i++) values_h[i] = 1.0;
float * values;
cudaMalloc(&values, sizeof(float) * n);
cudaMemcpy(values, &values_h[0], sizeof(float) * n, cudaMemcpyDefault);
float * aggregates;
cudaMalloc(&aggregates, sizeof(float) * n);
int * remaining;
cudaMalloc(&remaining, sizeof(int));
size_t size = 0;
void * buffer = NULL;
cub::DeviceReduce::ReduceByKey(
buffer,
size,
keys,
unique_keys,
values,
aggregates,
remaining,
reduction_op,
n);
cudaMalloc(&buffer, sizeof(char) * size);
cub::DeviceReduce::ReduceByKey(
buffer,
size,
keys,
unique_keys,
values,
aggregates,
remaining,
reduction_op,
n);
int remaining_h;
cudaMemcpy(&remaining_h, remaining, sizeof(int), cudaMemcpyDefault);
std::vector < float > aggregates_h(remaining_h);
cudaMemcpy(&aggregates_h[0], aggregates, sizeof(float) * remaining_h, cudaMemcpyDefault);
for (int i = 0; i < remaining_h; i++) {
std::cout << i << ", " << aggregates_h[i] << std::endl;
}
cudaFree(buffer);
cudaFree(keys);
cudaFree(unique_keys);
cudaFree(values);
cudaFree(aggregates);
cudaFree(remaining);
}
当我包含“-gencode arch=compute_35,code=sm_35”(对于 Kepler GTX Titan)时,它会产生错误的结果,但是当我完全忽略这些标志时,它有效。
$ nvcc cub_test.cu
$ ./a.out
0, 4000
1, 1000
2, 2680
$ nvcc cub_test.cu -gencode arch=compute_35,code=sm_35
$ ./a.out
0, 4000
1, 1000
2, 768
我使用了一些其他 CUB 调用没有问题,只有这个行为不正常。我还在 GTX 1080 Ti 上尝试了 运行 这段代码(使用
compute_61、sm_61) 并看到相同的行为。
省略这些编译器标志是正确的解决方案吗?
在一台机器上试过:
- cuda 8.0
- ubuntu16.04
- gcc 5.4.0
- 幼崽 1.6.4
- Kepler GTX Titan(计算能力 3.5)
另一个是:
- cuda 8.0
- ubuntu16.04
- gcc 5.4.0
- 幼崽 1.6.4
- Pascal GTX 1080 Ti(计算能力 6.1)
听起来您应该在 CUB repository issues page 提交错误报告。
编辑: 我可以重现这个问题:
[joeuser@myhost:/tmp]$ nvcc -I/opt/cub -o a a.cu
nvcc warning : The 'compute_20', 'sm_20', and 'sm_21' architectures are deprecated, and may be removed in a future release (Use -Wno-deprecated-gpu-targets to suppress warning).
[joeuser@myhost:/tmp]$ ./a
0, 4000
1, 1000
2, 2680
[joeuser@myhost:/tmp]$ nvcc -I/opt/cub -o a a.cu -gencode arch=compute_30,code=sm_30
[joeuser@myhost:/tmp]$ ./a
0, 4000
1, 1000
2, 512
相关信息:
- CUDA:8.0.61
- nVIDIA 驱动程序:375.39
- 分布:GNU/Linux薄荷 18.1
- Linux内核:4.4.0
- 海湾合作委员会:5.4.0-6ubuntu1~16.04.4
- 幼崽:1.6.4
- GPU:GTX 650 Ti(计算能力 3.0)
在我的一个项目中,我在使用 CUB 时看到了一些不正确的结果 DeviceReduce::ReduceByKey。但是,使用相同的 inputs/outputs 和 thrust::reduce_by_key 会产生预期的结果。
#include "cub/cub.cuh"
#include <vector>
#include <iostream>
#include <cuda.h>
struct AddFunctor {
__host__ __device__ __forceinline__
float operator()(const float & a, const float & b) const {
return a + b;
}
} reduction_op;
int main() {
int n = 7680;
std::vector < uint64_t > keys_h(n);
for (int i = 0; i < 4000; i++) keys_h[i] = 1;
for (int i = 4000; i < 5000; i++) keys_h[i] = 2;
for (int i = 5000; i < 7680; i++) keys_h[i] = 3;
uint64_t * keys;
cudaMalloc(&keys, sizeof(uint64_t) * n);
cudaMemcpy(keys, &keys_h[0], sizeof(uint64_t) * n, cudaMemcpyDefault);
uint64_t * unique_keys;
cudaMalloc(&unique_keys, sizeof(uint64_t) * n);
std::vector < float > values_h(n);
for (int i = 0; i < n; i++) values_h[i] = 1.0;
float * values;
cudaMalloc(&values, sizeof(float) * n);
cudaMemcpy(values, &values_h[0], sizeof(float) * n, cudaMemcpyDefault);
float * aggregates;
cudaMalloc(&aggregates, sizeof(float) * n);
int * remaining;
cudaMalloc(&remaining, sizeof(int));
size_t size = 0;
void * buffer = NULL;
cub::DeviceReduce::ReduceByKey(
buffer,
size,
keys,
unique_keys,
values,
aggregates,
remaining,
reduction_op,
n);
cudaMalloc(&buffer, sizeof(char) * size);
cub::DeviceReduce::ReduceByKey(
buffer,
size,
keys,
unique_keys,
values,
aggregates,
remaining,
reduction_op,
n);
int remaining_h;
cudaMemcpy(&remaining_h, remaining, sizeof(int), cudaMemcpyDefault);
std::vector < float > aggregates_h(remaining_h);
cudaMemcpy(&aggregates_h[0], aggregates, sizeof(float) * remaining_h, cudaMemcpyDefault);
for (int i = 0; i < remaining_h; i++) {
std::cout << i << ", " << aggregates_h[i] << std::endl;
}
cudaFree(buffer);
cudaFree(keys);
cudaFree(unique_keys);
cudaFree(values);
cudaFree(aggregates);
cudaFree(remaining);
}
当我包含“-gencode arch=compute_35,code=sm_35”(对于 Kepler GTX Titan)时,它会产生错误的结果,但是当我完全忽略这些标志时,它有效。
$ nvcc cub_test.cu
$ ./a.out
0, 4000
1, 1000
2, 2680
$ nvcc cub_test.cu -gencode arch=compute_35,code=sm_35
$ ./a.out
0, 4000
1, 1000
2, 768
我使用了一些其他 CUB 调用没有问题,只有这个行为不正常。我还在 GTX 1080 Ti 上尝试了 运行 这段代码(使用 compute_61、sm_61) 并看到相同的行为。
省略这些编译器标志是正确的解决方案吗?
在一台机器上试过:
- cuda 8.0
- ubuntu16.04
- gcc 5.4.0
- 幼崽 1.6.4
- Kepler GTX Titan(计算能力 3.5)
另一个是:
- cuda 8.0
- ubuntu16.04
- gcc 5.4.0
- 幼崽 1.6.4
- Pascal GTX 1080 Ti(计算能力 6.1)
听起来您应该在 CUB repository issues page 提交错误报告。
编辑: 我可以重现这个问题:
[joeuser@myhost:/tmp]$ nvcc -I/opt/cub -o a a.cu
nvcc warning : The 'compute_20', 'sm_20', and 'sm_21' architectures are deprecated, and may be removed in a future release (Use -Wno-deprecated-gpu-targets to suppress warning).
[joeuser@myhost:/tmp]$ ./a
0, 4000
1, 1000
2, 2680
[joeuser@myhost:/tmp]$ nvcc -I/opt/cub -o a a.cu -gencode arch=compute_30,code=sm_30
[joeuser@myhost:/tmp]$ ./a
0, 4000
1, 1000
2, 512
相关信息:
- CUDA:8.0.61
- nVIDIA 驱动程序:375.39
- 分布:GNU/Linux薄荷 18.1
- Linux内核:4.4.0
- 海湾合作委员会:5.4.0-6ubuntu1~16.04.4
- 幼崽:1.6.4
- GPU:GTX 650 Ti(计算能力 3.0)