博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux:CPU私有变量(per-CPU变量)
阅读量:5760 次
发布时间:2019-06-18

本文共 3022 字,大约阅读时间需要 10 分钟。

一、简介


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:

转载于:https://www.cnblogs.com/hehehaha/p/6332293.html

你可能感兴趣的文章
我的友情链接
查看>>
Pytorch中的BatchNorm
查看>>
Go语言中多字节字符的处理
查看>>
我的友情链接
查看>>
P3376 【模板】网络最大流
查看>>
随机数 iPhone开发随想:rand()还是arc4random()
查看>>
将时间字符串转换为时间类型
查看>>
DBD模块不能安装
查看>>
GPU架构
查看>>
【Android】【Gradle】【Jenkins】构建Android apk时版本自增设计
查看>>
(转)网上看的一篇文章,感觉会给程序员一些启发
查看>>
myeclipse快捷键大全
查看>>
explain执行计划分析
查看>>
我的友情链接
查看>>
PHP5.4 运算符的 流程控制
查看>>
linux系统启动流程
查看>>
基于web2.0学习平台
查看>>
Window/Unix服务器维护必备的8个小常识
查看>>
lucene5.0建立索引并进行查找
查看>>
CSVDE批量导入域用户
查看>>