当前位置: 首页 > news >正文

C语言中奇技淫巧04-仅对指定函数启用编译优化

相信很多人使用GCC编译代码时,都会接触到gcc -O0/1/2/3/s,知道它可以对工程进行全局优化。

事实上,除了全局优化外,使用GCC扩展方式,我们还可以仅对部分关键函数实施差异化编译优化。

在GCC编译器中,attribute((optimize(“Ox”))) 可以为单个函数显式指定优化级别,覆盖全局编译选项(如 -O0 或 -Os)。这一特性适用于需要对特定函数进行针对性优化的场景(例如性能关键路径),而其他函数保持较低优化级别以便调试。
使用示例:

#include <stdio.h>// 全局编译级别为 -O0(默认不优化)
// 但对 foo 函数单独启用 O3 优化
__attribute__((optimize("O3")))
int foo(int a, int b) {int i, j, v;for (i = 0; i < a; i++) {for (j = 0; j < b; j++) {v += i*j;	}}return v;
}//本函数使用默认优化级-O0,与foo()进行优化对比
int foo2(int a, int b) {int i, j, v;for (i = 0; i < a; i++) {for (j = 0; j < b; j++) {v += i*j;	}}return v;
}int main(void) {int a = 0, b = 0;a = foo(10, 2); // main 函数仍遵循全局 -O0b = foo(10, 2);return 0;
}

使用gcc test.c -g 进行编译,并使用objdump -dS a.out进行反汇编,可以看出foo()foo2()函数汇编代码大不相同。

其中,foo()由于函数包含 计算密集型嵌套循环(v += i*j),-O3 触发了 自动向量化,通过 128位 SSE2 指令(如 pmuludq、paddd)并行处理多个 j 值的乘法和累加,将循环吞吐量提升数倍。

__attribute__((optimize("O3")))
int foo(int a, int b) {1130:       f3 0f 1e fa             endbr64int i, j, v;for (i = 0; i < a; i++) {1134:       85 ff                   test   %edi,%edi1136:       0f 8e f3 00 00 00       jle    122f <foo+0xff>113c:       41 89 f1                mov    %esi,%r9d113f:       41 89 f2                mov    %esi,%r10d1142:       44 8d 5e ff             lea    -0x1(%rsi),%r11d1146:       31 c9                   xor    %ecx,%ecx1148:       41 c1 e9 02             shr    $0x2,%r9d114c:       41 83 e2 fc             and    $0xfffffffc,%r10d1150:       45 31 c0                xor    %r8d,%r8dfor (j = 0; j < b; j++) {1153:       85 f6                   test   %esi,%esi1155:       0f 8e c1 00 00 00       jle    121c <foo+0xec>115b:       66 0f 6f 35 bd 0e 00    movdqa 0xebd(%rip),%xmm6        # 2020 <_IO_stdin_used+0x20>1162:       001163:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)1168:       41 83 fb 15             cmp    $0x15,%r11d116c:       0f 86 b9 00 00 00       jbe    122b <foo+0xfb>1172:       66 41 0f 6e f8          movd   %r8d,%xmm7
int foo(int a, int b) {1177:       66 0f 6f 1d 91 0e 00    movdqa 0xe91(%rip),%xmm3        # 2010 <_IO_stdin_used+0x10>117e:       00117f:       31 c0                   xor    %eax,%eax1181:       66 0f ef d2             pxor   %xmm2,%xmm21185:       66 0f 70 e7 00          pshufd $0x0,%xmm7,%xmm4118a:       66 0f 6f ec             movdqa %xmm4,%xmm5118e:       66 0f 73 d5 20          psrlq  $0x20,%xmm51193:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)1198:       66 0f 6f c3             movdqa %xmm3,%xmm0119c:       83 c0 01                add    $0x1,%eax119f:       66 0f fe de             paddd  %xmm6,%xmm3v += i*j;11a3:       66 0f 6f c8             movdqa %xmm0,%xmm111a7:       66 0f 73 d0 20          psrlq  $0x20,%xmm011ac:       66 0f f4 cc             pmuludq %xmm4,%xmm111b0:       66 0f f4 c5             pmuludq %xmm5,%xmm011b4:       66 0f 70 c9 08          pshufd $0x8,%xmm1,%xmm111b9:       66 0f 70 c0 08          pshufd $0x8,%xmm0,%xmm011be:       66 0f 62 c8             punpckldq %xmm0,%xmm111c2:       66 0f fe d1             paddd  %xmm1,%xmm2for (j = 0; j < b; j++) {11c6:       44 39 c8                cmp    %r9d,%eax11c9:       75 cd                   jne    1198 <foo+0x68>11cb:       66 0f 6f c2             movdqa %xmm2,%xmm011cf:       66 0f 73 d8 08          psrldq $0x8,%xmm011d4:       66 0f fe d0             paddd  %xmm0,%xmm211d8:       66 0f 6f c2             movdqa %xmm2,%xmm011dc:       66 0f 73 d8 04          psrldq $0x4,%xmm011e1:       66 0f fe d0             paddd  %xmm0,%xmm211e5:       66 0f 7e d0             movd   %xmm2,%eax11e9:       01 c1                   add    %eax,%ecx11eb:       44 89 d0                mov    %r10d,%eax11ee:       44 39 d6                cmp    %r10d,%esi11f1:       74 19                   je     120c <foo+0xdc>11f3:       89 c2                   mov    %eax,%edx11f5:       41 0f af d0             imul   %r8d,%edx11f9:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)1200:       83 c0 01                add    $0x1,%eaxv += i*j;1203:       01 d1                   add    %edx,%ecxfor (j = 0; j < b; j++) {1205:       44 01 c2                add    %r8d,%edx1208:       39 f0                   cmp    %esi,%eax120a:       7c f4                   jl     1200 <foo+0xd0>for (i = 0; i < a; i++) {120c:       41 83 c0 01             add    $0x1,%r8d1210:       44 39 c7                cmp    %r8d,%edi1213:       0f 85 4f ff ff ff       jne    1168 <foo+0x38>}}return v;
}1219:       89 c8                   mov    %ecx,%eax121b:       c3                      retfor (i = 0; i < a; i++) {121c:       41 83 c0 01             add    $0x1,%r8d1220:       44 39 c7                cmp    %r8d,%edi1223:       0f 85 2a ff ff ff       jne    1153 <foo+0x23>1229:       eb ee                   jmp    1219 <foo+0xe9>for (j = 0; j < b; j++) {122b:       31 c0                   xor    %eax,%eax122d:       eb c4                   jmp    11f3 <foo+0xc3>for (i = 0; i < a; i++) {122f:       31 c9                   xor    %ecx,%ecx
}1231:       89 c8                   mov    %ecx,%eax1233:       c3                      ret

通过 SIMD 指令并行处理数据、循环分块适配向量长度、寄存器深度复用以消除内存访问,最终实现执行速度的大幅提升。

而使用默认优化级别的foo2()函数未对循环做任何展开,也未调用SIMD指令进行优化:

//本函数使用默认优化级-O0,与foo()进行优化对比
int foo2(int a, int b) {1234:       f3 0f 1e fa             endbr641238:       55                      push   %rbp1239:       48 89 e5                mov    %rsp,%rbp123c:       89 7d ec                mov    %edi,-0x14(%rbp)123f:       89 75 e8                mov    %esi,-0x18(%rbp)int i, j, v;for (i = 0; i < a; i++) {1242:       c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%rbp)1249:       eb 23                   jmp    126e <foo2+0x3a>for (j = 0; j < b; j++) {124b:       c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%rbp)1252:       eb 0e                   jmp    1262 <foo2+0x2e>v += i*j;1254:       8b 45 f4                mov    -0xc(%rbp),%eax1257:       0f af 45 f8             imul   -0x8(%rbp),%eax125b:       01 45 fc                add    %eax,-0x4(%rbp)for (j = 0; j < b; j++) {125e:       83 45 f8 01             addl   $0x1,-0x8(%rbp)1262:       8b 45 f8                mov    -0x8(%rbp),%eax1265:       3b 45 e8                cmp    -0x18(%rbp),%eax1268:       7c ea                   jl     1254 <foo2+0x20>for (i = 0; i < a; i++) {126a:       83 45 f4 01             addl   $0x1,-0xc(%rbp)126e:       8b 45 f4                mov    -0xc(%rbp),%eax1271:       3b 45 ec                cmp    -0x14(%rbp),%eax1274:       7c d5                   jl     124b <foo2+0x17>}}return v;1276:       8b 45 fc                mov    -0x4(%rbp),%eax
}1279:       5d                      pop    %rbp127a:       c3                      ret

如果需要对多个函数应用相同优化,也可使用 #pragma GCC optimize 作用于代码块:

#pragma GCC push_options
#pragma GCC optimize("O2")int bar(int x) { /* O2 优化 */ }
int baz(int y) { /* O2 优化 */ }#pragma GCC pop_options // 恢复全局优化级别

注意事项:

  1. 不是 C 语言标准!!!C 语言标准(如 C99、C11、C17 等)仅定义了语言的语法、语义和标准库,未规定编译器优化相关的属性语法。attribute 关键字是 GCC(GNU Compiler Collection)为代表的编译器引入的 非标准扩展,用于向编译器传递额外信息(如优化策略、代码生成约束等)。
    主要由 GCC、Clang 等兼容 GCC 扩展的编译器支持,MSVC、ICC 等其他编译器可能不支持或使用不同语法(如 MSVC 使用 __declspec 或 #pragma)。若代码中使用此类扩展,可能导致在非 GCC 系编译器上编译失败,需通过条件编译(如 #ifdef GNUC)处理兼容性。
  2. 优化级别语法: 可指定具体级别(O0/O1/O2/O3/Os),或附加选项(如 optimize(“O2”, “unroll-loops”))。
  3. 与全局优化的关系: 函数属性优先级高于全局编译选项,但部分全局优化(如 -ffast-math)可能仍会影响函数。
http://www.lryc.cn/news/599622.html

相关文章:

  • 恋爱时间倒计时网页设计与实现方案
  • C#观察者模式示例代码
  • Idefics2:构建视觉-语言模型时,什么是重要的
  • ‌通向数字孪生的大门:掌握RVT到3DTiles的关键转换流程
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 主页-评论用户时间占比环形饼状图实现
  • 经验累积分布函数VS累积分布函数
  • Vue nextTick
  • 基于多模型AI训练与验证系统开发
  • 移动端设备能部署的llm
  • MC_GearInPos电子齿轮
  • Pytest tmp_path 实战指南:测试中的临时目录管理
  • 基于单片机的数字电压表设计
  • MyBatis-Plus 指南
  • 光耦合器:新能源世界的“绿色信使“
  • 全面解析MySQL(3)——CRUD进阶与数据库约束:构建健壮数据系统的基石
  • Krpano 工具如何调节全景图片切割之后的分辨率
  • 代码随想录算法训练营第三十一天
  • 卡尔曼滤波器噪声方差设置对性能影响的仿真研究
  • MATLAB 设置默认启动路径为上次关闭路径的方法
  • 【优选算法】链表
  • 从 SQL Server 到 KingbaseES V9R4C12,一次“无痛”迁移与深度兼容体验实录
  • UG创建的实体橘黄色实体怎么改颜色?
  • 每日算法-数组合并
  • [RPA] Excel中的字典处理
  • ubuntu22.04.4锁定内核应对海光服务器升级内核无法启动问题
  • CPU(中央处理器)和GPU(图形处理器)的区别
  • 在线事务型的业务、实时分析类业务、离线处理类型的业务
  • 如何提高微信小程序的应用速度
  • 代码随想录算法训练营第五十三天|图论part4
  • 基于spring boot的纺织品企业财务管理系统(源码+论文)