c++ - 哪个缓存最友好?

标签 c++ opengl caching memory-management data-oriented-design

我正在努力掌握面向数据的设计以及如何在考虑缓存的情况下进行最佳编程。基本上有两种情况,我无法完全确定哪个更好,为什么 - 拥有一个对象 vector 更好,还是拥有多个包含对象原子数据的 vector 更好?

A)对象 vector 示例

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

    size_t vertexDataSize;
    size_t normalDataSize;
};

std::vector<A> gMeshes;

for_each(gMeshes as mesh)
{
    glBindVertexArray(mesh.mVAO);
    glDrawElements(GL_TRIANGLES, mesh.mIndices, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

    ....
}

B) 带有原子数据的 vector

std::vector<GLsizei> gIndices;
std::vector<GLuint> gVBOs;
std::vector<GLuint> gIndexBuffers;
std::vector<GLuint> gVAOs;
std::vector<size_t> gVertexDataSizes;
std::vector<size_t> gNormalDataSizes;

size_t numMeshes = ...;

for (index = 0; index++; index < numMeshes)
{
    glBindVertexArray(gVAOs[index]);
    glDrawElements(GL_TRIANGLES, gIndices[index], GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

    ....
}

哪一个内存效率更高且对缓存更友好,从而减少了缓存未命中并提高了性能,为什么?

最佳答案

根据您所谈论的缓存级别的不同,缓存的工作方式如下:

  • 如果数据已经在缓存中,那么访问起来很快
  • 如果数据不在缓存中,那么您会产生成本,但是整个缓存行(或页面,如果我们谈论的是 RAM 与交换文件而不是缓存与 RAM)被带入缓存,因此访问接近错过地址不会错过。
  • 如果幸运的话,内存子系统将检测顺序访问并预取它认为您将需要的数据。

所以天真地要问的问题是:

  1. 发生了多少次缓存未命中? -- B 获胜,因为在 A 中,您为每条记录获取了一些未使用的数据,而在 B 中,您只能在迭代结束时获取一个小的舍入误差。因此,为了访问所有必要的数据,假设有大量记录,B 提取较少的缓存行。如果记录的数量微不足道,那么缓存性能可能与代码的性能关系很小或根本没有关系,因为使用足够小数据量的程序会发现它一直都在缓存中。
  2. 访问是顺序的吗? -- 在这两种情况下是的,尽管在情况 B 中这可能更难检测,因为有两个交错的序列而不是只有一个。

因此,我希望 B 能够更快对于这段代码。然而:

  • 如果这是对数据的唯一访问,那么您可以通过从 struct 中删除大部分数据成员来加速 A。所以这样做。据推测,事实上这并不是您程序中对数据的唯一访问,其他访问可能会以两种方式影响性能:它们实际花费的时间,以及它们是否使用您需要的数据填充缓存。
  • 我所期望的和实际发生的经常是不同的事情,如果你有能力测试它,依赖猜测是没有意义的。在最好的情况下,顺序访问意味着任何代码中都没有缓存未命中。测试性能不需要没有特殊工具(尽管它们可以使它更容易),只需要一个带秒针的时钟。必要时,用手机充电器制作一个钟摆。
  • 我忽略了一些并发症。根据硬件的不同,如果你对 B 不走运,那么在最低缓存级别你会发现对一个 vector 的访问正在逐出对另一个 vector 的访问,因为相应的内存恰好使用缓存中的相同位置。这将导致两次缓存未命中每条记录。这只会发生在所谓的“直接映射缓存”上。 “双向缓存”或更好的方式可以挽救局面,因为即使它们在缓存中的首选位置相同,也允许两个 vector 的 block 共存。我不认为 PC 硬件通常使用直接映射缓存,但我不确定,我对 GPU 了解不多。

关于c++ - 哪个缓存最友好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19126228/

相关文章:

opengl - MSYS2 OpenGL 设置

php - W3 Total Cache - 允许编辑者从缓存中清除单个帖子

c++ - 单链表的根节点是否被视为列表的一部分?

c++ - 进入系统,Linux下的CRTL功能与Eclipse

java - 有没有一种方法可以使用多个 LWJGL 上下文

opengl - 透视投影矩阵说明(第二行)

java - 在不影响上次修改时间戳的情况下从 Infinispan 缓存中获取条目

ios - AVPlayerItem 加载未知文件扩展名(缓存文件)

c++ - 如何修复 OpenSSL 不正确的数据传输?

c++ - CPP 错误: "called object type ' int (hashTable::*)(int, int )' is not a function or function pointer"