为什么这段代码非常慢?任何与缓存行为有关的事情?
Why this code extremely slow?Any thing related to cache behavior?
我开始了一些面向数据的设计实验。我最初开始做一些 oop 代码,发现有些代码非常慢,不知道为什么。下面是一个例子: 我有一个游戏对象
class GameObject
{
public:
float m_Pos[2];
float m_Vel[2];
float m_Foo;
void UpdateFoo(float f){
float mag = sqrtf(m_Vel[0] * m_Vel[0] + m_Vel[1] * m_Vel[1]);
m_Foo += mag * f;
}
};
然后我使用 new 创建 1,000,000 个对象,然后循环调用 UpdateFoo((
for (unsigned i=0; i<OBJECT_NUM; ++i)
{
v_objects[i]->UpdateFoo(10.0);
}
完成循环大约需要 20 毫秒。当我注释掉 float m_Pos[2] 时发生了奇怪的事情,所以对象看起来像这样
class GameObject
{
public:
//float m_Pos[2];
float m_Vel[2];
float m_Foo;
void UpdateFoo(float f){
float mag = sqrtf(m_Vel[0] * m_Vel[0] + m_Vel[1] * m_Vel[1]);
m_Foo += mag * f;
}
};
突然间,循环大约需要 150 毫秒才能完成。如果我把任何东西放在m_Vel之前,那就快多了。我试着在m_Vel和m_Foo或其他地方之间放一些填充物,除了m_Vel之前的地方......慢。
我在发布版本i2008-4790中的vs2008和vs2010上进行了测试 知道这种差异是如何发生的吗?它是否与任何缓存一致性行为有关。
这是整个示例:
#include <iostream>
#include <math.h>
#include <vector>
#include <Windows.h>
using namespace std;
class GameObject
{
public:
//float m_Pos[2];
float m_Velocity[2];
float m_Foo;
void UpdateFoo(float f)
{
float mag = sqrtf(m_Velocity[0] * m_Velocity[0] + m_Velocity[1] *
m_Velocity[1]);
m_Foo += mag * f;
}
};
#define OBJECT_NUM 1000000
int main(int argc, char **argv)
{
vector<GameObject*> v_objects;
for (unsigned i=0; i<OBJECT_NUM; ++i)
{
GameObject * pObject = new GameObject;
v_objects.push_back(pObject);
}
LARGE_INTEGER nFreq;
LARGE_INTEGER nBeginTime;
LARGE_INTEGER nEndTime;
QueryPerformanceFrequency(&nFreq);
QueryPerformanceCounter(&nBeginTime);
for (unsigned i=0; i<OBJECT_NUM; ++i)
{
v_objects[i]->UpdateFoo(10.0);
}
QueryPerformanceCounter(&nEndTime);
double dWasteTime = (double)(nEndTime.QuadPart-
nBeginTime.QuadPart)/(double)nFreq.QuadPart*1000;
printf("finished: %f", dWasteTime);
// for (unsigned i=0; i<OBJECT_NUM; ++i)
// {
// delete(v_objects[i]);
// }
}
然后我使用 new 创建 1,000,000 个对象,然后循环 调用 UpdateFoo((
那里有你的问题。不要单独分配一百万个将使用通用分配器重复处理的小东西。
尝试连续或连续存储对象。一个简单的解决方案是将它们全部存储在一个大std::vector
中。要在恒定时间内删除,您可以将要删除的元素与最后一个元素交换并弹出。如果需要稳定的索引,可以留下一个孔,以便在插入时回收(可以使用空闲列表或堆栈方法(。如果您需要不会失效的稳定指针,deque
可能是一个选项,结合使用"漏洞"的想法,使用空闲列表或单独的索引堆栈来回收/覆盖。
您也可以只使用空闲列表分配器并对其使用新放置,同时小心地使用相同的分配器释放并手动调用 dtor,但这会变得更快,并且需要更多的练习才能比数据结构方法做得好。相反,我建议只寻求将游戏对象存储在某个大容器中,以便您重新控制所有内容将驻留在内存中的位置以及由此产生的空间位置。
我在 vs2008 和 vs2010 的发布版本上进行了测试,i7-4790 知道如何 这种差异可能发生吗?它是否与任何缓存一致相关 行为。
如果您正在正确进行基准测试和构建项目,则当内存较小时,分配器可能会对内存进行更多碎片GameObject
从而导致更多的缓存未命中。这似乎是最有可能的解释,但如果没有一个好的分析器,很难确定。
也就是说,与其进一步分析,我推荐上面的解决方案,这样你就不必担心分配器在哪里分配内存中的每一个微小的东西。
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 如何在不产生任何垃圾的情况下获得C中的像素
- 为什么我不能在 C++ 中的特定函数重载中调用同一函数的任何其他重载?
- cmake更新缓存的变量
- 试图对缓存进行跨步测试,但程序并没有结束
- C++映射有2个键,这样任何1个键都可以用来获取值
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- RtlCaptureStackBackTrace未捕获任何帧
- 缓存std::数组的选定元素,并在c++中自动保持其一致性
- 通过ccmake在cmake中缓存依赖选项
- 链表c++插入,所有情况都已检查,但没有任何工作
- C++模板函数,用于比较任何无符号整数和有符号整数
- Arduino millis() - millis() 怎么能等于 0 以外的任何东西?
- 尝试摆脱任何堆内存分配
- 为什么这段代码非常慢?任何与缓存行为有关的事情?
- 任何类型的缓存机制
- 缓存错过压力测试:令人惊叹的结果.任何解释
- 在C/ c++中通过int main()返回0,在任何操作系统上,清除程序在任何(RAM,缓存或任何…)内存中使用的所有
- 为什么我的8M L3缓存不能为大于1M的数组提供任何好处?