C++ std::映射(和族)查找性能问题

C++ std::映射(和族)查找性能问题,c++,c++11,dictionary,stdmap,bit-fields,C++,C++11,Dictionary,Stdmap,Bit Fields,我正在编写一个位域抽象类,它围绕一个32位的内存块u32=unsigned int,并提供对该内存中各个位或范围的访问 为了实现这一点,我使用了一个std::map,其中唯一键是指向表示助记符的C字符数组的指针,而不是std::string,值是一个包含位字段属性(如助记符、起始位置、长度、初始值和字段值)的结构。所有这些属性都是常量,并在启动时定义,但字段值除外,该字段值仅在基础u32值更改时更改。 还要注意:我刚刚将助记符指针值重新用作唯一键 这在模拟器中使用,其中每秒调用多次getBitf

我正在编写一个位域抽象类,它围绕一个32位的内存块u32=unsigned int,并提供对该内存中各个位或范围的访问

为了实现这一点,我使用了一个std::map,其中唯一键是指向表示助记符的C字符数组的指针,而不是std::string,值是一个包含位字段属性(如助记符、起始位置、长度、初始值和字段值)的结构。所有这些属性都是常量,并在启动时定义,但字段值除外,该字段值仅在基础u32值更改时更改。 还要注意:我刚刚将助记符指针值重新用作唯一键

这在模拟器中使用,其中每秒调用多次getBitfieldValue(返回只读位字段值)

在使用-O2和我能找到的任何速度优化编译和分析VS 2015 update 3下的代码时,它显示getBitfieldValue函数,以及通过扩展std::find占用了大约60-70%的总cpu时间。。。太慢了

我尝试过使用其他映射实现,如Boost::flat_映射、google::dense_hash_映射或std::unordered_映射,虽然它们有些帮助,但仍然太慢了~50-60%

我的猜测是,我使用映射的目的是错误的,但考虑到只有5-20位的映射较小的查找大小,我不确定。。。只是看起来太慢了。大部分时间也会花在查找同一字段上

相关类源代码可在此处找到:

启动时如何初始化映射的示例仅一次性运行:

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)
关于如何减少查找时间有什么想法吗?或者我需要同时更改实现吗?

IIUC,使用字典std::map或std::unordered\u map是一种巨大的过度使用。也许您应该使用以下方法:

该类应该只是一个整数或至多一个std::bitset的内部存储的包装器

助记符应该是枚举,而不是std::strings

在内部,让一个std::vector有效地将每个枚举值映射到。如果您使用的是c++11枚举,请参阅如何将枚举值转换为std::vector中的位置

每个操作只需获取助记符,通过索引查找位掩码,并将其应用于内部存储器

IIUC,使用字典std::map或std::unordered_map是一种巨大的过度使用。也许您应该使用以下方法:

该类应该只是一个整数或至多一个std::bitset的内部存储的包装器

助记符应该是枚举,而不是std::strings

在内部,让一个std::vector有效地将每个枚举值映射到。如果您使用的是c++11枚举,请参阅如何将枚举值转换为std::vector中的位置

每个操作只需获取助记符,通过索引查找位掩码,并将其应用于内部存储器


为什么不使用std::bitset呢?所以您测量了您的代码使用了多少CPU。但是,它真的很慢吗?CPU或运行时的百分比与它是否真的足够快无关。您的程序的运行时间是多少?它必须等待用户输入吗?如果用户输入了什么,用户是否需要等待超过几毫秒?用户需要等待多长时间?任何少于半秒钟的事情实际上都是瞬间发生的。你真的想在0.4秒而不是0.5秒的时间里把事情复杂化吗?也许你应该考虑使用STD::unOrdEdjPad,它使用散列,并且应该更快,而std::map使用二进制搜索。如果您确实有5-20个位域映射,那么您可能会发现向量上的线性迭代比不同类型的映射工作得更快。1。我不确定你所说的使用std::bitset是什么意思——至少我必须在这个范围内执行一次迭代,因为它没有内置范围操作符。2.是的,它和现实世界中的表现一样慢。模拟CPU的运行频率约为300 MHz,目前我非常怀疑它是否接近这一频率。最终将应用用户输入。3.已经尝试过std::无序的_映射,没有明显的帮助。4.如果没有其他帮助的话,我也可以按照其中一个答案的建议尝试一下。为什么不使用std::bitset呢?所以您测量了您的代码使用了多少CPU。但是,它真的很慢吗?CPU或运行时的百分比与它是否真的足够快无关。您的程序的运行时间是多少?它必须等待用户输入吗?如果用户输入了什么,用户是否需要等待超过几毫秒?用户需要等待多长时间?任何少于半秒钟的事情实际上都是瞬间发生的。你真的想把事情复杂化,可能在0.4秒而不是0.5秒内运行吗?也许你应该考虑使用ST。
d::unordered_映射使用散列,应该更快,而std::map使用二进制搜索。如果您确实有5-20个位域映射,那么您可能会发现向量上的线性迭代比不同类型的映射工作得更快。1。我不确定你所说的使用std::bitset是什么意思——至少我必须在这个范围内执行一次迭代,因为它没有内置范围操作符。2.是的,它和现实世界中的表现一样慢。模拟CPU的运行频率约为300 MHz,目前我非常怀疑它是否接近这一频率。最终将应用用户输入。3.已经尝试过std::无序的_映射,没有明显的帮助。4.如果没有其他帮助,我也可以按照其中一个答案的建议尝试。正如我在评论中提到的,我不确定std::bitset在需要迭代位集时对性能有何帮助,因为它不提供范围函数,也不总是单位。我将尝试enum和vectors的组合,看看效果如何。@marco9999我将进一步了解您的代码。在任何情况下,我建议您考虑用枚举替换STD::String助记符。最后使用STD::vector和有序索引键,从0个EnUM/int开始。效果更好。“我猜这张地图太夸张了。”马可9999很高兴它帮了你。很抱歉,我没有机会进一步了解您的代码工作,您知道。。。。最好的。正如我在评论中提到的,当我需要迭代一个位集时,我不确定std::bitset对性能有什么帮助,因为它不提供范围函数,也不总是单个位。我将尝试enum和vectors的组合,看看效果如何。@marco9999我将进一步了解您的代码。在任何情况下,我建议您考虑用枚举替换STD::String助记符。最后使用STD::vector和有序索引键,从0个EnUM/int开始。效果更好。“我猜这张地图太夸张了。”马可9999很高兴它帮了你。很抱歉,我没有机会进一步了解您的代码工作,您知道。。。。祝你一切顺利。