Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
cpu流水线技术_流水线结构在CPU中的运用是一种,希望能够帮助你!!!。
CPU在执行指令的时候,一条指令并不是一下就完成的,会有生命周期,例如很经典的有MIPS五级流水线,一条指令执行完毕需要五步
这五步中的前三步,在这个网页中有更好的说明,还有图。计算机指令在CPU中的执行过程(图文版)
如果是普通的逻辑,就是当一条指令执行完“写回”之后再进行下一条指令的“取指”,但是这样会有很大的浪费,因为第一条指令在执行译码的时候,取指、执行、访存和写回都是空着的。下图就是一条指令执行过程中的硬件电路的原理图。
理想情况下,最好的办法就是,第一条指令只要开始执行译码,第二条指令就进来,第一条指令进入执行的时候,第二条指令进入译码,第三条指令进入取指。一个五级流水线结构在七个机器周期内有三个指令被全部执行完毕。如下图所示的效果
正如上面所说,CPU流水线的存在,第一条指令只要过了取指,第二条指令就进入流水线了,但是第一条指令还没执行完呢,第二条指令就进来,进啥呢?我们都不知道,CPU肯定更不知道了,就只能猜,这个猜就是分支预测。如果猜对了,那很好,执行效率会很高,如果猜错了,就要把已经装填好的指令全部退掉,重新装填,成本也是很高的。不管怎么做肯定都是猜,所以最好的办法肯定是尽量避免分支预测。
不同的处理器会有不同的处理方式,SPARC和MIIPS最要用的方法是:预测条件跳转不会发生,因此总是顺序取下一条指令推测执行,仅当条件跳转指令被求值确实发生了跳转,才会把非顺序的指令插入。分支预测的过程发生在执行阶段之前,在其中插入一个分支延迟间隙,也就是发现错误退出的时候,这个指令也已经执行过两次了。
这个方法看起来就比较笨。
利用分支指令发生转移的历史进行预测,并根据实际执行情况,进行动态调整,目前所有的处理器都用动态预测,这个的准确率能到90%。
剩下的还有饱和计数、两级自适应预测、局部预测、全局预测很多很多,这都是根据硬件决定的。
按照前面介绍的分支预测方法,大部分都是根据之前的行为来预测后续的行为,也就是说当输入的数据是大量且无规律的,同时有参数判断过程的存在,下一次执行的指令就不确定了,就可以认为有一大部分的数据都会分支预测错误。因此解决问题的方法就有两个:
#include<chrono> #include<iostream> #include<algorithm> #include<vector> #include<cstdlib> #include<time.h> #define NUM #define VEC_CONTENT 1000 void randomCase(const std::vector<int>& randomVec) { auto start = std::chrono::system_clock::now(); long long minusSum = 0; for(auto valVec : randomVec) if(valVec<0) minusSum += valVec; auto end = std::chrono::system_clock::now(); std::cout<<"randomCase's result is "<<minusSum<<", and time cost is "; std::cout<<std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count(); std::cout<<"ms"<<std::endl; return ; } void sortedCase(const std::vector<int>& randomVec) { std::vector<int>sortedVec = randomVec; std::sort(sortedVec.begin(), sortedVec.end()); auto start = std::chrono::system_clock::now(); long long minusSum = 0; for(auto valVec : sortedVec) if(valVec<0) minusSum += valVec; auto end = std::chrono::system_clock::now(); std::cout<<"sortedCase's result is "<<minusSum<<", and time cost is "; std::cout<<std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count(); std::cout<<"ms"<<std::endl; return ; } void bitCase(const std::vector<int>& randomVec) { std::vector<int>sortedVec = randomVec; auto start = std::chrono::system_clock::now(); long long minusSum = 0; for(auto valVec : sortedVec) minusSum += (valVec>>31) & valVec; auto end = std::chrono::system_clock::now(); std::cout<<"bitCase's result is "<<minusSum<<", and time cost is "; std::cout<<std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count(); std::cout<<"ms"<<std::endl; return ; } void vecCreate(std::vector<int>& randomVec) { size_t n = randomVec.size(); for(size_t i=0; i<n; ++i) randomVec[i] = std::rand()%((VEC_CONTENT<<1) + 1) - VEC_CONTENT; } int main(void) { std::srand((unsigned)time(nullptr)); std::vector<int>randomVec(NUM); vecCreate(randomVec); randomCase(randomVec); sortedCase(randomVec); bitCase(randomVec); return 0; }
没用O2的时候输出结果如下
randomCase's result is -, and time cost is 17ms sortedCase's result is -, and time cost is 8ms bitCase's result is -, and time cost is 9ms
可见排好序之后速度会快很多,和bitcase的效果差不多。不过如果把排序时间算上就比random慢了,但是我看到说有的时候把排序时间算上还比randomcase快的,但不知道是不是和java有关系。
这个分支预测的问题,一般只会发生在大量无序数据判断的时候。
那既然if可以用位预算提速,是不是所有的if都要换呢?我觉得这样并不好,因为如果数据量不大,对效率的提升微乎其微,而且最大的问题是可读性会变得很差。
部分资料和图来自下面的网站
https://zhuanlan.zhihu.com/p/
https://zh.wikipedia.org/wiki/%E5%88%86%E6%94%AF%E9%A0%90%E6%B8%AC%E5%99%A8
https://blog.csdn.net/hanzefeng/article/details/
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
上一篇
已是最后文章
下一篇
已是最新文章