C++性能优化系列——3D高斯核卷积计算(七)Intrinsic实现2D高斯卷积

本篇基于 C++性能优化系列——3D高斯核卷积计算(六)交换维度计算2D卷积 中2D高斯卷积的计算逻辑,通过Intrinsic函数实现相同的功能并对比性能差异。

复用一维卷积

复用之前实现的函数,用指令实现对x维度的计算

void Conv2D_Fuse_InstructX(float* pSrcSlice, int iDim[2], float* pKernel, int iKernelSize, float* pBuffer, float* pDstSlice,float* pSimdKernel)
	{
		//combination
		int iHalfKernel = iKernelSize / 2;
		for (int y = 0; y < (iDim[1] - iKernelSize + 1); y++)
		{
			float* pDstLine = pDstSlice + (y + iHalfKernel) * iDim[0];
			float* pTmpLine = pBuffer + (y + iHalfKernel) * iDim[0];
			for (int kx = 0; kx < iKernelSize; ++kx)
			{
				float* pSrcLine = pSrcSlice + (y + kx) * iDim[0];
#pragma omp simd
				for (int i = 0; i < iDim[0]; i++)
				{
					pTmpLine[i] += pSrcLine[i] * pKernel[kx];
				}
			}
			Conv1D_Ins_Cmb_Unroll2(pTmpLine, iDim[0], pKernel, iKernelSize, pDstLine, pSimdKernel);
		}
	}

说明:函数Conv1D_Ins_Cmb_Unroll2通过Intrinsic实现一维卷积功能,具体细节参考 C++性能优化系列——3D高斯核卷积计算(四)Intrinsic实现一维卷积与循环展开

执行时间

TestConv2D(Conv2D_Fuse_InstructX) cost total Time(ms) 2817
TestConv2D cost Time(ms) 0.5634

可以看到函数调用耗时与上一版基本持平。

y维度Intrinsic实现

函数实现

void Conv2D_Fuse_InstructYX(float* pSrcSlice, int iDim[2], float* pKernel, int iKernelSize, float* pBuffer, float* pDstSlice, float* pSimdKernel)
	{
		//combination
		int iHalfKernel = iKernelSize / 2;
		for (int y = 0; y < (iDim[1] - iKernelSize + 1); y++)
		{
			float* pDstLine = pDstSlice + (y + iHalfKernel) * iDim[0];
			float* pTmpLine = pBuffer + (y + iHalfKernel) * iDim[0];
			for (int kx = 0; kx < iKernelSize; ++kx)
			{
				float* pSrcLine = pSrcSlice + (y + kx) * iDim[0];
				__m256 ker = _mm256_loadu_ps(pSimdKernel + 8 * kx);
				for (int i = 0; i < iDim[0]; i += 16)
				{
					__m256 src1 = _mm256_loadu_ps(pSrcLine + i);
					__m256 dst1 = _mm256_loadu_ps(pTmpLine + i);
					dst1 = _mm256_fmadd_ps(ker, src1, dst1);
					_mm256_storeu_ps(pTmpLine + i, dst1);
					__m256 src2 = _mm256_loadu_ps(pSrcLine + i + 8);
					__m256 dst2 = _mm256_loadu_ps(pTmpLine + i + 8);
					dst2 = _mm256_fmadd_ps(ker, src2, dst2);
					_mm256_storeu_ps(pTmpLine + i + 8, dst2);
				}
			}
			Conv1D_Ins_Cmb_Unroll2(pTmpLine, iDim[0], pKernel, iKernelSize, pDstLine, pSimdKernel);
		}
	}

根据之前的经验,通过调用Intrinsic函数手动向量化,for语句对应汇编指令执行过多。这里对y维度的计算进行了手动2倍循环展开。同时,因为x维度的大小为432,是8的整数倍,这里为了追求更优的性能,忽略的拓展性,不实现标量计算部分。
执行时间

TestConv2D(Conv2D_Fuse_InstructYX) cost total Time(ms) 2783
TestConv2D cost Time(ms) 0.5566

VTune性能分析

没有提示整体执行情况中的突出热点
在这里插入图片描述

指令执行数量

在这里插入图片描述

可以看到总的执行指令与ICC向量化版本基本相同。CPI也相差不大。

在这里插入图片描述
执行指令最多的地方依然是计算X维度的卷积计算。可以看到完全用指令实现的版本,for语句执行次数依然超过了内部计算部分指令总的执行次数。这里已经对for进行了2倍展开,解释不了两个版本还会存在这么大的差别的原因。
对应汇编执行情况
在这里插入图片描述
反汇编中可以看到add 0x40执行了最多的次数,能够和for语句的内部逻辑对应上。说明VTune统计的确实是for对应执行指令数量。

总结

通过Intrinsic函数做向量化时,由于对应for语句的相对低效执行,使最终执行速度和完全由编译器向量化版本的差别不大。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值