umount -R
바인드 마운트된 하위 트리를 마운트 해제하는 데 0.2초가 걸리는 이유는 무엇입니까 ? 하위 트리를 마운트하는 데는 0.02초, 전파 플래그를 변경하는 데는 0.00초밖에 걸리지 않습니다.
(현재 설치 세트를 하위 디렉토리에 복제하고 변경한 다음 스위치를 사용하여 해당 디렉토리로 전환하려고 합니다 pivot_mount
. 그러나 제가 관찰한 대기 시간은 실제로 이 목적으로는 용납할 수 없습니다.)
이 연습에서는 /
하위 마운트가 공유 마운트라고 가정합니다. Linux는 기본적으로 이 작업을 수행하지 않지만체계하다.
# 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
추가 테스트
strace -cw
쇼에서 실행
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
90.44 0.180113 5297 34 umount2
...
umount2()
따라서 마지막 작업에는 34개의 개별 호출이 필요했지만 다른 작업은 MS_REC(재귀) 플래그를 사용하는 쌍에 대한 한 번의 호출로만 구성되었다는 점을 지적하는 것 외에는 mount()
그다지 이해하기 어렵습니다 . 헤더 데이터와 마찬가지로 time
이제는 벽시계 시간입니다. strace -c
시스템 시간(즉, 커널이 소비한 CPU 시간)을 표시하면 총 0.009초에 불과합니다.
그래도 몇 가지 흥미로운 점을 지적합니다. 대신 사용하면 umount -l /mnt/a
총 시간이 0.02초로 줄어듭니다. 이는 단일 umount2()
호출을 사용하여 하위 트리를 분리 /mnt/a
하고 백그라운드에서 정리를 수행합니다.
단일 호출을 보면 strace -ttt -T -e trace=umount2 umount -R /mnt/a
단일 호출 수는 0.002초에서 0.012초 사이로 상대적으로 고르게 분포되어 있지만 뚜렷한 패턴이 없으며 반복하면 패턴이 일관되지 않은 것처럼 보입니다.
umount -R
실행 후 perf record -a
, 및 에 여러 핫스팟 perf report
이 표시됩니다 . 그 과정이 전혀 나오지 않습니다. 이는 커널이나 사용자 공간에서 소요되는 CPU 시간이 무시할 수 있는 이유를 설명할 수 있습니다 .gsd-housekeeping
gvfs-udisks2-volume-monitor
systemd
umount
time
umount
(테스트 중에 각 프로세스의 CPU 사용량을 집계하는 보다 포괄적인 방법이 있는 사람이 있다면 매우 흥미로울 것입니다.)
다른 프로세스는 각 설치 이벤트에 대한 응답으로 일부 처리를 수행할 수 있습니다.
예를 들어, 0.4초가 걸린 실행에서 systemd는 내 CPU 4개 중 하나를 사용하여 0.13초를 담당하는 것처럼 보였습니다.
# 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
그러나 이는 프라이빗 마운트 네임스페이스에서 실행할 때 동일한 지연이 발생하므로 올바른 설명이 아닌 것 같습니다. 이 경우 perf record -a
다른 프로세스는 표시되지 않고 umount
프로세스(및 성능 자체)만 표시됩니다.
# 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
이 경우 CPU는 관련성이 없는 것 같습니다. 2.3Ghz에서 실행할 수 있는 CPU 코어가 4개 있지만 perf stat -a
전체적으로 CPU 사용량은 5% 미만입니다. ("CPU 사용은 무시하세요. -a
사용하면 항상 풀값을 보여주는 것 같아요 ).
# 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
그러나 일부 프로세스는 여전히 이 이벤트에 응답합니다. umount는 여전히 시스템 로그에 78줄 메시지를 트리거합니다.
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?
findmnt
예를 들어 다음에 이것을 실행하는 경우 끔찍한 재귀와 같은 전파가 생성되는 것을 방지 합니다 --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
답변1
따라서 무언가를 기다리는 데 시간을 소비한다고 생각합니다 umount
(CPU 시간이 매우 적게 걸리거나 나가기 때문입니다 user
) sys
. 왜 기다리고 있는지 알아봅시다...
# perf trace -g -e sched:* umount2 -R /mnt/a
perf record
여러 스케줄러 추적 지점이 표시되었으며 가장 눈에 띄는 것은 입니다 sched:sched_switch
.
Samples: 21 of event 'sched:sched_switch', Event count (approx.): 21
Children Self Trace output ▒
- 100.00% 100.00% umount:1888 [120] D ==> swapper/3:0 [120] ▒
0 ▒
__umount2 ▒
entry_SYSCALL_64_fastpath ▒
sys_umount ▒
do_umount ▒
namespace_unlock ▒
synchronize_sched ▒
__wait_rcu_gp ▒
wait_for_completion ▒
schedule_timeout ▒
schedule ▒
__schedule ▒
__schedule
__wait_rcu_gp()
RCU 유예 기간을 나타냅니다. namespace_unlock()
in은 fs/namespace.c
다음을 포함하는 일종의 전역 동기화입니다 synchronize_rcu()
.모두"현재 실행의 RCU 읽기 측의 중요한 부분이 완료되었습니다." "RCU 유예 기간이 몇 밀리초 연장되었습니다... 이러한 상황은 경험상 읽기 지향 상황에서 RCU를 사용하는 주된 이유입니다." 네임스페이스를 마운트하는 것은 "기본 읽기"로 간주됩니다.
이 "몇 밀리초"는 34개 호출 각각에 대해 5밀리초의 평균 대기 시간을 차지하는 것으로 보입니다 umount2()
.