這裡介紹如何在 Linux 中以特定的 CPU 核心執行程式,不要讓系統自動排程。
現在不管是伺服器或是一般個人電腦的 CPU 大部分都是多核心的架構,而各種應用軟體、編譯器與作業系統也受到這個趨勢的影響,也都會有針對多核心處理器做的最佳化設計。
通常在多核心的作業系統中常使用處理器的親和性(processor affinity,亦稱 CPU pinning)來處理需要高效能計算的應用,這個技術是屬於作業系統的一個特殊功能,它可以讓行程在特定的 CPU 核心中持續執行,不受作業系統排程的干擾。
將行程綁定在特定的 CPU 核心上有許多優點,例如一個 cache bound 的程式跟其他比較耗費 CPU 計算的程式一起執行時,將程式綁定在特定的 CPU 核心可以減少 cache miss 的狀況。另外在兩個行程頻繁的藉由 shared memory 進行溝通時,將兩個行程都綁定在同一個 NUMA 節點中也可以增進執行效率。
這裡我們會以 Linux 系統為例,介紹如何在 Linux 系統中將一般的程式綁定在一個選定的處理器核心中執行。
taskset
,透過這個指令使用者就可以設定或取得行程的處理器親和性。
taskset
在 Linux 中 taskset
是屬於 util-linux
套件中的一部分,但是大部分的 Linux 發行版預設都會安裝,所以通常不需要自己動手裝。如果你的系統沒有安裝這個套件,可以按照下面的方式安裝。
Debian 系列的 Linux(Ubuntu、Linux Mint 等)可用 apt 安裝:
sudo apt-get install util-linux
Red Hat 系列的 Linux(Fedora、CentOS 等),則可使用 yum:
sudo yum install util-linux
若要查看指定行程的處理器親和性,可以使用 taskset
加上 -p
參數再加上行程的 ID(process ID):
taskset -p PID
其中 PID
就是行程的 ID,例如:
taskset -p 2915
輸出為:
pid 2915's current affinity mask: ff
輸出的 affinity mask 是一個十六進位的 bitmask,將其轉換為二進位格式之後,若位元值為 1 則代表該行程可以在這個位元對應的 CPU 核心中執行,若位元值為 0 則代表該行程不允許在這個位元對應的 CPU 核心中執行。
在上面這個例子中十六進位的 ff
轉成二進位的格式會是 11111111
,這八個 1
分別代表該行程可以在第 0 到第 7 個 CPU 核心中執行,最低(最右邊)的位元代表第 0 個 CPU 核心,次低的代表第 1 個,以次類推。
如果 affinity mask 是一個 0x11
,則代表可在第 0 個與第 4 個 CPU 核心執行。
如果感覺以 bitmask 表示法不容易理解,可以加上 -c
參數,讓 taskset
直接輸出 CPU 的核心列表:
taskset -cp 2915
輸出為:
pid 2915's current affinity list: 0-7
taskset
亦可設定行程的 core mask,將指定的行程固定在特定的 CPU 核心中執行:
taskset -p COREMASK PID
其中 COREMASK
就是指定的十六進位 core mask,PID
則為行程的 ID。除此之外,亦可使用 -c
參數以 CPU 的核心列表來指定:
taskset -cp CORELIST PID
其中 CORELIST
為 CPU 核心列表,以逗點分個各個核心的編號或是使用連字號指定連續的區間,例如:0,2,5,7-10
。
例如若要將一個行程固定在第 0 個與第 4 個 CPU 核心,則使用:
taskset -p 0x11 9030
輸出為:
pid 9030's current affinity mask: ff pid 9030's new affinity mask: 11
亦可使用 CPU 核心列表的方式:
taskset -cp 0,4 9030
兩種方式都是一樣的。
在 Linux 中的使用者必須有開啟 CAP_SYS_NICE 這個權限,才能更動行程的處理器親和性,而若只是要查看處理器親和性的設定,則沒有限制(任何使用者皆可查詢)。
除了更改現有行程的處理器親和性,使用者也可以使用 taskset
指定 CPU 核心來執行一個新的程式:
taskset COREMASK EXECUTABLE
其中 EXECUTABLE
是要執行的程式。
例如若要以第 0 個 CPU 核心執行 vlc
則使用:
taskset 0x1 vlc
taskset
可以指定行程所使用的 CPU 核心,但是不代表其他的行程不會使用這些被指定的 CPU 核心,如果你想讓其他的行程干擾你要執行的程式,讓指定的核心只能被自己設定的行程使用,可以使用 isolcpus
這個 Linux 核心(kernel)參數,這個參數可以讓特定的 CPU 核心在開機時就被保留下來。
設定的方式有兩種,一個是在開機時使用 boot loader 所提供的自訂開機參數功能,手動加入 isolcpus=cpu_id
參數,或是直接加在 GRUB 的設定檔中,這樣 Linux 的排程器(scheduler)在預設的狀況下就不會將任何一般行程放在這個被保留的 CPU 核心中執行,只有那些被 taskset
特別指定的行程可以使用這些 CPU 核心。
舉例來說,如果想讓第 0 個與第 1 個 CPU 核心都被保留下來,則在開機時加入
isolcpus=0,1
這個 Linux 核心參數,然後再使用 taskset
指令將這兩個 CPU 核心指定給要執行的程式使用即可。
參考資料:Xmodulo