Linux -- 進程或線程獨占CPU


如果想讓特定進程或線程獨占某一或某些CPU,我們需要做三件事.

一,隔離CPU,避免其它線程run在被隔離的CPU上.

二,綁定所有的interrupts到非隔離的CPU上,避免被隔離的CPU收到interrupt.

三,據你希望地,把特定的線程綁定到某一被隔離的CPU上.

1.CPU isolation

如果想讓特定進程或線程獨占某一或某些CPU,我們需要避免其它進程運行在該CPU上.因此,我們所做的第一步是CPU隔離.

CPU隔離的方法:

修改Linux內核的啟動參數isolcpus. isolcpus將從線程調度器中移除選定的CPU,這些被移除的CPU稱為"isolated" CPU. 若想要在被隔離的CPU上run進程,必須調用CPU親和度相關的syscalls.

具體的修改方法是在/ boot/grub/grub.conf的kernel列最末尾加上isolcpus=x,y,… (代表將CPUx CPUy隔離)

隔離CPU還有一些其它方法,但是這種方法是首選方法,也是redhat的推薦方法.

另一方法利用了CPU親和性的繼承性,即子進程會繼承父進程的CPU親和性.由於所有進程都是init的子進程,我們可以設置init的CPU親和性,這樣一來,所有的進程都具有了與init相同的CPU親和性.然后我們可以更改我們需要的進程的CPU親和性來達到獨占.

2.Interrupt request(IRQ)

被隔離的CPU雖然沒有線程run在上面,但是仍會收到interrupt.

Interrupt request是硬件級別的服務請求.詳情見附錄,此處不表.我們需要知道的是IRQ有一個親和度屬性smp_affinity. smp_affinity決定允許哪些CPU核心處理IRQ.

在redhat(其它發行版未知)中,某一特定IRQ的親和度值儲存在/proc/irq/IRP_NUMBER/smp_affinity文件中.此文件僅ROOT用戶可見.儲存的值是一個十六進制位掩碼(hexadecimal bit-mask),代表着系統的所有CPU核心.

命令cat /proc/interrupts可以看到所有設備的interrupts信息,第一列即為IRP_NUMBER.

命令cat /proc/irq/32/smp_affinity可以看到IRQ號為32的親和度.默認值為f,代表這個IRP能被所有CPU接受處理.

命令echo 1 >/proc/irq/32/smp_affinity把IRQ號為32的親和度值設為1,代表這個IRP僅能被CPU0接受處理

照此,我們可以據要求任意綁定IRQ到CPU

雖然我們已經做了很大努力,但是仍有一部分中斷沒有被綁定,例如: Single function call interrupts, Local timer interrupts等等

3.綁定進程到CPU

在以上兩步,我們摒除了一部分外界的干擾.最后一步,我們要綁定進程到隔離的CPU上.

首先我們要了解CPU親和性這個概念.

CPU親和性就是進程在某個給定的CPU上盡量長時間的運行而不被遷移到其它處理器的傾向性.Linux內核進程調度器天生就具有”軟CPU親和性”,這意味着進程通常不會在處理器之間頻繁遷移.

2.6+的Linux內核還包含一種機制.它讓開發人員可以編程實現”硬CPU親和性”.這意味着應用程序可以顯示地指定在哪個處理器上運行.

我們所說的綁定進程到CPU就是實現硬CPU親和性.

代碼級別的親和度設定:

int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask);

設定某個進程的CPU親和度

例碼見: http://man7.org/linux/man-pages/man2/sched_setaffinity.2.html

int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);

設定某個線程的CPU親和度

例碼見: http://man7.org/linux/man-pages/man3/pthread_setaffinity_np.3.html

以上兩者都使用到

CPU宏:

http://man7.org/linux/man-pages/man3/CPU_SET.3.html

void CPU_ZERO(cpu_set_t *set)   //初始化CPU集
void CPU_SET(int cpu,cpu_set_t *set)  //向CPU集中添加某個CPU
void CPU_CLR(int cpu,cpu_set_t *set)  //從CPU集中移除某個CPU
int CPU_ISSET(int cou,cpu_set_t *set)  //檢查CPU集中是否存在某個CPU
int CPU_COUNT(cpu_set_t *set)          //返回CPU集中CPU的個數
使用taskset指定CPU親和性:

運行時指定:

命令taskset –c 0,2,3 simulotion.x 代表在CPU0,CPU2,CPU3上運行名為simulation.x的程序

運行后指定:

命令 taskset –p –c 0,2 7013 代表綁定pid為7013的進程到CPU0,CPU2上

Numatcl程序也有類似taskset的功能,此處不表

 

附錄:

1.https://stackoverflow.com/questions/13583146/whole-one-core-dedicated-to-single-process

2.CPU isolation:
https://access.redhat.com/solutions/15482

3.IRQ: https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/s-cpu-irq.html

4.Processor Affinity Bitmask
https://www.intervalzero.com/library/RTX/WebHelp/Content/PROJECTS/Application Development/UsingFunctionality/Specifying_a_Processor_Affinity_Bitmask.htm

這是一個32位的二進制串.最低位代表CPU0,最高位代表CPU31(如果有的話)

5.taskset:
http://www.glennklockwood.com/hpc-howtos/process-affinity.html#2-2-round-robin-scheduling

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM