CPU 綁定技術(shù)

全文轉(zhuǎn)載自 CPU綁定技術(shù),侵刪。

概念

什么是CPU Affinity?Affinity 是進(jìn)程的一個(gè)屬性,這個(gè)屬性指明了進(jìn)程調(diào)度器能夠把這個(gè)進(jìn)程調(diào)度到哪些CPU上。
在Linux中,我們可以利用 CPU affinity 把一個(gè)或多個(gè)進(jìn)程綁定到一個(gè)或多個(gè)CPU上。CPU Affinity分為2種:

  • soft affinity 僅是一個(gè)建議,如果不可避免,調(diào)度器還是會把進(jìn)程調(diào)度到其它的CPU上。
  • hard affinity 是調(diào)度器必須遵守的規(guī)則。

為什么需要CPU綁定

  • 增加CPU緩存的命中率
    CPU之間是不共享緩存的,如果進(jìn)程頻繁的在各個(gè) CPU 間進(jìn)行切換,需要不斷的使舊 CPU 的 cache 失效。如果進(jìn)程只在某個(gè)CPU上執(zhí)行,則不會出現(xiàn)失效的情況。

  • 適合time-sensitive應(yīng)用
    real-timetime-sensitive應(yīng)用中,我們可以把系統(tǒng)進(jìn)程綁定到某些CPU上,把應(yīng)用進(jìn)程綁定到剩余的CPU上。典型的設(shè)置是,把應(yīng)用綁定到某個(gè)CPU上,把其它所有的進(jìn)程綁定到其它的CPU上。

綁定進(jìn)程和CPU

使用taskset指令
程序內(nèi)部使用代碼
#define _GNU_SOURCE

#include <sched.h>

long sched_setaffinity(pid_t pid, unsigned int len, unsigned long *user_mask_ptr);

long sched_getaffinity(pid_t pid, unsigned int len, unsigned long *user_mask_ptr);

從函數(shù)名以及參數(shù)名都很明了,唯一需要解釋的是第三個(gè)參數(shù), 這個(gè)參數(shù) select 中的 fd_set 比較類似,每個(gè)bit代表一個(gè)CPU。

  • 設(shè)置 affinity 的例子
    unsigned long mask = 7; /* processors 0, 1, and 2 */
    unsigned int len = sizeof(mask);
    if (sched_setaffinity(pid, len, &mask) < 0) 
        perror("sched_setaffinity");
    
  • 獲取 affinity 的例子
    unsigned long mask;
    unsigned int len = sizeof(mask);
    if (sched_getaffinity(pid, len, &mask) < 0) 
    {
        perror("sched_getaffinity");
        return -1;
    }
    
    printf("my affinity mask is: %08lx\n", mask);
    
綁定線程和CPU

與進(jìn)程的情況相似,線程親和性的設(shè)置和獲取主要通過下面兩個(gè)函數(shù)來實(shí)現(xiàn):

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

從函數(shù)名以及參數(shù)名都很明了,唯一需要點(diǎn)解釋下的可能就是cpu_set_t這個(gè)結(jié)構(gòu)體了。這個(gè)結(jié)構(gòu)體的理解類似于select中的fd_set,可以理解為cpu集,也是通過約定好的宏來進(jìn)行清除、設(shè)置以及判斷:

void CPU_ZERO(cpu_set_t *set);   //初始化,設(shè)為空   
void CPU_SET(int cpu, cpu_set_t *set);   //將某個(gè)cpu加入cpu集中        
void CPU_CLR(int cpu, cpu_set_t *set);   //將某個(gè)cpu從cpu集中移出      
int CPU_ISSET(int cpu, const cpu_set_t *set);    //判斷某個(gè)cpu是否已在cpu集中設(shè)置了 

進(jìn)程獨(dú)占CPU

如何實(shí)現(xiàn)一個(gè)或多個(gè)進(jìn)程獨(dú)占一個(gè)或多個(gè)CPU? 即調(diào)度器只能把指定的進(jìn)程調(diào)度至指定的CPU。最簡單的方法是利用fork()的繼承特性,子進(jìn)程繼承父進(jìn)程的affinity。這種方法無需修改和編譯內(nèi)核代碼。
init進(jìn)程是所有進(jìn)程的祖先,我們可以設(shè)置init進(jìn)程的affinity來達(dá)到設(shè)置所有進(jìn)程的affinity的目地,然后把我們自己的進(jìn)程綁定到目地CPU上。這樣就到達(dá)了在指定CPU上只運(yùn)行指定的的進(jìn)程的目地。
那么,如何修改init進(jìn)程的affinity?我們只需在/etc/rc.d/rc.sysinit或/etc/rc.sysinit中,起始處增加如下兩行,其中bind是6.1小節(jié)編譯生成的可執(zhí)行文件,rc.sysinit文件是init進(jìn)程運(yùn)行的第一個(gè)腳本。

線程獨(dú)占CPU

通過內(nèi)核參數(shù)isolcpus 來指示系統(tǒng)保留CPU。然后把目標(biāo)線程綁定至保留的CPU。

代碼測試
綁定進(jìn)程
#define _GNU_SOURCE
 
#include <stdlib.h>
#include <stdio.h>
#include <sched.h>
 
int main(int argc, char *argv[])
{
    unsigned long new_mask;
    unsigned long cur_mask;
    unsigned int len = sizeof(new_mask);
    pid_t pid;
 
    if (argc != 3) {
   fprintf(stderr,
                "usage: %s [pid] [cpu_mask]\n",
                argv[0]);
   return -1;
    }
 
    pid = atol(argv[1]);
    sscanf(argv[2], "%08lx", &new_mask);
 
    if (sched_getaffinity(pid, len,
                          &cur_mask) < 0) {
   perror("sched_getaffinity");
   return -1;
    }
 
    printf("pid %d's old affinity: %08lx\n",
           pid, cur_mask);
 
    if (sched_setaffinity(pid, len, &new_mask)) {
   perror("sched_setaffinity");
   return -1;
    }
 
    if (sched_getaffinity(pid, len,
                          &cur_mask) < 0) {
   perror("sched_getaffinity");
   return -1;
    }
 
    printf(" pid %d's new affinity: %08lx\n",
           pid, cur_mask);
 
    return 0;
}
綁定線程
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
 
void *myfun(void *arg)
{
    cpu_set_t mask;
    cpu_set_t get;
    char buf[256];
    int i;
    int j;
    int num = sysconf(_SC_NPROCESSORS_CONF);
    printf("system has %d processor(s)\n", num);
 
    for (i = 0; i < num; i++) {
        CPU_ZERO(&mask);
        CPU_SET(i, &mask);
        if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0) {
            fprintf(stderr, "set thread affinity failed\n");
        }
        CPU_ZERO(&get);
        if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) < 0) {
            fprintf(stderr, "get thread affinity failed\n");
        }
        for (j = 0; j < num; j++) {
            if (CPU_ISSET(j, &get)) {
                printf("thread %d is running in processor %d\n", (int)pthread_self(), j);
            }
        }
        j = 0;
        while (j++ < 100000000) {
            memset(buf, 0, sizeof(buf));
        }
    }
    pthread_exit(NULL);
}
 
int main(int argc, char *argv[])
{
    pthread_t tid;
    if (pthread_create(&tid, NULL, (void *)myfun, NULL) != 0) {
        fprintf(stderr, "thread create failed\n");
        return -1;
    }
    pthread_join(tid, NULL);
    return 0;
}

參考
[1] http://www.linuxjournal.com/article/6799?page=0,0
[2] http://blog.chinaunix.net/uid-26739406-id-3181199.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 概念 什么是CPU Affinity?Affinity是進(jìn)程的一個(gè)屬性,這個(gè)屬性指明了進(jìn)程調(diào)度器能夠把這個(gè)進(jìn)程調(diào)度...
    梅_梅閱讀 1,426評論 3 4
  • 完全公平調(diào)度CFS CFS(Completely Fair Scheduler)試圖按照對 CPU 時(shí)間的 “最大...
    batbattle閱讀 3,615評論 0 5
  • 進(jìn)程調(diào)度:在可運(yùn)行態(tài)進(jìn)程之間分配有限處理器時(shí)間資源的內(nèi)核子系統(tǒng)。通俗來說就是,各個(gè)進(jìn)程之間如何有規(guī)律的使用CPU。...
    batbattle閱讀 3,393評論 0 9
  • 相思爬過櫥窗 壓出年華刻在玻璃上的夢想 聽風(fēng)吹過海浪 小人兒行走在弄堂小巷 任鐘聲驅(qū)逐遮陽 把北國的涂鴉惹上南墻 ...
    文帝風(fēng)塵閱讀 259評論 0 7
  • 文/爿天 最近一段時(shí)間屬于自己思維快速迭代和行動(dòng)變更的摸索期。高強(qiáng)度的學(xué)習(xí)加上對于之前行為模式的不斷調(diào)整,使得最近...
    爿天閱讀 506評論 1 1

友情鏈接更多精彩內(nèi)容