① linux 性能優化-- cpu 切換以及cpu過高
本文先介紹了cpu上下文切換的基礎知識,以及上下文切換的類型(進程,線程等切換)。然後介紹了如何查看cpu切換次數的工具和指標的解釋。同時對日常分析種cpu過高的情況下如何分析和定位的方法做了一定的介紹,使用一個簡單的案例進行分析,先用top,pidstat等工具找出佔用過高的進程id,然後通過分析到底是用戶態cpu過高,還是內核態cpu過高,並用perf 定位到具體的調用函數。(來自極客時間課程學習筆記)
1、多任務競爭CPU,cpu變換任務的時候進行CPU上下文切換(context switch)。CPU執行任務有4種方式:進程、線程、或者硬體通過觸發信號導致中斷的調用。
2、當切換任務的時候,需要記錄任務當前的狀態和獲取下一任務的信息和地址(指針),這就是上下文的內容。因此,上下文是指某一時間點CPU寄存器(CPU register)和程序計數器(PC)的內容, 廣義上還包括內存中進程的虛擬地址映射信息.
3、上下文切換的過程:
4、根據任務的執行形式,相應的下上文切換,有進程上下文切換、線程上下文切換、以及中斷上下文切換三類。
5、進程和線程的區別:
進程是資源分配和執行的基本單位;線程是任務調度和運行的基本單位。線程沒有資源,進程給指針提供虛擬內存、棧、變數等共享資源,而線程可以共享進程的資源。
6、進程上下文切換:是指從一個進程切換到另一個進程。
(1)進程運行態為內核運行態和進程運行態。內核空間態資源包括內核的堆棧、寄存器等;用戶空間態資源包括虛擬內存、棧、變數、正文、數據等
(2)系統調用(軟中斷)在內核態完成的,需要進行2次CPU上下文切換(用戶空間-->內核空間-->用戶空間),不涉及用戶態資源,也不會切換進程。
(3)進程是由內核來管理和調度的,進程的切換只能發生在內核態。所以,進程的上下文不僅包括了用戶空間的資源,也包括內核空間資源。
(4)進程的上下文切換過程:
(5)、下列將會觸發進程上下文切換的場景:
7、線程上下文切換:
8、中斷上下文切換
快速響應硬體的事件,中斷處理會打斷進程的正常調度和執行。同一CPU內,硬體中斷優先順序高於進程。切換過程類似於系統調用的時候,不涉及到用戶運行態資源。但大量的中斷上下文切換同樣可能引發性能問題。
重點關注信息:
系統的就緒隊列過長,也就是正在運行和等待 CPU 的進程數過多,導致了大量的上下文切換,而上下文切換又導致了系統 CPU 的佔用率升高。
這個結果中有兩列內容是我們的重點關注對象。一個是 cswch ,表示每秒自願上下文切換(voluntary context switches)的次數,另一個則是 nvcswch ,表示每秒非自願上下文切換(non voluntary context switches)的次數。
linux的中斷使用情況可以從 /proc/interrupts 這個只讀文件中讀取。/proc 實際上是 Linux 的一個虛擬文件系統,用於內核空間與用戶空間之間的通信。/proc/interrupts 就是這種通信機制的一部分,提供了一個只讀的中斷使用情況。
重調度中斷(RES),這個中斷類型表示,喚醒空閑狀態的 CPU 來調度新的任務運行。這是多處理器系統(SMP)中,調度器用來分散任務到不同 CPU 的機制,通常也被稱為處理器間中斷(Inter-Processor Interrupts,IPI)。
這個數值其實取決於系統本身的 CPU 性能。如果系統的上下文切換次數比較穩定,那麼從數百到一萬以內,都應該算是正常的。但當上下文切換次數超過一萬次,或者切換次數出現數量級的增長時,就很可能已經出現了性能問題。這時,需要根據上下文切換的類型,再做具體分析。
比方說:
首先通過uptime查看系統負載,然後使用mpstat結合pidstat來初步判斷到底是cpu計算量大還是進程爭搶過大或者是io過多,接著使用vmstat分析切換次數,以及切換類型,來進一步判斷到底是io過多導致問題還是進程爭搶激烈導致問題。
CPU 使用率相關的重要指標:
性能分析工具給出的都是間隔一段時間的平均 CPU 使用率,所以要注意間隔時間的設置,特別是用多個工具對比分析時,你一定要保證它們用的是相同的間隔時間。比如,對比一下 top 和 ps 這兩個工具報告的 CPU 使用率,默認的結果很可能不一樣,因為 top 默認使用 3 秒時間間隔,而 ps 使用的卻是進程的整個生命周期。
top 和 ps 是最常用的性能分析工具:
這個輸出結果中,第三行 %Cpu 就是系統的 CPU 使用率,top 默認顯示的是所有 CPU 的平均值,這個時候你只需要按下數字 1 ,就可以切換到每個 CPU 的使用率了。繼續往下看,空白行之後是進程的實時信息,每個進程都有一個 %CPU 列,表示進程的 CPU 使用率。它是用戶態和內核態 CPU 使用率的總和,包括進程用戶空間使用的 CPU、通過系統調用執行的內核空間 CPU 、以及在就緒隊列等待運行的 CPU。在虛擬化環境中,它還包括了運行虛擬機佔用的 CPU。
預先安裝 stress 和 sysstat 包,如 apt install stress sysstat。
stress 是一個 Linux 系統壓力測試工具,這里我們用作異常進程模擬平均負載升高的場景。而 sysstat 包含了常用的 Linux 性能工具,用來監控和分析系統的性能。我們的案例會用到這個包的兩個命令 mpstat 和 pidstat。
下面的 pidstat 命令,就間隔 1 秒展示了進程的 5 組 CPU 使用率,
包括:
perf 是 Linux 2.6.31 以後內置的性能分析工具。它以性能事件采樣為基礎,不僅可以分析系統的各種事件和內核性能,還可以用來分析指定應用程序的性能問題。
第一種常見用法是 perf top,類似於 top,它能夠實時顯示佔用 CPU 時鍾最多的函數或者指令,因此可以用來查找熱點函數,使用界面如下所示:
輸出結果中,第一行包含三個數據,分別是采樣數(Samples)如2K、事件類型(event)如cpu-clock:pppH和事件總數量(Event count)如:371909314。
第二種常見用法,也就是 perf record 和 perf report。 perf top 雖然實時展示了系統的性能信息,但它的缺點是並不保存數據,也就無法用於離線或者後續的分析。而 perf record 則提供了保存數據的功能,保存後的數據,需要你用 perf report 解析展示。
1.啟動docker 運行進程:
2.ab工具測試伺服器性能
ab(apache bench)是一個常用的 HTTP 服務性能測試工具,這里用來模擬 Ngnix 的客戶端。
3.分析過程
CPU 使用率是最直觀和最常用的系統性能指標,在排查性能問題時,通常會關注的第一個指標。所以更要熟悉它的含義,尤其要弄清楚:
這幾種不同 CPU 的使用率。比如說:
碰到 CPU 使用率升高的問題,你可以藉助 top、pidstat 等工具,確認引發 CPU 性能問題的來源;再使用 perf 等工具,排查出引起性能問題的具體函數.
② linux運維常用命令
| 線上查詢及幫助命令 |
man:全稱為manual,用於查看系統中自帶的各種參考手冊;
help:用於顯示shell內部命令的幫助信息;
| 文件和目錄操作命令 |
ls:全拼list,列出目錄的內容及其內容屬性信息;
cd:全拼change directory,切換當前工作目錄至dirName(目錄參數);
cp:全稱,復制文件或目錄;
find:用於在指定目錄及目錄下查找文件;
mkdir:全拼make directories,創建目錄;
mv:全拼move,移動或重命名文件;
pwd:全拼print working directory,顯示當前工作目錄的絕對路徑;
rename:可用字元串替換的方式批量改變文件名;
rm:全拼remove,刪除一個或多個文件或目錄。必須格外小心地使用該命令;
rmdir:全拼remove empty directories,刪除空目錄;
touch:修改文件或者目錄的時間屬性,包括存取時間和更改時間。若文件不存在,系統會建立一個新的文件;
| 查看文件及內容處理命令 |
cat:全拼concatenate,用於連接多個文件並且列印到屏幕輸出或重定向到指定文件中,可查看文件內容;
tac:cat的反向拼寫,因此命令的功能為反向顯示文件內容。文件內容的最後一行先顯示,第一行最後顯示;
less:可以隨意瀏覽文件,而more僅能向前移動,卻不能向後移動,而且less在查看之前不會載入整個文件;
head:顯示文件的開頭的內容。在默認情況下,head命令顯示文件的頭10行內容;
tail:查看文件尾部內容,有一個常用的參數-f常用於查閱正在改變的文件。可以看到最新的文件內容;
| 文件壓縮及解壓縮命令 |
tar:tar命令是用來建立,還原備份文件的工具程序,它可以加入,解開備份文件內的文件;
unzip:用於解壓縮zip文件;
gzip:用於壓縮文件。gzip是個使用廣泛的壓縮程序,文件經它壓縮過後,其名稱後面會多出".gz"的擴展名;
zip:用來將文件壓縮成為常用的zip格式。
③ linux怎麼進入內核源碼安裝perf
這個如果源里有,就從源里安裝,不同發行版有所不同
debian/ubuntu應該是sudo apt-get install linux-headers-`uname -r`
④ 查看linux電腦gpu的參數
1、Linux查看顯卡信息:
lspci | grep -i vga
2、使用nvidia GPU可以:
lspci | grep -i nvidia
表頭釋義:
Fan:顯示風扇轉速,數值在0到100%之間,是計算機的期望轉速,如果計算機不是通過風扇冷卻或者風扇壞了,顯示出來就是N/A;
Temp:顯卡內部的溫度,單位是攝氏度;
Perf:表徵性能狀態,從P0到P12,P0表示最大性能,P12表示狀態最小性能;
Pwr:能耗表示;
Bus-Id:涉及GPU匯流排的相關信息;
Disp.A:是Display Active的意思,表示GPU的顯示是否初始化;
Memory Usage:顯存的使用率;
Volatile GPU-Util:浮動的GPU利用率;
Compute M:計算模式;
下邊的Processes顯示每塊GPU上每個進程所使用的顯存情況。
如果要周期性的輸出顯卡的使用情況,可以用watch指令實現:
watch -n 10 nvidia-smi
命令行參數-n後邊跟的是執行命令的周期,以s為單位。
⑤ 如何編譯linux的 perf
perf的代碼是linux kernel代碼的一部分, 在./tools/perf/目錄下面。linux kernel代碼可以從官網下載
希望能幫到你
⑥ 如何在Linux用戶和內核空間中進行動態跟蹤
你不記得如何在代碼中插入探針點了嗎? 沒問題!了解如何使用uprobe和kprobe來動態插入它們吧。 基本上,程序員需要在源代碼匯編指令的不同位置插入動態探針點。
探針點
探針點是一個調試語句,有助於探索軟體的執行特性(即,執行流程以及當探針語句執行時軟體數據結構的狀態)。printk是探針語句的最簡單形式,也是黑客用於內核攻擊的基礎工具之一。
因為它需要重新編譯源代碼,所以printk插入是靜態的探測方法。內核代碼中重要位置上還有許多其他靜態跟蹤點可以動態啟用或禁用。 Linux內核有一些框架可以幫助程序員探測內核或用戶空間應用程序,而無需重新編譯源代碼。Kprobe是在內核代碼中插入探針點的動態方法之一,並且uprobe在用戶應用程序中執行此操作。
使用uprobe跟蹤用戶空間
可以通過使用thesysfs介面或perf工具將uprobe跟蹤點插入用戶空間代碼。
使用sysfs介面插入uprobe
考慮以下簡單測試代碼,沒有列印語句,我們想在某個指令中插入探針:
[source,c\n.test.c
#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>
編譯代碼並找到要探測的指令地址:
# gcc -o test test.\n# objmp -d test
假設我們在ARM64平台上有以下目標代碼:
0000000000400620 <func_1>: 400620\t90000080\tadr\tx0, 410000 <__FRAME_END__+0xf6f8>
並且我們想在偏移量0x620和0x644之間插入探針。執行以下命令:
# echo 'p:func_2_entry test:0x620' > /sys/kernel/debug/tracing/uprobe_event\n# echo 'p:func_1_entry test:0x644' >> /sys/kernel/debug/tracing/uprobe_event\n# echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable# ./test&
在上面的第一個和第二個echo語句中,p告訴我們這是一個簡單的測試。(探測器可以是簡單的或返回的。)func_n_entry是我們在跟蹤輸出中看到的名稱,名稱是可選欄位,如果沒有提供,我們應該期待像p_test_0x644這樣的名字。test 是我們要插入探針的可執行二進制文件。如果test 不在當前目錄中,則需要指定path_to_test / test。
0x620或0x640是從程序啟動開始的指令偏移量。請注意>>在第二個echo語句中,因為我們要再添加一個探針。所以,當我們在前兩個命令中插入探針點之後,我們啟用uprobe跟蹤,當我們寫入events/ uprobes / enable時,它將啟用所有的uprobe事件。程序員還可以通過寫入在該事件目錄中創建的特定事件文件來啟用單個事件。一旦探針點被插入和啟用,每當執行探測指令時,我們可以看到一個跟蹤條目。
讀取跟蹤文件以查看輸出:
# cat /sys/kernel/debug/tracing/trac\n# tracer: no\n\n# entries-in-buffer/entries-written: 8/8\n#P:\n\n# _-----=> irqs-of\n# / _----=> need-resche\n# | / _---=> hardirq/softir\n# || / _--=> preempt-dept\n# ||| / dela\n# TASK-PID CP\n# |||| TIMESTAMP FUNCTION# | | | |||| | |
我們可以看到哪個CPU完成了什麼任務,什麼時候執行了探測指令。
返回探針也可以插入指令。當返回該指令的函數時,將記錄一個條目:
# echo 0 > /sys/kernel/debug/tracing/events/uprobes/enabl\n# echo 'r:func_2_exit test:0x620' >> /sys/kernel/debug/tracing/uprobe_event\n# echo 'r:func_1_exit test:0x644' >> /sys/kernel/debug/tracing/uprobe_event\n# echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable
這里我們使用r而不是p,所有其他參數是相同的。請注意,如果要插入新的探測點,需要禁用uprobe事件:
test-3009 [002] .... 4813.852674: func_1_entry: (0x400644)
上面的日誌表明,func_1返回到地址0x4006b0,時間戳為4813.852691。
# echo 0 > /sys/kernel/debug/tracing/events/uprobes/enabl\n# echo 'p:func_2_entry test:0x630' > /sys/kernel/debug/tracing/uprobe_events count=%x\n# echo 1 > /sys/kernel/debug/tracing/events/uprobes/enabl\n# echo > /sys/kernel/debug/tracing/trace# ./test&
當執行偏移量0x630的指令時,將列印ARM64 x1寄存器的值作為count =。
輸出如下所示:
test-3095 [003] .... 7918.629728: func_2_entry: (0x400630) count=0x1
使用perf插入uprobe
找到需要插入探針的指令或功能的偏移量很麻煩,而且需要知道分配給局部變數的CPU寄存器的名稱更為復雜。 perf是一個有用的工具,用於幫助引導探針插入源代碼中。
除了perf,還有一些其他工具,如SystemTap,DTrace和LTTng,可用於內核和用戶空間跟蹤;然而,perf與內核配合完美,所以它受到內核程序員的青睞。
# gcc -g -o test test.c# perf probe -x ./test func_2_entry=func_\n# perf probe -x ./test func_2_exit=func_2%retur\n# perf probe -x ./test test_15=test.c:1\n# perf probe -x ./test test_25=test.c:25 numbe\n# perf record -e probe_test:func_2_entry -e\nprobe_test:func_2_exit -e probe_test:test_15\n-e probe_test:test_25 ./test
如上所示,程序員可以將探針點直接插入函數start和return,源文件的特定行號等。可以獲取列印的局部變數,並擁有許多其他選項,例如調用函數的所有實例。 perf探針用於創建探針點事件,那麼在執行./testexecutable時,可以使用perf記錄來探測這些事件。當創建一個perf探測點時,可以使用其他錄音選項,例如perf stat,可以擁有許多後期分析選項,如perf腳本或perf報告。
使用perf腳本,上面的例子輸出如下:
# perf script
使用kprobe跟蹤內核空間
與uprobe一樣,可以使用sysfs介面或perf工具將kprobe跟蹤點插入到內核代碼中。
使用sysfs介面插入kprobe
程序員可以在/proc/kallsyms中的大多數符號中插入kprobe;其他符號已被列入內核的黑名單。還有一些與kprobe插入不兼容的符號,比如kprobe_events文件中的kprobe插入將導致寫入錯誤。 也可以在符號基礎的某個偏移處插入探針,像uprobe一樣,可以使用kretprobe跟蹤函數的返回,局部變數的值也可以列印在跟蹤輸出中。
以下是如何做:
; disable all events, just to insure that we see only kprobe output in trace\n# echo 0 > /sys/kernel/debug/tracing/events/enable; disable kprobe events until probe points are inseted\n# echo 0 > /sys/kernel/debug/tracing/events/kprobes/enable; clear out all the events from kprobe_events\n to insure that we see output for; only those for which we have enabled
[root@pratyush ~\n# more /sys/kernel/debug/tracing/trace# tracer: no\n\n# entries-in-buffer/entries-written: 9037/9037\n#P:8\n# _-----=> irqs-of\n# / _----=> need-resche\n# | / _---=> hardirq/softirq#\n|| / _--=> preempt-depth#\n ||| / delay# TASK-PID CPU#\n |||| TIMESTAMP FUNCTION#\n | | | |||| | |
使用perf插入kprobe
與uprobe一樣,程序員可以使用perf在內核代碼中插入一個kprobe,可以直接將探針點插入到函數start和return中,源文件的特定行號等。程序員可以向-k選項提供vmlinux,也可以為-s選項提供內核源代碼路徑:
# perf probe -k vmlinux kfree_entry=kfre\n# perf probe -k vmlinux kfree_exit=kfree%retur\n# perf probe -s ./ kfree_mid=mm/slub.c:3408 \n# perf record -e probe:kfree_entry -e probe:kfree_exit -e probe:kfree_mid sleep 10
使用perf腳本,以上示例的輸出:
關於Linux命令的介紹,看看《linux就該這么學》,具體關於這一章地址3w(dot)linuxprobe/chapter-02(dot)html