【问题标题】:Does this approach positvely impact branch prediction?这种方法是否会对分支预测产生积极影响?
【发布时间】:2018-07-29 12:49:49
【问题描述】:

我一直在尝试创建一种回调函数,在此过程中我意识到我更喜欢的回调函数也可能会改变 CPU 在后台处理分支预测的方式。我知道过度优化是一个应该避免的事情,尤其是在早期,但这是一种非常适合我使用的方法,并且具有避免缓存未命中的效果将是一个很好的奖励。

但是,我对 CPU 架构的了解不足以自己回答这个问题,所以我很好奇是否有人知道这是否会影响分支预测的处理方式,以及它是否以有益的方式这样做。

我的初始解决方案如下所示:(请注意较大的块)

enum _myenum { t1, t2, t3 }myenum; //enumerator and switch 

switch (myenum){
case t1: 
    { /*a block*/ }
    break;
case t2: 
    { /*another block*/ }
    break;
case t3: 
    { /*yet another block*/ }
    break;
default: break;
}

以及适合我使用的解决方案:

enum _myenum { t1, t2, t3 }myenum; //same enum
//a map of lambdas/functions
std::map<_myenum, std::function<void()>>lambda_map{ 
    { t1, [&]() {/*a block*/} },
    { t2, [&]() {/*another block*/ }},
    { t3, [&]() {/*yet another block*/ }}
}; 

lambda_map[myenum](); //to run the callback

我将在哪里运行lambda_map[myenum]();,而不是更难跟踪的开关功能。

但是 lambda 指针映射是否可以让 CPU 避免潜在的缓存未命中?就我所知,不必预测 if 语句或运行 switch 案例,而是根据 set myenum 变量跳转到特定函数,应该可以做到这一点,对吧?或者至少以某种方式影响它。

我很好奇 lambda_map[enum](); 在分支预测和避免缓存未命中方面是否比通过可能情况列表的 switch 语句更好。

【问题讨论】:

  • 根据枚举值,std::array 会比 map 更好。
  • 您是否只是因为不喜欢switch 声明而想要更改?或者你有没有测量和分析发现它是你代码中的一个实际瓶颈?还是您刚刚落入过早优化的陷阱?首先编写好的、可读和可维护的代码。然后,如果它不是“足够好”(通常足够好),则测量和分析以找到瓶颈并仅修复这些瓶颈(使用大量 cmets 和文档)。
  • @Someprogrammerdude 我在问题中提到它不是为了优化,而是出于好奇
  • 您正在用地图(或数组,如 Jarod42 建议的那样)查找来替换可能的分支预测错误:我在这个领域不是很专家,但我假设您正在减慢您的程序而不是提高性能
  • 您应该使用map.find 只进行一次查找。

标签: c++ branch-prediction


【解决方案1】:

我将在哪里运行 lambda_mapmyenum;而不是难以追踪的开关功能。

这可能是误导您的原因。 switch statement 不一定比一些类似地图的结构“更难跟踪”。事实上,由于编译器的优化,它很可能被实现为一个跳转表,即一个跳转指令数组,类似于你想象的第二个解决方案。

在你的情况下,使用std::map 肯定会因为间接(以及随之而来的缓存未命中)而变慢,并且因为它使用二进制搜索来查找值。您想要的是一个函数指针数组 (std::array)(使用 std::function 或 lambdas),使用枚举数作为索引。在数组不可行的情况下(由于键的性质),可以使用 hashmap (std::unordered_map)。

就性能而言,如果不进行分析,就无法判断函数数组方法是否优于编译器优化开关。

话虽如此,我经常发现自己编写数组或哈希图(函数或非函数)来代替 switch 语句,因为个人偏好从样式(块嵌套、放置......)到实际可维护性。也是因为我不喜欢 switch 语句的结构。对最后一部分持保留态度:我相信有些人更喜欢类似开关的结构而鄙视替代方案。

【讨论】:

  • 正如我们所说,我正在研究 lambda 指针的数组+枚举。感谢您写出答案
猜你喜欢
  • 2015-08-12
  • 1970-01-01
  • 2017-06-16
  • 1970-01-01
  • 2016-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-20
相关资源
最近更新 更多