一、简介

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. packer的基本使用

    工具的产生,一定是为了解决某些痛点,那么痛点是? 你们在工作中是不是经常用到各种云?aliyun, aws, digitalOcean and so on? 你们的规模不大不小,经常去云平台上点一点, ...

  2. ng-select 下拉的两种方式

    <!doctype html><html lang="en"><head> <meta charset="UTF-8" ...

  3. C# 获取字符串中的英文字母

    string str20 = "ABC123"; string strSplit1,strSplit2; //取出字符串中所有的英文字母 strSplit1 = Regex.Rep ...

  4. wifi 破解笔记

        最近小夜刚刚学习了无线WiFi的密码破解,感觉很神奇,不过以下操作都是作为学习测试的内容进行的,希望志同道合的小伙伴切不要触碰法律的红线哦!       话不多说,直接上硬菜.     实验环 ...

  5. bzoj 4180: 字符串计数

    Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', ...

  6. 【CodeVs 6128 Lence的方块们】

    ·希望除了内部人员以外能有人通过这道题,因为这是大米饼第一次改编的题 ·我所见到的"本题原版"的题解也很少,搜索一下应该是: #include<stdio.h> #in ...

  7. BZOJ2989 数列(二进制分组)

    这题其实可以cdq分治做,但是如果强制在线的话,这里有个牛逼方法叫二进制分组. 它的基本思想是把修改操作按二进制分组,遇到修改就在尾部加一个,并与之前的合并,比如之前有23(16+4+2+1)个,加了 ...

  8. 好久没用IJ写Java 之 《求输入的一个数中包含奇数、偶数、零的个数》

    /** *Created by xuzili at 22:12 on 2018/4/4 */ // 以上注释使用了IntelliJ Idea的File-Settings-Editor-Live Tem ...

  9. 线性表 linear_list 顺序存储结构

    可以把线性表看作一串珠子 序列:指其中的元素是有序的 注意last和length变量的内在关系 注意:将元素所占的空间和表长合并为C语言的一个结构类型 静态分配的方式,分配给一个固定大小的存储空间之后 ...

  10. java怎样获取CPU占用率和硬盘占用率

    通过jmx可以监控vm内存使用,系统内存使用等,以下是网上某博客代码,特点是通过window和linux命令获得CPU使用率. 利用java程序实现获取计算机cpu利用率和内存使用信息. packag ...