【发布时间】:2019-09-06 00:48:27
【问题描述】:
我正在开发对延迟敏感的软件。今天,我决定通过在联合中使用 BitField 结构来使我的结构更小,并将该 BitField 结构读取为一个整数,我将其用作我的哈希函数的唯一键。我期望从唯一键上的散列获得比对我的类的属性散列的按位运算稍微(如果不是很多)更好的性能,但结果证明进行按位运算来获取散列键要快得多?我一直试图找出原因,但我无法得出任何结论。
这是我的代码:http://quick-bench.com/OkNuVOxdVtW8g7OWUXjqcvYlNrs
#include <functional>
struct GroupTupleInformation {
unsigned int src : 12;
unsigned int dst : 12;
unsigned int flow_id : 8;
};
union GroupTupleData {
GroupTupleInformation info;
uint32_t hash_key;
};
struct GroupTuple {
constexpr void setSrc(uint16_t s) noexcept { data.info.src = s; }
constexpr uint16_t getSrc() const noexcept { return data.info.src; }
constexpr void setDst(uint16_t d) noexcept { data.info.dst = d; }
constexpr uint16_t getDst() const noexcept { return data.info.dst; }
constexpr void setFlowId(uint8_t f) noexcept { data.info.flow_id = f; }
constexpr uint8_t getFlowId() const noexcept { return data.info.flow_id; }
constexpr uint32_t getHashKey() const noexcept { return data.hash_key; }
private:
GroupTupleData data;
};
struct UnionHashFn {
constexpr std::size_t operator()(const GroupTuple& gtup) const noexcept {
return gtup.getHashKey();
}
};
struct CombinedHashFn {
std::size_t operator()(const GroupTuple& gtup) const noexcept {
std::hash<uint16_t> hasher{};
return hasher(gtup.getSrc()) ^ hasher(gtup.getDst()) ^
hasher(gtup.getFlowId());
}
};
static void UnionHashFnBench(benchmark::State& state) {
unsigned long i = 0;
UnionHashFn hasher;
GroupTuple group_tuple;
size_t key = 0;
for (auto _ : state) {
group_tuple.setSrc(i++ % 32);
group_tuple.setDst(i++ % 32);
group_tuple.setFlowId(i++ % 32);
key = hasher(group_tuple);
benchmark::DoNotOptimize(key);
}
}
BENCHMARK(UnionHashFnBench);
static void CombinedHashFnBench(benchmark::State& state) {
unsigned long i = 0;
CombinedHashFn hasher;
GroupTuple group_tuple;
size_t key = 0;
for (auto _ : state) {
group_tuple.setSrc(i++ % 32);
group_tuple.setDst(i++ % 32);
group_tuple.setFlowId(i++ % 32);
key = hasher(group_tuple);
benchmark::DoNotOptimize(key);
}
}
BENCHMARK(CombinedHashFnBench);
PS:我知道基准化映射或 unordered_map 比对哈希函数的成本进行基准测试更复杂,而且我也知道我为从班级中获取哈希所做的按位操作并不是获取哈希的好方法,只是为了举个简单的例子
【问题讨论】:
-
需要 extra 个 CPU 周期才能从内存字中解压缩位域。要更新位域,您必须读取内存字,然后写入它,只需选定的位已更新;而不是简单地写一个记忆词。
-
哦哦。位域。这些似乎总是一个好主意,但回想起来很少会以这种方式结束。为什么不是简单的位掩码?至少这样你就知道内部发生了什么,而不是隐藏太多。
-
@tadman 因为我的两个队友不习惯并且害怕位掩码,所以我使用位域来获得易于理解的界面。
-
啊,我想他们会学会害怕位域而不是位掩码。除非您有数十亿个这样的东西,否则可能不值得麻烦。您是否对非位域版本(只是一个普通结构)进行了基准测试,以查看它在速度和内存使用方面的表现?它会将您推向 64 位值,但这不会是现代系统的世界末日。
-
“因为我的两个队友不舒服并且害怕位掩码”您正在开发低延迟软件而队友对位掩码感到害怕?真的吗?缓存行怎么样,这让他们疯狂?
标签: c++ performance-testing benchmarking compiler-optimization