一、简介

2.6内核上一个新的特性就是per-CPU变量。顾名思义,就是每个处理器上有此变量的一个副本。
per-CPU的最大优点就是,对它的访问几乎不需要锁,因为每个CPU都在自己的副本上工作。
tasklet、timer_list等机制都使用了per-CPU技术。

二、API使用

注意,2.6内核是抢占式的。
所以在访问per-CPU变量时,应使用特定的API来避免抢占,即避免它被切换到另一个CPU上被处理。

per-CPU变量可以在编译时声明,也可以在系统运行时动态生成

实例一:

编译期间创建一个per-CPU变量:
DEFINE_PER_CPU(int,my_percpu); //声明一个变量
DEFINE_PER_CPU(int[3],my_percpu_array); //声明一个数组 使用编译时生成的per-CPU变量:
ptr = get_cpu_var(my_percpu); //
使用ptr
put_cpu_var(my_percpu); // 当然,也可以使用下列宏来访问特定CPU上的per-CPU变量
per_cpu(my_percpu, cpu_id); // per-CPU变量导出,供模块使用:
EXPORT_PER_CPU_SYMBOL(per_cpu_var);
EXPORT_PER_CPU_SYMBOL_GPL(per_cpu_var);

实例二:

动态分配per-CPU变量:
void *alloc_percpu(type);
void *__alloc_percpu(size_t size, size_t align); 使用动态生成的per-CPU变量:
int cpu;
cpu = get_cpu();
ptr = per_cpu_ptr(my_percpu);
//使用ptr
put_cpu();

三、实现

使用上面的API为什么就能避免抢占问题呢,看看代码实现就知道了:

#define get_cpu_var(var) (*({ \
extern int simple_identifier_##var(void); \
preempt_disable(); \
&__get_cpu_var(var); }))
#define put_cpu_var(var) preempt_enable()
#define get_cpu() ({ preempt_disable(); smp_processor_id(); })
#define put_cpu() preempt_enable()

关键就在于 preempt_disable 和 preempt_enable 两个调用,分别是禁止抢占和开启抢占
抢占相关的东东以后再看

per-cpu 变量的引入有效的解决了SMP系统中处理器对锁得竞争,每个cpu只需访问自己的本地变量。本文阐述了per-cpu变量在2.6内核上的实现和相关操作。
在系统编译阶段我们就手工的定义了一份所有的per-cpu变量,这些变量的定义是通过宏DEFINE_PER_CPU实现的:
11 #define DEFINE_PER_CPU(type, name) \
12 __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name

从上面的代码我们可以看出,手工定义的所有per-cpu变量都是放在.data.percpu段的。注意上面的宏只是在SMP体系结构下才如此定义。如果不是SMP结构的计算机那么只是简单的把所有的per-cpu变量放到全局变量应该放到的地方。

单CPU的per-cpu变量定义:

  27 #else /* ! SMP */
28
29 #define DEFINE_PER_CPU(type, name) \
30 __typeof__(type) per_cpu__##name

在了解了上述代码后,我们还必须弄清楚一点:单CPU的计算机中使用的per-cpu变量就是通过上述宏定义的放在全局数据区的per-cpu变 量。而在SMP体系结构中,我们使用却不是放在.data.percpu段的变量,设想一下如果使用这个变量,那么应该哪个CPU使用呢?事实上,SMP 下,每个cpu使用的都是在.data.percpu段中的这些per-cpu变量的副本,有几个cpu就创建几个这样的副本。

在系统初始化期 间,start_kernel()函数中调用setup_per_cpu_areas()函数,用于为每个cpu的per-cpu变量副本分配空间,注意 这时alloc内存分配器还没建立起来,该函数调用alloc_bootmem函数为初始化期间的这些变量副本分配物理空间。

 332 static void __init setup_per_cpu_areas(void)
/* */
333 {
334 unsigned long size, i;
335 char *ptr;
336
337 /* Copy section for each CPU (we discard the original) */
338 size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
339 #ifdef CONFIG_MODULES
340 if (size < PERCPU_ENOUGH_ROOM)
341 size = PERCPU_ENOUGH_ROOM;
342 #endif
343
344 ptr = alloc_bootmem(size * NR_CPUS);
345
346 for (i = 0; i < NR_CPUS; i++, ptr += size) {
347 __per_cpu_offset[i] = ptr - __per_cpu_start;
348 memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
349 }
350 }
351 #endif /* !__GENERIC_PER_CPU */

上述函数,在分配好每个cpu的per-cpu变量副本所占用的物理空间的同时,也对__per_cpu_offset[NR_CPUS]数组进行了初始化用于以后找到指定CPU的这些per-cpu变量副本。

  15 #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
16 #define __get_cpu_var(var) per_cpu(var, smp_processor_id())

这两个宏一个用于获得指定cpu的per-cpu变量,另一个用于获的本地cpu的per-cpu变量,可以自己分析一下。

from:http://blog.chinaunix.net/uid-24148050-id-300576.html

linux:CPU私有变量(per-CPU变量)的更多相关文章

  1. linux内核中的每cpu变量

    一.linux中的每cpu变量 看linux内核代码的时候,会发现大量的per_cpu(name, cpu),get_cpu_var(name)等出现cpu字眼的语句.从语句的意思可以看出是要使用与当 ...

  2. linux内核同步之每CPU变量、原子操作、内存屏障、自旋锁【转】

    转自:http://blog.csdn.net/goodluckwhh/article/details/9005585 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] 一每 ...

  3. 8.变量内存CPU原理

    编译器先明确是什么类型,然后明确变量名,变量表管理所有的变量,不在变量表内部的变量不能引用.每个变量对应一整块内存 a+1所计算出来的值在寄存器中,只有变量可以被赋值,变量必须在内存里面 c语言内嵌汇 ...

  4. Linux学习之十一、环境变量的功能

    环境变量的功能 可以利用两个命令来查阅,分别是 env 与 export 呢! 范例一:列出目前的 shell 环境下的所有环境变量与其内容. [root@www ~]# env SHELL 告知我们 ...

  5. Linux bash篇,基本信息和变量

    1.shells目录       /etc/shells 2.查看用户所具有的shell    /etc/passwd 3.查看当前用户执行过的shell      ~/.bash_history 4 ...

  6. Linux下如何查看高CPU占用率线程

    转于:http://www.cnblogs.com/lidabo/p/4738113.html 目录(?)[-] proc文件系统 proccpuinfo文件 procstat文件 procpidst ...

  7. linux top命令中各cpu占用率含义

    linux top命令中各cpu占用率含义 [尊重原创文章摘自:http://www.iteye.com/topic/1137848]0.3% us 用户空间占用CPU百分比 1.0% sy 内核空间 ...

  8. 如何用Linux的命令正确识别cpu的个数和核数【转】

    判断依据: 1.具有相同core id的cpu是同一个core的超线程. 2.具有相同physical id的cpu是同一颗cpu封装的线程或者cores. 英文版: 1.Physical id an ...

  9. linux 下查看机器是cpu是几核的(转)

    几个cpu more /proc/cpuinfo |grep "physical id"|uniq|wc -l 每个cpu是几核(假设cpu配置相同) more /proc/cpu ...

随机推荐

  1. HTML的各种基本标签

      一 .head中的各种标签                1.       <!DOCTYPE html><html>文档类型声明   声明当前文件是一个HTML5文件文档 ...

  2. libevent中evmap实现(哈希表)

    libevent中,需要将大量的监听事件event进行归类存放,比如一个文件描述符fd可能对应多个监听事件,对大量的事件event采用监听的所采用的数据结构是event_io_map,其实现通过哈希表 ...

  3. ORACLE 行转列 案例解析

    -- 创建 国家城市信息 临时表                  WITH T_NATION_CITY_INFO AS(        SELECT '北京'   AS CITY,'中国' AS N ...

  4. java---interrupt、interrupted和isInterrupted的区别

    1.interrupt()  interrupt方法用于中断线程.调用该方法的线程的状态为将被置为"中断"状态. 注意:线程中断仅仅是置线程的中断状态位,不会停止线程.需要用户自己 ...

  5. [LeetCode] Set Mismatch 设置不匹配

    The set S originally contains numbers from 1 to n. But unfortunately, due to the data error, one of ...

  6. volume 方式使用 Secret - 每天5分钟玩转 Docker 容器技术(157)

    Pod 可以通过 Volume 或者环境变量的方式使用 Secret,今天先学习 Volume 方式. Pod 的配置文件如下所示: ① 定义 volume foo,来源为 secret mysecr ...

  7. TCP三次握手详解及释放连接过程

    TCP在传输之前会进行三次沟通,一般称为"三次握手",传完数据断开的时候要进行四次沟通,一般称为"四次挥手". 两个序号和三个标志位: (1)序号:seq序号, ...

  8. Java数据类型与SQL数据类型的映射

    Java数据类型与SQL数据类型的映射 SQL Data Type Java Data Type char/varchar/longvarchar String numeric/decimal jav ...

  9. 线段树——codevs 1690 开关灯

    先来一发题目: 1690 开关灯 时间限制: 1 s 空间限制: 128000 KB 题目描述 Description YYX家门前的街上有N(2<=N<=100000)盏路灯,在晚上六点 ...

  10. [CTSC 1999]拯救大兵瑞恩&[网络流24题]孤岛营救问题

    Description $1944$ 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图.迷宫 ...