在对齐大小的数组和非对齐大小的数组上速度不同

Speed different on aligned-size array and non-aligned-size array

本文关键字:数组 对齐 速度      更新时间:2023-10-16

我尝试对对齐大小数组和非对齐大小数组进行操作,但结果让我感到困惑,非对齐大小数组比对齐大小数组快,这是我的代码:

TimeMeter timeMeter;
const int N = 100000;
_Tp A[64];
_Tp B[65];
int szA = sizeof(A);
int szB = sizeof(B);
//  Method 1
timeMeter.start();
for ( int n = 0; n < N; n++ )
{
    memset(A, 0, szA);
}
timeMeter.stop();
printf("Method 1 Time usage = %f msn", timeMeter.span());
//  Method 2
timeMeter.start();
for ( int n = 0; n < N; n++ )
{
    memset(B, 0, szB);
}
timeMeter.stop();
printf("Method 2 Time usage = %f msn", timeMeter.span());
  • _Tpchar(8)时,方法1花费2.195ms,方法2花费2.175ms
  • _Tpint(32)时,方法1耗时13.313ms,方法2耗时5.987ms
  • _Tpdouble(64)时,方法1花费14.266ms,方法2花费11.304ms

您的基准测试无效,原因如下:

  1. 这里似乎没有检查对齐。你只是有两个不同大小的数组。此外,memset也不会太在意对齐,因为它在字节级别工作。
  2. 正如ildjarn所指出的,在如此小的内存上使用memset并不是很好。这实在是太快了,但这本身并不是一个大问题。
  3. …您没有使用您所设置的任何内存。优化器可以有效地消除对memset的所有调用,只保留一个。
  4. 当你不使用任何内存时,CPU实际上可能会做大量的重新排序/缓存,特别是在循环之间。
  5. 您的基准测试在许多操作系统上的运行时间接近时间片大小(您没有说哪一个,所以我猜在许多linux上的时间片是1ms)。这意味着操作系统切换开销可能会极大地改变你的测试结果。
  6. 数组是一个接一个分配的。cpu倾向于预测排序,因此这实际上可能会影响结果。试着改变循环的顺序,看看是否会有不同。
  7. 你没有说明你正在使用什么计时。许多计时器根本没有ms精度测试所需的分辨率,因此您可能会在结果中得到偏差。

类型必须在自身内部对齐,即char必须在1字节边界上对齐,int必须在4字节边界上对齐,double必须在8字节边界上对齐。

要真正测试未对齐的访问,请尝试执行

_Tp* A = (_Tp*)((char*)(new char[num * sizeof(_Tp)]) + 1);
...
delete[] (_Tp*)((char*)A - 1);

此外,memset将所有内容视为指向一系列char的指针,这些指针永远不会对齐,因此无论您对数组做什么,您都无法让memset进行未对齐的写入。