【发布时间】:2021-07-08 07:56:46
【问题描述】:
我使用 mmap、读写系统调用来复制文件。我想看看 mmap 速度的优势。
我考虑了四种复制方式:
- 读+写
- 读取+mmap
- 写+mmap
- mmap+mmap
但是,结果是不管块大小,mmap总是比读写慢。
源代码:
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
constexpr long MAP_SIZE = 1L*1024*1024*1024;
constexpr int BLOCK_SIZE = 256;
using namespace std;
void test1(int fd1, int fd2){
// read+write
char buf[BLOCK_SIZE];
lseek(fd1, 0, SEEK_SET);
lseek(fd2, 0, SEEK_SET);
clock_t t1 = clock();
for(long i = 0; i < MAP_SIZE / BLOCK_SIZE; i++){
// use for fair
off_t file_offset = i*BLOCK_SIZE;
off_t page_align_offset = i*BLOCK_SIZE & ~(sysconf(_SC_PAGE_SIZE)-1);
off_t in_page_offset = file_offset-page_align_offset;
int mm_len = in_page_offset+BLOCK_SIZE;
read(fd1, buf, BLOCK_SIZE);
write(fd2, buf, BLOCK_SIZE);
}
clock_t t2 = clock();
cout << "total size is: " << MAP_SIZE << endl;
cout << "block size is: " << BLOCK_SIZE << endl;
cout << "read+write use " << (clock() - t1) * 1.0 / CLOCKS_PER_SEC * 1000 << "ms" << endl;
}
void test2(int fd1, int fd2){
// mmap+write
char *buf;
lseek(fd1, 0, SEEK_SET);
lseek(fd2, 0, SEEK_SET);
clock_t t1 = clock();
for(long i = 0; i < MAP_SIZE / BLOCK_SIZE; i++){
off_t file_offset = i*BLOCK_SIZE;
off_t page_align_offset = i*BLOCK_SIZE & ~(sysconf(_SC_PAGE_SIZE)-1);
off_t in_page_offset = file_offset - page_align_offset;
int mm_len = in_page_offset + BLOCK_SIZE;
buf = (char *)mmap(NULL, mm_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, page_align_offset);
write(fd2, buf+in_page_offset, BLOCK_SIZE);
munmap(buf, mm_len);
}
clock_t t2 = clock();
cout << "total size is: " << MAP_SIZE << endl;
cout << "block size is: " << BLOCK_SIZE << endl;
cout << "mmap+write use " << (clock() - t1) * 1.0 / CLOCKS_PER_SEC * 1000 << "ms" << endl;
}
void test3(int fd1, int fd2){
// read+mmap
char buf1[BLOCK_SIZE];
char* buf2;
lseek(fd1, 0, SEEK_SET);
lseek(fd2, 0, SEEK_SET);
clock_t t1 = clock();
for(long i = 0; i < MAP_SIZE / BLOCK_SIZE; i++){
off_t file_offset = i*BLOCK_SIZE;
off_t page_align_offset = i*BLOCK_SIZE & ~(sysconf(_SC_PAGE_SIZE)-1);
off_t in_page_offset = file_offset-page_align_offset;
int mm_len = in_page_offset+BLOCK_SIZE;
read(fd1, buf1, BLOCK_SIZE);
buf2 = (char *)mmap(NULL, mm_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, page_align_offset);
memcpy(buf2+in_page_offset, buf1, BLOCK_SIZE);
munmap(buf2, mm_len);
}
clock_t t2 = clock();
cout << "total size is: " << MAP_SIZE << endl;
cout << "block size is: " << BLOCK_SIZE << endl;
cout << "read+mmap use " << (clock() - t1) * 1.0 / CLOCKS_PER_SEC * 1000 << "ms" << endl;
}
void test4(int fd1, int fd2){
// mmap+mmap
char* buf1;
char* buf2;
clock_t t1 = clock();
for(long i = 0; i < MAP_SIZE / BLOCK_SIZE; i++){
off_t file_offset = i*BLOCK_SIZE;
off_t page_align_offset = i*BLOCK_SIZE & ~(sysconf(_SC_PAGE_SIZE)-1);
off_t in_page_offset = file_offset-page_align_offset;
int mm_len = in_page_offset+BLOCK_SIZE;
buf1 = (char *)mmap(NULL, mm_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, page_align_offset);
buf2 = (char *)mmap(NULL, mm_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, page_align_offset);
memcpy(buf2+in_page_offset, buf1+in_page_offset, BLOCK_SIZE);
munmap(buf1, mm_len);
munmap(buf2, mm_len);
}
clock_t t2 = clock();
cout << "total size is: " << MAP_SIZE << endl;
cout << "block size is: " << BLOCK_SIZE << endl;
cout << "mmap+mmap use " << (clock() - t1) * 1.0 / CLOCKS_PER_SEC * 1000 << "ms" << endl;
}
int main(int argc, char *argv[])
{
int fd1, fd2;
fd1 = shm_open("shm1", O_RDWR|O_CREAT, 0644);
fd2 = shm_open("shm2", O_RDWR|O_CREAT, 0644);
// fd1 = open("f1", O_RDWR|O_CREAT, 0644);
// fd2 = open("f2", O_RDWR|O_CREAT, 0644);
if(fd1 < 0 || fd2 < 0){
printf("shm_open failed\n");
exit(1);
}
if (ftruncate(fd1, MAP_SIZE) < 0){
printf("ftruncate failed\n");
exit(1);
}
if (ftruncate(fd2, MAP_SIZE) < 0){
printf("ftruncate failed\n");
exit(1);
}
test1(fd1, fd2);
test2(fd1, fd2);
test3(fd1, fd2);
test4(fd1, fd2);
}
显示 mmap 较慢的结果之一:
total size is: 1073741824
block size is: 4096
read+write use 254.571ms
total size is: 1073741824
block size is: 4096
mmap+write use 486.342ms
total size is: 1073741824
block size is: 4096
read+mmap use 537.277ms
total size is: 1073741824
block size is: 4096
mmap+mmap use 737.734ms
【问题讨论】:
-
我想看看 mmap 速度的优势。 你从哪里得到
mmap()更快的想法?它不是。所有read()和write()所要做的就是将数据从存储复制到进程地址空间,或者从进程地址空间复制到存储。mmap()必须这样做和在进程地址空间中创建虚拟页面,和分配物理页面, 和创建虚拟到物理的映射。 那么就可以复制数据了。 (是的,您可以使用read()或write()获得页面错误,但您可以控制它。您将使用mmap()有多个页面错误...) -
read()和write()需要将fd1数据复制到用户空间,而不是将它们复制到fd2但mmap只需要构建页面映射并复制一次 -
所以?
mmap()是 SLOW。你刚刚学会了。 -
我不这么认为。比较 1 和 4,1 做了两份,4 只做了一份和两次缺页。但是缺页只是修改页表。它应该比复制数据更快
-
你不这么认为吗? Well, one Linus Torvalds would vehemently disagree with you 我强烈怀疑他比你更了解如何处理内存。同样:
mmap()是 SLOW。请注意,您看到mmap()花费的时间是read()/write()的三倍。这完全与 Linus 响应的性能差异相同...加上 ça 变化,加上 c'est la meme 选择