CPU 使用率 1% 的進程導致平均負載為 1.5

CPU 使用率 1% 的進程導致平均負載為 1.5

我們最近觀察到我們的嵌入式系統上的平均負載約為 1.5,儘管幾乎所有進程都應該處於休眠狀態(根據htop)。

該系統是一個雙核心 Cortex-A9,運行使用 buildroot 建構的即時 Linux 核心 (4.14.126)。我們使用 initramfs 作為根檔案系統,並且沒有交換,所以肯定有無磁碟 I/O在正常操作期間。

經過一番挖掘,我們發現負載是由一個名為的程式引起的更新,它為我們提供了一個方便的軟體更新網路介面(我們非常希望繼續使用它)。

當我用來time估計該應用程式的平均 cpu 使用率時(透過計算(使用者+系統)/真實),我得到的值只有 1% 左右,考慮到 1.5 的平均負載,這沒有多大意義。

我知道平均負載還包括處於該TASK_UNINTERRUPTIBLE狀態的進程,這些進程不會影響 CPU 使用率。我不明白的是為什麼該應用程式的任何線程/進程都會處於該狀態。

為了進一步分析情況,我使用捕獲了內核跟踪LTNG,這表明 swupdate 所做的唯一事情是(每 50 毫秒): 在此輸入影像描述

這個(每 100 毫秒): 在此輸入影像描述

正如你所看到的,有一些看起來是基於套接字的 IPC,並且有一個 select 正在等待某物。在 IPC 情況下,一個線程似乎主要阻塞 in nanosleep(),而另一個線程阻塞 in accept(),據我所知,這兩個線程都不應該消耗任何系統資源。

僅供參考:兩張螢幕截圖的時基相同,IPC 大約需要 1 分鐘。總共 500-600μs(考慮到 50ms 的間隔,與觀察到的 1% CPU 使用率非常吻合)

那麼,是什麼導致了這裡的負載呢?

答案1

由於狀態 R 和 D 中的任務都會增加 Linux 負載,因此您可以對系統中處於這兩種狀態之一的所有執行緒進行取樣。例如:

for x in {1..100} ; do ps -aeos,user,comm,wchan | grep "^[RD]" ; sleep 0.1 ; done | sort | uniq -c | sort -nbr | head -20

下面的範例輸出,您需要忽略顯示您自己的ps進程始終處於活動狀態的第一行 - 因為它是執行所有取樣的進程:

# for x in {1..100} ; do
>   ps -aeos,user,comm,wchan | grep "^[RD]"
>   sleep 0.1
> done | sort | uniq -c | sort -nbr | head -20

    100 R root     ps              -
      3 R oracle   oracle_14047_li -
      2 R root     rcu_sched       rcu_gp_kthread
      2 R root     rcu_sched       -
      2 R root     kworker/1:2-eve -
      2 R oracle   perl            -
      2 R oracle   ora_vktm_lin19c hrtimer_nanosleep
      2 D root     md10_raid10     md_super_wait
      2 D oracle   ora_ckpt_linprd md_write_start
      1 R redis    redis-server    -
      1 R oracle   ora_vktm_linprd hrtimer_nanosleep
      1 R oracle   ora_m001_linprd -
      1 D root     xfsaild/dm-18   rq_qos_wait
      1 D oracle   ora_mz00_lin19c x64_sys_io_destroy
      1 D oracle   ora_lg00_lin19c inode_dio_wait
      1 D oracle   ora_dbrm_lin19c msleep

除非您在舊核心上運行,否則您應該以 root 身份運行它,因為新核心會屏蔽其他使用者進程的 WCHAN 值。

您可以比這更深入(但不能使用 ps),您也可以採樣/proc/PID/syscall/proc/PID/stack獲取系統呼叫和內核堆疊追蹤資訊。我為此編寫了一個名為 Linux Process Snapper ( psn) 的工具,因此您可以對此類效能問題進行相當高階的深入分析,而無需求助於核心追蹤:

[tanel@linux01 ~]$ sudo psn -G syscall,wchan

Linux Process Snapper v0.18 by Tanel Poder [https://0x.tools]
Sampling /proc/syscall, stat, wchan for 5 seconds... finished.


=== Active Threads ==========================================================================================

 samples | avg_threads | comm             | state                  | syscall         | wchan                 
-------------------------------------------------------------------------------------------------------------
     511 |      255.50 | (kworker/*:*)    | Disk (Uninterruptible) | [kernel_thread] | blkdev_issue_flush 
     506 |      253.00 | (oracle_*_l)     | Disk (Uninterruptible) | pread64         | do_blockdev_direct_IO 
      28 |       14.00 | (oracle_*_l)     | Running (ON CPU)       | [running]       | 0                     
       1 |        0.50 | (collectl)       | Running (ON CPU)       | [running]       | 0                     
       1 |        0.50 | (mysqld)         | Running (ON CPU)       | [running]       | 0                     
       1 |        0.50 | (ora_lgwr_lin*c) | Disk (Uninterruptible) | io_submit       | inode_dio_wait        
       1 |        0.50 | (oracle_*_l)     | Disk (Uninterruptible) | pread64         | 0                     
       1 |        0.50 | (oracle_*_l)     | Running (ON CPU)       | [running]       | SYSC_semtimedop       
       1 |        0.50 | (oracle_*_l)     | Running (ON CPU)       | [running]       | read_events           
       1 |        0.50 | (oracle_*_l)     | Running (ON CPU)       | read            | 0                     
       1 |        0.50 | (oracle_*_l)     | Running (ON CPU)       | semtimedop      | SYSC_semtimedop       

您可以比這更深入,相關的部落格文章在這裡:

答案2

CPU 使用率和負載是不同的指標。事實上,負載可能高於 1。 Load表示負載:有多少進程正在運作和等待運行。

正如您可能知道的那樣(從問題的討論中),I/O 通常是此類等待之一,因此它會增加負載。但是您也可以擁有可能導致等待的信號/信號量/鎖,而這些可能只是由一個不執行 I/O 的進程引起的。例如,如果一個進程每秒喚醒一次,並且有許多進程正在等待來自該進程的數據,則會獲得更高的負載(等於等待的進程數)。

你可能將管道視為 I/O,但 mmap 和鎖...你是否將其歸類為 IO?它們不會出現在bio(區塊I/O)中,因此您可能在許多負載統計資料中看不到它們。

通常找出這一點的更簡單方法是:阻止進程並檢查它在哪裡。多次執行此操作,您應該會看到一個函數被阻塞(並且您可能會發現它比其他函數更頻繁)。

答案3

我在大約 450 MHz 的 i.mx28 上運行的嵌入式系統上遇到了同樣的問題。

htop持續顯示 50% CPU 使用率,完全是由其中一項swupdate任務引起的。

當瀏覽mongoose_interface.c您的 100 毫秒觀察時,在閱讀以下內容時觸發start_mongoose()

                mg_mgr_poll(&mgr, 100);

我實驗性地將 100 更改為 1000,重新編譯並重新啟動後,CPU 使用率下降到swupdate線程的 2% 左右,如htop.

如前所述,這是實驗性的,因為這些數字讓我覺得太巧了。我沒有調查過是否會出現任何副作用。

相關內容