发新帖本帖赏金 50.00元(功能说明)我要提问
返回列表
打印
[开发工具]

探讨Keil中优化等级与运行效率关系

[复制链接]
269|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
DKENNY|  楼主 | 2024-6-26 14:02 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 DKENNY 于 2024-6-26 14:23 编辑

#申请原创# @21小跑堂
    在软件开发中,编译器优化选项是提高程序执行效率的关键工具。特别是在嵌入式系统开发中,不同编译器的优化选项可以对代码的性能产生显著影响,本文将探讨Keil编译器中不同优化等级对代码执行效率的关系。

## Keil优化等级说明
  Keil编译器的优化等级是编译过程中一个重要的设置,它可以显著影响程序的性能和大小。

  为什么需要进行编译优化?
  进行编译优化是为了提高程序的性能和效率。编译优化的主要用途包括:
    - 提高执行速度:通过优化代码,减少程序运行时的指令数量,从而加快程序的执行速度。
    - 减少内存占用:优化可以帮助减少程序的大小,降低对内存的需求,这在资源受限的嵌入式系统中尤为重要。
    - 电源管理:优化后的代码可以更有效地使用处理器资源,这有助于降低能耗,延长电池寿命。
    - 提高可靠性和稳定性:优化可以消除代码中的冗余和不必要的部分,有助于提高程序的稳定性和可靠性。

  Keil有几个不同的优化等级:
    - O0这是无优化等级,编译器不会尝试优化代码。这对于调试非常有用,因为生成的代码会非常接近你的原始代码,使得跟踪和理解程序的行为变得容易。
    - O1这个等级提供了基本优化。编译器会尝试不影响代码可读性的前提下,进行一些基本的性能改进。
    - O2在这个等级,编译器会进行更多的优化,如代码重排和循环优化,以提高执行速度和减少代码大小。
    - O3这是最高的优化等级,编译器会尝试所有可能的优化技术来提高程序的运行效率,即使这可能会增加代码的大小。



## 测试环境:
    开发板:APM32F407
    主频:168MHz

### 1.Test_add测试

    一个简单的加法运算。

核心代码:
void add(u32 n)
{
    u32 a = 0, b = 0;
    while (n-- > 0)
    {
        a = b + n;
    }
}

//执行100000次
void test_add(void)
{
    u32 n = 100000;

    while (n-- > 0)
    {
        add(100000);
    }

    return;
}

测试结果:
    如下图是依次选择-O0,-O1,-O2,-O3得到的代码执行时间。



### 2.Test_FFT测试

    这是一个较复杂的运算,FFT代表快速傅里叶变换。

核心代码:
#define PI 3.14159265358979323846
#define N 1024 // 定义FFT的点数

typedef struct
{
    double real;
    double imag;
} complex32;

//typedef unsigned int u32;

int count = 0;

// 位反转置换函数
void bitReversal(complex32 *pSrc, u32 n)
{
    u32 i, j, k;
    for (i = 1, j = 0; i < n; i++)
    {
        for (k = n >> 1; k > (j ^= k); k >>= 1)
        {
        }
        if (i < j)
        {
            complex32 temp = pSrc[i];
            pSrc[i] = pSrc[j];
            pSrc[j] = temp;
        }
    }
}

// 迭代FFT函数
void iterativeFFT(complex32 *pSrc, u32 n)
{
    // 预先计算Wn数组
    complex32 *Wn = (complex32 *)malloc(sizeof(complex32) * n / 2);
    for (u32 i = 0; i < n / 2; i++)
    {
        Wn[i].real = cos(2 * PI * i / n);
        Wn[i].imag = -sin(2 * PI * i / n);
    }

    // 位反转置换
    bitReversal(pSrc, n);

    // FFT主循环
    for (u32 s = 1; s <= log2(n); s++)
    {
        u32 m = 1 << s;
        u32 m2 = m >> 1;
        complex32 w;
        w.real = 1.0;
        w.imag = 0.0;
        for (u32 j = 0; j < m2; j++)
        {
            for (u32 k = j; k < n; k += m)
            {
                u32 t = k + m2;
                complex32 u = pSrc[k];
                complex32 v;
                v.real = w.real * pSrc[t].real - w.imag * pSrc[t].imag;
                v.imag = w.real * pSrc[t].imag + w.imag * pSrc[t].real;
                pSrc[k].real = u.real + v.real;
                pSrc[k].imag = u.imag + v.imag;
                pSrc[t].real = u.real - v.real;
                pSrc[t].imag = u.imag - v.imag;
            }
            complex32 wn = Wn[n / m * j];
            w.real = w.real * wn.real - w.imag * wn.imag;
            w.imag = w.real * wn.imag + w.imag * wn.real;
        }
    }
    free(Wn);
}

测试结果:

    如下图是依次选择-O0,-O1,-O2,-O3得到的代码执行时间。


### 测试数据对比:
  
优化等级
  
Test_add(单位:秒)
Test_fft(单位:秒)
-O0
298.978190
68.000412
-O1
239.971474
62.022487
-O2
179.987680
61.009636
-O3
179.987680
61.985575

### 测试数据分析:
    - 对于简单的加法操作(test_add),随着编译优化等级的提升,执行时间显著减少。特别是从 -O0-O1 ,以及从 -O1-O2,我们看到了明显的性能提升。然而,从 -O2-O3,性能提升不再明显,执行时间保持不变,这表明对于简单运算,-O2 已经足够优化。

    - 对于复杂的运算,如快速傅里叶变换(test_fft),优化等级的提升同样带来了性能的提升,但提升幅度相对较小。从 -O0-O1 有一定的性能提升,而从 -O1-O2,我们看到了最佳的执行时间,但从 -O2-O3,执行时间反而略有增加。

    打个简单的比方,当你让电脑做一些非常基本的事情,比如简单的加法,提高编译器的优化水平就像是给电脑喝了能量饮料,它会变得更快。但是,就像人在喝了太多能量饮料后不会变得更聪明一样,电脑在处理复杂的数学问题时,即使优化了,也不会有太大的提升。这是因为复杂的问题本身就很难处理,就像是需要解决一个超级难的数独谜题,而不仅仅是数数那么简单。
    所以,当你让电脑做更复杂的事情,比如快速傅里叶变换(一种复杂的运算),即使你给它更多的能量饮料(也就是更高级的优化),它也只能快那么一点点。因为这时候,电脑不仅要算数,还要记住很多东西,还要做很多决定,这些都会让它慢下来。
    总之,让电脑做简单的事情时,优化可以大大提高速度。但是对于复杂的任务,优化帮助不大,因为任务本身就很难。

## 总结
    总的来说,随着编译优化等级的提高,简单和复杂的运算都有性能提升,但简单运算的提升更为显著。这可能是因为编译器优化更容易对简单的重复操作进行优化,如循环展开、指令重排等。而对于复杂运算,尽管优化也有帮助,但由于算法本身的复杂性,优化空间可能不如简单运算那么大。此外,复杂运算可能涉及更多的内存访问和分支预测,这些因素也会影响优化的效果。

    附件为该测试的工程源码,有需要的可自行下载。
Compilation_Optimization.zip (788.06 KB)




使用特权

评论回复

打赏榜单

21小跑堂 打赏了 50.00 元 2024-06-27
理由:恭喜通过原创审核!期待您跟多的原创作品~

评论
21小跑堂 2024-6-27 13:23 回复TA
Keil中优化等级变换的代码执行速度问题探讨,作者通过实际测试对比不同优化等级下MCU执行速度的对比,并通过自己的理解巧妙地解释速度的变化和变化程度的问题,十分形象。关于编译器的优化还有更多可探讨的问题,包括内存占用和带来的相关隐患,欢迎各位大佬发挥自己的独特见解。 
发新帖 本帖赏金 50.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

20

主题

35

帖子

4

粉丝