最近我们的项目有计算性能瓶颈,需要在1s内完成400次8192点的FFT,所以优化就成重中之重
那我们的代码运行的速度和哪些因素相关那?
1.算法本身的复杂程度,这一点最为重要,这个层面的优化可以最大程度的减少算法的复杂度
2.平台的运算速度,多核、dsp、gpu、vpu的使用会使算法这对应的平台上速度大大加快
3.特殊的运算单元,有些特殊的运算单元支持超带宽存取,有的甚至达到256bit甚至512bit,有的还支持多位运算数同时运算
4.存储器存取方式
5.当然最重要还是你写的代码
为了方便演示,我这里使用一个图像处理的例子,不能用定位算法啊,这涉及保密了,哈哈
我这里用的例子是将RPG格式图像YUV
为了验证算法的可行性我们先用matlab做下模拟
原图
clear;
clc;
RGB = imread('mi.jpg');
R = RGB(:,:,1);
G = RGB(:,:,2);
B = RGB(:,:,3);
x = size(RGB,1);
y = size(RGB,2);
% RGB2YUV
Y = 0.299*R + 0.587*G + 0.114*B;
U = -0.147*R- 0.289*G + 0.436*B;
V = 0.615*R - 0.515*G - 0.100*B;
YUV = cat(3, Y, U, V);
figure;
imshow(YUV);
我是直接在pc上跑的,每次优化的效果可能不明显,因为我的pc配置太高了,哈哈哈
下面是c的实现,为了方便我直接从matlab导出数据放到数组中,在这过程中我也做了一次优化了,就是把二位的图像放在以为数组中存储,cpu处理一维数组的速度比多维数组速度快
#include
#include
#include "R.h"
#include "G.h"
#include "B.h"
#define LEN 0xAB900 //540 * 1280
void rgb2yuv_opti(int *R, int *G, int *B, int *Y, int *U, int *V)
{
long i;
for (i = 0; i < LEN; ++i)
{
Y[i] = 0.299 * R[i] + 0.587 * G[i] + 0.114 * B[i];
U[i] = -0.147 * R[i] - 0.289 * G[i] + 0.436 * B[i];
V[i] = 0.615 * R[i] - 0.515 * G[i] - 0.100 * B[i];
}
}
void main()
{
int *Y = (int *)malloc(LEN * sizeof(int));
int *U = (int *)malloc(LEN * sizeof(int));
int *V = (int *)malloc(LEN * sizeof(int));
struct timeval start, end;
gettimeofday( &start, NULL );
rgb2yuv_opti(R, G, B, Y, U, V);
gettimeofday( &end, NULL );
int timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
printf("time: %d us\n", timeuse);//微秒
}
time:25221 us
第一次优化
1.因为因为图像深度都是0-255之间的,所以把int改成unsigned short
2.机器对浮点数运算速度比较慢,所以我们把小数改成整数
int rgb2yuv_opti(unsigned short *R, unsigned short *G, unsigned short *B, unsigned short *Y, unsigned short *U, unsigned short *V)
{
long long i;
for (i = 0; i < LEN; ++i)
{
Y[i] = (299 * R[i] + 587 * G[i] + 114 * B[i])/1000;
U[i] = (-147 * R[i] - 289 * G[i] + 436 * B[i])/1000;
V[i] = (615 * R[i] - 515 * G[i] - 100 * B[i])/1000;
}
}
哈哈 时间缩短了接近一半 time: 14038 us
第二次优化
1.因为 299/1000 约等于 1224/4096(这样会稍微的丢失精度),然后出操作用>>替代 /
int rgb2yuv_opti(unsigned short *R, unsigned short *G, unsigned short *B, unsigned short *Y, unsigned short *U, unsigned short *V)
{
long long i;
for (i = 0; i < LEN; ++i)
{
Y[i] = (1224 * R[i] + 2404 * G[i] + 467 * B[i])>>12;
U[i] = (-602 * R[i] - 1183 * G[i] + 1785 * B[i])>>12;
V[i] = (2519 * R[i] - 2109 * G[i] - 409 * B[i])>>12;
}
}
时间有所短了一些 time: 11876 us
第三次优化
1.充分利用CPU中的三个ALU并行计算
int rgb2yuv_opti(unsigned short *R, unsigned short *G, unsigned short *B, unsigned short *Y, unsigned short *U, unsigned short *V)
{
long long i;
for (i = 0; i < LEN; i += 3)
{
Y[i] = (1224 * R[i] + 2404 * G[i] + 467 * B[i])>>12;
U[i] = (-602 * R[i] - 1183 * G[i] + 1785 * B[i])>>12;
V[i] = (2519 * R[i] - 2109 * G[i] - 409 * B[i])>>12;
Y[i+1] = (1224 * R[i+1] + 2404 * G[i+1] + 467 * B[i+1])>>12;
U[i+1] = (-602 * R[i+1] - 1183 * G[i+1] + 1785 * B[i+1])>>12;
V[i+1] = (2519 * R[i+1] - 2109 * G[i+1] - 409 * B[i+1])>>12;
Y[i+2] = (1224 * R[i+2] + 2404 * G[i+2] + 467 * B[i+2])>>12;
U[i+2] = (-602 * R[i+2] - 1183 * G[i+2] + 1785 * B[i+2])>>12;
V[i+2] = (2519 * R[i+2] - 2109 * G[i+2] - 409 * B[i+2])>>12;
}
}
时间进一步缩短 time: 9530 us
到这里我优化的演示就到这里吧,其实我们fft算法中用到的优化方法比这个要多得多比如说:
1.查表法,我们将很多固定的数据事先算好放到表中,使用宏定义也是这个道理,这个方法优化特别明显
2.把经常调用的函数用inline定义,这样函数会被放到内存,中加快速度
3.把经常用到的内存区域mmap到内存中,提高速度
4.充分利用硬件资源,我们的dsp支持最大256位数据存取,可以8个数同时乘加操作等等
源码放在这里
https://download.csdn.net/download/bin_zhang1/10530464