На примере работы утилиты
dd сравним накладные расходы strace, perf и bpftrace (eBPF).Для начала запустим
dd без оберток:# dd if=/dev/zero of=/dev/null bs=512 count=100k
102400+0 records in
102400+0 records out
52428800 bytes (52 MB, 50 MiB) copied, 0.0229283 s, 2.3 GB/s
Скорость в 2.3GB/s будет эталонной, с которой и будем все сравнивать.
strace
# strace -c dd if=/dev/zero of=/dev/null bs=512 count=100k
102400+0 records in
102400+0 records out
52428800 bytes (52 MB, 50 MiB) copied, 1.73851 s, 30.2 MB/s
...
Падение скорости в ~76 раз, неплохо поработали!
perf
# perf stat -e 'syscalls:sys_enter_*' dd if=/dev/zero of=/dev/null bs=512 count=100k
102400+0 records in
102400+0 records out
52428800 bytes (52 MB, 50 MiB) copied, 0.0287921 s, 1.8 GB/s
Замедление на треть уже и не выглядит чем-то страшным:)
bpftrace
# bpftrace -e 'tracepoint:syscalls:sys_enter_* /comm == "dd"/
{ @[probe] = count(); }' -c '/usr/bin/dd if=/dev/zero of=/dev/null bs=512 count=100k'
102400+0 records in
102400+0 records out
52428800 bytes (52 MB, 50 MiB) copied, 0.0475401 s, 1.1 GB/s
Хваленный eBPF дал оверхеда более чем в 2 раза! А говорили, что "eBPF это про скорость" :(
——————————————————
С
strace всё ясно: он через ptrace приостанавливает dd на каждом syscall, с переходом в kernel mode и обратно. Но в чем eBPF не справился? Давайте обсудим!
Важно помнить: dd генерирует много системных вызовов, поэтому такой большой оверхед у `strace`. Цифры выше это скорее утрированный пример, но суть отражают верно.