暗无天日

=============>DarkSun的个人博客

使用sendfile系统调用加速文件传输

今天学到了一个新系统调用:sendfile,它专门用来在两个文件描述符之间传输数据.

#include <sys/sendfile.h>

ssize_t  sendfile(int  out_fd,  int in_fd, off_t *offset, size_t count);

在引入 sendfile 系统调用之前,要传输文件内容(拷贝文件或通过网络传输文件)往往需要经过下面几个步骤:

如此算来,至少要经过两次上下文切换和一次数据拷贝的动作,甚至在文件内容巨大的时候这个流程可能需要流转多次。

考虑到拷贝文件这个动作实在太过常见,因此系统引入了 sendtofile 系统调用,这样只需要一个系统调用就行了,在传输巨大文件时能够极大地节省CPU时间。

另外,通过strace跟踪系统调用,居然发现 cpdd 命令还是用的read和write的方式来进行文件之间的数据传输的。

date >d.tmp
strace cp d.tmp d1.tmp 2>&1
echo '------------------------------------'
strace dd if=d.tmp of=d.tmp bs=512 2>&1
execve("/usr/bin/cp", ["cp", "d.tmp", "d1.tmp"], 0x7ffeb19b6740 /* 55 vars */) = 0
brk(NULL)                               = 0x560d6be64000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffff3d40290) = -1 EINVAL (无效的参数)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (没有那个文件或目录)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=328885, ...}) = 0
mmap(NULL, 328885, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f1b680aa000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/libacl.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\30\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=30504, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1b680a8000
mmap(NULL, 2125984, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1b67ea0000
mprotect(0x7f1b67ea7000, 2093056, PROT_NONE) = 0
mmap(0x7f1b680a6000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6000) = 0x7f1b680a6000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/libattr.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\21\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=18112, ...}) = 0
mmap(NULL, 2113560, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1b67c9b000
mprotect(0x7f1b67c9f000, 2093056, PROT_NONE) = 0
mmap(0x7f1b67e9e000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7f1b67e9e000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360o\2\0\0\0\0\0"..., 832) = 832
lseek(3, 64, SEEK_SET)                  = 64
read(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784) = 784
lseek(3, 848, SEEK_SET)                 = 848
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
lseek(3, 880, SEEK_SET)                 = 880
read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\250\257l\201\313(\243{\363\245F\227\v\366B$"..., 68) = 68
fstat(3, {st_mode=S_IFREG|0755, st_size=2133648, ...}) = 0
lseek(3, 64, SEEK_SET)                  = 64
read(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784) = 784
lseek(3, 848, SEEK_SET)                 = 848
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
lseek(3, 880, SEEK_SET)                 = 880
read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\250\257l\201\313(\243{\363\245F\227\v\366B$"..., 68) = 68
mmap(NULL, 1844408, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1b67ad8000
mprotect(0x7f1b67afd000, 1654784, PROT_NONE) = 0
mmap(0x7f1b67afd000, 1351680, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7f1b67afd000
mmap(0x7f1b67c47000, 299008, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16f000) = 0x7f1b67c47000
mmap(0x7f1b67c91000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b8000) = 0x7f1b67c91000
mmap(0x7f1b67c97000, 13496, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f1b67c97000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1b67ad5000
arch_prctl(ARCH_SET_FS, 0x7f1b67ad5740) = 0
mprotect(0x7f1b67c91000, 12288, PROT_READ) = 0
mprotect(0x7f1b67e9e000, 4096, PROT_READ) = 0
mprotect(0x7f1b680a6000, 4096, PROT_READ) = 0
mprotect(0x560d69f87000, 4096, PROT_READ) = 0
mprotect(0x7f1b68125000, 4096, PROT_READ) = 0
munmap(0x7f1b680aa000, 328885)          = 0
brk(NULL)                               = 0x560d6be64000
brk(0x560d6be85000)                     = 0x560d6be85000
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=6180864, ...}) = 0
mmap(NULL, 6180864, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f1b674f0000
close(3)                                = 0
geteuid()                               = 1000
stat("d1.tmp", {st_mode=S_IFREG|0644, st_size=43, ...}) = 0
stat("d.tmp", {st_mode=S_IFREG|0644, st_size=43, ...}) = 0
newfstatat(AT_FDCWD, "d1.tmp", {st_mode=S_IFREG|0644, st_size=43, ...}, 0) = 0
openat(AT_FDCWD, "d.tmp", O_RDONLY)     = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=43, ...}) = 0
openat(AT_FDCWD, "d1.tmp", O_WRONLY|O_TRUNC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1b680d9000
read(3, "2019\345\271\264 09\346\234\210 16\346\227\245 \346\230\237\346\234\237\344\270\200 17"..., 131072) = 43
write(4, "2019\345\271\264 09\346\234\210 16\346\227\245 \346\230\237\346\234\237\344\270\200 17"..., 43) = 43
read(3, "", 131072)                     = 0
close(4)                                = 0
close(3)                                = 0
munmap(0x7f1b680d9000, 139264)          = 0
lseek(0, 0, SEEK_CUR)                   = 40
close(0)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++
------------------------------------
execve("/usr/bin/dd", ["dd", "if=d.tmp", "of=d.tmp", "bs=512"], 0x7ffde0cfb688 /* 55 vars */) = 0
brk(NULL)                               = 0x557745690000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffed1db1bb0) = -1 EINVAL (无效的参数)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (没有那个文件或目录)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=328885, ...}) = 0
mmap(NULL, 328885, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f1fe38dd000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360o\2\0\0\0\0\0"..., 832) = 832
lseek(3, 64, SEEK_SET)                  = 64
read(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784) = 784
lseek(3, 848, SEEK_SET)                 = 848
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
lseek(3, 880, SEEK_SET)                 = 880
read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\250\257l\201\313(\243{\363\245F\227\v\366B$"..., 68) = 68
fstat(3, {st_mode=S_IFREG|0755, st_size=2133648, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1fe38db000
lseek(3, 64, SEEK_SET)                  = 64
read(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784) = 784
lseek(3, 848, SEEK_SET)                 = 848
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
lseek(3, 880, SEEK_SET)                 = 880
read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\250\257l\201\313(\243{\363\245F\227\v\366B$"..., 68) = 68
mmap(NULL, 1844408, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1fe3718000
mprotect(0x7f1fe373d000, 1654784, PROT_NONE) = 0
mmap(0x7f1fe373d000, 1351680, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7f1fe373d000
mmap(0x7f1fe3887000, 299008, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16f000) = 0x7f1fe3887000
mmap(0x7f1fe38d1000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b8000) = 0x7f1fe38d1000
mmap(0x7f1fe38d7000, 13496, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f1fe38d7000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f1fe38dc580) = 0
mprotect(0x7f1fe38d1000, 12288, PROT_READ) = 0
mprotect(0x557743ce2000, 4096, PROT_READ) = 0
mprotect(0x7f1fe3958000, 4096, PROT_READ) = 0
munmap(0x7f1fe38dd000, 328885)          = 0
rt_sigaction(SIGINT, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGUSR1, {sa_handler=0x557743cd3f60, sa_mask=[INT USR1], sa_flags=SA_RESTORER, sa_restorer=0x7f1fe37527e0}, NULL, 8) = 0
rt_sigaction(SIGINT, {sa_handler=0x557743cd3f50, sa_mask=[INT USR1], sa_flags=SA_RESTORER|SA_NODEFER|SA_RESETHAND, sa_restorer=0x7f1fe37527e0}, NULL, 8) = 0
brk(NULL)                               = 0x557745690000
brk(0x5577456b1000)                     = 0x5577456b1000
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=6180864, ...}) = 0
mmap(NULL, 6180864, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f1fe3133000
close(3)                                = 0
openat(AT_FDCWD, "d.tmp", O_RDONLY)     = 3
dup2(3, 0)                              = 0
close(3)                                = 0
lseek(0, 0, SEEK_CUR)                   = 0
openat(AT_FDCWD, "d.tmp", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
dup2(3, 1)                              = 1
close(3)                                = 0
read(0, "", 512)                        = 0
close(0)                                = 0
close(1)                                = 0
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 0
fstat(0, {st_mode=S_IFREG|0644, st_size=2997, ...}) = 0
read(0, "# Locale name alias data base.\n#"..., 4096) = 2997
read(0, "", 4096)                       = 0
close(0)                                = 0
openat(AT_FDCWD, "/usr/share/locale/zh_CN.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (没有那个文件或目录)
openat(AT_FDCWD, "/usr/share/locale/zh_CN.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (没有那个文件或目录)
openat(AT_FDCWD, "/usr/share/locale/zh_CN/LC_MESSAGES/coreutils.mo", O_RDONLY) = 0
fstat(0, {st_mode=S_IFREG|0644, st_size=219071, ...}) = 0
mmap(NULL, 219071, PROT_READ, MAP_PRIVATE, 0, 0) = 0x7f1fe38f8000
close(0)                                = 0
openat(AT_FDCWD, "/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = -1 ENOENT (没有那个文件或目录)
openat(AT_FDCWD, "/usr/lib/gconv/gconv-modules", O_RDONLY|O_CLOEXEC) = 0
fstat(0, {st_mode=S_IFREG|0644, st_size=56352, ...}) = 0
read(0, "# GNU libc iconv configuration.\n"..., 4096) = 4096
read(0, "1002//\tJUS_I.B1.002//\nmodule\tJUS"..., 4096) = 4096
read(0, "ISO-IR-110//\t\tISO-8859-4//\nalias"..., 4096) = 4096
read(0, "\t\tISO-8859-14//\nalias\tISO_8859-1"..., 4096) = 4096
read(0, "IC-ES//\nalias\tEBCDICES//\t\tEBCDIC"..., 4096) = 4096
read(0, "DIC-CP-ES//\t\tIBM284//\nalias\tCSIB"..., 4096) = 4096
read(0, "\tIBM863//\nalias\tOSF1002035F//\t\tI"..., 4096) = 4096
read(0, "37//\t\tIBM937//\nmodule\tIBM937//\t\t"..., 4096) = 4096
read(0, "JIS//\t\t\tEUC-JP//\nmodule\tEUC-JP//"..., 4096) = 4096
read(0, "ias\tISO2022CN//\t\tISO-2022-CN//\nm"..., 4096) = 4096
read(0, "_5427-EXT//\nalias\tISO_5427EXT//\t"..., 4096) = 4096
brk(0x5577456d2000)                     = 0x5577456d2000
read(0, "st\nmodule\tMAC-SAMI//\t\tINTERNAL\t\t"..., 4096) = 4096
read(0, "12//\t\tINTERNAL\t\tIBM1112\t\t1\nmodul"..., 4096) = 4096
read(0, "\tCP9448//\t\tIBM9448//\nalias\tCSIBM"..., 4096) = 3104
read(0, "", 4096)                       = 0
close(0)                                = 0
write(2, "\350\256\260\345\275\225\344\272\2060+0 \347\232\204\350\257\273\345\205\245\n\350\256\260\345\275\225\344\272\206"..., 46记录了0+0 的读入
记录了0+0 的写出
) = 46
openat(AT_FDCWD, "/usr/share/locale/zh.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (没有那个文件或目录)
openat(AT_FDCWD, "/usr/share/locale/zh/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (没有那个文件或目录)
write(2, "0 bytes copied, 0.00256732 s, 0."..., 380 bytes copied, 0.00256732 s, 0.0 kB/s) = 38
write(2, "\n", 1
)                       = 1
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++