【发布时间】:2017-01-06 23:51:42
【问题描述】:
我希望写入char * 缓冲区需要相同的时间,而不管内存的现有内容如何1。你不会吗?
但是,在缩小基准中的不一致范围时,我遇到了一个显然不正确的案例。包含全零的缓冲区的行为在性能方面与填充 42 的缓冲区大不相同。
从图形上看,这看起来像(详情如下):
这是我用来生成上述代码的代码3:
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include <time.h>
volatile char *sink;
void process(char *buf, size_t len) {
clock_t start = clock();
for (size_t i = 0; i < len; i += 678)
buf[i] = 'z';
printf("Processing took %lu μs\n",
1000000UL * (clock() - start) / CLOCKS_PER_SEC);
sink = buf;
}
int main(int argc, char** argv) {
int total = 0;
int memset42 = argc > 1 && !strcmp(argv[1], "42");
for (int i=0; i < 5; i++) {
char *buf = (char *)malloc(BUF_SIZE);
if (memset42)
memset(buf, 42, BUF_SIZE);
else
memset(buf, 0, BUF_SIZE);
process(buf, BUF_SIZE);
}
return EXIT_SUCCESS;
}
我在我的 Linux 机器上编译它,例如:
gcc -O2 buffer_weirdness.cpp -o buffer_weirdness
...当我使用零缓冲区运行版本时,我得到:
./buffer_weirdness zero
Processing took 12952 μs
Processing took 403522 μs
Processing took 626859 μs
Processing took 626965 μs
Processing took 627109 μs
请注意,第一次迭代很快,而剩余的迭代可能需要 50 倍更长的时间。
当缓冲区第一次被42填满时,处理总是很快的:
./buffer_weirdness 42
Processing took 12892 μs
Processing took 13500 μs
Processing took 13482 μs
Processing took 12965 μs
Processing took 13121 μs
行为取决于 `BUF_SIZE(在上面的示例中为 1GB) - 更大的大小更有可能显示问题,并且还取决于当前的主机状态。如果我不理会主机一段时间,慢速迭代可能需要 60,000 μs,而不是 600,000 - 所以快 10 倍,但仍然比快速处理时间慢约 5 倍。最终,时间回到了完全缓慢的行为。
该行为也至少部分取决于透明的大页面 - 如果我禁用它们2,慢速迭代的性能提高了大约 3 倍,而快速迭代则保持不变。 p>
最后一点是,进程的 total 运行时间比简单地计时 process 例程要近得多(事实上,零填充,THP 关闭版本大约是比其他速度快 2 倍,大致相同)。
这是怎么回事?
1 除了一些非常不寻常的优化之外,例如编译器了解缓冲区已经包含的值并删除相同值的写入,这在此处不会发生。
2sudo sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled"
3 这是原始基准的提炼版本。是的,我泄漏了分配,克服它 - 它导致了一个更简洁的例子。原始示例没有泄漏。实际上,当您不泄漏分配时,行为会发生变化:可能是因为 malloc 可以将区域重新用于下一次分配,而不是向操作系统请求更多内存。
【问题讨论】:
-
无法重现,观察到的行为很可能是编译器/操作系统/硬件特定的
-
我无法重现时序的大小;对于 0 或 42,我得到 0-1µs。
-
@Slava - 我在几个不同的 Linux 机器上复制了它,但它似乎与物理内存的数量有关 - 在具有更多 RAM 的系统上,我需要增加
BUF_SIZE或运行更多反复看效果。就像有一些有限的资源,与内存成正比,被用完了。 -
你运行了多少次这个实验?
-
在互联网上搜索“数据缓存命中未命中”。
标签: c++ linux performance memory-management malloc