理解处理器的“分支预测逻辑”,优化程序性能
2013-10-22 17:51
393 查看
一、什么是“分支预测逻辑”?为什么需要它?
由于处理器通过流水线技术来提高性能,而流水线要求事先知道接下来要执行的具体指令,才能保持流水线中充满待执行的指令。当在程序中遇到分支语句/条件跳转时,问题就出现了,处理器不确定下一条指令是什么,这时就需要进行“分支预测逻辑”来确定哪一条指令进入流水线。
如果预测了一个分支加入流水线,之后确发现它是错误的分支,处理器要回退该错误预测执行的工作,再用正确的指令填充流水线。这样一个错误的预测会严重浪费时钟周期,导致程序性能下降。
举个例子:一个人走到一个岔路口(分支语句),他不知道正确的路是左边还是右边。如果他选择了一条路走了一会后发现不对,他就要再返回到岔路口再走另外一条路,白白耗费了时间。如果他能一次就找到争取的路就好了(分支预测逻辑的必要性)。如何能做到呢?如果他要多次走过岔路口,发现总是右边的路是对的,这时候当再遇到岔路口时,他就可以预测右边的路是正确的(分支预测逻辑的一种原理)。
二、怎样根据“分支预测逻辑”来优化程序性能?
1.一个排序后提升程序性能的例子:
25行是个岔路口,如果随机数是乱序的,分支预测的结果只有50%的正确率,严重影响性能。
然而去掉15行的注释后再执行,由于数组有序,前一部分循环在分支处总是选择同样的分支(<128),这样每到分支处就很容易预测成功,预测成功的概率在90%以上。程序执行速度加快!
还有一种利用位运算避免分支预测的巧妙方法:
把25、26行替换为:
2.编译器在将代码编译成汇编语言时,处理分支语句时,遇到条件判断的表达时很容易计算的情况,会用条件数据传送指令代替条件控制转移指令,使得无需预测下一条指令,从而改进代码效率。
由于处理器通过流水线技术来提高性能,而流水线要求事先知道接下来要执行的具体指令,才能保持流水线中充满待执行的指令。当在程序中遇到分支语句/条件跳转时,问题就出现了,处理器不确定下一条指令是什么,这时就需要进行“分支预测逻辑”来确定哪一条指令进入流水线。
如果预测了一个分支加入流水线,之后确发现它是错误的分支,处理器要回退该错误预测执行的工作,再用正确的指令填充流水线。这样一个错误的预测会严重浪费时钟周期,导致程序性能下降。
举个例子:一个人走到一个岔路口(分支语句),他不知道正确的路是左边还是右边。如果他选择了一条路走了一会后发现不对,他就要再返回到岔路口再走另外一条路,白白耗费了时间。如果他能一次就找到争取的路就好了(分支预测逻辑的必要性)。如何能做到呢?如果他要多次走过岔路口,发现总是右边的路是对的,这时候当再遇到岔路口时,他就可以预测右边的路是正确的(分支预测逻辑的一种原理)。
二、怎样根据“分支预测逻辑”来优化程序性能?
1.一个排序后提升程序性能的例子:
#include <algorithm> #include <ctime> #include <iostream> int main() { // 产生随机数数组,随机数在0-255之间 const unsigned arraySize = 32768; int data[arraySize]; for (unsigned c = 0; c < arraySize; ++c) data[c] = std::rand() % 256; // 关键:加上这句后程序运行明显会更快! //std::sort(data, data + arraySize); // 测试 clock_t start = clock(); long long sum = 0; for (unsigned i = 0; i < 100000; ++i) { for (unsigned c = 0; c < arraySize; ++c) { if (data[c] >= 128) //条件分支 sum += data[c]; } } double elapsedTime = static_cast<double>(clock() - start) / CLOCKS_PER_SEC; std::cout << elapsedTime << std::endl; std::cout << "sum = " << sum << std::endl; }
25行是个岔路口,如果随机数是乱序的,分支预测的结果只有50%的正确率,严重影响性能。
然而去掉15行的注释后再执行,由于数组有序,前一部分循环在分支处总是选择同样的分支(<128),这样每到分支处就很容易预测成功,预测成功的概率在90%以上。程序执行速度加快!
还有一种利用位运算避免分支预测的巧妙方法:
把25、26行替换为:
int t = (data[c] - 128) >> (sizeof(int) - 1); sum += (~t & data[c]);
2.编译器在将代码编译成汇编语言时,处理分支语句时,遇到条件判断的表达时很容易计算的情况,会用条件数据传送指令代替条件控制转移指令,使得无需预测下一条指令,从而改进代码效率。
相关文章推荐
- 深入理解计算机系统:程序性能优化
- 深入理解计算机系统之旅(五)优化程序性能
- 如何理解Android程序运行性能优化
- 程序性能优化-深入理解计算机系统
- cs app深入理解计算机系统:第五章 优化程序性能 几个优化的java实现
- 《深入理解计算机系统 第3版》学习笔记——第5章 优化程序性能(程序优化方法总结)
- 优化程序性能 计算机系统结构 深入理解计算机系统
- [读书笔记]深入理解计算机系统 第6章 优化程序性能
- 对于程序性能优化的理解
- 深入理解计算机系统之旅(五)优化程序性能
- 深入理解计算机系统--优化程序性能
- 对于程序性能优化的理解
- 深入理解计算机系统:优化程序性能
- 优化程序性能(2)——处理器相关的优化
- 开源处理器Rocket的分支预测机制研究与性能评估(二)
- 深入理解计算机系统——第05章——优化程序性能
- 深入理解计算机系统(5.1)------优化程序性能
- 深入理解计算机系统阅读笔记-优化程序性能
- 深入理解计算机系统:优化程序性能
- 5、深入理解计算机系统笔记:优化程序性能