【发布时间】:2016-05-02 23:32:07
【问题描述】:
我实现了一个用于压力梯度计算的内核。根据我使用的算法和之前的部分,ngb_list[] 是随机的,我没有合并内存访问。然而,内核的双精度 FLOP 效率是 TESLA K40 上峰值性能的 0.2%。好像很低……!
还有:
全局内存负载效率:45.05%
全局内存存储效率:100.00%
有没有办法提高 DP FLOP 效率和 Global Memory Load Efficiency?
你可以在这里找到代码:
#include <cuda.h>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/device_ptr.h>
#include <thrust/sequence.h>
#include <thrust/reduce.h>
#include <thrust/scan.h>
#include <thrust/execution_policy.h>
#include <iostream>
#include <time.h>
#include <cmath>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <numeric>
typedef double Float;
__global__ void pGrad_calculator(Float* pressure, Float* pressure_list,
Float* interactionVectors_x, Float* interactionVectors_y, Float* interactionVectors_z,
int* ngb_offset, int* ngb_size, int* ngb_list,
Float* pressureGrad_x, Float* pressureGrad_y, Float* pressureGrad_z,
int num){
unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num){
for (int j = ngb_offset[idx]; j < (ngb_offset[idx] + ngb_size[idx]); j++){
Float pij = (pressure[idx] + pressure[ngb_list[j]]);
pressureGrad_x[idx] += interactionVectors_x[j] * pij;
pressureGrad_y[idx] += interactionVectors_y[j] * pij;
pressureGrad_z[idx] += interactionVectors_z[j] * pij;
}
pressureGrad_x[idx] *= 0.5;
pressureGrad_y[idx] *= 0.5;
pressureGrad_z[idx] *= 0.5;
}
}
int main(){
const int num = 1 << 20;
const int tb = 1024;
int bg = (num + tb - 1) / tb;
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
//ngb_size
thrust::device_vector<int> ngb_size(num,27);
//ngb_offset
thrust::device_vector<int> ngb_offset(num);
thrust::exclusive_scan(ngb_size.begin(),ngb_size.end(), ngb_offset.begin());
//ngh list
int ngbSize = thrust::reduce(ngb_size.begin(),ngb_size.end());
std::cout << "ngbSize" << ngbSize << std::endl;
thrust::device_vector<int> ngb_list(ngbSize);
srand((unsigned)time(NULL));
for (int i = 0; i < num; i++){
int R = (rand()%(num - 0)) + 0;
ngb_list[i] = R;
}
//pressure
thrust::device_vector<Float> d_pressure(num);
thrust::sequence(d_pressure.begin(),d_pressure.end(),1);
//interaction vectors
thrust::device_vector<Float> d_xInteractionVectors(ngbSize,1);
thrust::device_vector<Float> d_yInteractionVectors(ngbSize,0);
thrust::device_vector<Float> d_zInteractionVectors(ngbSize,0);
//pressure gradients
thrust::device_vector<Float> pGradx(num);
thrust::device_vector<Float> pGrady(num);
thrust::device_vector<Float> pGradz(num);
//Pressure list
thrust::device_vector<Float> pressure_list(ngbSize,0);
cudaEventRecord(start);
pGrad_calculator<<<bg,tb>>>(thrust::raw_pointer_cast(&d_pressure[0]),
thrust::raw_pointer_cast(&pressure_list[0]),
thrust::raw_pointer_cast(&d_xInteractionVectors[0]),
thrust::raw_pointer_cast(&d_yInteractionVectors[0]),
thrust::raw_pointer_cast(&d_zInteractionVectors[0]),
thrust::raw_pointer_cast(&ngb_offset[0]),
thrust::raw_pointer_cast(&ngb_size[0]),
thrust::raw_pointer_cast(&ngb_list[0]),
thrust::raw_pointer_cast(&pGradx[0]),
thrust::raw_pointer_cast(&pGrady[0]),
thrust::raw_pointer_cast(&pGradz[0]),
num);
cudaEventRecord(stop);
cudaEventSynchronize(stop);
float milliseconds = 0;
cudaEventElapsedTime(&milliseconds, start, stop);
std::cout << "KERNEL TIME = " << milliseconds << " milliseconds" << std::endl;
return 0;
}
【问题讨论】:
-
从您的内核看来,它具有较低的计算复杂度和大量的全局内存加载和存储,这就是您在分析结果中看到的。此外,根据大小向量,内核可能非常发散。
-
我认为这个问题的唯一答案是否定的 - FLOP 与内存事务的比率非常低,并且未合并负载。
-
正如其他人所指出的,您将受到此内核中带宽的最大影响。您可以尝试将
const __restrict__添加到interactionVectors以查看这是否有助于提高读取性能。请参阅docs.nvidia.com/cuda/kepler-tuning-guide/… 了解更多信息。 -
@talonmies 执行循环 Unroll 将显着提高性能。你还有什么意见吗?
-
@jefflarkin 谢谢你的评论。我测试了一下,好像没有效果。
标签: performance cuda gpu gpgpu