一、简介

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. BZOJ 4551[Tjoi2016&Heoi2016]树(树链剖分+二分)

    Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记 ...

  2. C# 删除文件夹

    三种方法 1.这种方法简单,能删除文件夹内的所有文件(文件及子目录) DirectoryInfo di = new DirectoryInfo(string Path);         di.Del ...

  3. 文件上传详解 (HTML FILE)

    FileUpload 对象 在 HTML 文档中 <input type="file"> 标签每出现一次,一个 FileUpload 对象就会被创建. 该元素包含一个文 ...

  4. [LeetCode] Number Of Corner Rectangles 边角矩形的数量

    Given a grid where each entry is only 0 or 1, find the number of corner rectangles. A corner rectang ...

  5. Field的getModifiers()方法返回int类型值表示该字段的修饰符

    其中,该修饰符是java.lang.reflect.Modifier的静态属性. 对应表如下: PUBLIC: 1PRIVATE: 2PROTECTED: 4STATIC: 8FINAL: 16SYN ...

  6. 获取IE下载历史的具体实现

    背景: 博主去年在国内某知名互联网公司做URL安全检测时写的一份草稿. 最后却没用到项目上. 当时主要想用于URL网址安全的入库以及更新,需要建立下载文件以及URL的安全属性关联. 逻辑大致是这样的: ...

  7. 基于vfs实现自己的文件系统

    1.Linux 文件系统组成结构 linux文件系统有两个重要的特点:一个是文件系统抽象出了一个通用文件表示层--虚拟文件系统或称做VFS.另外一个重要特点就是它的文件系统支持动态安装(或说挂载等), ...

  8. 【NOIP2013】传染病控制

    题目背景 近来,一种新的传染病肆虐全球.蓬莱国也发现了零星感染者,为防止该病在蓬莱国大范围流行,该国政府决定不惜一切代价控制传染病的蔓延.不幸的是,由于人们尚未完全认识这种传染病,难以准确判别病毒携带 ...

  9. ●BZOJ 3129 [Sdoi2013]方程

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3129 题解: 容斥,扩展Lucas,中国剩余定理 先看看不管限制,只需要每个位置都是正整数时 ...

  10. 【Codeforces Round #435 (Div. 2) A B C D】

    CF比赛题目地址:http://codeforces.com/contest/862 A. Mahmoud and Ehab and the MEX ·英文题,述大意:      输入n,x(n,x& ...