我想比较mmap()
&的性能。 read()
文件大小从1KB到1GB不等(因子10的增量)。
我这样做的方法是读取整个文件(按顺序),然后将输出写入另一个文件中,并测量时间。
代码:
对于read()
代码,我有:
19 char text[1000];
. . . . . .
77 while((bytes_read=read(d_ifp,text,1000))>0)
78 {
79 write(d_ofp, text, bytes_read);
80 }
对于mmap()
代码,我有:
20 //char *data;
21 uintmax_t *data;
22 //int *data;
. . . . . .
86 if((data = (uintmax_t*)mmap((caddr_t)0, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) == (uintmax_t*)(-1))
87 {
88 perror("mmap");
89 exit(1);
90 }
96 int j=0;
97 while (i<=sbuf.st_size)
98 {
99 fprintf(ofp, "data[%d]=%ju\n", i, data[j]);
101 i=i+sizeof(*data);
102 j++;
103 }
mmap()
的计算时间取决于我声明data
指针(char
,int
,uintmax_t
)的方式,以防万一read()
的变化取决于缓冲区的大小 - text
。
输出:
现在mmap
被证明非常缓慢,这是令人惊讶的:
[read]: f_size: 1K B, Time: 8e-06 seconds
[read]: f_size: 10K B, Time: 1.4e-05 seconds
[read]: f_size: 100K B, Time: 8.3e-05 seconds
[read]: f_size: 1M B, Time: 0.000612 seconds
[read]: f_size: 10M B, Time: 0.009652 seconds
[read]: f_size: 100M B, Time: 0.12094 seconds
[read]: f_size: 1G B, Time: 6.5787 seconds
[mmap]: f_size: 1K B, Time: 0.002922 seconds
[mmap]: f_size: 10K B, Time: 0.004116 seconds
[mmap]: f_size: 100K B, Time: 0.020122 seconds
[mmap]: f_size: 1M B, Time: 0.22538 seconds
[mmap]: f_size: 10M B, Time: 2.2079 seconds
[mmap]: f_size: 100M B, Time: 22.691 seconds
[mmap]: f_size: 1G B, Time: 276.36 seconds
问题:
1.如果我将read
代码中的缓冲区大小等于mmap
代码中的类型大小,评估是否正确/合理?
2.比较这两者的正确方法是什么?
修改
我将fprintf
代码中的mmap
更改为write
,现在性能更好,但非常奇怪,对于较大的文件大小,性能会下降。这是预料之中的吗?
(我在两种情况下都将数据写入/dev/null
):
[mmap]: f_size: 1K B, Time: 3.3e-05 seconds
[mmap]: f_size: 10K B, Time: 2e-06 seconds
[mmap]: f_size: 100K B, Time: 2e-06 seconds
[mmap]: f_size: 1M B, Time: 4e-06 seconds
[mmap]: f_size: 10M B, Time: 3e-06 seconds
[mmap]: f_size: 100M B, Time: 2e-06 seconds
[mmap]: f_size: 1G B, Time: 2e-06 seconds
答案 0 :(得分:3)
这有点推测,因为我可能没有想到所有的含义:
在第一种情况下,大部分时间都是:
read(2)
系统调用(其中许多)的开销
write(2)
系统调用,不会超出系统调用开销(见下文)在第二种情况下,大部分时间都是:
mmap
)。 这实际上并没有读取任何内容。内核只是检查你是否拥有权限并假装“映射”数据。
write(2)
系统调用的开销。我假设您对较大的文件执行的write
次呼叫较少在Linux writing to /dev/null
中实现如下:
static ssize_t write_null(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
return count;
}
这大致意味着:“只说出我们做过的过程”。这意味着永远不会触及mmap
内存 - &gt;永远不会读取该文件。所以每次你只承担执行系统调用的费用。所以你做的write
越少,你在中断中浪费的时间越少,无论如何都不会做任何事情。
总之,在这两种情况下,write
都是便宜的,无操作电话。但在第一个read
实际上花费,因为实际上必须从文件中提取数据。
printf
案例怎么样?在这种情况下,您正在主动触摸内存mmap
ed,从而迫使内核停止说谎并实际读取文件中的数据。除此之外,您还打印了它,这取决于正在使用的缓冲stdio
,也不时触发系统调用。为了防止你写入屏幕,这是特别昂贵的,因为stdout
默认为行缓冲。