【发布时间】:2016-09-29 08:44:59
【问题描述】:
我正在编写一个位域抽象类,它围绕一块 32 位内存 (u32 = unsigned int) 并提供对该内存中各个位或范围的访问。
为了实现这一点,我使用了一个 std::map,其中唯一键是 pointer(不是 std::string),指向表示助记符的 C 字符数组,其值为包含位域属性(如助记符、起始位置、长度、初始值和字段值)的结构。所有这些属性都是常量并在启动时定义,除了仅在基础 u32 值更改时更改的字段值。 (另请注意:我刚刚重用了助记指针值作为唯一键)。
这是在模拟器中使用的,其中 getBitfieldValue() 每秒被调用多次,它返回位域值(只读)。
在 VS 2015 更新 3 下编译和分析代码(使用 -O2 和我能找到的任何速度优化),它表明 getBitfieldValue() 函数和扩展 std::find() 占用了大约 60-70%总 CPU 时间...太慢了。
我尝试过使用其他地图实现,例如 Boost::flat_map、google::dense_hash_map 或 std::unordered_map,它们有些帮助,但最终还是太慢了 (~50-60%)。
我的猜测是我将映射用于错误的目的,但考虑到只有 5-20 个位域映射(查找大小很小),我不确定......这似乎太慢了。大部分时间也会花在查找相同的字段上。
相关类源码可以在这里找到:BitfieldMap32
地图在启动时如何初始化的示例(仅运行一次):
struct Fields
{
static constexpr char * ADDR = "ADDR";
static constexpr char * SPR = "SPR";
};
ExampleClass() // constructor
{
// registerField(mnemonic, start position, length, initial value)
registerField(Fields::ADDR, 0, 31, 0);
registerField(Fields::SPR, 31, 1, 0);
}
以及如何访问字段值(只读):
// getFieldValue definition.
const u32 & BitfieldMap32_t::getFieldValue(const char* fieldName)
{
return mFieldMap.find(fieldName)->second.mFieldValue;
}
// Field access.
const u32 value = ExampleClassPointer->getFieldValue(Fields::ADDR)
关于如何减少查找时间的任何想法?还是我需要一起更改实现?
【问题讨论】:
-
为什么不使用 std::bitset ?
-
因此您测量到您的代码使用了如此多的 CPU。但是,真的是慢吗? CPU 或运行时间的百分比是否真的“足够快”并不重要。你的程序的运行时间是多少?它必须等待用户输入吗?如果用户输入一些东西,用户是否必须等待超过几毫秒?用户需要等待多长时间?任何不到半秒的时间实际上看起来几乎是瞬间的。你真的想让事情复杂化(可能是很多)以在 0.4 秒而不是 0.5 秒内运行吗?
-
也许你应该考虑使用
std::unordered_map,它使用散列并且应该更快,而std::map使用二进制搜索。 -
如果您真的有 5-20 个位域映射,那么您可能会发现向量上的线性迭代比不同类型的映射工作得更快。
-
1.不确定使用 std::bitset 是什么意思-至少我必须在范围内执行迭代,因为它没有内置“范围”运算符。 2. 是的,它在现实世界中的性能很慢。模拟 CPU 运行在 ~300 MHz,我非常怀疑它目前是否接近该值。最终将应用用户输入。 3. 已经尝试过 std::unordered_map,没有显着帮助。 4. 如果没有其他帮助,我也可以按照其中一个答案的建议尝试。
标签: c++ c++11 dictionary stdmap bit-fields