cuda与cpu高斯列主消元求解线性方程组速度比较

cuda与cpu高斯列主消元求解线性方程组速度比较

 

  最近看了看cuda上面用c语言进行的编程,踩了很多的坑,在这里记录一下。

  完整程序已上传:https://download.csdn.net/download/qq_41910473/12917838

  配置环境:VS2017  cuda10.0  Runtime,cpu:i5 8600K ,显卡:GTX 1060

  求解公式是:A*x = b,   A: N*N方阵,x:N维列向量,b: N维列向量,求解未知量x向量。

      求解方法:分别在gpu与cpu上进行高斯列主消元,比较运行的时间。

  求解的过程分为三步:

                               1、求最大值进行行交换。

                               2、消元。

                               3、回代。

   程序分为两部分,第一部分用cuda实现,第二部分在cpu实现,并分别统计运行时间。最终得出结论当矩阵维度大于1000时GPU运行速度快于CPU,而当矩阵维度小于等于1000时GPU运行速度慢于CPU。程序中有很多地方可以进行优化例如使用共享内存、线程块的分配,由于题主只是证明CUDA在解线性方程可以进行加速所以就没有进行更细节的优化。

最终得出的结论:数据规模较小的话,例如:100*100线性方程组GPU并行求解速度远低于CPU迭代求解速度。数据规模较大,例如:2000*2000的线性方程组求解在GPU上可以得到显著的加速效果。

   cuda程序:

   __global__ void GaussKernelA(),单线程执行该函数来求解第k步时第k列的最大值并把该最大值所在的行交换到第k行。

__global__ void GaussKernelA(double *augmentedMatrixGPU, int k, int n) {    //K :消元第k步,n:增广矩阵的行数
	int i = blockIdx.x * blockDim.x + threadIdx.x;
	int j = blockIdx.y * blockDim.y + threadIdx.y;

	int s;
	double temp, r;

	if (i == 0 && j == 0) {  //限定只有单线程执行该核函数
		s = k;
		r = fabs(augmentedMatrixGPU[k*(n + 1) + k]);
		for (int i = k; i < n; i++) {
			if (r < fabs(augmentedMatrixGPU[i*(n + 1) + k])) {
				r = fabs(augmentedMatrixGPU[i*(n + 1) + k]);
				s = i;
			}
		}
		if (s != k) {   //交换矩阵的两行
			Change(augmentedMatrixGPU + k * (n + 1), augmentedMatrixGPU + s * (n + 1), n);
		}
	}
}

 __global__ void augmented(),__global__ void GaussKernelB,高斯消元。

__global__ void augmented(double *augmentedMatrixGPU, int k, int n) {
	int i = blockIdx.x * blockDim.x + threadIdx.x;
	int j = blockIdx.y * blockDim.y + threadIdx.y;

	if (i == j && j > k && j < n  && augmentedMatrixGPU[k * (n + 1) + k] != 0) {
		augmentedMatrixGPU[j * (n + 1) + k] = augmentedMatrixGPU[j * (n + 1) + k] / augmentedMatrixGPU[k * (n + 1) + k];
	}

}

 

__global__ void GaussKernelB(double *augmentedMatrixGPU, int k, int n) {
	int i = blockIdx.x * blockDim.x + threadIdx.x;
	int j = blockIdx.y * blockDim.y + threadIdx.y;

	if (i > k && i < n + 1 && j > k && j < n  && augmentedMatrixGPU[k * (n + 1) + k] != 0) {
		augmentedMatrixGPU[j * (n + 1) + i] = augmentedMatrixGPU[j * (n + 1) + i] -
			augmentedMatrixGPU[j * (n + 1) + k] *
			augmentedMatrixGPU[k * (n + 1) + i];
	}
}

    所有的核函数都用的是一维数组进行数据的存储,并把Ax = b,A与b进行合并以增广矩阵的形式进行存储。先用cudaMemcpy把数据从CPU 拷贝到GPU,再用cudaDeviceSynchronize()进行GPU线程同步然后在开始计时,在CPU  for循环中进行逻辑控制,把矩阵的消元与计算放到GPU中执行。(坑1:在计时停止前一定要加cudaDeviceSynchronize(),因为CPU与GPU是异步执行的,在for循环结束时GPU的可能仍在执行,若不加同步函数,计时函数(QueryPerformanceCounter(&stop))就会在GPU没有运行完之前就停止计时,导致时间不准确我当时不加同步函数,计时为:0.02ms左右,加同步函数,计时为:1.5ms)。本次计算只进行消元的计时,回代是在CPU上完成的。

cudaMemcpy(augmentedMatrixGPU, augmentedMatrix, sizeof(double)* n * (n + 1), cudaMemcpyHostToDevice);

	cudaDeviceSynchronize();
	QueryPerformanceCounter(&start);
	for (int k = 0; k < n - 1; k++) {
		GaussKernelA << <1, 1 >> > (augmentedMatrixGPU, k, n);
		augmented << <gridDim, blockDim >> > (augmentedMatrixGPU, k, n);
		GaussKernelB << <gridDim, blockDim >> > (augmentedMatrixGPU, k, n);
	}
	cudaDeviceSynchronize();
	QueryPerformanceCounter(&stop);
	time = 1000 * (stop.QuadPart - start.QuadPart) / frequence;
	printf("GPU time is : %fms", (time));

	cudaMemcpy(augmentedMatrix, augmentedMatrixGPU, sizeof(double)* n * (n + 1), cudaMemcpyDeviceToHost);

CPU:高斯消元程序

QueryPerformanceCounter(&sta);  //计时开始
	for (int k = 0; k < n - 1; k++) {
		max = fabs(d[k][k]);
		cols = k;
		for (int i = k; i < n; i++) {   //求最值
			if (max < fabs(d[i][k])) {
				max = fabs(d[i][k]);
				cols = i;
			}
		}
		if (cols != k) {  //交换行
			for (int j = k; j <= n; j++) {
				temp = d[cols][j];
				d[cols][j] = d[k][j];
				d[k][j] = temp;
			}
		}
		if (!d[k][k]) {
			printf("err------------------------------------\n");
			return -1;
		}
		for (int p = k + 1; p < n; p++) {    //消元
			d[p][k] = d[p][k] / d[k][k];
			for (int h = k + 1; h <= n; h++) {
				d[p][h] = d[p][h] - d[k][h] * d[p][k];
			}
		}
	}
	x[n - 1] = d[n - 1][n] / d[n - 1][n - 1];    //回代
	for (int i = n - 2; i >= 0; i--) {
		s = d[i][n];
		for (int j = i + 1; j <= n; j++) {
			s = s - x[j] * d[i][j];
		}
		x[i] = s / d[i][i];
	}
	QueryPerformanceCounter(&sto);  //计时结束
	time2 = 1000 * (sto.QuadPart - sta.QuadPart) / frequence;
	printf("CPU time is : %fms\n", time2);

运行时间比较:

矩阵:1000*1000

         

矩阵: 1500*1500

         

矩阵: 2000*2000

        

 

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值