如何比较mmap和读取性能

时间:2014-04-25 09:18:21

标签: c performance mmap

我想比较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指针(charintuintmax_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

1 个答案:

答案 0 :(得分:3)

这有点推测,因为我可能没有想到所有的含义:


在第一种情况下,大部分时间都是:

  • 执行read(2)系统调用(其中许多)的开销
    • 将数据从一个文件复制到进程可访问的内存。实际从设备读取(旋转HDD或其他任何东西)
    • 主导了时间
  • 执行write(2)系统调用,不会超出系统调用开销(见下文)

在第二种情况下,大部分时间都是:

  • 执行单个系统调用的开销(一个mmap)。 这实际上并没有读取任何内容。内核只是检查你是否拥有权限并假装“映射”数据。
    • 一旦你开始做某事 - 比如读或写 - 内核实际上会将它映射到内存中,这需要时间( pagefaults
  • 执行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默认为行缓冲。