有没有办法避免此功能中的分支/条件逻辑?

Jer*_*ner 2 c++ optimization conditional

我的程序中有以下简单功能:

enum {
   TABLE_INDEX_TYPE_UINT8 = 0,
   TABLE_INDEX_TYPE_UINT16,
   TABLE_INDEX_TYPE_UINT32,
};

// inline method
uint8_t MyTable :: GetTableIndexTypeForTableSize(uint32_t tableSize) const
{
   // Deliberately testing for strictly-less-than-255/65535 here, 
   // because 255 and 65535 are used as special sentinel values
   return (tableSize < 255) ? TABLE_INDEX_TYPE_UINT8 
        : ((tableSize < 65535) ? TABLE_INDEX_TYPE_UINT16 : TABLE_INDEX_TYPE_UINT32);
}
Run Code Online (Sandbox Code Playgroud)

在程序的当前版本中,只要tableSize发生更改,我都会调用此方法,并将结果存储在成员变量中以便快速重用,并且效果很好。

但是,今天,我正在尝试reduce sizeof(MyTable),并且做到这一点的一种方法是摆脱不必要的成员变量。由于上述函数的缓存结果始终是可重新计算的(基于tableSize成员变量的当前值),因此我修改了代码以在需要GetTableIndexTypeForTableSize(tableSize)时调用。

这也可以正常工作(并且可以减少sizeof(MyTable)4个字节),但是在性能基准测试中却导致性能的可衡量的降低(〜5%),我相信这是因为当前的实现GetTableIndexForTableSize()包括两个分支-操作。

所以我的问题是,是否有一种聪明的方法可以重新实现上述功能,从而不需要任何分支,从而避免5%的速度下降?(我认为使用查找表将是一个坏主意,因为我将用RAM访问延迟代替分支错误预测延迟,从而使事情变得更慢)

rob*_*oke 5

如果您仔细选择枚举值,应该可以按位或自己选择正确的枚举值。我怀疑这样做会更快吗。

#include <cstdint>
enum {
  TABLE_INDEX_TYPE_UINT8 = 0,
  TABLE_INDEX_TYPE_UINT16 = 1,
  TABLE_INDEX_TYPE_UINT32 = 3
};

uint8_t MyTable::GetTableIndexTypeForTableSize(uint32_t tableSize) const
{
  return (tableSize >= 255) | ( (tableSize >= 65535) << 1 );
}
Run Code Online (Sandbox Code Playgroud)

  • return(tableSize&gt; = 255)+(tableSize&gt; = 65535);`使您可以保留旧的枚举值。 (2认同)