【发布时间】:2014-12-08 13:15:37
【问题描述】:
在尝试使用内存映射文件创建数 GB 的文件(大约 13gb)时,我遇到了 mmap() 的问题。最初的实现是在 Windows 上的 c++ 中使用 boost::iostreams::mapped_file_sink 完成的,一切都很好。然后代码在 Linux 上运行,在 Windows 上花费几分钟的时间在 Linux 上变成了几个小时。
这两台机器是相同硬件的克隆:Dell R510 2.4GHz 8M Cache 16GB Ram 1TB Disk PERC H200 Controller。
Linux 是使用 3.8 内核和 g++ 4.83 的 Oracle Enterprise Linux 6.5。
有人担心 boost 库可能存在问题,因此使用 boost::interprocess::file_mapping 和本机 mmap() 完成了实现。这三个都表现出相同的行为。当 Linux 性能严重下降时,Windows 和 Linux 性能达到一定水平。
完整的源代码和性能数据链接如下。
// C++ code using boost::iostreams
void IostreamsMapping(size_t rowCount)
{
std::string outputFileName = "IoStreamsMapping.out";
boost::iostreams::mapped_file_params params(outputFileName);
params.new_file_size = static_cast<boost::iostreams::stream_offset>(sizeof(uint64_t) * rowCount);
boost::iostreams::mapped_file_sink fileSink(params); // NOTE: using this form of the constructor will take care of creating and sizing the file.
uint64_t* dest = reinterpret_cast<uint64_t*>(fileSink.data());
DoMapping(dest, rowCount);
}
void DoMapping(uint64_t* dest, size_t rowCount)
{
inputStream->seekg(0, std::ios::beg);
uint32_t index, value;
for (size_t i = 0; i<rowCount; ++i)
{
inputStream->read(reinterpret_cast<char*>(&index), static_cast<std::streamsize>(sizeof(uint32_t)));
inputStream->read(reinterpret_cast<char*>(&value), static_cast<std::streamsize>(sizeof(uint32_t)));
dest[index] = value;
}
}
最后一次测试是用 Python 完成的,以便用另一种语言重现。脱落发生在同一个地方,所以看起来是同一个问题。
# Python code using numpy
import numpy as np
fpr = np.memmap(inputFile, dtype='uint32', mode='r', shape=(count*2))
out = np.memmap(outputFile, dtype='uint64', mode='w+', shape=(count))
print("writing output")
out[fpr[::2]]=fpr[::2]
对于 c++ 测试,Windows 和 Linux 具有相似的性能,最高可达 3 亿个 int64(Linux 看起来稍快一些)。对于 C++ 和 Python,Linux 上的性能似乎下降了大约 3Gb(4 亿 * 每个 int64 8 字节 = 3.2Gb)。
我知道在 32 位 Linux 上 3Gb 是一个神奇的边界,但我不知道 64 位 Linux 的类似行为。
结果的要点是,在 4 亿个 int64 上,Windows 需要 1.4 分钟,而 Linux 需要 1.7 小时。我实际上正在尝试映射接近 13 亿个 int64。
谁能解释一下为什么 Windows 和 Linux 之间的性能如此不同?
任何帮助或建议将不胜感激!
Updated Results 更新了 Python 代码...Python 速度现在可与 C++ 媲美
Original Results 注意:Python 结果已过时
【问题讨论】:
-
你的 Linux 机器有多少内存?
-
@MatsPetersson 16GB 内存
-
你可以尝试使用 madvise() 看看它是否改变了什么?您可能需要尝试各种建议参数:man7.org/linux/man-pages/man2/madvise.2.html
-
我建议检查 64 位 Linux 上的行为并查看结果。
-
fyi,numpy 数组中的一个整数,dtype
uint32正好占用 4 个字节。每次使用标量索引访问数组时都会创建一个新的 Python 整数(无限精度,超过 4 个字节)(装箱/拆箱很昂贵,这就是为什么应该使用向量操作:out[fpr[::2]]=fpr[::2])