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,¶m);
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,¶m);
pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED);
#endif
//modify current process's all pthread
//這個函式在核心裡也可以用,設定當前task sched_setscheduler(current, SCHED_FIFO, ¶m);
ret = sched_setscheduler(getpid(),SCHED_RR,¶m);
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);