19|极致优化(下):如何实现高性能的 C 程序?
于航
该思维导图由 AI 生成,仅供参考
你好,我是于航。
在上一讲中,我介绍了几个用于编写高性能 C 代码的实用技巧。今天,我们继续聊这个话题,来讨论其他几种常见的 C 代码和程序优化技巧,它们分别是利用循环展开、使用条件传送指令、尾递归调用优化,以及为编译器指定更高的编译优化等级。
技巧五:循环展开(Loop Unrolling)
为了让你更好地理解“循环展开”这个优化技巧背后的原理,我们先从宏观角度看看 CPU 是如何运作的。
早期的 CPU 在执行指令时,是以串行的方式进行的,也就是说,一个指令的执行开始,需要等待前一个指令的执行完全结束。这种方式在实现上很简单,但存在的问题也十分明显:由于指令的执行是一个涉及多个功能单元的复杂过程,而在某一时刻,CPU 也只能够对指令进行针对当前所在阶段的特定处理。
那么,将 CPU 处理指令的流程划分为不同阶段,并让它对多条指令同时进行多种不同处理,这样是否可以进一步提升 CPU 的吞吐量呢?事实正是如此。
现代 CPU 为了进一步提升指令的执行效率,通常会将单一的机器指令再进行拆分,以达到指令级并行的目的。比如,对于一个基本的五级 RISC 流水线来说,CPU 会将指令的执行细分为指令提取(IF)、指令译码(ID)、指令执行(EX)、内存访问(MEM),以及寄存器写回(WB)共五个步骤。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文介绍了实现高性能 C 程序的一些实用技巧,包括循环展开、条件传送指令、尾递归调用优化和编译优化等级。循环展开通过增加循环结构每次迭代时计算的元素个数,减少循环次数,优化 CPU 的指令集并行与流水线调度,提升程序执行效率。条件传送指令能有效避免使用条件分支指令带来的 CPU 周期浪费。使用更高的编译优化等级能让编译器自动进行更多程序执行细节上的优化。尾递归调用优化通过将函数的递归调用过程优化为循环结构,减少了程序执行时对 `call` 指令的调用次数,提升了程序的执行性能。文章还提到了“达夫设备(Duff's Device)”的作用和实现原理。这些技巧能帮助读者优化 C 程序,提升程序性能。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入 C 语言和程序运行原理》,新⼈⾸单¥59
《深入 C 语言和程序运行原理》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(5)
- 最新
- 精选
- 纳兰容若老师您好 我看达夫设备的功能是针对字节的拷贝,达夫设备的效率和标准库中的memcpy哪个效率更高一些呢 多谢老师指教
作者回复: 在大多数情况下,请优先使用标准库中提供的方法,这里也就是 memcpy。达夫设备只是提出了使用循环展开进行优化的一种方式,而这种方式也仅适用于当时它出现的那个特殊场景中,也就是“将 16 位的无符号整数从一个数组中复制到 MMIO 寄存器”。而标准库中的方法在考虑常见性能优化策略的同时,还可能还会使用一些独立于架构的不同优化方式。除此之外,从兼容性、易用性、可读性上也更具优势。
2022-04-202 - 八怪老师 __builtin_expect 能有效减少分支预测带来的性能损失吗?
作者回复: 如果合理使用的话(场景合适),理论上是可以的,Linux 内核里也有在用这些扩展函数。但实际使用时还是建议配合 profiler 检验一下优化效果。
2022-03-22 - fee1in而当五个阶段全部执行完毕后,CPU 会更新指令指针(PC),将其指向下一个需要执行的指令 应该是在IF结束后,更新PC把 不然跳转指令就会出问题
作者回复: 这里针对五级 RISC 流水线来说,实际上 PC 的值一般是在 IF 阶段就可以计算(预测)好的,然后在 WB 之后才会实际更新到 PC 寄存器中。
2022-01-28 - 术子米德🤔☕️🤔☕️🤔 优化,仅知道方法,非常容易出现伪优化 优化,确定度量方法,才能控制住优化真正效果 度量一段实现代码执行所需的耗时,即总指令数,以及每个时钟周期执行的指令数,即IPC=Instructions-Per-Cycle,这两个指标抓住,大部分情况下打开编译器优化,就达到技巧所谓的优化效果 如果要有更多的优化,都是要选择新的算法或者结合业务和运行环境的各种适配性调优,语言层面的技巧开不出更多的花🌹2022-01-26311
- liu_liu看了达夫设备的代码,原来 switch case 语句还可以这样用,涨见识了。2022-01-261
收起评论