【问题标题】:determining the optimal buffer size for file read in linux确定 linux 中文件读取的最佳缓冲区大小
【发布时间】:2018-10-14 23:40:17
【问题描述】:

我正在编写一个从标准输入读取并写入标准输出的 C 程序。但它会缓冲数据,以便仅在读取特定数量的字节后才执行写入(=SIZE)

#include<stdio.h>
#include<stdlib.h>

#define SIZE 100

int main()
{
        char buf[SIZE];
        int n=0;
        //printf("Block size = %d\n", BUFSIZ);

        while( ( n = read(0, buf, sizeof(buf)) ) > 0 )
                write(1, buf, n);
        exit(0);
}

我在托管在 Oracle Virtual Box(4GB RAM,2 核)上的 Ubuntu 18.04 上运行该程序,并针对不同的缓冲区大小值测试该程序。我已将标准输入重定向到来自一个文件(其中包含动态创建的随机数),并将标准输出重定向到 /dev/null。这是用于运行测试的 shell 脚本:

#!/bin/bash

# $1 - step size  (bytes)
# $2 - start size (bytes)
# $3 - stop size (bytes)

echo "Changing buffer size from $2 to $3 in steps of $1, and measuring time for copying."

buff_size=$2

echo "Test Data" >testData
echo "Step Size:(doubles from previous size) Start Size:$2 Stop Size:$3" >>testData

while [ $buff_size -le $3 ]
do
        echo "" >>testData
        echo -n "$buff_size," >>testData
        gcc -DSIZE=$buff_size copy.c    # Compile the program for cat, with new buffer size
        dd bs=1000 count=1000000 </dev/urandom >testFile        #Create testFile with random data of 1GB        
        (/usr/bin/time -f "\t%U, \t%S," ./a.out <testFile 1>/dev/null) 2>>testData
        buff_size=$(($buff_size * 2))
        rm -f a.out
        rm -f testFile
done

我正在测量执行程序并将其制成表格所花费的时间。测试运行会产生以下数据:

Test Data
Step Size:(doubles from previous size) Start Size:1 Stop Size:524288

1,      5.94,   17.81,

2,      5.53,   18.37,

4,      5.35,   18.37,

8,      5.58,   18.78,

16,     5.45,   18.96,

32,     5.96,   19.81,

64,     5.60,   18.64,

128,    5.62,   17.94,

256,    5.37,   18.33,

512,    5.70,   18.45,

1024,   5.43,   17.45,

2048,   5.22,   17.95,

4096,   5.57,   18.14,

8192,   5.88,   17.39,

16384,  5.39,   18.64,

32768,  5.27,   17.78,

65536,  5.22,   17.77,

131072, 5.52,   17.70,

262144, 5.60,   17.40,

524288, 5.96,   17.99,

由于我们使用不同的块大小,我没有看到用户+系统时间有任何显着变化。但理论上,随着块大小变小,同样大小的文件会产生很多系统调用,执行时间应该会更长。我在 Richard Stevens 的“Unix 环境中的高级编程”一书中看到了类似测试的测试结果,它表明如果复制中使用的缓冲区大小接近块大小,则用户+系统时间会显着减少。(在我的情况下, ext4 分区上的块大小为 4096 字节)

为什么我无法重现这些结果?我在这些测试中遗漏了一些因素吗?

【问题讨论】:

  • 谢谢@Alfe。正如您之前提到的,问题是当我通过编译器传递参数时,SIZE 的默认值没有被覆盖。注释掉#define SIZE 100 有帮助。观察结果与史蒂文斯获得的结果相似。随着我们接近 4096 及更大的块大小,从文件读取所需的时间大大减少。
  • (我将我的 cmets 迁移到了正确的答案中。)
  • 您能否使用更新的结果发布答案(或更新问题)。这是一个常见的用例,拥有这些数据会很棒

标签: linux performance unix filesystems system-calls


【解决方案1】:

您没有在源代码中禁用 #define SIZE 100 行,因此通过选项 (-DSIZE=1000) 的定义确实仅在此 #define 之上产生影响。在我的编译器上,我在编译时收到了一个警告 (&lt;command-line&gt;:0:0: note: this is the location of the previous definition)。

如果您注释掉#define,您应该能够修复此错误。

想到的另一个方面:

如果您在机器上创建一个文件并在此之后立即读取它,它将位于操作系统的磁盘缓存中(足够大以存储所有此文件),因此实际磁盘块大小不会有这里影响很大。

史蒂文斯的书写于 1992 年,当时 RAM 比今天贵得多,所以其中的某些信息可能已经过时。我也怀疑这本书的新版本是否已经删除了这些内容,因为总的来说它们仍然是正确的。

【讨论】:

  • 通过应用您上面提到的更改,我能够观察到执行时间(用户+系统时间)相对于缓冲区大小的变化。数据证实了这是一个普遍的事实。尽管 RAM 足够大,可以容纳我创建的文件(我的实验机器有 4GB 的 RAM,并且我正在创建 1GB 的文件用于测试),但我认为其中的很大一部分是为缓冲区缓存保留的。这可能就是为什么我仍然能够观察到这个特征的原因。
猜你喜欢
  • 2010-12-05
  • 1970-01-01
  • 2012-11-06
  • 2013-03-10
  • 1970-01-01
  • 2014-08-22
  • 1970-01-01
  • 2013-11-02
  • 2023-03-24
相关资源
最近更新 更多