本文主要是介绍linux -- per-CPU变量,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
per-CPU变量
per-CPU变量是一种存在与每个CPU本地的变量,对于每一种per-CPU变量,每个CPU在本地都有一份它的副本。
per-CPU变量的优点
- 多处理器系统(smp)中无需考虑与其他处理器的竞争问题(并非绝对的)
- 可以利用处理器本地的cache硬件,提高访问速度
per-CPU变量的分类
按照分配内存空间的类型来看,有两种:
- 静态per-CPU变量
- 动态per-CPU变量
静态的per-CPU变量在编译期就静态分配,动态per-CPU变量在程序运行时动态分配。
per-CPU变量的实现机制
静态per-CPU变量
相关宏
90 #ifndef PER_CPU_BASE_SECTION91 #ifdef CONFIG_SMP92 #define PER_CPU_BASE_SECTION ".data..percpu"93 #else94 #define PER_CPU_BASE_SECTION ".data"95 #endif96 #endif
定义和声明
4/*5 * Base implementations of per-CPU variable declarations and definitions, where6 * the section in which the variable is to be placed is provided by the7 * 'sec' argument. This may be used to affect the parameters governing the8 * variable's storage.9 *
/*
per-CPU变量声明和定义的基础实现,变量被放置的section由sec参数提供,这被用于影响管理参数变量的存储方式注意!用于声明和定义的sections必须匹配,以免由于编译器生成错误的代码来访问该节而发生链接错误。
*/10 * NOTE! The sections for the DECLARE and for the DEFINE must match, lest11 * linkage errors occur due the compiler generating the wrong code to access12 * that section.13 */14#define __PCPU_ATTRS(sec) \15 __percpu __attribute__((section(PER_CPU_BASE_SECTION sec))) \16 PER_CPU_ATTRIBUTES1718#define __PCPU_DUMMY_ATTRS \19 __attribute__((section(".discard"), unused))20#ifdef HAVE_MODEL_SMALL_ATTRIBUTE21# define PER_CPU_ATTRIBUTES __attribute__((__model__ (__small__)))22#endif73 * Normal declaration and definition macros.74 */75#define DECLARE_PER_CPU_SECTION(type, name, sec) \76 extern __PCPU_ATTRS(sec) __typeof__(type) name7778#define DEFINE_PER_CPU_SECTION(type, name, sec) \79 __PCPU_ATTRS(sec) PER_CPU_DEF_ATTRIBUTES \80 __typeof__(type) name81#endif83/*84 * Variant on the per-CPU variable declaration/definition theme used for85 * ordinary per-CPU variables.86 */87#define DECLARE_PER_CPU(type, name) \88 DECLARE_PER_CPU_SECTION(type, name, "")90#define DEFINE_PER_CPU(type, name) \91 DEFINE_PER_CPU_SECTION(type, name, "")
这么多宏,最后其实就是DEFINE_PER_CPU和DECLARE_PER_CPU最重要。
举个例子:
DECLARE_PER_CPU(int, python);
DEFINE_PER_CPU(int, python);
被展开为:
extern __percpu __attribute__((section("data..percou"))) int python;
__percpu __attribute__((section("data..percou"))) int python;
这里的定义实际把python变量放到.data…percpu段里。
看链接脚本:kernel/vmlinux.lds
定义了percpu区域的输出段,简单版本,需要对齐
所有percpu变量都会放到这个段里,__per_cpu_start和__per_cpu_end分别用于标识该区域的起始地址与终止地址。
在C代码中使用外部变量:extern char __per_cpu_load[], __per_cpu_start[], __per_cpu_end[];
来引用他们。
108 INIT_TEXT_SECTION(PAGE_SIZE)109 . = ALIGN(16);110 INIT_DATA_SECTION(16)111 PERCPU(4)676/**677 * PERCPU - define output section for percpu area, simple version678 * @align: required alignment679 *680 * Align to @align and outputs output section for percpu area. This681 * macro doesn't maniuplate @vaddr or @phdr and __per_cpu_load and682 * __per_cpu_start will be identical.683 *684 * This macro is equivalent to ALIGN(align); PERCPU_VADDR( , ) except685 * that __per_cpu_load is defined as a relative symbol against686 * .data.percpu which is required for relocatable x86_32687 * configuration.688 */689#define PERCPU(align) \690 . = ALIGN(align); \691 .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { \692 VMLINUX_SYMBOL(__per_cpu_load) = .; \693 VMLINUX_SYMBOL(__per_cpu_start) = .; \694 *(.data.percpu.first) \695 *(.data.percpu.page_aligned) \696 *(.data.percpu) \697 *(.data.percpu.shared_aligned) \698 VMLINUX_SYMBOL(__per_cpu_end) = .; \699 }
per-CPU变量使用案例
一个非常典型的案例:计数器
per-CPU变量非常适合做统计计数,内核专门有一个给予per-CPU变量设计的计数器(lib/percpu-counter.c)
比如在网络子系统中,要计算系统接受到的各类网络包的数量,这些包更新的频率是极快的,这就需要percpu的支持,系统中每个处理器都有这么一个对网络包数量进行计量的副本,变量更新时无需考虑多处理器竞争问题,想算出总数是只需将所有处理器的同一percpu副本相加即可。
这篇关于linux -- per-CPU变量的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!