【发布时间】:2020-09-26 00:32:50
【问题描述】:
我目前正在研究一种 GPU 渲染算法,我需要对这个结构的数组进行排序:
struct RadiosityData {
vec4 emission;
vec4 radiosity;
float nPixLight;
float nPixCam;
float __padding[2];
};
我正在使用以下代码对数组进行排序:
thrust::device_ptr<RadiosityData> dev_ptr = thrust::device_pointer_cast(GPUpointer_ssbo);
thrust::sort(dev_ptr, dev_ptr + N);
其中 GPUpointer_ssbo 是来自 cudaOpenGL 互操作的 GPU 指针,N 等于 ~300k。比较是通过:
__host__ __device__ bool operator<(const RadiosityData& lhs, const RadiosityData& rhs) { return (lhs.nPixCam > rhs.nPixCam); };
我的 GTX960M 的排序非常慢:没有排序,我的应用程序每帧大约 10 毫秒,而排序大约需要 35 毫秒。这意味着排序需要大约 25 毫秒。我正在用 VS-NSIGHT 测量执行时间
我知道这个问题可能是 GPU 同步问题,因为我在调用推力之前执行 OpenGL 操作。不过,我对这个说法并不信服,因为如果我用未排序的数组用OpenGL显示数据,总共还是需要10ms,这意味着OpenGL代码本身不存在同步问题。
这种“小”阵列的性能是预期的吗?有没有更好的 GPU 排序算法来解决这类问题?
------------编辑: 我正在使用默认的 VS2019 CUDA 命令编译发布,即:
驱动 API(NVCC 编译类型为 .cubin、.gpu 或 .ptx) 设置 CUDAFE_FLAGS=--sdk_dir "C:\Program Files (x86)\Windows Kits\10\" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\bin\nvcc.exe" --use-local-env -ccbin "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community \VC\Tools\MSVC\14.26.28801\bin\HostX86\x64" -x cu --keep-dir x64\Release -maxrregcount=0 --machine 64 --compile -cudart static -o x64\Release\sortBufferCUDA。 cu.obj "C:\Users\Jose\Desktop\RealTimeDiffuseIlumination\OpenGL-avanzado\sortBufferCUDA.cu"
运行时 API(NVCC 编译类型是混合对象或 .c 文件) 设置 CUDAFE_FLAGS=--sdk_dir "C:\Program Files (x86)\Windows Kits\10\" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\bin\nvcc.exe" --use-local-env -ccbin "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community \VC\Tools\MSVC\14.26.28801\bin\HostX86\x64" -x cu --keep-dir x64\Release -maxrregcount=0 --machine 64 --compile -cudart static -Xcompiler "/EHsc /nologo / fd /FS /Zi " -o x64\Release\sortBufferCUDA.cu.obj "C:\Users\Jose\Desktop\RealTimeDiffuseIlumination\OpenGL-avanzado\sortBufferCUDA.cu"
-------------编辑2:
以下是一个最小的工作示例:
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <thrust/device_ptr.h>
#include <thrust/sort.h>
#include <thrust/execution_policy.h>
#include <thrust/extrema.h>
#include <cuda_runtime_api.h>
#include <cuda.h>
#include <thrust/device_vector.h>
struct RadiosityData {
float emission[4];
float radiosity[4];
float nPixLight;
float nPixCam;
float __padding[2];
};
extern "C" void CUDAsort();
__host__ __device__ bool operator<(const RadiosityData& lhs, const RadiosityData& rhs) { return (lhs.nPixCam > rhs.nPixCam); };
int pri = 1;
thrust::device_vector<RadiosityData> dev;
void CUDAsort() {
if (pri == 1) {
pri = 0;
dev.resize(300000);
}
thrust::sort(dev.begin(), dev.end());
}
int main()
{
float time;
cudaEvent_t start, stop;
while (true) {
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0);
CUDAsort();
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&time, start, stop);
printf("Time to generate: %3.1f ms \n", time);
}
return 0;
}
【问题讨论】:
-
我可以在我的 GTX960 上在约 4.4 毫秒内对 300k 的这些结构进行排序(使用推力)。 GTX960 会比 960M 快一点,如果它快 5 倍,我会感到惊讶。除了排序之外,您可能还会测量其他事物。确保编译的是发布项目,而不是调试项目。即使在低端的 GT640 上也只需要大约 15 毫秒。
-
我也在 GTX2080Ti 上尝试过,大约需要 10 毫秒...我正在用 NSIGHT 测量 FPS,基本上注释和取消注释推力::sort 会产生 25 毫秒的差异...
-
我刚刚用我使用的编译命令更新了帖子。你觉得那里有什么问题吗?
-
不,我没有。我真的没想到这是一个发布/调试问题,因为当我在调试模式下编译时,我的排序时间会跳到 ~350 毫秒。 FWIW 您显示的代码对我来说没有意义。但我不会走这条路,因为你没有表现出像 minimal reproducible example 这样的东西。
-
哈哈,抱歉,我知道我没有,但那是因为我的代码太复杂,无法在此处发布。我可能会在 MRE 上工作然后回来。我只是想确定我遇到了问题,并且这不是 Thrust 的预期性能。你说这没有意义,因为我没有把其余的代码,对吧?或者你看到我展示的这几行有什么问题吗?