OK6410A 开发板 (八) 67 linux-5.11 OK6410A linux 内核同步机制 per-cpu的实现

  • 解决的问题是什么
SMP 引起的竞态 // 其实是避开了 SMP的竞态 , 因为 每个cpu 一个同名变量,SMP间根本不会有竞态发生
不能解决 其他原因 引起的竞态
  • 其他要点
在 CONFIG_SMP  下才有意义, 不配置 CONFIG_SMP   也能用,但是就失去了他的意义(作用,) 
	// 没有SMP,SMP引起的竞态根本就不存在了
	// 而 per-cpu 就是 因为 SMP引起的竞态 才被设计出来的

在某些体系结构上,per-CPU变量可使用的地址空间是受限的,要尽量保持这些变量比较小 // 在 arm 上好像没限制

per-cpu 并没有利用 同步原语 和 屏障,因为 per-cpu的实现 是 避开了SMP的竞态

  • 参考资料
https://zhuanlan.zhihu.com/p/157563328
https://zhuanlan.zhihu.com/p/260986194
应用场景及API
per-cpu 机制 解决了 三个情景下的 per-cpu 变量
	1. 内核静态percpu变量
	2. 模块静态percpu变量
	3. 动态percpu变量

	// 每个情景的实现有相同部分,又有不同部分

per-cpu 机制 针对 三个情景 提供了 几种初始化,几种api
	A. 	 per-cpu机制的初始化 setup_per_cpu_areas
	
	B1.  内核静态percpu变量的定义  DEFINE_PER_CPU(type, name)
	B2.  模块静态percpu变量的定义  DEFINE_PER_CPU(type, name)
	B3.  动态percpu变量的定义		alloc_percpu(type)
	
	C.   percpu变量地址的获取 	this_cpu_ptr(var)
	D.   percpu变量的获取			per_cpu(var,cpu)
per-cpu变量 内存相关
  • per-cpu变量 相关内存的初始化
给每一个cpu分配了一块内存pcpu_area(xKB)每个cpu的xKB内存都是连续的(同group的才连续).
N个cpu对应的内存大小是 N*x
一个xKB内存分块 分为 static reserved dynamic
// 整个 NR_CPU 个内存块 从 pcpu_base_addr 开始

每个cpu对应的内存块 大小是怎么决定的
// 根据 下面的三个值 以及一些 最大最小值(某个区间最小不能比什么小) 决定的值为Y,然后Y*cpu个数= x
// 1. static_size = __per_cpu_end - __per_cpu_start;
// 2. pcpu_embed_first_chunk 的第一个参数:reserved_size
// 2. pcpu_embed_first_chunk 的第二个参数:dyn_size

从 pcpu_base_addr  开始的 N*x大小的 空间是什么时候申请的
//setup_per_cpu_areas->pcpu_embed_first_chunk->alloc_fn/pcpu_dfl_fc_alloc->memblock_virt_alloc_from_nopanic
  • per-cpu变量 相关内存的管理方法(pcpu_slot)
一个xKB内存分块 分为 static reserved dynamic
reserved dynamic 被 chunk 管理 ,static 没有用 chunk 管理

per-cpu 有一个内存代理商 pcpu_slot , 管理了 这些 reserved dynamic
pcpu_slot 也是像 buddy 一样(利用order)管理内存的

pcpu_slot  是 从 buddy 和 memblock 申请的内存,申请的内存通过pcpu_chunk_relocate 加入 per-cpu // pcpu_slot 没有内存时,会从buddy申请
	其中一个内存块 pcpu_first_chunk 是 从 memblock 申请的
	其他的内存 都是从buddy申请的  

pcpu_slot  的消费者
	per-cpu 创建per-cpu变量的时候,会用到内存,则会从 pcpu_slot  申请
	只供 动态percpu变量 使用 alloc_percpu   申请
	模块静态percpu变量 也会使用
per-cpu变量的存放与获取
percpu变量的存放
	内核静态percpu变量 被 复制到 每个cpu的内存块的static区域,static 不可扩展(不存在空间不够的情况) 
	模块静态percpu变量 被 复制到 每个cpu的内存块的reserved区域,空间不够,reserved 可扩展
	动态percpu变量	 被 放在   每个cpu的内存块的dynamic 区域,空间不够,dynamic 可扩展

percpu变量的获取
	percpu变量存放后 给出一个 值 ptr,通过this_cpu_ptr(即ptr + delta + pcpu_unit_offsets[cpu]) 获取 percpu变量的 实际地址
	针对 内核静态percpu变量 	: ptr 的值 位于 __per_cpu_start __per_cpu_end 之间
		// 值是在编译的时候决定的
	针对 模块静态percpu变量 	: ptr 的值 为 chunk->base_addr + off - delta // delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
		// 针对cpu0不同的per-cpu变量, off 肯定不同,chunk->base_addr可能不同
	针对 动态percpu变量 	 	: ptr 的值 为 chunk->base_addr + off - delta // 和 模块静态percpu变量 的chunk 不是一个chunk
		// 针对cpu0不同的per-cpu变量, off 肯定不同,chunk->base_addr可能不同
其他
// linux-4.0

setup_per_cpu_areas
	pcpu_embed_first_chunk
		pcpu_build_alloc_info
			ptr = memblock_virt_alloc_nopanic(PFN_ALIGN(ai_size), 0) // 1000
		areas = memblock_virt_alloc_nopanic(areas_size, 0); // 1000

		ptr = alloc_fn(cpu, gi->nr_units * ai->unit_size, atom_size);/pcpu_dfl_fc_alloc
			memblock_virt_alloc_from_nopanic // 2c000	// ---------------------- per-cpu变量区域的申请,4核心,一个0xb000大小

		pcpu_setup_first_chunk
			group_offsets = memblock_virt_alloc // 4
			group_sizes = memblock_virt_alloc 	// 4
			unit_map = memblock_virt_alloc 			// 10
			unit_off = memblock_virt_alloc 			// 10 
			pcpu_slot = memblock_virt_alloc(		// 78
			schunk = memblock_virt_alloc 			// 44
			dchunk = memblock_virt_alloc 			// 44
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值