1. 程式人生 > >Linux程序或執行緒繫結到CPU+修改優先順序

Linux程序或執行緒繫結到CPU+修改優先順序

 

轉載自 https://www.cnblogs.com/swey/p/4469722.html

為了讓程式擁有更好的效能,有時候需要將程序或執行緒繫結到特定的CPU,這樣可以減少排程的開銷和保護關鍵程序或執行緒。

程序繫結到CPU

Linux提供一個介面,可以將程序繫結到特定的CPU:

#define _GNU_SOURCE         //這行必須在下面這include之前,否則CPU_SET不認識

#include <sched.h>

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

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

引數

pid:程序的id號,如果pid為0,則表示本程序

cpusetsize:mask的大小

mask:執行程序的CPU,可以通過以下函式操作mask

#define CPU_SET(cpu, cpusetp) //設定cpu

#define CPU_CLR(cpu, cpusetp) //刪除cpu

#define CPU_ISSET(cpu, cpusetp) //判斷cpu

#define CPU_ZERO(cpusetp) //初始化為0

示例程式碼

複製程式碼

#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <sched.h>
 
void WasteTime()
{
    int abc = 10000000;
    while(abc--)
    {
        int tmp = 10000*10000;
    }
    sleep(1);

}

int main(int argc, char **argv)
{
    cpu_set_t mask;
    while(1)
    {
 
        CPU_ZERO(&mask);
        CPU_SET(0, &mask); 
        if (sched_setaffinity(0, sizeof(mask), &mask) < 0) {
            perror("sched_setaffinity");
        }
        WasteTime();
 
        CPU_ZERO(&mask);
        CPU_SET(1, &mask); 
        if (sched_setaffinity(0, sizeof(mask), &mask) < 0) {
            perror("sched_setaffinity");
        }
        WasteTime();
     
        CPU_ZERO(&mask);
        CPU_SET(2, &mask); 
        if (sched_setaffinity(0, sizeof(mask), &mask) < 0) {
            perror("sched_setaffinity");
        }
        WasteTime();
     
        CPU_ZERO(&mask);
        CPU_SET(3, &mask); 
        if (sched_setaffinity(0, sizeof(mask), &mask) < 0) {
            perror("sched_setaffinity");
        }
        WasteTime();
    }
}

複製程式碼

 

測試

編譯之後執行程式,輸入命令top -p 程序id,輸入f(增加或者刪除top命令顯示列),上下按鍵移動游標到P (Last used CPU),按D鍵讓其高亮。然後按q鍵退出即可。可以看到P這列出來了。 (kernel 4.9)

 

執行緒繫結到CPU

不僅僅程序可以繫結到CPU,執行緒也可以。Linux提供一個介面,可以將執行緒繫結到特定的CPU:

#include <pthread.h>

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);

該介面與程序繫結到CPU的介面的使用方法基本一致。

當程序繫結到特定的CPU之後,執行緒還是可以繫結到其他的CPU的,沒有衝突。

示例程式碼

複製程式碼

#include <stdio.h>
#include <math.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>

void WasteTime()
{
    int abc = 10000000;
    while(abc--)
    {
        int tmp = 10000*10000;
    }
    sleep(1);

}

void *thread_func(void *param)
{
    cpu_set_t mask;
    while(1)
    {
         CPU_ZERO(&mask);
        CPU_SET(1, &mask); 

        if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
            &mask) < 0) {
            perror("pthread_setaffinity_np");
        }
 
        WasteTime();

         CPU_ZERO(&mask);
        CPU_SET(2, &mask); 
        if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
            &mask) < 0) {
            perror("pthread_setaffinity_np");
        }

        WasteTime();
    }
}
 
void *thread_func1(void *param)
{
    cpu_set_t mask;
    while(1)
    {
         CPU_ZERO(&mask);
        CPU_SET(3, &mask); 

        if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
            &mask) < 0) {
            perror("pthread_setaffinity_np");
        }
 
        WasteTime();

         CPU_ZERO(&mask);
        CPU_SET(4, &mask); 
        if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
            &mask) < 0) {
            perror("pthread_setaffinity_np");
        }

        WasteTime();
    }
}
 
int main(int argc, char *argv[])
{
    cpu_set_t mask;
     CPU_ZERO(&mask);
    CPU_SET(0, &mask); 
    if (sched_setaffinity(0, sizeof(mask), &mask) < 0) {
        perror("sched_setaffinity");
    }

    pthread_t my_thread;
 
    if (pthread_create(&my_thread, NULL, thread_func,
        NULL) != 0) {
        perror("pthread_create");
    }
    if (pthread_create(&my_thread, NULL, thread_func1,
        NULL) != 0) {
        perror("pthread_create");
    }
    while(1) { WasteTime(); }
    pthread_exit(NULL);

}

複製程式碼

 

測試

編譯之後執行程式,輸入命令top -p 程序id(這裡可以時task id,一個程序下可以有多個task,預設名字和程序一樣,可進proc/pid/task下檢視當前程序有多少個task),輸入f(增加或者刪除top命令顯示列),上下按鍵移動游標到P (Last used CPU),按D鍵讓其高亮。然後按q鍵退出即可。可以看到P這列出來了。

 

 

top命令列下,按下1,可以顯示各個core的使用情況

 

 

 

 

調整優先順序

可參考 http://blog.chinaunix.net/uid-24774106-id-3379478.html

            https://bbs.csdn.net/topics/340030105

在使用者層或者應用層,1表示優先順序最低,99表示優先順序最高。但是在核心中,[0,99]表示的實時程序的優先順序,0最高,99最低。[100,139]是普通程序折騰的範圍。應用層比較天真率直,就看大小,數字大,則優先順序高。ps檢視程序的優先順序也是如此。有意思的是,應用層實時程序最高優先順序的99,在ps看程序優先順序的時候,輸出的是139.

實時程序的優先順序設定可以通過sched_setsheduler設定,也可以通過sched_setparam設定優先順序的大小。

執行緒的優先順序,目前只清楚可通過下面在pthread_create時設定,執行緒體內怎麼設定還不清楚。

  
#define _GNU_SOURCE
#include <stdio.h>
#include <sched.h>
#include <pthread.h>
#include <unistd.h>
#include <math.h>
#include <stdlib.h>


static void *thread_entry(void *arg)
{

    int i = *(int *)arg;
    printf("thread_entry i=%d\n",i);
    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(0, &mask);
    if (pthread_setaffinity_np(pthread_self(), sizeof(mask),&mask) < 0) {
        perror("sched_setaffinity");
    }

    int policy;
    struct sched_param param;
    pthread_getschedparam(pthread_self(),&policy,&param);
    printf("policy=%d  priority=%d\n",policy,param.sched_priority);

    for(int i=0;i<1000;i++){
        for(int j=0;j<1000000;j++){
        }

        pthread_attr_init(&attr);
    }
    printf("thread %d exit\n",i);
    pthread_exit((void *)0);
}

static int threadnum[4] = {0,1,2,3};


void main (){
        int ret;

        struct sched_param param;
        param.sched_priority=51;

#if 0
        //only modify the pthread which use this attr
        pthread_attr_t attr;
        pthread_attr_init(&attr);
        
        pthread_attr_setschedpolicy(&attr,SCHED_RR);
        pthread_attr_setschedparam(&attr,&param);
        pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED);
#endif

        //modify current process's  all pthread

        //這個函式在核心裡也可以用,設定當前task   sched_setscheduler(current, SCHED_FIFO, &param);
        ret = sched_setscheduler(getpid(),SCHED_RR,&param);     

        pthread_t *thread =(pthread_t *) malloc(sizeof(pthread_t)*4);
        for (int i = 0; i < 3; i++) {
                pthread_create(&thread[i], NULL, thread_entry, (void *)&threadnum[i]);
        }
        pthread_create(&thread[3], NULL, thread_entry, (void *)&threadnum[3]);

        for (int i = 0; i < 4; i++) {
                ret = pthread_join(thread[i], NULL);
                if (ret != 0) {
                        printf("cpuwhile thread%d failed,error=%d\n", i,ret);
                } else {
                        printf("cpuwhile thread%d test success\n", i);
                }
        }


        //pthread_attr_destroy(&attr);

        printf("free!");

        if(thread != NULL)
                free(thread);