Por que umount -R
usa 0,2s para desmontar essa subárvore de montagens de ligação? Levou apenas 0.02s para montar a subárvore e 0.00s para alterar seus sinalizadores de propagação.
(Eu estava olhando para clonar o conjunto atual de montagens, para um subdiretório, alterando-as, depois mudando para elas usando pivot_mount
. Mas o atraso que estou observando não seria realmente aceitável para o propósito).
Este exercício assume /
e as submontagens são montagens compartilhadas. O Linux não os torna assim por padrão, mas systemd faz.
# mkdir /mnt/a
# mount --bind /mnt/a /mnt/a --make-private
# time mount --rbind / /mnt/a
0.00user 0.00system 0:00.02elapsed 9%CPU (0avgtext+0avgdata 3020maxresident)k
0inputs+0outputs (0major+135minor)pagefaults 0swaps
# time mount --make-rprivate /mnt/a
0.00user 0.00system 0:00.00elapsed 100%CPU (0avgtext+0avgdata 3184maxresident)k
0inputs+0outputs (0major+136minor)pagefaults 0swaps
# time umount -R /mnt/a
0.00user 0.00system 0:00.19elapsed 9%CPU (0avgtext+0avgdata 3392maxresident)k
0inputs+0outputs (0major+194minor)pagefaults 0swaps
Testes adicionais
A execução sob strace -cw
mostra
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
90.44 0.180113 5297 34 umount2
...
Portanto, não é super revelador, além de apontar que esta última operação requer 34% deumount2()
de chamadas individuais, enquanto ambas as outras incluem apenas uma chamada para mount()
, usando o sinalizador MS_REC (recursivo). Tal como acontece com os números de manchete de time
, este é o tempo de relógio de parede. strace -c
mostra a hora do sistema (ou seja, o tempo da CPU gasto no kernel), que tem apenas um total de 0,009s.
Embora aponte algo interessante. Usando umount -l /mnt/a
, reduz o tempo total para 0,02s. Isso usa uma única chamada umount2()
para desanexar a subárvore /mnt/a
(e fazer qualquer limpeza em segundo plano).
Olhando para as chamadas individuais com strace -ttt -T -e trace=umount2 umount -R /mnt/a
, a distribuição de tempos para chamadas individuais é relativamente uniforme; eles variam de 0,002s a 0,012s, mas não há um padrão claro, e o padrão não parece consistente se eu repeti-lo.
Depois de executar umount -R
em perf record -a
, perf report
mostra vários pontos de acesso em gsd-housekeeping
, gvfs-udisks2-volume-monitor
e systemd
. O processo umount
não é exibido. Isso poderia explicar por que time
mostrou umount
gastando tempo de CPU negligente no kernel ou no espaço do usuário.
(Eu ficaria muito interessado se alguém tiver uma maneira mais abrangente de agregar o uso de cpu por processo durante um teste:).
Os outros processos provavelmente estão processando em resposta a cada evento de montagem.
Por exemplo systemd parece ser responsável por usar 0.13s de um dos meus quatro processadores, durante uma corrida que levou 0.4s:
# systemctl set-property init.scope CPUAccounting=yes
# systemctl show --property CPUUsageNSec init.scope; time umount -R /mnt/a ; systemctl show --property CPUUsageNSec init.scope
CPUUsageNSec=2403124481
real 0m0.408s
user 0m0.015s
sys 0m0.020s
CPUUsageNSec=2534058385
# echo $(( 2534058385 - 2403124481 ))
130933904
Mas esta não parece ser a explicação correta, porque o mesmo atraso está acontecendo ao executar em um namespace de montagem particular. Nesse caso, perf record -a
não mostra os outros processos, apenas o processo umount
(e o próprio perf).
# unshare -m
# time mount --rbind / /mnt/a
real 0m0.005s
user 0m0.003s
sys 0m0.002s
# time mount --make-rprivate /mnt/a
real 0m0.005s
user 0m0.003s
sys 0m0.002s
# systemctl show --property CPUUsageNSec init.scope; time umount -R /mnt/a ; systemctl show --property CPUUsageNSec init.scope
CPUUsageNSec=3637792026
real 0m0.381s
user 0m0.026s
sys 0m0.018s
CPUUsageNSec=3645973005
# echo $((3645973005-3637792026))
8180979
A CPU não parece ser relevante neste caso. Eu tenho 4 núcleos de cpu capazes de rodar a 2.3Ghz, mas perf stat -a
mostra menos de 5% de uso de cpu no geral. (Ignore "CPUs utilizadas, acho que sempre mostra o valor total quando -a
é usado).
# time perf stat -a umount -R /mnt/a
Performance counter stats for 'system wide':
2079.333650 cpu-clock (msec) # 3.998 CPUs utilized
635 context-switches # 0.305 K/sec
23 cpu-migrations # 0.011 K/sec
333 page-faults # 0.160 K/sec
198,278,822 cycles # 0.095 GHz
138,734,277 instructions # 0.70 insn per cycle
31,401,067 branches # 15.102 M/sec
934,327 branch-misses # 2.98% of all branches
0.520083596 seconds time elapsed
real 0m0.543s
user 0m0.038s
sys 0m0.043s
No entanto, ainda há algum processo respondendo a este evento ... O umount ainda dispara 78 linhas de mensagens no log do sistema.
Feb 07 10:34:26 alan-laptop systemd[1]: proc-sys-fs-binfmt_misc.automount: Got automount request for /proc/sys/fs/binfmt_misc, triggered by 6040 (umount)
Feb 07 10:34:26 alan-laptop systemd[1]: proc-sys-fs-binfmt_misc.automount: Automount point already active?
Feb 07 10:34:26 alan-laptop systemd[1]: proc-sys-fs-binfmt_misc.automount: Got automount request for /proc/sys/fs/binfmt_misc, triggered by 6040 (umount)
Feb 07 10:34:26 alan-laptop systemd[1]: proc-sys-fs-binfmt_misc.automount: Automount point already active?
Note que findmnt
mostra que evitei criar qualquer propagação horrível recursiva, por exemplo se eu executar depois do --make-rprivate
:
findmnt -o TARGET,PROPAGATION
TARGET PROPAGATION
/ shared
├─/sys shared
│ ├─/sys/kernel/security shared
│ ├─/sys/fs/cgroup shared
│ │ ├─/sys/fs/cgroup/unified shared
│ │ ├─/sys/fs/cgroup/systemd shared
│ │ ├─/sys/fs/cgroup/net_cls,net_prio shared
│ │ ├─/sys/fs/cgroup/cpu,cpuacct shared
│ │ ├─/sys/fs/cgroup/devices shared
│ │ ├─/sys/fs/cgroup/freezer shared
│ │ ├─/sys/fs/cgroup/perf_event shared
│ │ ├─/sys/fs/cgroup/hugetlb shared
│ │ ├─/sys/fs/cgroup/memory shared
│ │ ├─/sys/fs/cgroup/blkio shared
│ │ ├─/sys/fs/cgroup/cpuset shared
│ │ └─/sys/fs/cgroup/pids shared
│ ├─/sys/fs/pstore shared
│ ├─/sys/fs/selinux shared
│ ├─/sys/kernel/debug shared
│ └─/sys/kernel/config shared
├─/proc shared
│ └─/proc/sys/fs/binfmt_misc shared
├─/dev shared
│ ├─/dev/shm shared
│ ├─/dev/pts shared
│ ├─/dev/mqueue shared
│ └─/dev/hugepages shared
├─/run shared
│ ├─/run/user/1000 shared
│ └─/run/user/42 shared
├─/usr shared
├─/tmp shared
├─/boot shared
└─/mnt/a private
└─/mnt/a private
├─/mnt/a/usr private
├─/mnt/a/sys private
│ ├─/mnt/a/sys/kernel/security private
│ ├─/mnt/a/sys/fs/cgroup private
│ │ ├─/mnt/a/sys/fs/cgroup/unified private
│ │ ├─/mnt/a/sys/fs/cgroup/systemd private
│ │ ├─/mnt/a/sys/fs/cgroup/net_cls,net_prio private
│ │ ├─/mnt/a/sys/fs/cgroup/cpu,cpuacct private
│ │ ├─/mnt/a/sys/fs/cgroup/devices private
│ │ ├─/mnt/a/sys/fs/cgroup/freezer private
│ │ ├─/mnt/a/sys/fs/cgroup/perf_event private
│ │ ├─/mnt/a/sys/fs/cgroup/hugetlb private
│ │ ├─/mnt/a/sys/fs/cgroup/memory private
│ │ ├─/mnt/a/sys/fs/cgroup/blkio private
│ │ ├─/mnt/a/sys/fs/cgroup/cpuset private
│ │ └─/mnt/a/sys/fs/cgroup/pids private
│ ├─/mnt/a/sys/fs/pstore private
│ ├─/mnt/a/sys/kernel/config private
│ ├─/mnt/a/sys/fs/selinux private
│ └─/mnt/a/sys/kernel/debug private
├─/mnt/a/dev private
│ ├─/mnt/a/dev/shm private
│ ├─/mnt/a/dev/pts private
│ ├─/mnt/a/dev/mqueue private
│ └─/mnt/a/dev/hugepages private
├─/mnt/a/run private
│ ├─/mnt/a/run/user/1000 private
│ └─/mnt/a/run/user/42 private
├─/mnt/a/proc private
│ └─/mnt/a/proc/sys/fs/binfmt_misc private
├─/mnt/a/tmp private
├─/mnt/a/boot private
└─/mnt/a/mnt/a private