如何在c ++中编写指令缓存友好程序?

Man*_*mar 14 c++ caching c++11 cachegrind c++14

最近Herb Sutter就"现代C++:你需要知道什么"发表了精彩演讲.本次演讲的主题是效率以及数据位置和访问内存的重要性.他还解释了内存(数组/向量)的线性访问如何被CPU所喜爱.他从另一个经典参考"Bob Nystrom的游戏表演"中就此主题举了一个例子.

阅读这些文章后,我得知有两种类型的缓存会影响程序性能:

  1. 数据缓存
  2. 指令缓存

Cachegrind工具还测量我们程序的缓存类型检测信息.许多文章/博客已经解释了第一点,以及如何实现良好的数据缓存效率(数据位置).

但是我没有获得关于主题指令缓存的更多信息以及我们应该在我们的程序中采取什么样的方法来实现更好的性能?根据我的理解,我们(程序员)对哪条指令或执行的命令没有多少控制权.

如果小型c ++程序解释了这个计数器(.ie指令缓存)将如何随着我们的编写程序风格而变化,那将是非常好的.程序员应遵循哪些最佳实践来达到更好的性能?

我的意思是,如果我们的程序(矢量与列表)以类似的方式解释第二点,我们可以理解数据缓存主题.这个问题的主要目的是尽可能地理解这个主题.

Tho*_*ews 10

任何改变执行流程的代码都会影响指令缓存.这包括函数调用和循环以及解除引用函数指针.

当执行分支或跳转指令时,处理器必须花费额外的时间来判断代码是否已经在指令高速缓存中,或者是否需要重新加载指令高速缓存(来自分支的目的地).

例如,某些处理器可能具有足够大的指令高速缓存来保存小循环的执行代码.有些处理器没有大的指令缓存,只需重新加载即可.重新加载指令高速缓存需要花费时间来执行指令.

搜索以下主题:

  • 循环展开
  • 条件指令执行(在ARM处理器上可用)
  • 内联函数
  • 指令管道

编辑1:编程技术以获得更好的性能
要提高性能并减少指令缓存重新加载,请执行以下操作:

减少"if"语句 设计代码以最小化"if"语句.这可能包括布尔代数,使用更多的数学或简化比较(他们真的需要吗?).更喜欢减少"then"和"else"子句的内容,以便编译器可以使用条件汇编语言指令.

将小函数定义为内联或宏
有一个与调用函数相关的开销,例如存储返回位置和重新加载指令缓存.对于具有少量语句的函数,请尝试向编译器建议它们是内联的.内联意味着将代码的内容粘贴到执行所在的位置,而不是进行函数调用.由于避免了函数调用,因此需要重新加载指令高速缓存.

展开循环
对于小的迭代,不要循环,而是重复循环的内容(某些编译器可能在更高的优化级别设置下执行此操作).重复的内容越多,循环顶部的分支数越少,重新加载指令缓存的次数越少.

使用表查找,而不是"if"语句
某些程序使用"if-else-if"梯形图将数据映射到值.每个"if"语句都是指令高速缓存中执行的中断.有时,通过一些小数学,可以将值放在像数组一样的表中,并以数学方式计算索引.一旦知道索引,处理器就可以在不中断指令高速缓存的情况下检索数据.

更改数据或数据结构
如果数据类型不变,则可以围绕数据优化程序.例如,处理消息分组的程序可以基于分组ID(思考函数指针数组)来基于其操作.功能将针对数据包处理进行优化.

将链表更改为数组或其他随机访问容器.可以使用数学而不是中断执行来访问数组的元素.必须遍历链接列表(循环)才能找到项目.

  • “展开循环”-> 我认为这是完全错误的。完整的循环很可能会保存在缓存中,分支到顶部应该不会造成任何问题。保持循环是代码存储在缓存中而不仅仅是预取的主要原因之一。实际上可能恰恰相反,建议不要展开循环以避免生成大量重复指令,这些指令会使您的代码更大并且不太可能适合缓存。 (2认同)