綁定掛載上的 umount -R
花費了不可忽略的時間,為什麼?
為什麼
umount -R
需要 0.2 秒來解除安裝綁定掛載的子樹?掛載子樹只用了 0.02 秒,更改其傳播標誌只用了 0.00 秒。(我正在考慮將目前的安裝集複製到一個子目錄,更改它們,然後使用 切換到它們
pivot_mount
。但是我觀察到的延遲對於這個目的來說實際上是不可接受的)。本練習假定
/
子掛載是共享掛載。Linux 預設情況下不會這樣做,但systemd 會這樣做。# 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 ...
因此,除了指出最後一個操作需要 34 個單獨
umount2()
的呼叫之外,它並不是超級有啟發性,而其他兩個都只包含一個呼叫mount()
,使用 MS_REC(遞歸)標誌。與 的標題數字一樣time
,這是掛鐘時間。strace -c
顯示系統時間(即在核心中花費的cpu時間),總共只有0.009s。儘管它確實指出了一些有趣的事情。改為使用
umount -l /mnt/a
,將總時間減少到 0.02 秒。這使用單個umount2()
呼叫來分離子樹/mnt/a
(並在後台進行任何清理)。用 看個呼
strace -ttt -T -e trace=umount2 umount -R /mnt/a
,個呼的次數分佈比較均勻;它們的範圍從 0.002s 到 0.012s,但沒有明確的模式,如果我重複它,模式看起來並不一致。在下執行後,
umount -R
在perf record -a
、和perf report
中顯示了幾個熱點。這個過程根本沒有出現。這可以解釋為什麼顯示在核心或使用者空間中花費的 CPU 時間可以忽略不計。gsd-housekeeping``gvfs-udisks2-volume-monitor``systemd``umount``time``umount
(如果有人在測試期間有更全面的方法來匯總每個程序的 cpu 使用情況,我會非常感興趣:)。
其他程序可能正在做一些處理以響應每個掛載事件。
例如,systemd 似乎負責使用我的四個 cpu 之一的 0.13s,在執行過程中需要 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
但這似乎不是正確的解釋,因為在私有掛載命名空間中執行時會發生相同的延遲。在這種情況下,
perf record -a
不顯示其他程序,只顯示umount
程序(和 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
在這種情況下,cpu 似乎無關緊要。我有 4 個能夠以 2.3Ghz 執行的 CPU 核心,但
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
因此,您認為
umount
花費時間等待某事(因為它在user
或中花費了很少的 cpu 時間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()
infs/namespace.c
是某種形式的全域同步,其中包括synchronize_rcu()
. 它一直等到所有“目前正在執行的 RCU 讀取端臨界區都已完成”。“RCU 寬限期延長數毫秒……這種情況是 RCU 用於以讀取為主的情況的經驗法則的主要原因”。我想掛載名稱空間被認為是“主要閱讀”。看起來這“幾毫秒”在 34 次呼叫中的平均等待時間為 5 毫秒
umount2()
。