per cpu
本帖最后由 镇水铁牛 于 2015-04-01 20:02 编辑per cpu的实现类似数组+禁止抢占,如果原cpu id为1的线程现在被迁移到cpu id为2上,假设没有要访问per cpu数据的线程,会去运行在cpu 1上,
1. 那岂不是其原cpu id为1的数据就无法被访问了?
2. 还有它只是禁止抢占,没有禁止本地中断,如果岂不是中断中不能访问per cpu了? 2.中断上下文会发生内核抢占吗?:em14: 1. “假设没有要访问per cpu数据的线程,会去运行在cpu 1上,”,这句话没太理解……
=============================================
per_cpu的一个典型场景是作为counter计数。
如果不使用per_cpu,那势必要使用全局counter+全局lock或者使用atomic_add,smp下的性能受影响。
换成per_cpu,每个cpu只更新自己的counter就可以了,并且per_cpu变量的内存布局,尽量保证不同cpu的counter不共享cacheline,这样最大程度的保证性能。
关于为什么要disable抢占,我的理解是,由于更新操作不是原子的,要避免这个r-m-w序列分布在不同的cpu上来完成。
如果需要获取全局counter的值,只需要把所有cpu的局部counter遍历一下累加起来就行。
需要注意,访问其它cpu的per_cpu counter时,其它cpu还是有可能在同时更新其local counter的,所以得到的全局counter只是一个瞬间的不严格的快照而已。(可以称为“测不准”么 :p)
遍历过程本身不需要disable抢占,通常循环变量都是stack上的局部变量,就算变量线程在多个cpu之间跳来跳去,总是能保证安全完成遍历的。——也许hotplug cpu的场景除外。
问题1:
/*
* We do not migrate tasks that are:
* 1) running (obviously), or
* 2) cannot be migrated to this CPU due to cpus_allowed, or
* 3) are cache-hot on their current CPU.
*/
问题2:
如果你真要在中断中访问per cpu,范例如下:
local_irq_save(flags);
pvec = &__get_cpu_var(lru_rotate_pvecs);
if (!pagevec_add(pvec, page))
pagevec_move_tail(pvec);
local_irq_restore(flags); 2. 可以看一下 Document/local_ops.txt
- Preemption (or interrupts) must be disabled when using local ops in
process context to make sure the process won't be migrated to a
different CPU between getting the per-cpu variable and doing the
actual local op.
- When using local ops , no special care must be
taken on a mainline kernel, since they will run on the local CPU [with
preemption already disabled]. I suggest, however, to explicitly
disable preemption anyway to make sure it will still work correctly on
-rt kernels.
您举的这个例子,入口/出口用到了irq_save/irq_restore,说明这段代码即可被用在interrupt context,也可用在process context。
如果仅用在interrupt context,就没有必要save和restore了。
不过也许您讨论的上下文是-rt内核,那上面那段话就不成立了。
回复 4# 镇水铁牛
回复 5# nswcfd
我把2.6初期的内核和最新的内核对比着看,是有很大差异。
页:
[1]