天天看點

cpu親和性

1. 概述

CPU親和性,是指程序在指定的CPU長時間運作,而盡量不向其他CPU遷移。

在多核CPU的機器上,每個CPU都有自己的緩存,如果程序不顯式的綁定CPU,那麼有可能在作業系統的排程下,在不同的CPU之間切換,那麼原先CPU上的緩存資料就沒什麼用了,新CPU上的緩存又沒有之前的資料,這就造成了緩存命中率降低。如果設定了CPU親和性,一個程序綁定了CPU之後,那麼緩存的命中率就能保持在一個較高的水準,進而提高程式性能,這就是為什麼要設定CPU親和性的原因。另一個好處是提高特定程序排程的優先級,比如一個對實時性要求高的程序做綁定,一方面可以保持它的實時性,另一方面也避免它去幹擾其他程序。

2. 相關指令

如下指令可以檢視某個程序(線程)運作在哪個CPU上

[[email protected] build]#  ps -eo pid,args,psr | grep ssh
  827 /usr/sbin/sshd -D             1
11436 sshd: [email protected]/1              3
11839 grep --color=auto ssh         2
17761 sshd: [email protected]/0              3
[[email protected] build]# pstree -p 827
sshd(827)─┬─sshd(11436)───bash(11441)───pstree(11906)
          └─sshd(17761)───bash(17767)───mysql(23070)
[[email protected] build]# ps -To 'pid,lwp,psr,cmd' -p 17761
  PID   LWP PSR CMD
17761 17761   3 sshd: [email protected]/0
           

超線程技術(Hyper-Threading), 把兩個邏輯核心(CPU core)模拟成兩個實體晶片,讓單個處理器都能使用線程級并行計算,常說的的雙核四線程/四核八線程指的就是支援超線程技術的CPU.[1] 要注意,超線程技術是通過延遲隐藏的方法,提高了處理器的性能,本質上,就是多個線程共享一個處理單元。是以,采用超線程技術所獲得的性能并不是真正意義上的并行。[2]

關聯指令,taskset

如下操作可以更改程序對應的CPU

[[email protected] build]# ps -eo pid,args,psr | grep top
12383 top                           3
12387 grep --color=auto top         0
[[email protected] build]# taskset -cp 2 12383
pid 12383's current affinity list: 0-3
pid 12383's new affinity list: 2
[[email protected] build]# ps -eo pid,args,psr | grep top
12383 top                           2
12415 grep --color=auto top         3
           

主要參數有兩個,更多資訊可以檢視man手冊

-p, --pid
              操作已存在的PID,而不是加載一個新的程式
 -c, --cpu-list
              聲明CPU的親和力使用數字表示而不是用位掩碼表示. 例如 0,5,7,9-11.
           

3. 掩碼

下面這一段摘自taskset的man手冊,主要講述CPU親和性中掩碼的作用。

簡而言之就是,

CPU關聯用位掩碼表示,最低階位對應第一個邏輯CPU,最高階位對應最後一個邏輯CPU。如果給出了一個無效的掩碼,則傳回一個錯誤。

用掩碼也可以指定一對多的關系,比如 0x00000003就是綁定0号和1号CPU。.

taskset is used to set or retrieve the CPU affinity of a running process given its PID or to launch a new COMMAND with a given CPU affinity. CPU affinity is a scheduler property that "bonds" a process to a given set of CPUs on the system. The Linux

scheduler will honor the given CPU affinity and the process will not run on any other CPUs. Note that the Linux scheduler also supports natural CPU affinity: the scheduler attempts to keep processes on the same CPU as long as practical for performance

reasons. Therefore, forcing a specific CPU affinity is useful only in certain applications.

The CPU affinity is represented as a bitmask, with the lowest order bit corresponding to the first logical CPU and the highest order bit corresponding to the last logical CPU. Not all CPUs may exist on a given system but a mask may specify more CPUs than

are present. A retrieved mask will reflect only the bits that correspond to CPUs physically on the system. If an invalid mask is given (i.e., one that corresponds to no valid CPUs on the current system) an error is returned. The masks are typically

given in hexadecimal. For example,

0x00000001

is processor #0

0x00000003

is processors #0 and #1

0xFFFFFFFF

is all processors (#0 through #31).

When taskset returns, it is guaranteed that the given program has been scheduled to a legal CPU

4. 程式設計執行個體

主要有兩個函數API,一個設定,一個擷取

  • sched_set_affinity() (用來修改位掩碼)
  • sched_get_affinity() (用來檢視目前的位掩碼)

一個關鍵資料結構

  • task_struct

修改掩碼的宏

void CPU_ZERO (cpu_set_t *set)
這個宏對 CPU 集 set 進行初始化,将其設定為空集。
void CPU_SET (int cpu, cpu_set_t *set)
這個宏将 cpu 加入 CPU 集 set 中。
void CPU_CLR (int cpu, cpu_set_t *set)
這個宏将 cpu 從 CPU 集 set 中删除。
int CPU_ISSET (int cpu, const cpu_set_t *set)
如果 cpu 是 CPU 集 set 的一員,這個宏就傳回一個非零值(true),否則就傳回零(false)。
           
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h> /* exit */
#include <unistd.h> /* sysconf */

int main(void) {
    int i, nrcpus;
    cpu_set_t mask;
    unsigned long bitmask = 0;

    // 把0号和1号1CPU加入到mask中
    CPU_ZERO(&mask);
    CPU_SET(0, &mask);
    CPU_SET(1, &mask);
    // 設定CPU親和性
    if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
        perror("sched_setaffinity");
        exit(EXIT_FAILURE);
    }

    // 擷取CPU情和性
    CPU_ZERO(&mask);
    if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
        perror("sched_getaffinity");
        exit(EXIT_FAILURE);
    }

    // 擷取邏輯CPU數量
    nrcpus = sysconf(_SC_NPROCESSORS_CONF);
    for (i = 0; i < nrcpus; i++) {
        if (CPU_ISSET(i, &mask)) {
            bitmask |= (unsigned long)0x01 << i;
            printf("processor #%d is set\n", i);
        }
    }

    printf("bitmask = %#lx\n", bitmask);

    exit(EXIT_SUCCESS);
}
           

outputs

[[email protected] cpu]# gcc affinity.c -o affinity
[[email protected] cpu]# ./affinity 
processor #0 is set
processor #1 is set
bitmask = 0x3
           

5. 使用場景

  • 需要處理大量計算的任務
  • 測試複雜應用的測試任務
  • 重要、敏感、實時性的任務

參考:

[0] https://zhuanlan.zhihu.com/p/259217757

[1] https://www.cnblogs.com/LubinLew/p/cpu_affinity.html

[2] https://baike.baidu.com/item/%E8%B6%85%E7%BA%BF%E7%A8%8B/86034?fromtitle=%E8%B6%85%E7%BA%BF%E7%A8%8B%E6%8A%80%E6%9C%AF&fromid=276864&fr=aladdin

[3] https://www.ibm.com/developerworks/cn/linux/l-affinity.html

繼續閱讀