亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

蟲蟲首頁| 資源下載| 資源專輯| 精品軟件
登錄| 注冊

您現(xiàn)在的位置是:首頁 > 技術(shù)閱讀 >  一文讀懂 | 進(jìn)程怎么綁定 CPU

一文讀懂 | 進(jìn)程怎么綁定 CPU

時間:2024-02-12

昨天在群里有朋友問:把進(jìn)程綁定到某個 CPU 上運(yùn)行是怎么實(shí)現(xiàn)的。

首先,我們先來了解下將進(jìn)程與 CPU 進(jìn)行綁定的好處。

進(jìn)程綁定 CPU 的好處:在多核 CPU 結(jié)構(gòu)中,每個核心有各自的L1、L2緩存,而L3緩存是共用的。如果一個進(jìn)程在核心間來回切換,各個核心的緩存命中率就會受到影響。相反如果進(jìn)程不管如何調(diào)度,都始終可以在一個核心上執(zhí)行,那么其數(shù)據(jù)的L1、L2 緩存的命中率可以顯著提高。

所以,將進(jìn)程與 CPU 進(jìn)行綁定可以提高 CPU 緩存的命中率,從而提高性能。而進(jìn)程與 CPU 綁定被稱為:CPU 親和性

設(shè)置進(jìn)程的 CPU 親和性

前面介紹了進(jìn)程與 CPU 綁定的好處后,現(xiàn)在來介紹一下在 Linux 系統(tǒng)下怎么將進(jìn)程與 CPU 進(jìn)行綁定的(也就是設(shè)置進(jìn)程的 CPU 親和性)。

Linux 系統(tǒng)提供了一個名為 sched_setaffinity 的系統(tǒng)調(diào)用,此系統(tǒng)調(diào)用可以設(shè)置進(jìn)程的 CPU 親和性。我們來看看 sched_setaffinity 系統(tǒng)調(diào)用的原型:

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

下面介紹一下 sched_setaffinity 系統(tǒng)調(diào)用各個參數(shù)的作用:

  • pid:進(jìn)程ID,也就是要進(jìn)行綁定 CPU 的進(jìn)程ID。
  • cpusetsize:mask 參數(shù)所指向的 CPU 集合的大小。
  • mask:與進(jìn)程進(jìn)行綁定的 CPU 集合(由于一個進(jìn)程可以綁定到多個 CPU 上運(yùn)行)。

參數(shù) mask 的類型為 cpu_set_t,而 cpu_set_t 是一個位圖,位圖的每個位表示一個 CPU,如下圖所示:



例如,將 cpu_set_t 的第0位設(shè)置為1,表示將進(jìn)程綁定到 CPU0 上運(yùn)行,當(dāng)然我們可以將進(jìn)程綁定到多個 CPU 上運(yùn)行。

我們通過一個例子來介紹怎么通過 sched_setaffinity 系統(tǒng)調(diào)用來設(shè)置進(jìn)程的 CPU 親和性:

#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv)
{
    cpu_set_t cpuset;

    CPU_ZERO(&cpuset);    // 初始化CPU集合,將 cpuset 置為空
    CPU_SET(2, &cpuset);  // 將本進(jìn)程綁定到 CPU2 上

    // 設(shè)置進(jìn)程的 CPU 親和性
    if (sched_setaffinity(0sizeof(cpuset), &cpuset) == -1) {
        printf("Set CPU affinity failed, error: %s\n", strerror(errno));
        return -1
    }

    return 0;
}

CPU 親和性實(shí)現(xiàn)

知道怎么設(shè)置進(jìn)程的 CPU 親和性后,現(xiàn)在我們來分析一下 Linux 內(nèi)核是怎樣實(shí)現(xiàn) CPU 親和性功能的。

本文使用的 Linux 內(nèi)核版本為 2.6.23

Linux 內(nèi)核為每個 CPU 定義了一個類型為 struct rq 的 可運(yùn)行的進(jìn)程隊列,也就是說,每個 CPU 都擁有一個獨(dú)立的可運(yùn)行進(jìn)程隊列。

一般來說,CPU 只會從屬于自己的可運(yùn)行進(jìn)程隊列中選擇一個進(jìn)程來運(yùn)行。也就是說,CPU0 只會從屬于 CPU0 的可運(yùn)行隊列中選擇一個進(jìn)程來運(yùn)行,而絕不會從 CPU1 的可運(yùn)行隊列中獲取。

所以,從上面的信息中可以分析出,要將進(jìn)程綁定到某個 CPU 上運(yùn)行,只需要將進(jìn)程放置到其所屬的 可運(yùn)行進(jìn)程隊列 中即可。

下面我們來分析一下 sched_setaffinity 系統(tǒng)調(diào)用的實(shí)現(xiàn),sched_setaffinity 系統(tǒng)調(diào)用的調(diào)用鏈如下:

sys_sched_setaffinity()
└→ sched_setaffinity()
└→ set_cpus_allowed()
└→ migrate_task()

從上面的調(diào)用鏈可以看出,sched_setaffinity 系統(tǒng)調(diào)用最終會調(diào)用 migrate_task 函數(shù)來完成進(jìn)程與 CPU 進(jìn)行綁定的工作,我們來分析一下 migrate_task 函數(shù)的實(shí)現(xiàn):

static int
migrate_task(struct task_struct *p, int dest_cpu, struct migration_req *req)
{
    struct rq *rq = task_rq(p);

    // 情況1:
    // 如果進(jìn)程還沒有在任何運(yùn)行隊列中
    // 那么只需要將進(jìn)程的 cpu 字段設(shè)置為 dest_cpu 即可
    if (!p->se.on_rq && !task_running(rq, p)) {
        set_task_cpu(p, dest_cpu);
        return 0;
    }

    // 情況2:
    // 如果進(jìn)程已經(jīng)在某一個 CPU 的可運(yùn)行隊列中
    // 那么需要將進(jìn)程從之前的 CPU 可運(yùn)行隊列中遷移到新的 CPU 可運(yùn)行隊列中
    // 這個遷移過程由 migration_thread 內(nèi)核線程完成

    // 構(gòu)建進(jìn)程遷移請求
    init_completion(&req->done);
    req->task = p;
    req->dest_cpu = dest_cpu;
    list_add(&req->list, &rq->migration_queue);

    return 1;
}

我們先來介紹一下 migrate_task 函數(shù)各個參數(shù)的意義:

  • p:要設(shè)置 CPU 親和性的進(jìn)程描述符。
  • dest_cpu:綁定的 CPU 編號。
  • req:進(jìn)程遷移請求對象(下面會介紹)。

所以,migrate_task 函數(shù)的作用就是將進(jìn)程描述符為 p 的進(jìn)程綁定到編號為 dest_cpu 的目標(biāo) CPU 上。

migrate_task 函數(shù)主要分兩種情況來將進(jìn)程綁定到某個 CPU 上:

  • 情況1:如果進(jìn)程還沒有在任何 CPU 的可運(yùn)行隊列中(不可運(yùn)行狀態(tài)),那么只需要將進(jìn)程描述符的 cpu 字段設(shè)置為 dest_cpu 即可。當(dāng)進(jìn)程變?yōu)榭蛇\(yùn)行時,會根據(jù)進(jìn)程描述符的 cpu 字段來自動放置到對應(yīng)的 CPU 可運(yùn)行隊列中。
  • 情況2:如果進(jìn)程已經(jīng)在某個 CPU 的可運(yùn)行隊列中,那么需要將進(jìn)程從之前的 CPU 可運(yùn)行隊列中遷移到新的 CPU 可運(yùn)行隊列中。遷移過程由 migration_thread 內(nèi)核線程完成,migrate_task 函數(shù)只是構(gòu)建一個進(jìn)程遷移請求,并通知 migration_thread 內(nèi)核線程有新的遷移請求需要處理。

而進(jìn)程遷移過程由 __migrate_task 函數(shù)完成,我們來看看 __migrate_task 函數(shù)的實(shí)現(xiàn):

static int 
__migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
{
    struct rq *rq_dest, *rq_src;
    int ret = 0, on_rq;
    ...
    rq_src = cpu_rq(src_cpu);    // 進(jìn)程所在的原可運(yùn)行隊列
    rq_dest = cpu_rq(dest_cpu);  // 進(jìn)程希望放置的目標(biāo)可運(yùn)行隊列
    ...
    on_rq = p->se.on_rq;  // 進(jìn)程是否在可運(yùn)行隊列中(可運(yùn)行狀態(tài))
    if (on_rq)
        deactivate_task(rq_src, p, 0);  // 把進(jìn)程從原來的可運(yùn)行隊列中刪除

    set_task_cpu(p, dest_cpu);

    if (on_rq) {
        activate_task(rq_dest, p, 0);   // 把進(jìn)程放置到目標(biāo)可運(yùn)行隊列中
        ...
    }
    ...
    return ret;
}

__migrate_task 函數(shù)主要完成以下兩個工作:

  • 把進(jìn)程從原來的可運(yùn)行隊列中刪除。
  • 把進(jìn)程放置到目標(biāo)可運(yùn)行隊列中。

其工作過程如下圖所示(將進(jìn)程從 CPU0 的可運(yùn)行隊列遷移到 CPU3 的可運(yùn)行隊列中):



如上圖所示,進(jìn)程原本在 CPU0 的可運(yùn)行隊列中,但由于重新將進(jìn)程綁定到 CPU3,所以需要將進(jìn)程從 CPU0 的可運(yùn)行隊列遷移到 CPU3 的可運(yùn)行中。

遷移過程首先將進(jìn)程從 CPU0 的可運(yùn)行隊列中刪除,然后再將進(jìn)程插入到 CPU3 的可運(yùn)行隊列中。

當(dāng) CPU 要運(yùn)行進(jìn)程時,首先從它所屬的可運(yùn)行隊列中挑選一個進(jìn)程,并將此進(jìn)程調(diào)度到 CPU 中運(yùn)行。

總結(jié)

從上面的分析可知,其實(shí)將進(jìn)程綁定到某個 CPU 只是將進(jìn)程放置到 CPU 的可運(yùn)行隊列中。

由于每個 CPU 都有一個可運(yùn)行隊列,所以就有可能會出現(xiàn) CPU 間可運(yùn)行隊列負(fù)載不均衡問題。如 CPU0 可運(yùn)行隊列中的進(jìn)程比 CPU1 可運(yùn)行隊列多非常多,從而導(dǎo)致 CPU0 的負(fù)載非常高,而 CPU1 負(fù)載非常低的情況。

當(dāng)出現(xiàn)上述情況時,就需要對 CPU 間的可運(yùn)行隊列進(jìn)行重平衡操作,有興趣的可以自行閱讀源碼或參考相關(guān)資料。


亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
久久午夜av| 久久精品最新地址| 国产午夜精品麻豆| 国产欧美一区二区三区沐欲 | 国产一区二区三区久久悠悠色av| 国产午夜精品久久| 亚洲人成人99网站| 午夜国产不卡在线观看视频| 亚洲综合日韩在线| 欧美伦理91| 一区精品在线播放| 亚洲欧美综合另类中字| 欧美电影专区| 国内外成人在线| 亚洲影院免费观看| 欧美高清在线视频观看不卡| 国产欧美亚洲精品| 中文亚洲字幕| 欧美日韩国语| 日韩视频在线永久播放| 午夜精品网站| 国产精品久久久久久久一区探花 | 欧美专区第一页| 男男成人高潮片免费网站| 国产欧美三级| 一区二区三区视频在线观看| 久久久高清一区二区三区| 久久久精品国产99久久精品芒果| 欧美激情成人在线视频| 亚洲国产精品美女| 久久综合久久美利坚合众国| 狠狠综合久久av一区二区小说| 香蕉免费一区二区三区在线观看 | 久久一日本道色综合久久| 国产精品亚洲一区二区三区在线| 99精品视频免费| 欧美日韩ab片| 日韩视频在线免费观看| 欧美国产视频在线| 亚洲国产片色| 欧美激情精品久久久久久| 在线观看一区二区视频| 久久久水蜜桃av免费网站| 激情视频一区二区| 欧美大片在线观看一区| 日韩视频一区二区| 国产精品久在线观看| 久久精品99| 亚洲电影免费观看高清完整版在线 | 欧美激情中文字幕乱码免费| 亚洲黄色成人久久久| 欧美激情视频一区二区三区不卡| 亚洲激情视频网站| 欧美性jizz18性欧美| 午夜视频一区二区| 国内精品伊人久久久久av影院| 免费不卡视频| 亚洲午夜激情网页| 国产一区二区日韩| 欧美黄色小视频| 亚洲无玛一区| 国产亚洲一级高清| 欧美激情一区二区三区在线视频| av成人手机在线| 黄色免费成人| 国产精品国产馆在线真实露脸| 久久精品2019中文字幕| 亚洲乱码久久| 激情校园亚洲| 影音先锋中文字幕一区| 欧美成人一区二区| 欧美一区二区免费观在线| 亚洲国产网站| 国产视频一区二区三区在线观看| 久久综合九色综合欧美就去吻| 在线亚洲欧美专区二区| 在线免费不卡视频| 国产日韩欧美视频| 欧美日韩国产成人| 免播放器亚洲一区| 久久激五月天综合精品| 亚洲图片自拍偷拍| 日韩午夜电影在线观看| 在线看一区二区| 国产午夜久久久久| 欧美日韩中文在线| 欧美裸体一区二区三区| 久久综合免费视频影院| 亚洲欧美中文字幕| 亚洲日本aⅴ片在线观看香蕉| 伊人成年综合电影网| 国产精品久久久91| 欧美电影免费观看网站| 久久久久久香蕉网| 久久国产88| 亚洲一区二区高清| 亚洲一区国产| 亚洲天堂偷拍| 亚洲深夜福利| 99爱精品视频| 永久免费视频成人| 国产手机视频一区二区| 欧美午夜精品久久久久久孕妇| 欧美成人午夜激情在线| 久久久久国产免费免费| 欧美一区二区三区日韩| 亚洲欧美在线网| 欧美一级专区| 久久久777| 久久婷婷综合激情| 欧美成人免费播放| 欧美日韩国产黄| 国产人久久人人人人爽| 国产精品久久久久久影院8一贰佰| 欧美日产在线观看| 欧美体内she精视频在线观看| 国产精品久久福利| 国产一区二区福利| 在线观看欧美黄色| 亚洲美女黄网| 亚洲一区不卡| 欧美一区二区三区的| 久久久7777| 欧美紧缚bdsm在线视频| 国产精品扒开腿做爽爽爽软件| 国产精品久久久久婷婷| 国产一区再线| 日韩视频在线观看| 久久久国产精品亚洲一区 | 最新日韩欧美| 日韩午夜免费| 久久精品二区亚洲w码| 久久亚洲精品网站| 欧美激情久久久| 欧美日韩综合另类| 国产伦精品一区| 欧美亚洲在线| 久久综合伊人| 国产精品高潮粉嫩av| 国产一区二区三区直播精品电影| 国产日韩欧美在线观看| 极品尤物av久久免费看| 亚洲精品乱码久久久久久日本蜜臀| 一级成人国产| 久久视频一区二区| 欧美日韩中文字幕精品| 激情婷婷久久| 亚洲综合国产激情另类一区| 美女啪啪无遮挡免费久久网站| 欧美午夜不卡影院在线观看完整版免费| 国产精品美腿一区在线看| 亚洲国产精品一区制服丝袜| 欧美在线播放一区二区| 欧美午夜在线视频| 在线不卡欧美| 在线午夜精品| 久久久精品国产免大香伊| 欧美96在线丨欧| 欧美视频免费在线| 亚洲伦理久久| 可以看av的网站久久看| 国产精品久久9| 国产精品99久久久久久白浆小说| 久久婷婷国产综合精品青草| 国产精品xxx在线观看www| 亚洲经典自拍| 欧美一级欧美一级在线播放| 欧美久色视频| 亚洲另类一区二区| 欧美成人有码| 亚洲成人资源网| 亚洲在线中文字幕| 久久久久国产精品人| 国产精品久久久久久久久免费桃花 | 欧美色偷偷大香| 在线电影国产精品| 欧美一区二区精品| 欧美日韩三级在线| 亚洲高清视频在线| 久久久91精品国产| 国产视频亚洲精品| 欧美在线观看网站| 国产精品午夜电影| 亚洲一区二区动漫| 免费观看日韩| 亚洲黄色av| 欧美激情按摩在线| 在线视频一区观看| 国产伦精品一区二区| 午夜免费在线观看精品视频| 国产农村妇女毛片精品久久麻豆| 午夜精品亚洲| 影音先锋亚洲电影| 欧美日本在线一区| 亚洲天堂激情| 国内激情久久| 欧美人与性禽动交情品| 亚洲欧美日韩国产综合| 在线观看福利一区| 欧美日韩国产限制|