求问percpu相关理解

magicphenix 2013-04-11 05:12:33
对于percpu这种同步机制,我的大致理解是每个cpu都有一个副本,这样可以每个cpu之间不干扰。
对此,我有几个问题:
1.同一个变量会在不同cpu上有不同副本,那这些副本直接需要同步么?怎么同步?(还是说这个变量只会在一个cpu上使用?万一有多个cpu运行同一段代码?)
2.有些资料上说percpu不提供对异步函数访问的保护,因此在同一个CPU上还要另外的同步原语的协作。对于这句话理解不是很清楚。用percpu的时候会禁止内核抢占,所以其实内核线程是不会发生冲突的?(对这个被保护的变量)再者,就算上用户线程上在单cpu上的操作,这个percpu本身就和异步函数在单个cpu上操作不在一个层面上吧?percpu是保护多cpu的
...全文
197 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
pro_or_gram 2013-04-23
  • 打赏
  • 举报
回复
http://www.makelinux.net/ldd3/chp-8-sect-5 有时间的时候,我会全部翻译一下。 8.5. Per-CPU Variables Per-CPU variables are an interesting 2.6 kernel feature. When you create a per-CPU variable, each processor on the system gets its own copy of that variable. This may seem like a strange thing to want to do, but it has its advantages. Access to per-CPU variables requires (almost) no locking, because each processor works with its own copy. Per-CPU variables can also remain in their respective processors' caches, which leads to significantly better performance for frequently updated quantities. 每个CPU都有一份该变量的拷贝,看起来挺怪异的,但是这样做是有好处的。访问per-CPU变量几乎不需要锁,因为每一个处理器有它自己的一份拷贝。per-CPU变量也可以驻留在各自的处理器的caches中,这对经常更新的量而言,有了很好的性能提升。 A good example of per-CPU variable use can be found in the networking subsystem. The kernel maintains no end of counters tracking how many of each type of packet was received; these counters can be u pdated thousands of times per second. Rather than deal with the caching and locking issues, the networking developers put the statistics counters into per-CPU variables. Updates are now lockless and fast. On the rare occasion that user space requests to see the values of the counters, it is a simple matter to add up each processor's version and return the total. The declarations for per-CPU variables can be found in <linux/percpu.h>. To create a per-CPU variable at compile time, use this macro: DEFINE_PER_CPU(type, name); If the variable (to be called name) is an array, include the dimension information with the type. Thus, a per-CPU array of three integers would be created with: DEFINE_PER_CPU(int[3], my_percpu_array); Per-CPU variables can be manipulated without explicit locking—almost. Remember that the 2.6 kernel is preemptible; it would not do for a processor to be preempted in the middle of a critical section that modifies a per-CPU variable. It also would not be good if your process were to be moved to another processor in the middle of a per-CPU variable access. For this reason, you must explicitly use the get_cpu_var macro to access the current processor's copy of a given variable, and call put_cpu_var when you are done. The call to get_cpu_var returns an lvalue for the current processor's version of the variable and disables preemption. Since an lvalue is returned, it can be assigned to or operated on directly. For example, one counter in the networking code is incremented with these two statements: Per-CPU变量可以在没有显式的锁的情况下进行访问——几乎。记住,2.6的内核是可抢占的;对于一个处理器而言,不应该在修改per-CPU变量的临界区的中间发生抢占。如果你的进程在per-CPU变量访问的中间被移到了另外的处理器,也是不好的。基于这个原因,你必须显式地使用get_cpu_var这个宏来访问一个给定的变量在当前处理器上的拷贝,当对变量的访问结束后,调用put_cpu_var。调用get_cpu_vat会返回一个lvalue,也就是该变量在当前处理器上的一个版本,并关闭抢占。因为返回了一个lvalue,它可以被赋值,或者直接进行操作。 get_cpu_var(sockets_in_use)++; put_cpu_var(sockets_in_use); You can access another processor's copy of the variable with: 可以使用per_cpu(variable, int cpu_id)访问该变量在其他处理器上的拷贝 per_cpu(variable, int cpu_id); If you write code that involves processors reaching into each other's per-CPU variables, you, of course, have to implement a locking scheme that makes that access safe. 如果你写的代码中涉及到了不止一个处理器,并且它们互相引用对方的per-CPU变量,你当然需要实现一种机制,使得这种访问是安全的。 Dynamically allocated per-CPU variables are also possible. These variables can be allocated with: void *alloc_percpu(type); void *_ _alloc_percpu(size_t size, size_t align); In most cases, alloc_percpu does the job; you can call _ _alloc_percpu in cases where a particular alignment is required. In either case, a per-CPU variable can be returned to the system with free_percpu. Access to a dynamically allocated per-CPU variable is done via per_cpu_ptr: per_cpu_ptr(void *per_cpu_var, int cpu_id); This macro returns a pointer to the version of per_cpu_var corresponding to the given cpu_id. If you are simply reading another CPU's version of the variable, you can dereference that pointer and be done with it. If, however, you are manipulating the current processor's version, you probably need to ensure that you cannot be moved out of that processor first. If the entirety of your access to the per-CPU variable happens with a spinlock held, all is well. Usually, however, you need to use get_cpu to block preemption while working with the variable. Thus, code using dynamic per-CPU variables tends to look like this: int cpu; cpu = get_cpu( ) ptr = per_cpu_ptr(per_cpu_var, cpu); /* work with ptr */ put_cpu( ); When using compile-time per-CPU variables, the get_cpu_var and put_cpu_var macros take care of these details. Dynamic per-CPU variables require more explicit protection. Per-CPU variables can be exported to modules, but you must use a special version of the macros: EXPORT_PER_CPU_SYMBOL(per_cpu_var); EXPORT_PER_CPU_SYMBOL_GPL(per_cpu_var); To access such a variable within a module, declare it with: DECLARE_PER_CPU(type, name); The use of DECLARE_PER_CPU (instead of DEFINE_PER_CPU) tells the compiler that an external reference is being made. If you want to use per-CPU variables to create a simple integer counter, take a look at the canned implementation in <linux/percpu_counter.h>. Finally, note that some architectures have a limited amount of address space available for per-CPU variables. If you create per-CPU variables in your code, you should try to keep them small.

4,436

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 内核源代码研究区
社区管理员
  • 内核源代码研究区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧