如何用C ++编写指令缓存友好程序
How to write instruction cache friendly program in c++?
最近,赫伯·萨特(Herb Sutter)发表了题为"现代C++:你需要知道的"的精彩演讲。本次演讲的主题是效率以及数据局部性和访问内存的重要性。他还解释了CPU如何喜欢内存(数组/矢量)的线性访问。他从另一个经典参考"Bob Nystrom的游戏性能"中举了一个例子。
阅读这些文章后,我了解到有两种类型的缓存会影响程序性能:
- 数据缓存
- 指令缓存
缓存研磨工具还测量我们程序的缓存类型检测信息。许多文章/博客已经解释了第一点以及如何实现良好的数据缓存效率(数据局部性)。
但是,我没有获得有关主题指令缓存以及我们应该在程序中注意哪些事情以实现更好的性能的太多信息?根据我的理解,我们(程序员)对执行哪个指令或什么顺序没有太多控制权。
如果小型 c++ 程序解释这个计数器(.i.e 指令缓存)如何随着我们的编写程序风格而变化,那就太好了。程序员应该遵循哪些最佳实践才能在这一点上实现更好的性能?
我的意思是,如果我们的程序以类似的方式(向量与列表)可以解释第二点,我们可以理解数据缓存主题。这个问题的主要目的是尽可能多地理解这个话题。
任何更改执行流的代码都会影响指令缓存。 这包括函数调用和循环以及取消引用函数指针。
当执行分支或跳转指令时,处理器必须花费额外的时间来决定代码是否已经在指令缓存中,或者是否需要重新加载指令缓存(从分支的目标)。
例如,某些处理器可能具有足够大的指令缓存来保存小循环的执行代码。 某些处理器没有大型指令缓存,只需重新加载即可。 重新加载指令高速缓存需要花费执行指令的时间。
搜索以下主题:
- 循环展开
- 条件指令执行(在 ARM 处理器上可用)
- 内联函数
- 指令流水线
编辑1:编程技术以获得更好的性能
要提高性能并减少指令高速缓存重新加载,请执行以下操作:
减少"如果"语句设计代码以最小化"if"语句。 这可能包括布尔代数,使用更多的数学或简化比较(他们真的需要吗? 倾向于减少"then"和"else"子句的内容,以便编译器可以使用条件汇编语言指令。
将小函数定义为内联函数或宏函数
存在与调用函数相关的开销,例如存储返回位置和重新加载指令缓存。 对于具有少量语句的函数,请尝试建议编译器将它们内联。 内联意味着将代码的内容粘贴到执行的位置,而不是进行函数调用。 由于避免了函数调用,因此需要重新加载指令缓存。
展开循环
对于小型迭代,不要循环,而是重复循环的内容(某些编译器可能会在更高的优化级别设置下执行此操作)。 重复的内容越多,循环顶部的分支数量就越少,重新加载指令缓存的需求就越少。
使用表查找,而不是"if"语句
一些程序使用"if-else-if"梯子将数据映射到值。 每个"if"语句都是指令缓存中执行的中断。 有时,只需一点数学运算,就可以将值像数组一样放在表中,并以数学方式计算索引。 一旦知道索引,处理器就可以在不中断指令缓存的情况下检索数据。
更改数据或数据结构
如果数据类型恒定,则可以围绕数据优化程序。 例如,处理消息数据包的程序可以根据数据包 ID (想想函数指针数组)来执行其操作。函数将针对数据包处理进行优化。
将链表更改为数组或其他随机访问容器。 可以使用数学而不是中断执行来访问数组的元素。 必须遍历(循环)链表才能找到项目。
- 试图对缓存进行跨步测试,但程序并没有结束
- 使用宏扩展的泛型:为什么指令缓存使用不当?
- 存储指令是否会阻止缓存未命中的后续指令?
- Qt 网页程序集缓存
- 多线程减慢程序速度:无错误共享,无互斥锁,无缓存未命中,无小工作量
- 正在从程序内存中分解x指令
- VS-2019程序在某些服务器上的第一条浮点指令上崩溃
- 如何在导致应用程序崩溃的代码中修复指令
- 将内联程序集与序列化指令一起使用
- 有没有办法刷新与程序相关的整个CPU缓存
- _mm_fmadd_pd程序收到信号SIGILL,非法指令
- 为新的指令集扩展程序进行了优化的代码的向后兼容性
- 设备驱动程序内存缓冲区处理器缓存问题
- PIN从指令地址获取程序集操作码
- 程序收到信号Sigill非法指令
- 减少指令缓存错过(在C 中)
- 为什么我的代码会导致指令缓存未命中
- clflush不刷新指令缓存
- 如何用C ++编写指令缓存友好程序
- 没有mpi指令的程序在mpirun中非常慢