ZHCUCO7B December   2024  – November 2025 F29H850TU , F29H859TU-Q1

 

  1.   1
  2.   摘要
  3.   商标
  4. 1引言
  5. 2性能优化
    1. 2.1 编译器设置
      1. 2.1.1 启用调试和源代码交叉列
      2. 2.1.2 优化控制
      3. 2.1.3 浮点数学
      4. 2.1.4 定点除法
      5. 2.1.5 单精度与双精度浮点
      6. 2.1.6 链接时优化 (LTO)
    2. 2.2 存储器设置
      1. 2.2.1 从 RAM 执行代码
      2. 2.2.2 从闪存执行代码
      3. 2.2.3 数据放置
    3. 2.3 代码结构和配置
      1. 2.3.1 内联
      2. 2.3.2 内联函数
      3. 2.3.3 易失性变量
      4. 2.3.4 函数参数
      5. 2.3.5 启用更广泛的数据访问
      6. 2.3.6 自动代码生成工具
      7. 2.3.7 准确剖析代码
    4. 2.4 应用代码优化
      1. 2.4.1 SDK 优化库
      2. 2.4.2 使用库优化代码尺寸
      3. 2.4.3 C29 特别指令
      4. 2.4.4 C29 并行性
      5. 2.4.5 首选 32 位变量和写入
      6. 2.4.6 编码风格及其对性能的影响
  6. 3参考资料
  7. 4修订历史记录

启用更广泛的数据访问

嵌入式系统中的许多操作涉及对存储器的连续数据访问(读取或写入)。由于 F29x 上的数据总线宽度为 64 位,此架构允许 64 位数据读取和写入。然而,大多数用户代码限制为 32 位数据,因此访问也限于 32 位。在某些情况下,尤其是数组访问,通过将代码重写为执行 64 位访问而非 32 位访问,可以实现显著性能提升。例如,下面的第一个代码块表示通过 32 位访问执行简单的内存缓冲区读取操作。

uint32_t mem_read_16k_cn(uint32_t *src)
{
    uint32_t i =0;
    uint32_t x =0;
    for (i=0;i<LEN_16K;i++) 
    { 
        x +=*src++; 
    }
    return x;
}

下一个代码块表示使用 64 位访问实现的相同操作,其效率是原来的两倍。

uint32_t mem_read_16k_opt(uint32_t *src)
{
    uint32_t i =0;
    uint64_t *s2 = (uint64_t*) src;
    uint32_t x =0;
    uint32_t x2 =0;
    for (i=0;i<LEN_16K>>1;i++) 
    {
        uint64_t temp =*s2++; 
        x += (temp>>32); 
        x2 += (temp&0xFFFFFFFF); 
    }
    return x+x2;
}

在许多情况下,编译器无需显式重写代码,而是通过将特定属性应用于底层数据,即可提高性能。如果数组已对齐,请使用 __attribute__((aligned(val)) 向编译器指示这样做。例如,数组上的 __attribute__((aligned(8)) 指示 8 字节对齐,并允许编译器一次加载 64 位而不是 32 位。这可以为矩阵乘法等运算带来性能优势。如果数组是全局数组并在函数中直接访问,则上述对齐规范就足够了(请参阅下面的第一个代码块)。另一方面,如果对齐数组作为指针传递到函数中,则需要将 __builtin_assume_aligned 属性应用于指针,以告知编译器该对象的对齐情况(请参阅下面的第二个代码块)。

__attribute__((aligned(8))) float A[100];
__attribute__((aligned(8))) float B[100];
__attribute__((aligned(8))) float C[100];
void matrix_mpy(void)
{ 
int32_T i; 
int32_T i_0; 
int32_T i_1; 
for (i_0 =0; i_0 <10; i_0++) 
{
    for (i =0; i <10; i++) 
    { 
        int32_T C_tmp, tmp; 
        C[10* i_0 + i] =0.0f;
        for (i_1 =0; i_1 <10; i_1++) 
        {
            C[10* i_0 + i] +=A[10* i_1 + i] *B[10* i_0 + i_1]; 
        } 
    } 
}
void matrix_mpy_f32_4by4(float (*restrict Ma_f32) [4], float (*restrict Mb_f32)[4], float (*restrict Mc_f32)[4])
{ 
int32_t i,j,k; 
// Use __builtin_assume_aligned to inform the compiler about alignment Ma_f32 = __builtin_assume_aligned(Ma_f32, 8); 
Mb_f32 = __builtin_assume_aligned(Mb_f32, 8); 
Mc_f32 = __builtin_assume_aligned(Mc_f32, 8);
..
}
注:

目前,编译器无法根据对象的物理地址(即仅基于位置属性)区分对齐。

注:

这种“矢量化”(即将较小数据类型的访问合并到较大数据类型)也可以使用 8 位和 16 位数据进行,编译器的未来版本已计划纳入该功能。