一、CPU亲和性
CPU亲和性又称CPU关联,可以映射到一个或多个CPU上。该技术基于对称多处理机操作系统中的native central queue调度算法。 队列(queue)中的每一个任务(进程或线程)都有一个标签(tag)来指定它们倾向的CPU。在分配处理器的阶段,每个任务就会 分配到它们所倾向的CPU上; 在多核运行的机器上,每个CPU本身自己会有缓存,在缓存中存着进程使用的数据,而没有绑定CPU的话,进程可能会被操作系 统调度到其他CPU上,如此CPU cache(高速缓冲存储器)命中率就低了,也就是说调到的CPU缓存区没有这类数据; - 【1】要先把内存或硬盘的数据载入缓存,而当缓存区绑定CPU后,程序就会一直在指定的CPU执行,不会被操作系统调度到其 他CPU,性能上会有一定的提高; - 【2】使用CPU绑定考虑的是将关键的进程隔离开,对于部分实时进程调度优先级提高,可以将其绑定到一个指定CPU核上,可 以保证实时进程的调度,也可以避免其他CPU上进程被该实时进程干扰; 调度算法对于处理器亲和性的支持各不相同。有些调度算法在它认为合适的情况下会允许把一个任务调度到不同的处理器上。比如当 两个计算密集型的任务(A和B)同时对一个处理器具有亲和性时,另外一个处理器可能就被闲置了。这种情况下许多调度算法会把 任务B调度到第二个处理器上,使得多处理器的利用更加充分; 处理器亲和性能够有效地解决一些高速缓存的问题,但却不能缓解负载均衡的问题。而且,在异构系统中,处理器亲和性问题会变 得更加复杂;
CPU的亲和性分为两种:软亲和性和硬亲和性; - 软CPU亲和性:进程要在指定的CPU上尽量长时间地运行而不被迁移到其他处理器上运行;Linux内核的自身特性,意味着进程通 常不会在处理器之间频繁迁移,以避免这种迁移对于计算能力的消耗,以达到最佳的平衡性; - 硬CPU亲和性的机制:这个机制让开发人员可以实现硬CPU亲和性。这意味着可以显式指定进程在哪个(或哪些)处理器上运行; 以此提高性能;
1.1 使用场景
保持高CPU缓存命中率
SMP、NUMA、MPP体系结构介绍
目前主流的服务器配置都是SMP架构,在SMP的环境下,每个CPU本身自己会有缓存,缓存着进程使用的信息,如果一个给定的进程迁移到其他地方去了,那么它就失去了利用 CPU 缓存的优势。实际上,如果正在使用的 CPU 需要为自己缓存 一些特殊的数据,那么所有其他 CPU 都会使这些数据在自己的缓存中失效。因此,如果有多个线程都需要相同的数据,那么将这些 线程绑定到一个特定的 CPU 上是非常有意义的,这样就确保它们可以访问相同的缓存数据(或者至少可以提高缓存的命中率)。否 则,这些线程可能会在不同的 CPU 上执行,这样会频繁地使其他缓存项失效;
测试复杂的应用程序
考虑一个需要进行线性可伸缩性测试的应用程序。有些产品声明可以在使用更多硬件时执行得更好。 我们不用购买多台机器(为每 种处理器配置都购买一台机器),而是可以:1.购买一台多处理器的机器;2.不断增加分配的处理器;3.测量每秒的事务数;4.评估 结果的可伸缩性;
二、使用接口
#inclde <sched.h> int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask); / @func: 将ID为pid的进程的CPU亲和性掩码设置为mask指定的值; 若pid为0,则使用当前调用进程; 如果pid指定的进程当前不在掩码中指定的cpu上运行,那么该进程将迁移到掩码中指定的一个cpu上掩码中指定的cpu; @param cpusetsize: sizeof(cpu_set_t); return: 成功返回0,失败返回-1; */ int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask); / @func: 获取pid的亲和性掩码,存入mask中; return: 成功返回0,失败返回-1; */ / 清除set */ void CPU_ZERO(cpu_set_t *set); / 设置 */ void CPU_SET(int cpu, cpu_set_t *set); / 移除 */ void CPU_CLR(int cpu, cpu_set_t *set); / 判断是否设置 */ int CPU_ISSET(int cpu, cpu_set_t *set); / CPU数量 */ int CPU_COUNT(cpu_set_t *set); void CPU_AND(cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2); void CPU_OR(cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2); void CPU_XOR(cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2); int CPU_EQUAL(cpu_set_t *set1, cpu_set_t *set2); cpu_set_t *CPU_ALLOC(int num_cpus); void CPU_FREE(cpu_set_t *set); size_t CPU_ALLOC_SIZE(int num_cpus); /*/usr/include/bits/sched.h*/ # define __CPU_SETSIZE 1024 # define __NCPUBITS (8 * sizeof (__cpu_mask)) /* Type for array elements in 'cpu_set'. */ typedef unsigned long int __cpu_mask; typedef struct {
__cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS]; } cpu_set_t; // 每一个bit都表示一个cpu状态
测试
========》Centos下几种CPU查看使用率的常用命令《=========
#include <stdint.h> #include <stdio.h> #include <sched.h> #include <pthread.h> #include <stdlib.h> static inline void print_cpu_mask(cpu_set_t cpu_mask) {
unsigned char flag = 0; printf("Cpu affinity is "); for (unsigned int i = 0; i < sizeof(cpu_set_t); i ++) {
if (CPU_ISSET(i, &cpu_mask)) {
if (flag == 0) {
flag = 1; printf("%d", i); } else {
printf(",%d", i); } } } printf(".\n"); } static inline void get_cpu_mask(pid_t pid, cpu_set_t *mask) {
if (sched_getaffinity(pid, sizeof(cpu_set_t), mask) == -1) {
perror("get cpu affinity failed.\n"); abort(); } } static inline void set_cpu_mask(pid_t pid, cpu_set_t *mask) {
if (sched_setaffinity(pid, sizeof(cpu_set_t), mask) == -1) {
perror("set cpu affinity failed.\n"); abort(); } } void *thread_func(void *param) {
cpu_set_t cpu_mask; get_cpu_mask(0, &cpu_mask); printf("Slave thread "); print_cpu_mask(cpu_mask); CPU_ZERO(&cpu_mask); CPU_SET(1, &cpu_mask); set_cpu_mask(0, &cpu_mask); get_cpu_mask(0, &cpu_mask); printf("Slave thread "); print_cpu_mask(cpu_mask); for (;;) {
; } } int main(int argc, char *argv[]) {
unsigned int active_cpu = 0; cpu_set_t cpu_mask; pthread_t thread; get_cpu_mask(0, &cpu_mask); print_cpu_mask(cpu_mask); CPU_ZERO(&cpu_mask); CPU_SET(active_cpu, &cpu_mask); set_cpu_mask(0, &cpu_mask); get_cpu_mask(0, &cpu_mask); printf("Master thread "); print_cpu_mask(cpu_mask); if (pthread_create(&thread, NULL, thread_func, NULL) != 0) {
perror("pthread_create failed.\n"); } pthread_join(thread, NULL); return 0; }
本次测试使用1号cpu,使用mpstat命令查看即可确认是否设置成功;
参考文章
关于CPU亲和性,这篇讲得最全面
Linux CPU亲缘性详解
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/97670.html