参考:http://www.cnblogs.com/wenqiang/p/6049978.html

最近的工作中对性能的要求比较高,下面简单做一下总结:

一、什么是cpu亲和性(affinity)

  CPU的亲和性, 就是进程要在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器,也称为CPU关联性;再简单的点的描述就将制定的进程或线程绑定到相应的cpu上;在多核运行的机器上,每个CPU本身自己会有缓存,缓存着进程使用的信息,而进程可能会被OS调度到其他CPU上,如此,CPU cache命中率就低了,当绑定CPU后,程序就会一直在指定的cpu跑,不会由操作系统调度到其他CPU上,性能有一定的提高。

  软亲和性(affinity):  就是进程要在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器,Linux 内核进程调度器天生就具有被称为 软 CPU 亲和性(affinity) 的特性,这意味着进程通常不会在处理器之间频繁迁移。这种状态正是我们希望的,因为进程迁移的频率小就意味着产生的负载小。

  硬亲和性(affinity):简单来说就是利用linux内核提供给用户的API,强行将进程或者线程绑定到某一个指定的cpu核运行。

  解释:在linux内核中,所有的进程都有一个相关的数据结构,称为 task_struct。这个结构非常重要,原因有很多;其中与 亲和性(affinity)相关度最高的是 cpus_allowed 位掩码。这个位掩码由 n 位组成,与系统中的 n 个逻辑处理器一一对应。 具有 4 个物理 CPU 的系统可以有 4 位。如果这些 CPU 都启用了超线程,那么这个系统就有一个 8 位的位掩码。 如果为给定的进程设置了给定的位,那么这个进程就可以在相关的 CPU 上运行。因此,如果一个进程可以在任何 CPU 上运行,并且能够根据需要在处理器之间进行迁移,那么位掩码就全是 1。实际上,这就是 Linux 中进程的缺省状态;(这部分内容在这个博客中有提到一点:http://www.cnblogs.com/wenqiang/p/4802619.html

  cpus_allowed用于控制进程可以在哪里处理器上运行

  • sched_set_affinity() (用来修改位掩码)
  • sched_get_affinity() (用来查看当前的位掩码)

二、进程与cpu的绑定

  sched_setaffinity可以将某个进程绑定到一个特定的CPU。你比操作系统更了解自己的程序,为了避免调度器愚蠢的调度你的程序,或是为了在多线程程序中避免缓存失效造成的开销,你可能会希望这样做

  在进行进程与cpu的绑定前,我们先了解编写程序需要准备的知识点

 SCHED_SETAFFINITY()                                                                      Linux Programmer's Manual                                                                     SCHED_SETAFFINITY(2)

 NAME
sched_setaffinity, sched_getaffinity - set and get a process's CPU affinity mask SYNOPSIS
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sched.h> int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
/*该函数设置进程为pid的这个进程,让它运行在mask所设定的CPU上.如果pid的值为0,
*则表示指定的是当前进程,使当前进程运行在mask所设定的那些CPU上.
*第二个参数cpusetsize是mask所指定的数的长度.通常设定为sizeof(cpu_set_t).
*如果当前pid所指定的进程此时没有运行在mask所指定的任意一个CPU上,
*则该指定的进程会从其它CPU上迁移到mask的指定的一个CPU上运行.*/ int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
/*该函数获得pid所指示的进程的CPU位掩码,并将该掩码返回到mask所指向的结构中.
*即获得指定pid当前可以运行在哪些CPU上.
*同样,如果pid的值为0.也表示的是当前进程*/ RETURN VALUE
On success, sched_setaffinity() and sched_getaffinity() return . On error, - is returned, and errno is set appropriately.

设置cpu affinity还需要用到一下宏函数

 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)。*/

下面下一个具体的例子:将当前进程绑定到0、1、2、3号cpu上

 #define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h> /* sysconf( _SC_NPROCESSORS_CONF ) 查看cpu的个数;打印用%ld长整。
* sysconf( _SC_NPROCESSORS_ONLN ) 查看在使用的cpu个数;打印用%ld长整 */
int main(int argc, char **argv)
{
int cpus = ;
int i = ;
cpu_set_t mask;
cpu_set_t get; cpus = sysconf(_SC_NPROCESSORS_CONF);
printf("cpus: %d\n", cpus); CPU_ZERO(&mask); /* 初始化set集,将set置为空*/
CPU_SET(, &mask); /* 依次将0、1、2、3号cpu加入到集合,前提是你的机器是多核处理器*/
CPU_SET(, &mask);
CPU_SET(, &mask);
CPU_SET(, &mask); /*设置cpu 亲和性(affinity)*/
if (sched_setaffinity(, sizeof(mask), &mask) == -) {
printf("Set CPU affinity failue, ERROR:%s\n", strerror(errno));
return -;
}
usleep(); /* 让当前的设置有足够时间生效*/ /*查看当前进程的cpu 亲和性*/
CPU_ZERO(&get);
if (sched_getaffinity(, sizeof(get), &get) == -) {
printf("get CPU affinity failue, ERROR:%s\n", strerror(errno));
return -;
} /*查看运行在当前进程的cpu*/
for(i = ; i < cpus; i++) { if (CPU_ISSET(i, &get)) { /*查看cpu i 是否在get 集合当中*/
printf("this process %d of running processor: %d\n", getpid(), i);
}
}
sleep(); //让程序停在这儿,方便top命令查看 return ;
}

运行结果如下:

 [root@localhost test]# ./test
cpus:
this process of running processor:
this process of running processor:
this process of running processor:
this process of running processor:

上面代码当中用到了syscall这个函数,顺便也在这里做一下说明

  syscall是执行一个系统调用,根据指定的参数number和所有系统调用的接口来确定调用哪个系统调用,用于用户空间跟内核之间的数据交换

  下面是syscall函数原型及一些常用的number 

 //syscall - indirect system call
SYNOPSIS
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <unistd.h>
#include <sys/syscall.h> /* For SYS_xxx definitions */ int syscall(int number, ...); /* sysconf( _SC_PAGESIZE ); 此宏查看缓存内存页面的大小;打印用%ld长整型。
sysconf( _SC_PHYS_PAGES ) 此宏查看内存的总页数;打印用%ld长整型。
sysconf( _SC_AVPHYS_PAGES ) 此宏查看可以利用的总页数;打印用%ld长整型。
sysconf( _SC_NPROCESSORS_CONF ) 查看cpu的个数;打印用%ld长整。
sysconf( _SC_NPROCESSORS_ONLN ) 查看在使用的cpu个数;打印用%ld长整。
(long long)sysconf(_SC_PAGESIZE) * (long long)sysconf(_SC_PHYS_PAGES) 计算内存大小。
sysconf( _SC_LOGIN_NAME_MAX ) 查看最大登录名长度;打印用%ld长整。
sysconf( _SC_HOST_NAME_MAX ) 查看最大主机长度;打印用%ld长整。
sysconf( _SC_OPEN_MAX ) 每个进程运行时打开的文件数目;打印用%ld长整。
sysconf(_SC_CLK_TCK) 查看每秒中跑过的运算速率;打印用%ld长整。*/

三、线程与cpu的绑定

线程于进程的绑定方法大体一致,需要注意的是线程绑定于进程的区别是所用函数不一样

线程绑定用到下面两个函数,跟进程类似就不做详细说明,下面直接贴出函数原型:

 NAME
pthread_setaffinity_np, pthread_getaffinity_np - set/get CPU affinity of a thread SYNOPSIS
#define _GNU_SOURCE /* See feature_test_macros(7) */
#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); Compile and link with -pthread. DESCRIPTION
The pthread_setaffinity_np() function sets the CPU affinity mask of the thread thread to the CPU set pointed to by cpuset. If the call is successful, and the thread is not
currently running on one of the CPUs in cpuset, then it is migrated to one of those CPUs. The pthread_getaffinity_np() function returns the CPU affinity mask of the thread thread in the buffer pointed to by cpuset. For more details on CPU affinity masks, see sched_setaffinity(). For a description of a set of macros that can be used to manipulate and inspect CPU sets, see CPU_SET(). The argument cpusetsize is the length (in bytes) of the buffer pointed to by cpuset. Typically, this argument would be specified as sizeof(cpu_set_t). (It may be some other
value, if using the macros described in CPU_SET() for dynamically allocating a CPU set.) RETURN VALUE
On success, these functions return ; on error, they return a nonzero error number

下面同样是个具体的例子:将当前线程绑定到0、1、2、3号cpu上

 #define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h> void *testfunc(void *arg)
{
int i, cpus = ;
cpu_set_t mask;
cpu_set_t get; cpus = sysconf(_SC_NPROCESSORS_CONF);
printf("this system has %d processor(s)\n", cpus); CPU_ZERO(&mask);
for (i = ; i < ; i++) { /*将0、1、2、3添加到集合中*/
CPU_SET(i, &mask);
} /* 设置cpu 亲和性(affinity)*/
if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < ) {
fprintf(stderr, "set thread affinity failed\n");
} /* 查看cpu 亲和性(affinity)*/
CPU_ZERO(&get);
if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) < ) {
fprintf(stderr, "get thread affinity failed\n");
} /* 查看当前线程所运行的所有cpu*/
for (i = ; i < cpus; i++) {
if (CPU_ISSET(i, &get)) {
printf("this thread %d is running in processor %d\n", (int)pthread_self(), i);
}
}
sleep(); //查看 pthread_exit(NULL);
} int main(int argc, char *argv[])
{
pthread_t tid;
if (pthread_create(&tid, NULL, (void *)testfunc, NULL) != ) {
fprintf(stderr, "thread create failed\n");
return -;
} pthread_join(tid, NULL);
return ;
}

运行结果如下:

 [root@localhost thread]# ./test
this system has processor(s)
this thread is running in processor
this thread is running in processor
this thread is running in processor
this thread is running in processor

linux进程、线程与cpu的亲和性(affinity)的更多相关文章

  1. [转帖]判断Linux进程在哪个CPU核运行的方法

    判断Linux进程在哪个CPU核运行的方法   原文网址:http://www.embeddedlinux.org.cn/html/xinshourumen/201601/30-5013.html 问 ...

  2. Linux进程线程学习笔记:运行新程序

    Linux进程线程学习笔记:运行新程序                                         周银辉 在上一篇中我们说到,当启动一个新进程以后,新进程会复制父进程的大部份上下 ...

  3. Linux 进程,线程 -- (未完)

    系统调用 Linux 将系内核的功能接口制作成系统调用, Linux 有 200 多个系统调用, 系统调用是操作系统的最小功能单元. 一个操作系统,以及基于操作系统的应用,都不能实现超越系统调用的功能 ...

  4. Linux编程之《进程/线程绑定CPU》

    Intro----- 通常我们在编写服务器代码时,可以通过将当前进程绑定到固定的CPU核心或者线程绑定到固定的CPU核心来提高系统调度程序的效率来提高程序执行的效率,下面将完整代码贴上. /***** ...

  5. Linux 进程,线程,线程池

    在linux内核,线程与进程的区别很小,或者说内核并没有真正所谓单独的线程的概念,进程的创建函数是fork,而线程的创建是通过clone实现的. 而clone与fork都是调用do_fork(),差异 ...

  6. linux 进程线程

    linux下进程的最大线程数.进程最大数.进程打开的文件数   ===========最大线程数============== linux 系统中单个进程的最大线程数有其最大的限制 PTHREAD_TH ...

  7. linux 进程线程拓展

    依次参考: 多线程和多进程的区别(小结) Linux内核源代码分析——fork()原理&多进程网络模型 Linux写时拷贝技术(copy-on-write) linux内核 do_fork 函 ...

  8. Linux中CPU亲和性(affinity)

    0.准备知识 超线程技术(Hyper-Threading):就是利用特殊的硬件指令,把两个逻辑内核(CPU core)模拟成两个物理芯片, 让单个处理器都能使用线程级并行计算,进而兼容多线程操作系统和 ...

  9. 【操作系统之十二】分支预测、CPU亲和性(affinity)

    一.分支预测 当包含流水线技术的处理器处理分支指令时就会遇到一个问题,根据判定条件的真/假的不同,有可能会产生转跳,而这会打断流水线中指令的处理,因为处理器无法确定该指令的下一条指令,直到分支执行完毕 ...

随机推荐

  1. Linux grep命令分析以及C语言版本的实现

    1.作用 Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expression Print,表示全 ...

  2. 某集团BI决策系统建设方案分享

    企业核心竞争能力的提升,需要强壮的运营管理能力,需要及时.准确.全面的业务数据分析作为参考与支撑. 某集团是大型时尚集团,内部报表系统用的QlikView,但是管理分配不够灵活,不能满足数据安全的要求 ...

  3. imx51-linux的cpuinfo之分析

    这两天客户提出来,我们的平板cat /proc/cpuinfo出来的信息中的serial怎么是0. 客户就是上帝啊,没办法,分析找问题贝. 我们先看一下目前的cat /proc/cpuinfo的信息: ...

  4. FPGA学习笔记(一)Verilog语法基础

    一.变量类型 ①数值 数值表示采用 <二进制位数>'<数值表示的进制><数值>的结构. 其中进制可以为b.o.d.h分别代表二.八.十.十六进制. 例如22'd0代 ...

  5. The 16th tip of DB Query Analyzer

                   The 16th tip of DB Query Analyzer      ---- SQL Schedule will be executed even DBMS h ...

  6. Universal-Image-Loader源码分析,及常用的缓存策略

    讲到图片请求,主要涉及到网络请求,内存缓存,硬盘缓存等原理和4大引用的问题,概括起来主要有以下几个内容: 原理示意图 主体有三个,分别是UI,缓存模块和数据源(网络).它们之间的关系如下: ① UI: ...

  7. PS 滤镜—— 径向模糊

    这里给出灰度图像的模糊算法,彩色图像只要分别对三个通道做模糊即可. %%%  radiation blur %%%   clc; clear all; close all; I=imread('4.j ...

  8. 实现去哪儿来回机票选择的view

    最近有个控件是实现和去哪儿和阿里旅行的app的选择日历效果,反编译没有效果的情况下我自己实现了个,大致的原理是: 上面是产品需要实现的效果,我看了下不就是一个ListView+gridView就能实现 ...

  9. EventQueue.invokeLater(new Runnable())

    public class EventQueueextends ObjectEventQueue 是一个与平台无关的类,它将来自于底层同位体类和受信任的应用程序类的事件列入队列. 它封装了异步事件指派机 ...

  10. asp.net 分布式探讨之Session共享问题

    ---恢复内容开始--- Session共享是分布式架构设计中的一大难点,尽管session共享的解决方案不少,但是.net 下的解决方案还是比较少,而且说明文档也很少. 之前尝试用memcached ...