【问题标题】:Using map in conjunction with vector and cache impact将地图与矢量和缓存影响结合使用
【发布时间】:2013-10-02 09:58:35
【问题描述】:

我正在考虑使用 map 将自定义 ID 映射到 vector 索引,例如;

struct Mesh
{
    GLsizei mIndices;
    GLuint mVBO;
    GLuint mIndexBuffer;
    GLuint mVAO;

    size_t vertexDataSize;
    size_t normalDataSize;
};

typedef uint32_t MeshID;

std::map<MeshID, uint16_t> gMeshIDIndexMap;
std::vector<Mesh> gMeshes;


std::vector<MeshID> drawCmds = {1, 1, 2, 3, 4, 5, 8, ,8 ,8, 9, 10, ...};  //sorted
std::for_each(drawCmds.begin(), drawCmds.end(), [](MeshID& id) 
{
    Mesh& mesh = gMeshes[gMeshIDIndexMap.at(id)];
    glBindVertexArray(mesh.mVAO);
    glDrawElements(GL_TRIANGLES, mesh.mIndexBuffer, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

    ....  
}     

由于 std::map 不将其元素存储在连续内存中,因此在每次新迭代时gMeshIDIndexMap.at(id) 都必须将一个全新的缓存行加载到缓存中。这会破坏缓存并导致大量缓存未命中,对吗?我可以做些什么来改进这一点并尽可能减少缓存未命中?

【问题讨论】:

  • 根据地图的大小和使用方式,boost::container::flat_map 可能是一个不错的选择。
  • 关于你如何使用地图?
  • @KaiserJohann 很公平,我把它写在一个答案中。

标签: c++ caching memory-management c++11


【解决方案1】:

如果您 (1) 首先用数据填充地图,然后 (2) 将其用于查找,并且 (3) 最后在完成后销毁它,那么 boost::container::flat_map 可能是您的不错选择。它基本上是一个排序的向量。优点(无耻地从网站上窃取):

  • 比标准关联容器更快的查找
  • 迭代速度比标准关联容器快得多
  • 小对象的内存消耗更少(如果使用 shrink_to_fit 则对于大对象 被使用)
  • 提高缓存性能(数据存储在连续内存中)

一个潜在的缺点:

  • 最坏的线性时间插入和线性时间删除

观察是容器经常按照上述模式使用(填充数据 - 用于查找 - 销毁)。如果您的使用符合此模式,则排序向量可能是一个不错的选择。

您需要将MeshID放入Mesh中。如果您知道或者可以对地图中的元素数量给出合理的估计,您甚至可以提前保留空间,这样元素就不必因为底层向量的缓冲区重新分配而移动。

我的建议和ComicSansMS' answer基本一样;我只建议你使用 boost 容器而不是滚动你自己的 flat_map。


当然,您的使用模式可能如下所示:您执行 (a) 查找或 (b) 在随机位置删除或 (c) 在随机位置插入;在您的地图的整个生命周期中,您会执行 (a) 或 (b) 或 (c) 看似随机的操作。在这种情况下,基于节点的容器,例如 std::map 可能是更好的选择。

【讨论】:

  • 这完全回答了我的问题..非常感谢阿里。
  • @BhupeshPant 我很高兴听到它! :)
猜你喜欢
  • 2012-12-07
  • 2022-07-20
  • 2017-07-02
  • 1970-01-01
  • 1970-01-01
  • 2020-03-05
  • 2021-07-27
  • 1970-01-01
  • 2013-03-08
相关资源
最近更新 更多