效率对比:分别用 C++Amp,C++ PPL,SSE/AVX,Serial(串行)计算矩阵乘法。

  1. 本次测试矩阵乘法未作分块优化。
  2. 未使用cuda测试。
  3. 采用微秒级的计时器。
  4. 分别对16阶方矩阵到4048阶方阵采用如下方式做乘法计算,统计结果。

1、C++Amp(GPU),
2、C++PPL(多线程16核),
3、SSE/AVX(单线程),
4、AVX-Db(单线程,双精度),
5、Serial(单线程串行)

对于不同阶数的矩阵乘法运算,运行时间统计如下(单位:秒),Rank表示矩阵阶数:

Rank : 16 32 64 128 256 512 1024 2048 2548 3048 3548 4048
C++Amp: 0.039954 0.000432 0.000460 0.000715 0.001594 0.005016 0.030988 0.426671 0.934444s 2.24189 3.799203 3.069859s
C++PPL : 0.000215 0.000128 0.000076 0.000227 0.001685 0.014039 0.271222 4.000625 8.792314 15.768285 27.04492 42.068705
SSE/AVX: 0.000005 0.000019 0.000087 0.000353 0.002055 0.01773 0.129564 2.449093 4.760192 7.474997 11.942498 17.434507
AVX-Db : 0.000004 0.000022 0.000080 0.00051 0.00419 0.032692 0.547273 4.430325 8.523084 13.997932 22.1742 33.316449
Serial : 0.000003 0.000025 0.000165 0.001467 0.013698 0.114402 0.939655 29.144466 70.799408 0 0 0
  • C++Amp在数据量小时候(64x64阶以内)没有速度优势,反而很慢,由于GPU数据交换花了大量时间。
  • SSE/AVX:宽指令在(128阶以内)速度最快。可以进一步通过多线程结合宽指令提速。
  • 串行方式低阶运算尚可,20阶以上开始落后。
    效率对比:分别用 C++Amp,C++ PPL,SSE/AVX,Serial(串行)计算矩阵乘法。_第1张图片
  • C++Amp在512x512以上表现出更高的效率。
  • PPL多线程方式一直不温不火,并未体现出横向对比优势。
  • AVX指令运算双精度浮点(AVX-double)在256阶以下速度尚可,阶数提高后效果不好。
    效率对比:分别用 C++Amp,C++ PPL,SSE/AVX,Serial(串行)计算矩阵乘法。_第2张图片
  • Serial串行运算在大于64阶以后,运行时间成指数级增加,基本没有应用价值。
    效率对比:分别用 C++Amp,C++ PPL,SSE/AVX,Serial(串行)计算矩阵乘法。_第3张图片
  • 在大于1000阶的高阶计算中,C++Amp(GPU加速)效率最高,其次是SSE/AVX宽指令浮点运算。
  • 采用Nvidia的cuda效果应该更好,但本次未作测试对比。
  • 综合考虑:“SSE/AVX+多线程”组合的实用性和效率最高,更适合轻量级的高速运用场景。 测试中SSE/AVX仅采用单线程,速度不俗,还可继续扩展为多线程提高速度。关键是SSE/AVX宽指令代码的依赖性极低,不需要额外的使用开销,不需要任何库支持(只需cpu指令集支持即可),能实现轻量级的高速并行计算。
  • 而采用C++Amp或cuda,面临低阶运算GPU数据交换开销远大于运算开销情况,得不偿失。他们都需要额外的库支持,且必须借助GPU。其中,cuda更是需要安装庞大的巨量库和驱动,且必须使用Nvidia显卡,移植性便捷性较差。

采用的部分模板类代码: “CLMatrix.h” 头文件.
测试代码:

//....其他头文件
#include 
#include 
#include 
#include "CLMatrix.h"  
using namespace concurrency;

int main() {
	CLMatrixD recd;	
	int cyc = 5;
	int rank = 16;
	for (; rank < 4100; )
	{
		if (rank > 1024) cyc = 1;
		//数据存储器用 CLMatrixT类,详 #include "CLMatrix.h" 头文件实现。
		CLMatrixF A(1, rank * rank, CLMatrixF::initRand_F_0_1), B(1, rank * rank, CLMatrixF::initRand_F_0_1);
		CLMatrixF A1(rank, rank, CLMatrixF::initRand_F_0_1), B1(rank, rank, CLMatrixF::initRand_F_0_1);
		CLMatrixD A2(rank, rank, CLMatrixD::initRand_F_0_1), B2(rank, rank, CLMatrixD::initRand_F_0_1);
		CLMatrixF C(1, rank * rank), D(rank, rank), E(rank, rank), F(rank, rank);
		CLMatrixD G(rank, rank);
		CLTick tk12;//高精度计时器
		auto tk0 = tk12.getSpendTime();
		for (int k = 0; k < cyc; k++)
		{
			array_view<const float, 2> va(rank, rank, &A[0][0]);
			array_view<const float, 2> vb(rank, rank, &B[0][0]);
			array_view<float, 2> vc(rank, rank, &C[0][0]);
			vc.discard_data();
			parallel_for_each(vc.extent,
				[=](index<2> idx) restrict(amp) {
					const unsigned int row = idx[0];
					const unsigned int col = idx[1];
					float r = 0;
					for (int i = 0; i < rank; i++)
					{
						r += va[row][i] * vb[i][col];
					}
					vc[idx] = r;
				});
			vc.synchronize();
		}
		auto tk1 = tk12.getSpendTime();
		for (int k = 0; k < cyc; k++)
		{
			parallel_for(0, rank, [=, &A1, &B1, &D](int i) {
				parallel_for(0, rank, [=, &i, &A1, &B1, &D](int j) {
					float r = 0;
					for (int k = 0; k < rank; k++){
						r += A1[i][k] * B1[k][j];
					}
					D[i][j] = r;
					});
				});
		}
		CLMatrix::setUseSSE(true);
		auto tk2 = tk12.getSpendTime();
		for (int k = 0; k < cyc; k++)
			::matrixMul(A1, B1, E);
		auto tk3 = tk12.getSpendTime();
		for (int k = 0; k < cyc; k++)
			::matrixMul(A2, B2, G);
		auto tk4 = tk12.getSpendTime();
		CLMatrix::setUseSSE(false);
		if (rank <= 2548)
			for (int k = 0; k < cyc; k++)
				::matrixMul(A1, B1, F);
		auto tk5 = tk12.getSpendTime();
		recd.add_col(
			{	double(rank),
				(tk1 - tk0) / cyc,
				(tk2 - tk1) / cyc,
				(tk3 - tk2) / cyc,
				(tk4 - tk3) / cyc,
				(tk5 - tk4) / cyc,
			}
		);
		cout << "\nRank = " << rank << ", finish! ...";
		if (rank < 2048)rank *= 2;
		else rank += 500;
	}
	recd.print("Time Spend Record")  //打印时间结果
		.printMatrix("D:\\Documents\\Desktop\\TimeSpend.txt"); //时间结果保存	
	return 1;
}

你可能感兴趣的:(编程,C++)