Skip to content

Commit 94905fb

Browse files
committed
io/lab/quiz: Mention copy_file_range syscall for cp
`coreutils` 9.0 reimplemented `cp` using the `copy_file_range()` syscall, which performs zero-copy [1]. Therefore, the existing comparison between `mmap_cp` and `cp` is no longer valid. This commit mentions the new implementation and its effects on performance. This version of `coreutils` is available by default on newer Ubuntu systems such as 23.04. [1] https://lists.gnu.org/archive/html/info-gnu/2021-09/msg00010.html Signed-off-by: Teodor Dutu <teodor.dutu@gmail.com>
1 parent 260a273 commit 94905fb

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

content/chapters/io/lab/quiz/mmap-read-write-benchmark.md

+24-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ According to the times shown by `benchmark_cp.sh`, which of the two implementati
1212

1313
+ they are roughly equivalent
1414

15+
+ `cp` is faster if it uses `copy_file_range()`
16+
1517
## Feedback
1618

1719
In our case, running the script a few times results in the following running times:
@@ -23,12 +25,12 @@ Benchmarking mmap_cp on a 1GB file...
2325

2426
real 0m30,597s
2527
user 0m0,569s
26-
sys 0m2,286s
28+
sys 0m2,286s
2729
Benchmarking cp on a 1 GB file...
2830

2931
real 0m36,012s
3032
user 0m0,039s
31-
sys 0m2,469s
33+
sys 0m2,469s
3234

3335

3436
student@os:/.../support/file-mappings$ ./benchmark_cp.sh
@@ -37,12 +39,12 @@ Benchmarking mmap_cp on a 1 GB file...
3739

3840
real 0m27,803s
3941
user 0m0,590s
40-
sys 0m2,114s
42+
sys 0m2,114s
4143
Benchmarking cp on a 1 GB file...
4244

4345
real 0m35,607s
4446
user 0m0,033s
45-
sys 0m2,564s
47+
sys 0m2,564s
4648
```
4749

4850
So it seems that using `mmap()` rather than `read()` and `write()` yields about a 15% increase in performance.
@@ -51,3 +53,21 @@ This depends on your storage device (SSD vs HDD) and its specific speed (like it
5153
So the more conservative answer is to say that this depends on external aspects and that, in general, the 2 implementations are more or less equivalent.
5254

5355
If you want to know why there isn't much of a difference between the 2 implementations, check out [this explanation](https://stackoverflow.com/a/27987994).
56+
57+
However, some newer Linux systems use an updated `cp` that doesn't use `read` and `write` anymore, but instead uses zero-copy, by means of the `copy_file_range()` syscall.
58+
This implementation is likely going to be significantly faster than the one using `mmap`, as shown in the snippet below:
59+
60+
```console
61+
student@os:/.../support/file-mappings$ ./benchmark_cp.sh
62+
make: Nothing to be done for 'all'.
63+
Benchmarking mmap_cp on a 1 GB file...
64+
65+
real 0m1,443s
66+
user 0m0,429s
67+
sys 0m0,971s
68+
Benchmarking cp on a 1 GB file...
69+
70+
real 0m0,821s
71+
user 0m0,001s
72+
sys 0m0,602s
73+
```

content/chapters/io/lab/quiz/syscalls-cp.md

+19
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ What syscalls does `cp` use to copy files?
1010

1111
+ `read()` and `write()`
1212

13+
+ `copy_file_range()`
14+
1315
- a combination of `read()` - `write()` and `mmap()`
1416

1517
## Feedback
@@ -40,3 +42,20 @@ write(4, "\35\277\207\243~\355(i\351^\1\346\312V\232\204\32\230~\376\20\245\"\30
4042
read(3, "\n)\334\275\331:R\236O\231\243\302\314\267\326\"\rY\262\21\374\305\275\3\332\23\345\16>\214\210\235"..., 131072) = 131072
4143
write(4, "\n)\334\275\331:R\236O\231\243\302\314\267\326\"\rY\262\21\374\305\275\3\332\23\345\16>\214\210\235"..., 131072) = 131072
4244
```
45+
46+
Alternatively, if your kernel version is `5.19` or newer, it's likely that `cp` will use `copy_file_range()`:
47+
48+
```console
49+
student@os:/.../support/file-mappings$ strace cp test-file.txt output.txt
50+
openat(AT_FDCWD, "test-file.txt", O_RDONLY) = 3
51+
newfstatat(3, "", {st_mode=S_IFREG|0664, st_size=1048576, ...}, AT_EMPTY_PATH) = 0
52+
openat(AT_FDCWD, "output.txt", O_WRONLY|O_CREAT|O_EXCL, 0664) = 4
53+
ioctl(4, BTRFS_IOC_CLONE or FICLONE, 3) = -1 EOPNOTSUPP (Operation not supported)
54+
newfstatat(4, "", {st_mode=S_IFREG|0644, st_size=0, ...}, AT_EMPTY_PATH) = 0
55+
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
56+
copy_file_range(3, NULL, 4, NULL, 9223372035781033984, 0) = 1048576
57+
copy_file_range(3, NULL, 4, NULL, 9223372035781033984, 0) = 0
58+
```
59+
60+
[This syscall](https://man7.org/linux/man-pages/man2/copy_file_range.2.html) copies files inside the kernel without having the data pass through the user space.
61+
This procedure is called zero-copy.

0 commit comments

Comments
 (0)