12

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

 3 years ago
source link: https://www.lujun9972.win/blog/2019/09/16/%E4%BD%BF%E7%94%A8sendfile%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%E5%8A%A0%E9%80%9F%E6%96%87%E4%BB%B6%E4%BC%A0%E8%BE%93/index.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

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

#include <sys/sendfile.h>

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

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

  • 调用 read 系统调用读取文件内容,这会产生一次上下文切换
  • 将内核中的数据拷贝到用户空间
  • 调用 wirte 函数调用写入数据,这又会产生一次上下文切换

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

考虑到拷贝文件这个动作实在太过常见,因此系统引入了 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 +++

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK