mmap() vs Java MappedByteBuffer performance?
mmap() vs Java MappedByteBuffer performance?
我一直在用现有的Java代码开发一个C++项目。我从同一个测试文件中读取了以下C++代码和Java代码,该文件由数百万个整数组成。
C++:
int * arr = new int[len]; //len is larger than the largest int from the data
fill_n(arr, len, -1); //fill with -1
long loadFromIndex = 0;
struct stat sizeResults;
long size;
if (stat(fileSrc, &sizeResults) == 0) {
size = sizeResults.st_size; //here size would be ~551950000 for 552M test file
}
mmapFile = (char *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, pageNum*pageSize);
long offset = loadFromIndex % pageSize;
while (offset < size) {
int i = htonl(*((int *)(mmapFile + offset)));
offset += sizeof(int);
int j = htonl(*((int *)(mmapFile + offset)));
offset += sizeof(int);
swapElem(i, j, arr);
}
return arr;
Java:
IntBuffer bb = srcFile.getChannel()
.map(MapMode.READ_ONLY, loadFromIndex, size)
.asIntBuffer().asReadOnlyBuffer();
while (bb.hasRemaining()) {
int i = bb.get();
int j = bb.get();
swapElem(i, j, arr); //arr is an int[] of the same size as the arr in C++ version, filled with -1
}
return arr;
C++和Java中的CCD_ 1是完全相同的。它比较和修改数组中的值,但原始代码发布在这里有点长。出于测试目的,我用以下函数替换了它,这样循环就不会是死代码:
void swapElem(int i, int j, int * arr){ // int[] in Java
arr[i] = j;
}
我认为C++版本应该优于java版本,但测试给出了相反的结果——java代码几乎比C++代码快两倍。有什么方法可以改进C++代码吗?
我觉得C++中的mmapFile+offset
可能重复了太多次,所以它是O(n)加法,而offset+=sizeof(int)
是O(n)加法,其中n是要读取的整数数。对于Java的IntBuffer.get()
,它只直接从缓冲区的索引中读取,因此除了缓冲区索引的O(n)增量为1之外,不需要进行加法运算。因此,包括缓冲区索引的增量,C++进行O(2n)加法,而Java进行O(n)加法。当涉及到数以百万计的数据时,可能会导致显著的性能差异。
按照这个想法,我修改了C++代码如下:
mmapBin = (char *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, pageNum*pageSize);
int len = size - loadFromIndex % pageSize;
char * offset = loadFromIndex % pageSize + mmapBin;
int index = 0;
while (index < len) {
int i = htonl(*((int *)(offset)));
offset += sizeof(int);
int j = htonl(*((int *)(offset)));
offset += sizeof(int);
index+=2*sizeof(int);
}
我以为性能会略有提高,但事实并非如此。
有人能解释为什么C++代码的工作速度比Java代码慢吗?谢谢
更新:
我必须道歉,当我说-O2不起作用时,我的一端出现了问题。我把Makefile搞砸了,所以C++代码没有使用-O2重新编译。我已经更新了性能,使用-O2的C++版本的性能优于Java版本。这可以解决这个问题,但如果有人想分享如何改进C++代码,我会关注的。一般来说,我希望它比Java代码快2倍,但目前还没有。感谢大家的投入
编译器:g++
标志:-墙-c-O2
Java版本:1.8.0_05
文件大小:552MB,所有4字节整数
处理器:2.53 GHz英特尔酷睿2双核
内存4GB 1067 MHz DDR3
更新的基准:
版本时间(ms)
C++:~1100
Java:~1400
C++(无while循环):~35
Java(没有while循环):~40
在这些代码之前,我有一些导致~35ms性能的东西(主要是用-1填充数组),但这在这里并不重要。
我对基准测试方法的正确性有些怀疑。这两个代码都是"死"代码。您实际上并没有在任何地方使用i和j,因此gcc编译器或Java JIT可能会决定实际删除循环,因为它对未来的代码流没有影响。
无论如何,我会将C++代码更改为:
mmapFile = (char *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, pageNum*pageSize);
long offset = loadFromIndex % pageSize;
int i, j;
int szInc = 2 * sizeof(int);
while (offset < size) {
scanf(mmapFile, "%d", &i);
scanf(mmapFile, "%d", &j);
offset += szInc; // offset += 8;
}
这相当于Java代码。此外,我将继续使用-O2作为编译标志。请记住,htonl
是Java代码似乎无法实现的额外转换。
- 没有找到相关文章