如何写出高质量c代码(三)速度优化

最近我们的项目有计算性能瓶颈,需要在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 <stdio.h>
#include <stdlib.h>
#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

猜你喜欢

转载自blog.csdn.net/bin_zhang1/article/details/80970451