2 次幂大小数据的性能优势?
Posted
技术标签:
【中文标题】2 次幂大小数据的性能优势?【英文标题】:Performance advantages of powers-of-2 sized data? 【发布时间】:2012-03-19 21:42:46 【问题描述】:如果我的游戏有一个 3D 世界,而且世界很大,所以需要分成块,如果有的话,128 字节块是否有主要的性能优势,比如 150 字节块?显然,chunks 中的对象仍然是整数字节大小。
即chunks[128][128][128]
比 chunks[150][150][150]
或 chunks[112][112][112]
快吗?之后是否还有其他副作用,例如过多的 RAM 浪费?还有其他需要考虑的因素吗?
我只是看到将所有内容存储在大小为 2 的幂的变量和数组中是一种惯例,但我不确定它是否有任何优点,以及是否可以更好地使用更多的人类数字,例如100 或 150。
【问题讨论】:
我认为这取决于数组的类型。非字节类型可能需要内存对齐。 在这种情况下,块中的每个对象都是 16 位,或者可能是另一个 2 的幂数(绝对是整数字节)。我想知道拥有 150 个 16 位对象是否比拥有 128 个对象慢(注意仍然有同样多的对象,它们只会被分成更多的部分) 假设您有 1000 人要运送,而您有可容纳 50 人的巴士。你认为什么更好?将人分成 50 人一组,或者将他们分成 72 人(或 38 人或其他)一组,然后在挤满公共汽车之前分成几组? 想象人们戴着不同颜色的帽子。如果您按与公交车容量不同的数字对他们进行分组,则每辆公交车都会有戴着不同颜色帽子的人。对数组“维度”使用 2 的幂可以提高每个数组组(从index
到就在 index + 1
之前)占用可以作为一个整体访问的一部分内存的机会。
作为警告:使用二次幂可能会导致超对齐冲突。请参阅 this 和 this。超级对齐(来自 2 步的幂)可以轻松地将性能提升 3 倍或更多。因此,您从换班换乘中获得的收益,很容易因缓存未命中和假混叠停顿而丢失(多次)。
【参考方案1】:
其他答案确实是正确的,即二次幂大小的数据将受益于使用移位而不是乘法。
然而,二次方尺寸数据有一个黑暗面。它会在你最意想不到的时候击中你。
查看以下两个问题/答案:
Matrix multiplication: Small difference in matrix size, large difference in timings Why are elementwise additions much faster in separate loops than in a combined loop?当您的数据集是二次方时,它们更有可能在内存中超级对齐。 (这意味着它们的地址可能在大的 2 次方上具有相同的模数。)
虽然这看起来很可取,但它们可能会导致:
Conflict Cache Misses 假别名档位(在上面的第二个链接中提到)如果您阅读了上面链接的两个问题,您会发现对齐会导致超过 3 倍的减速 - 这可能远远超过您从使用轮班而不是乘法中获得的任何好处。
因此,与所有性能问题一样,您需要衡量、衡量、衡量......并准备好期待任何事情发生。
您提到您正在代表一个 3D 空间 - 这正是那种会表现出二次幂的跨步内存访问的情况,这可能会导致速度变慢。
【讨论】:
+1,缓存未命中比您为寻址所花费的几个周期要糟糕得多! 是的,我很惊讶没有人提到对齐是一个缺点。不在答案中,也不在 cmets 中——尤其是考虑到 loop question 已收到的大量关注。我会早点回答这个问题,但是当被问到时,那是我所在时区的半夜。所以直到现在才看到。 感谢您提及缓存问题!不用乘法也可以实现两个大小的非幂。移位和加法将为您提供块大小,例如 129 或 255。移位然后加/减。虽然,值得检查您的目标硬件不能像移位和加/减一样快地执行乘法运算。【参考方案2】:它并不是完全“更快”,而是更好地利用了可用内存,因为硬件和操作系统以最有可能是 2 的幂的大小为单位管理内存。由于对齐要求,分配小于 2 的幂的东西通常会导致内存浪费。
如果您深入研究分配器和操作系统内存管理器,您会发现它们以二次方大小管理所有内容。操作系统通常以页的形式管理进程的内存,现在页大小通常为4096字节。所以如果你要分配一块 4000 字节,操作系统仍然会分配 4096 字节,剩下的 96 字节将被浪费。
【讨论】:
那么在分配 150^3 * 16 字节(6,750,000 字节)之后会浪费多少 RAM?数额很大吗? "剩下的 96 个字节将被浪费掉。"这是一个非常简化的视图。内存管理通常在几个层中完成,并且取决于管理器,这 96 个字节可以很好地用于其他变量。 @adelphus:确实是简化了,我只是想描述一个典型的概念案例。【参考方案3】:如果您通过以下方式访问数据:
chunks[150][150][150]
chucks[x][y][z] = 123;
然后处理器必须进行乘法运算(例如:z + 150 * (y + 150 * x) ...) 获取地址。
如果您使用 2 的幂常量,那么编译器可以进行一些优化,并使用移位而不是乘法。新的 CPU 使得乘法相当快,所以效果微乎其微。
使用大表会导致大量缓存未命中。因此,较小的表可能比较大的表更快,即使较大的表也具有 2 次幂大小的尺寸,而较小的则不会。
【讨论】:
【参考方案4】:2 的幂在软件中被大量使用,因为它是计算机使用的数基。
例如,操作系统将分配内存的块大小是 2 的幂,处理器中的缓存大小是 2 的幂,地址大小是 2 的幂等等。
还可以优化使用两个值的幂的运算 - 乘法或除法变成简单的位移。
基本上确保一切都使用 2 的幂可能会提高您的软件的性能,但通常编译器和/或操作系统会确保在您使用任意大小时以有效的方式利用您的数据。
【讨论】:
【参考方案5】:可能更快,可能更慢,可能是相同的速度。仅通过查看代码很难给出正确的答案。所以答案是:测量它,更改代码,再次测量它。如果您的代码必须在不同的计算机上运行,请在每台计算机上进行测量。
我倾向于假设二次方对齐通常会带来严重的麻烦,并且使用比需要更多的内存对性能没有帮助。使用适合某个缓存的一小部分内存执行大量操作,然后切换到下一部分内存通常会有所帮助。访问连续的内存地址通常会有所帮助。四舍五入以便您可以使用向量运算通常会有所帮助。
【讨论】:
以上是关于2 次幂大小数据的性能优势?的主要内容,如果未能解决你的问题,请参考以下文章
BigDecimal数据的加 减 乘 除 N次幂运算 以及比较大小