使用指针是一种预取数据的好方法吗?

时间:2016-05-17 19:28:06

标签: c++ pointers caching memory

最近我一直在阅读有关编写更多缓存友好代码的内容,而我在实践中尝试使用它但是我偶然发现了一些令人困惑的东西。

根据我的理解,预取数据允许cpu专注于手头的工作,而不必因为必须从内存中的各个位置获取数据而分散注意力。我在Mike Acton的数据导向设计讲座中看到的一个具体例子甚至提到在本地存储类成员有利于提高性能。 (例如,在for循环的条件中使用int some_count = m_SomeCount而不是使用成员m_SomeCount本身,因为类成员存储在内存中的其他位置而不是局部变量,因此无法正确缓存)。

说完后,请参阅下面的(普通)代码片段:

// Fetching the element several times
m_Entities[entity_id].status &= ~Entity::StatusFlags::kActive;
m_Entities[entity_id].components.clear();
m_Entities[entity_id].DoSomething(); 

// Fetching the element once, though now a pointer is used
Entity::Entity* entity = &m_Entities[entity_id];
entity->status &= ~Entity::StatusFlags::kActive;
entity->components.clear();
entity->DoSomething();

使用第二种方法(使用指针)你只需要从向量中获取一次元素,我想知道这是否真的有益于"缓存友好性"并且通常表现为每次想要修改元素时仍然需要取消引用指针。

非常感谢!

1 个答案:

答案 0 :(得分:1)

我不确定我是否称之为“预取” - 对我来说,这个术语指的是更低级别的技术,这些技术会加载缓存或管道,预计CPU很快就会需要数据。

然而,抛开术语差异,几乎今天的任何编译器(启用了优化)都会将表达式m_Entities[entity_id]折叠到一个寄存器中,以用作后续访问的指针。除非m_Entitiesentity_id可能存在别名,否则可能会在后续使用中发生变化。

即使知道不会(或应该)发生这样的别名,编译器有时也没有足够的信息来保证。

使用本地指针可以是一种干净的方法,以确保编译器不必担心别名的可能性。

在大多数情况下,它仍然是一种不太可能具有显着帮助的优化,尽管我确实遇到过代码,它还具有使代码更具可读性的好处。我认为很难说它会使代码的可读性降低,并且编译器可以自由地优化将指针存储在任何地方(如果不需要)。我不确定它是否应该变成悲观(anit-optimization)。

我能看到的唯一真正的缺点是:

  • 有人可能认为这是不必要的或不太可读的
  • 如果代码依赖进行别名(或者更改索引表达式的非别名副作用),那么行为就会变得不同而且你引入了一个错误。