软硬件FFT性能测试

  FFT在很多算法中都有应用,M6678 DSP支持软件FFT(调用DSP库),和硬件FFT(有一个独立的FFT硬件加速模块)。

测试条件

  • 操作系统 Win11
  • CCS 6.2.0
  • CGT-Tools 7.4.4
  • XDCTools 3.25.5.94
  • SYS/BIOS 6.33.6.50
  • DSPLIB C66x 3.4.0.4
  • MATHLIB C66x 3.1.2.4
  • 256kB L2 Cache, 32kB L1P/D Cache
  • 堆区放在DDR,待处理数据与结果数据都在堆区开辟;
  • 待处理的数据均为单精度浮点数,实部虚部交叉存储;
  • 处理器主时钟 1GHz

测试结果

1、 单次运算
  软件FFT以调用FFT函数开始计时,Cache写回之后结束计时。硬件FFT以启动FFT计算开始,收到FFT完成中断后结束计时。

FFT点数 软件FFT 硬件FFT
32 1327 ns 5292 ns
64 1840 ns 5828 ns
128 3078 ns 6372 ns
256 3956 ns 6918 ns

  可以看到单次FFT运算,软件FFT更快,我猜测可能是中断开销比较大,或者是硬件FFT在数据传输的时候有一个固有的开销。

2、连续多次运算
  我目前有一个二维FFT计算的需求,对MxN的二维数据,需要连续对M行数据分别进行N点FFT计算再转置,再进行M点N行FFT计算和转置。以同样的起始和结束条件进行测试,得到以下平均每次FFT计算的时间开销:

测试条件 软件FFT平均每次耗时 硬件FFT平均每次耗时
32次32点 696 ns 180 ns
64次64点 806 ns 163 ns
128次128点 3219 ns 271 ns
256次256点 5113 ns 563 ns

相关测试工程

二维FFT计算分解

  对二维FFT运算的使用,最普适的就是从复数到复数的变换。即使我想对一个二维的实数矩阵进行FFT,也可以将实数转换成复数表示然后做FFT。
  但这样做的效率不太高,结合实际的应用场景,我最近想做二维FFT是为了加速卷积运算,“时域卷积等于频域相乘”。因此FFT的源数据是实数,而且在这种应用场景下IFFT的结果数据也是实数。
  综合了一些考虑之后,我设计了一个用于调用硬件FFT的类CFftManager。它主要支持下面这些功能:

FFT2d_R2R

  有些实数数据我们先验地知道它是中心对称的,那么它做FFT的结果也会是实数,这个在我之前KCF算法推导的第三篇文章中有提到,因为旋转因子是中心对称的,只要实数也满足同样的对称性,那么计算中的虚部就会都抵消只剩下实数。
  “FFT_R2R_T”表示从实数到实数的变换,并且会进行转置。只要连续调用该函数两次就能实现二维的实数到实数的FFT变换。虽然这里命名是“R2R”,但实际上中间的计算结果是有可能有虚数存在的。只有输入数据不光在二维上中心对称,而且在一维上也中心对称结果才只有实数。若输入数据仅仅满足二维的中心对称,第一次FFT之后得到的结果中是有虚数的,然后在完成第二次FFT之后才只剩实数。

  用户给定需要进行FFT的实数数据SRC,结果可以输出到SRC中,也可以存放到另外的DST空间。
  由CFftManager类管理两块临时空间TempR和TempI用于存放FFT的结果,再由DMA将FFT结果搬运到目的空间,并进行转置。TempR空间不仅仅是用来存放FFT结果中的实数,也起到了存放输入的虚数的作用。因此一个完整的二维FFT2d_R2R的计算,第一步需要先将TempR清零。然后连续调用两次FFT_R2R_T即可得到正确结果。

FFT2d_R2C

  由CFftManager类管理的TempR和TempI是连续的两块存储空间。一般的实数到复数的二维FFT的计算过程如下图所示:

  首先计算由一维的实数到复数的FFT,此时输入的数据的实部和虚部是分开存储的,可以在第一次转置的时候顺便将存储方式改为交叉存储。而后需要进行第二次FFT,然后再进行第二次转置。
  为什么要交叉存储?交叉存储能够方便处理器从存储器中取操作数。比如取一个复数,这个复数如果是连续存放的,很可能就只需要一条指令就能够完成取操作数。这个在我的前面的文章里由提到关于复数乘法运算时,如果复数存放方式是[imag, real, imag, …],那么每次就只需要一条LDDW指令就可以完成取操作数,并且接着就可以进行复数乘法计算。
  但是硬件FFT所支持的复数交叉存放方式是[real, imag, real, …]的形式。为了应对不同的需求我写了两个FFT_C2C_T的函数,它们都是完成FFT复数到复数的变换,只是最后一步的转置有一点点区别。“FFT_C2C_T”输出结果是按照[imag, real, imag, …]的方式存放的,更适合后续需要进行复数乘法的应用场景;“FFT_C2C_TN”结尾的“N”取自Normal,结果是按照[real, imag, real, …]的方式存放的,更加符合一般的用法。

IFFT2d_C2R

  IFFT没有什么特殊的地方,在确定输出一定为实数的情况下,我只是将最后计算的结果中的实数部分进行了提取并转置后存放到指定的DST空间中。

CFftManager类定义

  每次计算二维的FFT都需要从两个维度分别计算一维的FFT,每次都需要等待一维的FFT计算完成,即接收到完成中断才能进行下一步。这部分前后衔接的工作涉及中断,所以不适合放到类里去实现。我把前面提到的计算步骤分别写成几个独立的成员函数,在实际应用过程中进行组合即可。

/*** @brief Hardware FFT caculation manager* */
class CFftManager{private:CSL_Edma3ChannelHandle m_hCha;CSL_Edma3ChannelObj m_ChaObj;float *m_pTempR;float *m_pTempI;float *m_pMid1;float *m_pMid2;Bool m_bInitDone;int m_nCicId;uint8_t getPowOfLen(uint16_t nLength);public:CFftManager();~CFftManager();/*** @brief allocate temp space, TempR and TempI.** @param maxWidth max FFT length* @param maxHeight max FFT lines* @return int*/int init(int maxWidth, int maxHeight);/*** @brief attach FFT finish interrupt to EDMA channel and enable EDMA interrupt* user should setup a Hwi for the event* * @param coreId core ID* @return int*/int HwInit(int coreId);/*** @brief do FFT and transpose. * source data is central symmetry real data* pSrc and pDst can point to the same space* using m_pTempR as input imag data and output imag data* * @param pSrc input only real part data* @param pDst output only real part data* @param nLen FFT points* @param nRows number of rows* @return int */int FFT_R2R_T(float *pSrc, float *pDst, int nLen, int nRows);/*** @brief do FFT and transpose* source data is half size of dst data(dst data is complex)* when pSrc and pDst is same, carefully check if source data space is large enough* * @param pSrc input only real part data* @param pDst output real part and imaginary part data, cross storeage stratagy* @param nLen FFT points* @param nRows number of rows* @return int */int FFT_R2C_T(float *pSrc, float *pDst, int nLen, int nRows);/*** @brief do FFT and transpose*  real is in high address, imag is in low address* [imag, real, imag, real , ...]* * @param pSrc * @param pDst * @param nLen FFT points* @param nRows number of rows* @return int */int FFT_C2C_T(float *pSrc, float *pDst, int nLen, int nRows);/*** @brief do FFT and transpose normal mode* real is in low address, imag is in high address* [real, imag, real, imag , ...]* * @param pSrc * @param pDst * @param nLen FFT points* @param nRows number of rows* @return int */int FFT_C2C_TN(float *pSrc, float *pDst, int nLen, int nRows);int IFFT_C2C_T(float *pSrc, float *pDst, int nLen, int nRows);int IFFT_C2R_T(float *pSrc, float *pDst, int nLen, int nRows);void ClearInterruptFlag();void ClearTempR(size_t nSize);
};

具体应用方式

  创建一个专门用来执行FFT的Task,其他Task可以通过命令队列将要执行的FFT计算发送到队列里,同时需要发送一个启动信号。FFTTask收到启动信号后读取命令队列,然后执行,完成之后发送FFT完成的信号量。
  在调用FFT硬件进行计算的过程中,MainTask仍然可以进行一些其它的计算。MainTask也可以一股脑儿地将要进行计算地任务都发送到命令队列里,处理完其它事情后再回过头来检查FFT完成的信号量的个数是否达到预期,然后进行后续处理,这样可以最大限度地利用硬件FFT的加速功能。

typedef enum FFT2dType
{FFT2d_R2R = 0,FFT2d_R2C,FFT2d_R2C_N,IFFT2d_C2R
} FFT2dType;typedef struct FFTCmd{Queue_Elem _elem;FFT2dType eType;float *pSrc;float *pDst;int nWidth;int nHeight;
} FFTCmd;Void FFTTskFxn(UArg a0, UArg a1)
{FFTCmd *pCmd = NULL;int nWidth, nHeight;// init in main// FftMgr.init(FFT_POINT, FFT_POINT);// FftMgr.HwInit(0);for (;;){Semaphore_pend(hFFTStartSem, BIOS_WAIT_FOREVER);pCmd = (FFTCmd *)Queue_dequeue(hFFTQue);nWidth = pCmd->nWidth;nHeight = pCmd->nHeight;switch (pCmd->eType){case FFT2d_R2R:FftMgr.ClearTempR(sizeof(float) * pCmd->nWidth * pCmd->nHeight);FftMgr.FFT_R2R_T(pCmd->pSrc, pCmd->pDst, nWidth, nHeight);Semaphore_pend(hFFTHwiSem, BIOS_WAIT_FOREVER);FftMgr.FFT_R2R_T(pCmd->pDst, pCmd->pDst, nHeight, nWidth);Semaphore_pend(hFFTHwiSem, BIOS_WAIT_FOREVER);// TODO check resultCache_inv(pCmd->pDst, sizeof(float) * nWidth * nHeight, Cache_Type_ALLD, 1);break;case FFT2d_R2C:FftMgr.FFT_R2C_T(pCmd->pSrc, pCmd->pDst, nWidth, nHeight);Semaphore_pend(hFFTHwiSem, BIOS_WAIT_FOREVER);FftMgr.FFT_C2C_T(pCmd->pDst, pCmd->pDst, nHeight, nWidth);Semaphore_pend(hFFTHwiSem, BIOS_WAIT_FOREVER);Cache_inv(pCmd->pDst, sizeof(float) * nWidth * nHeight * 2, Cache_Type_ALLD, 1);break;case FFT2d_R2C_N:FftMgr.FFT_R2C_T(pCmd->pSrc, pCmd->pDst, nWidth, nHeight);Semaphore_pend(hFFTHwiSem, BIOS_WAIT_FOREVER);FftMgr.FFT_C2C_TN(pCmd->pDst, pCmd->pDst, nHeight, nWidth);Semaphore_pend(hFFTHwiSem, BIOS_WAIT_FOREVER);Cache_inv(pCmd->pDst, sizeof(float) * nWidth * nHeight * 2, Cache_Type_ALLD, 1);break;case IFFT2d_C2R:FftMgr.IFFT_C2C_T(pCmd->pSrc, pCmd->pSrc, nWidth, nHeight);Semaphore_pend(hFFTHwiSem, BIOS_WAIT_FOREVER);FftMgr.IFFT_C2R_T(pCmd->pSrc, pCmd->pDst, nHeight, nWidth);Semaphore_pend(hFFTHwiSem, BIOS_WAIT_FOREVER);Cache_inv(pCmd->pDst, sizeof(float) * nWidth * nHeight, Cache_Type_ALLD, 1);break;default:assert(0); // FFT type errorbreak;}Semaphore_post(hFFTDoneSem);}
}

硬件FFT加速模块的应用相关推荐

  1. 英飞凌 AURIX 系列单片机的HSM详解(5)——HSM硬件加速模块的使用

    本系列的其它几篇文章: <英飞凌 AURIX 系列单片机的HSM详解(1)--何为HSM> <英飞凌 AURIX 系列单片机的HSM详解(2)--与HSM相关的UCB和寄存器> ...

  2. 硬件3D加速指南(转)

    硬件3D加速指南(转)[@more@] 内容简介:本指南描述了如何在Gentoo Linux的XFree86中使用XFree-DRM以获得3D加速. 1. 前言 什么是硬件3D加速?我为什么需要使用它 ...

  3. 虚拟机使用的是此版本 VMware Workstation 不支持的硬件版本。 模块“Upgrade”启动失败。 未能启动虚拟机(修改.vmx文件virtualHW.version = “xx“字段)

    1.找到并通过记事本程序打开虚拟机的.vmx文件: 2.找到文件中的virtualHW.version = "19"字段,修改该字段为virtualHW.version = &qu ...

  4. 海思芯片硬件java加速_海思Hi3719C V100芯片简介

    主要特点 CPU:arm Cortex A9 双核;独立的 I-Cache.D-Cache.L2 Cache;集成多媒体加速引擎 NEON;支持硬件 Java 加速;集成硬件浮点协处理器 3D GPU ...

  5. HDU5322 - cdq分治FFT加速dp

    5322 Hope [CDQ分治FFT加速计算dp] 题意 每一个每一个排列,排列中每个数向它后面第一个比它大的数连一条边. 每个排列对于答案的贡献是这个排列所生成的图中的每一个联通量中点的个数的平方 ...

  6. P1919 FFT加速高精度乘法

    P1919 FFT加速高精度乘法 传送门:https://www.luogu.org/problemnew/show/P1919 题意: 给出两个n位10进制整数x和y,你需要计算x*y. 题解: 对 ...

  7. 计算机硬件加速怎么开,怎么开启显卡硬件加速?开启显卡硬件的加速功能步骤...

    在我们的电脑中,显卡已经有一定的效能水准,但当我们在开启玩游戏画面或是影音文件时仍然不是很流畅很清晰,这是为什么呢?这就要问你:你使用了显卡硬件的加速功能没有?如果没有使用,那你的显卡就还没有完全发挥 ...

  8. [Chromium中文文档]Chrom{e,ium}{,OS}中的硬件视频加速

    Chrom{e,ium}{,OS}中的硬件视频加速 转载请注明出处:https://ahangchen.gitbooks.io/chromium_doc_zh/content/zh//General_ ...

  9. 虚拟机使用的是此版本 VMware Workstation 不支持的硬件版本。 模块“Upgrade”启动失败。 未能启动虚拟机的解决方案

    虚拟机使用的是此版本 VMware Workstation 不支持的硬件版本. 模块"Upgrade"启动失败. 未能启动虚拟机. 分析:该虚拟机环境之前使用的VMware版本与你 ...

  10. 虚拟机使用的是此版本 VMware Workstation 不支持的硬件版本。 模块“Upgrade”启动失败。 未能启动虚拟机。

    问题:虚拟机使用的是此版本 VMware Workstation 不支持的硬件版本. 模块"Upgrade"启动失败. 未能启动虚拟机. 分析:该虚拟机环境之前使用的VMware版 ...

最新文章

  1. R语言可视化包ggplot2绘制分组的条形图(bar plot、柱状图)实战:多变量柱状图
  2. Java并发编程-CountDownLatch
  3. 如何构建银行数据仓库
  4. GridView绑定数据源 绑定DataReader /DataSet /DataTable
  5. java 中都有什么结构_java中都有哪些数据结构?
  6. 高内聚低耦合通俗理解_带你从入门到精通——「高内聚低耦合」
  7. poj2229 基础的动态规划算法 挑战程序设计竞赛
  8. 理解Monad,一份monad的解惑指南
  9. 回顾云计算项目的得与失
  10. SQLite的查询优化
  11. 微信小程序教学第三章(含视频):小程序中级实战教程:列表-静态页面制作...
  12. 能制作引导系统型U盘的几个软件工具
  13. win10磁盘管理_win10合并磁盘分区教程
  14. 音量公式_家庭影院功放功率与音量之间的秘密
  15. 2006年10大变态站名网站排名
  16. Nacos本地进行了远程配置而远程未配置相关信息而导致应用报内存泄漏问题的异常
  17. 人工智能与复杂网络_为什么我与智能手机的关系变得复杂
  18. 聚力国家工业信息安全发展,未来智安加入工业信息安全产业发展联盟
  19. 剑指 Offer 52—— 两个链表的第一个公共节点
  20. Python中and和or的运算规则,短路计算

热门文章

  1. 转 可以word ,excel ,pdf ,ppt 导入和导出的思维导图
  2. 分布式定时任务的解决方案
  3. 个人商业画布分析-0408-v1.0王玉娟
  4. 北京大学计算机语言学,北京大学计算语言学教育部重点实验室
  5. 谷歌浏览器不支持html2.0,谷歌浏览器不能播放视频怎么办_chrome浏览器无法播放视频的解决方法-系统城...
  6. 微观社会调查数据:中国家庭追踪调查 CFPS
  7. OA无纸化办公系统对公司管理的作用
  8. 计算机博弈 六子棋 人机/人人对弈系统开发
  9. 毕设不要慌,论文写作法
  10. 基于RFID的图书馆管理