File I/O Buffering 235
z Each row shows the average of 20 runs for the given buffer size. In these tests,
as in other tests shown later in this chapter, the file system was unmounted and
remounted between each execution of the program to ensure that the buffer
cache for the file system was empty. Timing was done using the shell time
command.
Since the total amount of data transferred (and hence the number of disk opera-
tions) is the same for the various buffer sizes, what Table 13-1 illustrates is the over-
head of making read() and write() calls. With a buffer size of 1 byte, 100 million calls
are made to read() and write(). With a buffer size of 4096 bytes, the number of invo-
cations of each system call falls to around 24,000, and near optimal performance is
reached. Beyond this point, there is no significant performance improvement,
because the cost of making read() and write() system calls becomes negligible com-
pared to the time required to copy data between user space and kernel space, and
to perform actual disk I/O.
The final rows of Table 13-1 allow us to make rough estimates of the times
required for data transfer between user space and kernel space, and for file I/O.
Since the number of system calls in these cases is relatively small, their contri-
bution to the elapsed and CPU times is negligible. Thus, we can say that the
System CPU time is essentially measuring the time for data transfers between
user space and kernel space. The Elapsed time value gives us an estimate of the
time required for data transfer to and from the disk. (As we’ll see in a moment,
this is mainly the time required for disk reads.)
In summary, if we are transferring a large amount of data to or from a file, then by
buffering data in large blocks, and thus performing fewer system calls, we can
greatly improve I/O performance.
The data in Table 13-1 measures a range of factors: the time to perform read()
and write() system calls, the time to transfer data between buffers in kernel space
and user space, and the time to transfer data between kernel buffers and the disk.
Let’s consider the last factor further. Obviously, transferring the contents of the
Table 13-1: Time required to duplicate a file of 100 million bytes
BUF_SIZE
Time (seconds)
Elapsed Total CPU User CPU System CPU
1 107.43 107.32 8.20 99.12
2 54.16 53.89 4.13 49.76
4 31.72 30.96 2.30 28.66
8 15.59 14.34 1.08 13.26
16 7.50 7.14 0.51 6.63
32 3.76 3.68 0.26 3.41
64 2.19 2.04 0.13 1.91
128 2.16 1.59 0.11 1.48
256 2.06 1.75 0.10 1.65
512 2.06 1.03 0.05 0.98
1024 2.05 0.65 0.02 0.63
4096 2.05 0.38 0.01 0.38
16384 2.05 0.34 0.00 0.33
65536 2.06 0.32 0.00 0.32