我昨天已经发布了这个问题,但并没有受到好评,虽然我现在有坚实的责备,请耐心等待。以下是系统规格:
现在我有一个全局内存读取繁重的应用程序,因此我尝试在我正在读取全局内存的每个地方使用__ldg
指令对其进行优化。但是,__ldg
根本没有提高性能,运行时间大约减少了4倍。所以我的问题是,如何用glob_mem[index]
替换__ldg(glob_mem + index)
可能会导致性能下降?这是我的问题的原始版本供您重现:
请
CPP=g++
CPPFLAGS=-Wall -O4 -std=c++0x -lcudart -lcurand
LIBDIRS=/usr/local/cuda/lib64
NVCC=nvcc
NVCCINCLUDE=/usr/local/cuda/include
NVCC_COMPILER_FLAGS=-Iinclude/ -O4 -arch compute_35 -code sm_35 -c
TARGET=example
.PHONY: all clear clean purge
all: $(TARGET)
$(TARGET): kernel.o main.cpp
@echo Linking executable "$(TARGET)" ...
@$(CPP) $(CPPFLAGS) $(addprefix -I,$(NVCCINCLUDE)) $(addprefix -L,$(LIBDIRS)) -o $@ $^
kernel.o: kernel.cu
@echo Compiling "$@" ...
$(NVCC) $(addprefix -I,$(NVCCINCLUDE)) $(NVCC_COMPILER_FLAGS) $< -o $@
clean: clear
clear:
@echo Removing object files ...
-@rm -f *.o
purge: clear
@echo Removing executable ...
-@rm -f $(TARGET)
的main.cpp
#include <chrono>
#include <cstdio>
#include "kernel.cuh"
using namespace std;
int main()
{
auto start = chrono::high_resolution_clock::now();
double result = GetResult();
auto elapsed = chrono::high_resolution_clock::now() - start;
printf("%.3f, elapsed time: %.3f \n", result, (double)chrono::duration_cast<std::chrono::microseconds>(elapsed).count());
return 0;
}
kernel.cuh
#ifndef kernel_cuh
#define kernel_cuh
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
double GetResult();
#endif
kernel.cu
#include "kernel.cuh"
class DeviceClass
{
double* d_a;
public:
__device__ DeviceClass(double* a)
: d_a(a) {}
__device__ void foo(double* b, const int count)
{
int tid = threadIdx.x + (blockDim.x * blockIdx.x);
double result = 0.0;
for (int i = 0; i < count; ++i)
{
result += d_a[i];
//result += __ldg(d_a + i);
}
b[tid] = result;
}
};
__global__ void naive_kernel(double* c, const int count, DeviceClass** deviceClass)
{
(*deviceClass)->foo(c, count);
}
__global__ void create_device_class(double* a, DeviceClass** deviceClass)
{
(*deviceClass) = new DeviceClass(a);
}
double GetResult()
{
const int aSize = 8388608;
const int gridSize = 8;
const int blockSize = 1024;
double* h_a = new double[aSize];
for (int i = 0; i <aSize; ++i)
{
h_a[i] = aSize - i;
}
double* d_a;
cudaMalloc((void**)&d_a, aSize * sizeof(double));
cudaMemcpy(d_a, h_a, aSize * sizeof(double), cudaMemcpyHostToDevice);
double* d_b;
cudaMalloc((void**)&d_b, gridSize * blockSize * sizeof(double));
DeviceClass** d_devicesClasses;
cudaMalloc(&d_devicesClasses, sizeof(DeviceClass**));
create_device_class<<<1,1>>>(d_a, d_devicesClasses);
naive_kernel<<<gridSize, blockSize>>>(d_b, aSize, d_devicesClasses);
cudaDeviceSynchronize();
double h_b;
cudaMemcpy(&h_b, d_b, sizeof(double), cudaMemcpyDeviceToHost);
cudaFree(d_a);
cudaFree(d_b);
return h_b;
}
那么它是什么...在我的应用程序中,我有一些全局数据由类DeviceClass的成员变量指向,它在设备上创建,就像新的/删除CUDA演示所示。
答案 0 :(得分:2)
使用__ldg
的版本较慢的原因是NVCC编译器无法在此特定方案中正确执行循环展开优化。该问题已提交给身份证号为1605303的NVIDIA.NVIDIA团队最近的回复如下:
虽然我们尚未向您传达此信息,但我们已对您的问题进行了事先调查。您的问题的解决方案是改进我们在后端编译器中的循环展开启发式 - 嵌入在ptxas中的编译器。我们评估了在CUDA 8.0中解决此问题的可能性,但是修复问题的初始解决方案导致了不可接受的回归。由于其他限制因素,我们无法及时为CUDA 8.0制定适当的解决方案。
我们正积极致力于在未来的CUDA版本中解决您的问题(在CUDA 8.0之后)。我们将确保随时向您通报我们的进展情况。