csapp-5-优化程序性能
Chapter 5 优化程序性能
编译器的能力和局限性
- 内存别名使用:两个指针可能指向同一个内存位置
- 可能出现这种问题,编译器必须进行检查和处理,这限制了可能的优化
- restrict 关键字,可以告知编译器两个指针不能指向同一块内存,编译器可以进行进一步的优化
内联函数替换(inline substitution)
- 将函数调用替换成函数体;减轻调用的深度
消除循环中的低效率
- 比如将复杂的函数加入循环;此时考虑设置局部变量
- 消除循环中的过程调用;考虑返回值来优化
void combine3(vec_ptr v, data_t* dest) { |
- 上述过程汇编是会发现,每次累积变量的数值都要读入内存再写回内存
- 解决方案:引入临时变量,该临时变量使用寄存器存储;最后只写入一次内存
void combine3(vec_ptr v, data_t* dest) { |
处理器操作的抽象模型
数据流图
- 可以把循环寄存器单独拿出来;根据不同循环操作的周期可以大概估计出该程序性能瓶颈位置
循环展开
- 通过增加每次迭代计算的数量;减少循环的迭代次数
- 但是循环展开可能优化程度有限;取决于关键路径的执行过程
提高并行性
- 整数运算可以;但是浮点数的加法和乘法不能结合;由于浮点数的舍入和溢出可能造成不同的结果
- 重新结合变换,将括号的位置改变;可能可以继续优化程序的性能
循环展开和并行积累在多个值中,是提高程序性能的更可靠方法
- SIMD:单指令流多数据流方式执行程序;每次运算执行向量的计算
限制因素
- 寄存器溢出:如果溢出,将两个数相乘直接保存在寄存器的优势消失
- 分支预测和预测错误惩罚:惩罚是19个时钟周期
- 循环分支被预测为选择分支,只在最后一次导致预测错误惩罚
- 书写适合用条件传送实现的代码:三元操作符代替if-else
内存性能
加载的性能:除开使用cache,每次进行取取操作数,都需要访存
存储的性能:每次存放结果,也需要访存
注意程序中可能存在潜在的加载-存储相关的操作(src和dest指向相同的地址或者dest依赖于src计算后存储的新结果)
http://tom-jerr.github.io/2023/09/12/CSAPP/5-%E4%BC%98%E5%8C%96%E7%A8%8B%E5%BA%8F%E6%80%A7%E8%83%BD/
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 LZY的Code生活!