我正在使用mmap来读取文件。现在,当文件大小约为880 MB时,需要大约0.5秒来迭代文件。
现在我通过复制文件内容将文件大小增加了10倍。现在再次使用mmap需要大约1分钟。
我认为迭代的时间应该随文件大小线性增加。
这是简单的测试代码
FILE *fp = fopen64("filename", "rm");
if (fp == NULL)
{
perror(NULL);
}
struct stat st;
fstat(fileno(fp), &st);
off_t fileSize = st.st_size;
char *data = (char *)mmap64(NULL, fileSize, PROT_READ,MAP_PRIVATE,fileno(fp), 0);
off_t ptr =0;
char c =(char)0;
while(ptr < fileSize) { c += data[ptr++] ;}
std::cout << c << "\n";
以下是结果。
对于fileSize 880MB
real 0m0.501s
user 0m0.447s
sys 0m0.053s
对于fileSize 8.8 GB
real 0m57.685s
user 0m10.773s
sys 0m3.690s
答案 0 :(得分:3)
访问时间不是常数,数据集越大,访问时间就越慢。我建议阅读Latency Numbers Every Programmer Should Know。
如果运行基准测试并调整数据集大小,您将看到性能发生变化的几个范围。
当数据集适合L1缓存时,性能最快。 L1缓存很小,比如每个内核64 KiB,但速度很快(约1个周期的访问时间,几乎和寄存器一样快)。
当您需要L2缓存时,性能会突然下降。 L2缓存比L1缓存更大,更慢。性能下降大概是10倍左右。
当数据集对于L2缓存而言太大但适合RAM时,性能会再次下降。缓存未命中的性能下降了10倍左右。
当数据集对于RAM而言太大但适合磁盘时,性能会下降。假设你有一个快速的SSD,性能命中率就像1000倍的缓存未命中,如果你有一个非SSD硬盘驱动器,可能会达到100,000倍。
您的880 MB数据集整齐地适合8 GiB的RAM,但是8,800 MB的数据集却没有,它们不能同时驻留。随机访问模式有点过分,但即使使用线性访问模式,您的页面也会从缓存中逐出,内核必须一遍又一遍地从磁盘中读取它们。
很高兴假装你拥有无限量的存储空间,但存储速度相同,但这种情况甚至都不是真的。
实际上,将文件放入内存的唯一两种方法是使用read
或mmap
。其他选项只是这两个选项之上的层。对于不在页面缓存中的数据的顺序访问,read
和mmap
之间的差异无关紧要,请参阅mmap() vs. reading blocks
访问模式将改变数据集变大时性能下降的程度,但它不会改变这样一个事实,即数据集太大而无法驻留不能比磁盘快。
如果您要转到mmap
然后使用open
而不是fopen
,则fopen
是不必要的。
"m"
的{{1}}标记不符合您的想法,此处没有用处。
请勿使用fopen
,open64
,fopen64
或任何废话。只需使用mmap64
即可。这是现代的做事方式,当然,它只与32位系统相关 - 而且由于您在零偏移处使用#define _FILE_OFFSET_BITS 64
,所以没有点。
致电mmap
但是继续是错误的。 perror
功能并非普遍可用,但可以满足您的需求。
没有充分的理由不在这里使用err()
,但它不会改变任何内容。
以下是更一致的错误检查代码的外观:
MAP_SHARED