有没有办法在这个函数中避免 branching/conditional-logic ?
Is there a way to avoid branching/conditional-logic in this function?
我的程序中有这个简单的函数:
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);
}
在我程序的当前版本中,只要 tableSize
发生变化,我就会调用此方法,并将结果存储在一个成员变量中以便快速重用,并且工作正常。
不过,今天我正在尝试减少 sizeof(MyTable)
,其中一种方法是删除不必要的成员变量。由于上述函数的缓存结果总是 re-computable (基于 tableSize
成员变量的当前值),我修改了代码以在任何时候调用 GetTableIndexTypeForTableSize(tableSize)
需要代替。
这也很好用(并且允许我将 sizeof(MyTable)
减少 4 个字节,是的),但它导致我的性能基准测试中的性能下降可测量 (~5%) -- 我相信那是因为 GetTableIndexForTableSize()
的当前实现包括两个分支操作。
所以我的问题是,是否有一种聪明的方法可以重新实现上述功能,使其不需要任何分支,从而避免 5% 的减速? (我假设使用 lookup-table 将是
坏主意,因为我会用 RAM 访问延迟替换分支预测错误延迟,使事情变得更慢)
如果您仔细选择枚举值,应该可以按位或自己得到正确的枚举值。不过我怀疑它会快得多。
#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 );
}
我的程序中有这个简单的函数:
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);
}
在我程序的当前版本中,只要 tableSize
发生变化,我就会调用此方法,并将结果存储在一个成员变量中以便快速重用,并且工作正常。
不过,今天我正在尝试减少 sizeof(MyTable)
,其中一种方法是删除不必要的成员变量。由于上述函数的缓存结果总是 re-computable (基于 tableSize
成员变量的当前值),我修改了代码以在任何时候调用 GetTableIndexTypeForTableSize(tableSize)
需要代替。
这也很好用(并且允许我将 sizeof(MyTable)
减少 4 个字节,是的),但它导致我的性能基准测试中的性能下降可测量 (~5%) -- 我相信那是因为 GetTableIndexForTableSize()
的当前实现包括两个分支操作。
所以我的问题是,是否有一种聪明的方法可以重新实现上述功能,使其不需要任何分支,从而避免 5% 的减速? (我假设使用 lookup-table 将是 坏主意,因为我会用 RAM 访问延迟替换分支预测错误延迟,使事情变得更慢)
如果您仔细选择枚举值,应该可以按位或自己得到正确的枚举值。不过我怀疑它会快得多。
#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 );
}