Cuda 为什么glm::dot比helper_math.h';s和我的实现 问题
我在cuda中遇到了一些glm矩阵向量乘法的性能问题,记录在中(链接,因为它可能对其他人有用) 在做一些性能测试时,我发现glm的点积实现比cuda的helper_math.h实现更快Cuda 为什么glm::dot比helper_math.h';s和我的实现 问题,cuda,glm-math,Cuda,Glm Math,我在cuda中遇到了一些glm矩阵向量乘法的性能问题,记录在中(链接,因为它可能对其他人有用) 在做一些性能测试时,我发现glm的点积实现比cuda的helper_math.h实现更快 inline __host__ __device__ float dot(float4 a, float4 b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } 我试图模仿glm的实现,但性能保持不变: inline __host__ _
inline __host__ __device__ float dot(float4 a, float4 b)
{
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}
我试图模仿glm的实现,但性能保持不变:
inline __host__ __device__ float dot(float4 a, float4 b)
{
float4 tmp = a * b;
return (tmp.x + tmp.y) + (tmp.z + tmp.w);
}
在我看来,这就是glm的实施:
template <typename T, precision P>
struct compute_dot<detail::tvec4, T, P>
{
GLM_FUNC_QUALIFIER static T call(detail::tvec4<T, P> const & x, detail::tvec4<T, P> const & y)
{
detail::tvec4<T, P> tmp(x * y);
return (tmp.x + tmp.y) + (tmp.z + tmp.w);
}
};
结果
差别非常明显:
time for cuda glm (dot): 223 milliseconds
time for cuda helper math (dot): 307 milliseconds
测试方法
我使用以下内核进行测试(类似于glm、numElements 2000000、innerLoopSize 100)和std::chrono::high_resolution_时钟的测量
__global__ void cuDotKernel(const float4 *vectors, float4 *result, int numElements, int innerLoopSize) {
int i = blockDim.x * blockIdx.x + threadIdx.x;
if(i < numElements) {
result[i] = vectors[i];
if(i>1 && i < NUM_ELEMENTS - 1) {
for(int j=0; j<innerLoopSize; j++) {
result[i].y = dot(vectors[i+1], vectors[i]);
result[i].x = dot(vectors[i-1], vectors[i]);
result[i].z = dot(vectors[i+1], result[i]);
result[i].w = dot(vectors[i-1], result[i]);
}
}
}
}
\uuuu全局\uuuuu无效cuDotKernel(常量float4*向量、float4*结果、整数元素、整数innerLoopSize){
int i=blockDim.x*blockIdx.x+threadIdx.x;
如果(i1&&i 对于(int j=0;j我以向量不会“爆炸”的方式更改了测试数据。这意味着它们保持在合理的范围[0.0-1000.0]。现在计时非常相似
cuda编译器似乎能够在glm的情况下优化某些计算,但在helper_math的情况下却无法优化。尝试通过引用传递点
参数,并尝试使用\uuuuuForceInline\uuuuuuuu
限定符。变化不大,只有几毫秒。有时向上,有时向下,所以它没有什么意义。我知道ess编译器正在优化。这可能也是为什么我用a*=b
编辑的版本没有改变任何东西的原因。重现问题的代码属于问题,而不是外部链接。imo在这种情况下,这只会扩大问题。此外,包含依赖项是不可行的,因此imo需要一个指向任何人都可以访问的repo的链接可以克隆甚至简单地下载更有用。但我还是要添加内核:)
__global__ void cuDotKernel(const float4 *vectors, float4 *result, int numElements, int innerLoopSize) {
int i = blockDim.x * blockIdx.x + threadIdx.x;
if(i < numElements) {
result[i] = vectors[i];
if(i>1 && i < NUM_ELEMENTS - 1) {
for(int j=0; j<innerLoopSize; j++) {
result[i].y = dot(vectors[i+1], vectors[i]);
result[i].x = dot(vectors[i-1], vectors[i]);
result[i].z = dot(vectors[i+1], result[i]);
result[i].w = dot(vectors[i-1], result[i]);
}
}
}
}