Cuda NVCC没有';t展开小型嵌套循环
我想知道,为什么NVCC不能为小矩阵(N=4)展开下面的Cholesky分解内核 显然,循环没有展开,并且使用了昂贵的本地内存(我的目标是只在寄存器中执行所有操作) 我这样调用函数:Cuda NVCC没有';t展开小型嵌套循环,cuda,Cuda,我想知道,为什么NVCC不能为小矩阵(N=4)展开下面的Cholesky分解内核 显然,循环没有展开,并且使用了昂贵的本地内存(我的目标是只在寄存器中执行所有操作) 我这样调用函数: T l[N*N]; for(int i = 0; i < N*N; ++i){ l[i] = buffer[offset+i]; } choleskyKernel2<T,N>(l); for(int i = 0; i < N*N;
T l[N*N];
for(int i = 0; i < N*N; ++i){
l[i] = buffer[offset+i];
}
choleskyKernel2<T,N>(l);
for(int i = 0; i < N*N; ++i){
buffer[offset+i] = l[i];
}
tl[N*N];
对于(int i=0;i
有没有一种方法可以正确地展开这个循环,这样所有的事情都可以在寄存器中完成
编辑:
完整代码:
#include <thrust/device_vector.h>
template<typename T, int N>
__device__ inline
void choleskyKernel2(T* C){
#pragma unroll
for (int i = 0; i < N; i++){
#pragma unroll
for (int j = 0; j <= i; j++) {
double s = 0;
#pragma unroll
for (int k = 0; k < j; k++){
s += C[i*N+k] * C[j*N+k];
}
s = C[i*N+j] - s;
C[i*N+j] = (i == j) ?
sqrt(s) :
(1.0 / C[j*N+j] * (s));
}
}
}
template<typename T, int N>
__global__ static
void test3(T* buffer){
const int matrixElements = N * N;
T l[matrixElements];
for(int i = 0; i < matrixElements; ++i){
l[i] = buffer[i];
}
choleskyKernel2<T,N>(l);
for(int i = 0; i < matrixElements; ++i){
buffer[i] = l[i];
}
}
int main(){
thrust::device_vector<double> d_data(16);
test3<double,4> <<< 1,1 >>>(thrust::raw_pointer_cast(d_data.data()));
}
#包括
模板
__设备在线
空核2(T*C){
#布拉格展开
对于(int i=0;i
虽然我无法告诉您为什么nvcc(或者实际上是代表nvcc执行设备代码编译的cicc)没有展开您的循环,但我可以向您展示如何更改代码以使其展开
转向
#pragma展开
对于(int i=0;i 对于(int j=0;j),只有CUDA编译器的维护人员才能肯定地回答这个问题。然而,一些常见的编译器展开试探法是:(1)从展开最内层循环开始(2)在编译时使用已知的“小”跳闸计数完全展开循环(3)使用“大”跳闸计数部分展开循环。最内层循环具有“小”跳闸计数但是可变跳闸计数,因此会使条件(2)和(3)失效。为什么不为(int j=0;ji)break;
?目标是创建一个与编译器的展开启发式方法匹配的控制流。历史上,CUDA编译器不擅长使用break
语句展开循环,在这种情况下,这似乎仍然是正确的。真的吗?我的意思是,一个具有固定数量的迭代且不干扰循环的循环身体中的计数器?展开不是很简单吗?或者更确切地说,你确定nvcc不擅长展开这些吗?对人类来说可能很简单,对一台没有编程的机器来说很难。试试看。。。
T l[N*N];
for(int i = 0; i < N*N; ++i){
l[i] = buffer[offset+i];
}
choleskyKernel2<T,N>(l);
for(int i = 0; i < N*N; ++i){
buffer[offset+i] = l[i];
}
#include <thrust/device_vector.h>
template<typename T, int N>
__device__ inline
void choleskyKernel2(T* C){
#pragma unroll
for (int i = 0; i < N; i++){
#pragma unroll
for (int j = 0; j <= i; j++) {
double s = 0;
#pragma unroll
for (int k = 0; k < j; k++){
s += C[i*N+k] * C[j*N+k];
}
s = C[i*N+j] - s;
C[i*N+j] = (i == j) ?
sqrt(s) :
(1.0 / C[j*N+j] * (s));
}
}
}
template<typename T, int N>
__global__ static
void test3(T* buffer){
const int matrixElements = N * N;
T l[matrixElements];
for(int i = 0; i < matrixElements; ++i){
l[i] = buffer[i];
}
choleskyKernel2<T,N>(l);
for(int i = 0; i < matrixElements; ++i){
buffer[i] = l[i];
}
}
int main(){
thrust::device_vector<double> d_data(16);
test3<double,4> <<< 1,1 >>>(thrust::raw_pointer_cast(d_data.data()));
}
#pragma unroll
for (int i = 0; i < N; i++){
#pragma unroll
for (int j = 0; j <= i; j++) {
#pragma unroll
for (int i = 0; i < N; i++) {
#pragma unroll
for (int j = 0; j < N; j++)
if (j <= i) {