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

9 篇文章 0 订阅
  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 :163264128256512102420482548304835484048
C++Amp:0.0399540.0004320.0004600.0007150.0015940.0050160.0309880.4266710.934444s2.241893.7992033.069859s
C++PPL :0.0002150.0001280.0000760.0002270.0016850.0140390.2712224.0006258.79231415.76828527.0449242.068705
SSE/AVX:0.0000050.0000190.0000870.0003530.0020550.017730.1295642.4490934.7601927.47499711.94249817.434507
AVX-Db :0.0000040.0000220.0000800.000510.004190.0326920.5472734.4303258.52308413.99793222.174233.316449
Serial :0.0000030.0000250.0001650.0014670.0136980.1144020.93965529.14446670.799408000
  • C++Amp在数据量小时候(64x64阶以内)没有速度优势,反而很慢,由于GPU数据交换花了大量时间。
  • SSE/AVX:宽指令在(128阶以内)速度最快。可以进一步通过多线程结合宽指令提速。
  • 串行方式低阶运算尚可,20阶以上开始落后。
    在这里插入图片描述
  • C++Amp在512x512以上表现出更高的效率。
  • PPL多线程方式一直不温不火,并未体现出横向对比优势。
  • AVX指令运算双精度浮点(AVX-double)在256阶以下速度尚可,阶数提高后效果不好。
    在这里插入图片描述
  • Serial串行运算在大于64阶以后,运行时间成指数级增加,基本没有应用价值。
    在这里插入图片描述
  • 在大于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 <windows.h>
#include <amp.h>
#include <ppl.h>
#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;
}
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值