1*4882a593Smuzhiyun 2*4882a593Smuzhiyun.. _local_ops: 3*4882a593Smuzhiyun 4*4882a593Smuzhiyun================================================= 5*4882a593SmuzhiyunSemantics and Behavior of Local Atomic Operations 6*4882a593Smuzhiyun================================================= 7*4882a593Smuzhiyun 8*4882a593Smuzhiyun:Author: Mathieu Desnoyers 9*4882a593Smuzhiyun 10*4882a593Smuzhiyun 11*4882a593SmuzhiyunThis document explains the purpose of the local atomic operations, how 12*4882a593Smuzhiyunto implement them for any given architecture and shows how they can be used 13*4882a593Smuzhiyunproperly. It also stresses on the precautions that must be taken when reading 14*4882a593Smuzhiyunthose local variables across CPUs when the order of memory writes matters. 15*4882a593Smuzhiyun 16*4882a593Smuzhiyun.. note:: 17*4882a593Smuzhiyun 18*4882a593Smuzhiyun Note that ``local_t`` based operations are not recommended for general 19*4882a593Smuzhiyun kernel use. Please use the ``this_cpu`` operations instead unless there is 20*4882a593Smuzhiyun really a special purpose. Most uses of ``local_t`` in the kernel have been 21*4882a593Smuzhiyun replaced by ``this_cpu`` operations. ``this_cpu`` operations combine the 22*4882a593Smuzhiyun relocation with the ``local_t`` like semantics in a single instruction and 23*4882a593Smuzhiyun yield more compact and faster executing code. 24*4882a593Smuzhiyun 25*4882a593Smuzhiyun 26*4882a593SmuzhiyunPurpose of local atomic operations 27*4882a593Smuzhiyun================================== 28*4882a593Smuzhiyun 29*4882a593SmuzhiyunLocal atomic operations are meant to provide fast and highly reentrant per CPU 30*4882a593Smuzhiyuncounters. They minimize the performance cost of standard atomic operations by 31*4882a593Smuzhiyunremoving the LOCK prefix and memory barriers normally required to synchronize 32*4882a593Smuzhiyunacross CPUs. 33*4882a593Smuzhiyun 34*4882a593SmuzhiyunHaving fast per CPU atomic counters is interesting in many cases: it does not 35*4882a593Smuzhiyunrequire disabling interrupts to protect from interrupt handlers and it permits 36*4882a593Smuzhiyuncoherent counters in NMI handlers. It is especially useful for tracing purposes 37*4882a593Smuzhiyunand for various performance monitoring counters. 38*4882a593Smuzhiyun 39*4882a593SmuzhiyunLocal atomic operations only guarantee variable modification atomicity wrt the 40*4882a593SmuzhiyunCPU which owns the data. Therefore, care must taken to make sure that only one 41*4882a593SmuzhiyunCPU writes to the ``local_t`` data. This is done by using per cpu data and 42*4882a593Smuzhiyunmaking sure that we modify it from within a preemption safe context. It is 43*4882a593Smuzhiyunhowever permitted to read ``local_t`` data from any CPU: it will then appear to 44*4882a593Smuzhiyunbe written out of order wrt other memory writes by the owner CPU. 45*4882a593Smuzhiyun 46*4882a593Smuzhiyun 47*4882a593SmuzhiyunImplementation for a given architecture 48*4882a593Smuzhiyun======================================= 49*4882a593Smuzhiyun 50*4882a593SmuzhiyunIt can be done by slightly modifying the standard atomic operations: only 51*4882a593Smuzhiyuntheir UP variant must be kept. It typically means removing LOCK prefix (on 52*4882a593Smuzhiyuni386 and x86_64) and any SMP synchronization barrier. If the architecture does 53*4882a593Smuzhiyunnot have a different behavior between SMP and UP, including 54*4882a593Smuzhiyun``asm-generic/local.h`` in your architecture's ``local.h`` is sufficient. 55*4882a593Smuzhiyun 56*4882a593SmuzhiyunThe ``local_t`` type is defined as an opaque ``signed long`` by embedding an 57*4882a593Smuzhiyun``atomic_long_t`` inside a structure. This is made so a cast from this type to 58*4882a593Smuzhiyuna ``long`` fails. The definition looks like:: 59*4882a593Smuzhiyun 60*4882a593Smuzhiyun typedef struct { atomic_long_t a; } local_t; 61*4882a593Smuzhiyun 62*4882a593Smuzhiyun 63*4882a593SmuzhiyunRules to follow when using local atomic operations 64*4882a593Smuzhiyun================================================== 65*4882a593Smuzhiyun 66*4882a593Smuzhiyun* Variables touched by local ops must be per cpu variables. 67*4882a593Smuzhiyun* *Only* the CPU owner of these variables must write to them. 68*4882a593Smuzhiyun* This CPU can use local ops from any context (process, irq, softirq, nmi, ...) 69*4882a593Smuzhiyun to update its ``local_t`` variables. 70*4882a593Smuzhiyun* Preemption (or interrupts) must be disabled when using local ops in 71*4882a593Smuzhiyun process context to make sure the process won't be migrated to a 72*4882a593Smuzhiyun different CPU between getting the per-cpu variable and doing the 73*4882a593Smuzhiyun actual local op. 74*4882a593Smuzhiyun* When using local ops in interrupt context, no special care must be 75*4882a593Smuzhiyun taken on a mainline kernel, since they will run on the local CPU with 76*4882a593Smuzhiyun preemption already disabled. I suggest, however, to explicitly 77*4882a593Smuzhiyun disable preemption anyway to make sure it will still work correctly on 78*4882a593Smuzhiyun -rt kernels. 79*4882a593Smuzhiyun* Reading the local cpu variable will provide the current copy of the 80*4882a593Smuzhiyun variable. 81*4882a593Smuzhiyun* Reads of these variables can be done from any CPU, because updates to 82*4882a593Smuzhiyun "``long``", aligned, variables are always atomic. Since no memory 83*4882a593Smuzhiyun synchronization is done by the writer CPU, an outdated copy of the 84*4882a593Smuzhiyun variable can be read when reading some *other* cpu's variables. 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun 87*4882a593SmuzhiyunHow to use local atomic operations 88*4882a593Smuzhiyun================================== 89*4882a593Smuzhiyun 90*4882a593Smuzhiyun:: 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun #include <linux/percpu.h> 93*4882a593Smuzhiyun #include <asm/local.h> 94*4882a593Smuzhiyun 95*4882a593Smuzhiyun static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0); 96*4882a593Smuzhiyun 97*4882a593Smuzhiyun 98*4882a593SmuzhiyunCounting 99*4882a593Smuzhiyun======== 100*4882a593Smuzhiyun 101*4882a593SmuzhiyunCounting is done on all the bits of a signed long. 102*4882a593Smuzhiyun 103*4882a593SmuzhiyunIn preemptible context, use ``get_cpu_var()`` and ``put_cpu_var()`` around 104*4882a593Smuzhiyunlocal atomic operations: it makes sure that preemption is disabled around write 105*4882a593Smuzhiyunaccess to the per cpu variable. For instance:: 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun local_inc(&get_cpu_var(counters)); 108*4882a593Smuzhiyun put_cpu_var(counters); 109*4882a593Smuzhiyun 110*4882a593SmuzhiyunIf you are already in a preemption-safe context, you can use 111*4882a593Smuzhiyun``this_cpu_ptr()`` instead:: 112*4882a593Smuzhiyun 113*4882a593Smuzhiyun local_inc(this_cpu_ptr(&counters)); 114*4882a593Smuzhiyun 115*4882a593Smuzhiyun 116*4882a593Smuzhiyun 117*4882a593SmuzhiyunReading the counters 118*4882a593Smuzhiyun==================== 119*4882a593Smuzhiyun 120*4882a593SmuzhiyunThose local counters can be read from foreign CPUs to sum the count. Note that 121*4882a593Smuzhiyunthe data seen by local_read across CPUs must be considered to be out of order 122*4882a593Smuzhiyunrelatively to other memory writes happening on the CPU that owns the data:: 123*4882a593Smuzhiyun 124*4882a593Smuzhiyun long sum = 0; 125*4882a593Smuzhiyun for_each_online_cpu(cpu) 126*4882a593Smuzhiyun sum += local_read(&per_cpu(counters, cpu)); 127*4882a593Smuzhiyun 128*4882a593SmuzhiyunIf you want to use a remote local_read to synchronize access to a resource 129*4882a593Smuzhiyunbetween CPUs, explicit ``smp_wmb()`` and ``smp_rmb()`` memory barriers must be used 130*4882a593Smuzhiyunrespectively on the writer and the reader CPUs. It would be the case if you use 131*4882a593Smuzhiyunthe ``local_t`` variable as a counter of bytes written in a buffer: there should 132*4882a593Smuzhiyunbe a ``smp_wmb()`` between the buffer write and the counter increment and also a 133*4882a593Smuzhiyun``smp_rmb()`` between the counter read and the buffer read. 134*4882a593Smuzhiyun 135*4882a593Smuzhiyun 136*4882a593SmuzhiyunHere is a sample module which implements a basic per cpu counter using 137*4882a593Smuzhiyun``local.h``:: 138*4882a593Smuzhiyun 139*4882a593Smuzhiyun /* test-local.c 140*4882a593Smuzhiyun * 141*4882a593Smuzhiyun * Sample module for local.h usage. 142*4882a593Smuzhiyun */ 143*4882a593Smuzhiyun 144*4882a593Smuzhiyun 145*4882a593Smuzhiyun #include <asm/local.h> 146*4882a593Smuzhiyun #include <linux/module.h> 147*4882a593Smuzhiyun #include <linux/timer.h> 148*4882a593Smuzhiyun 149*4882a593Smuzhiyun static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0); 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun static struct timer_list test_timer; 152*4882a593Smuzhiyun 153*4882a593Smuzhiyun /* IPI called on each CPU. */ 154*4882a593Smuzhiyun static void test_each(void *info) 155*4882a593Smuzhiyun { 156*4882a593Smuzhiyun /* Increment the counter from a non preemptible context */ 157*4882a593Smuzhiyun printk("Increment on cpu %d\n", smp_processor_id()); 158*4882a593Smuzhiyun local_inc(this_cpu_ptr(&counters)); 159*4882a593Smuzhiyun 160*4882a593Smuzhiyun /* This is what incrementing the variable would look like within a 161*4882a593Smuzhiyun * preemptible context (it disables preemption) : 162*4882a593Smuzhiyun * 163*4882a593Smuzhiyun * local_inc(&get_cpu_var(counters)); 164*4882a593Smuzhiyun * put_cpu_var(counters); 165*4882a593Smuzhiyun */ 166*4882a593Smuzhiyun } 167*4882a593Smuzhiyun 168*4882a593Smuzhiyun static void do_test_timer(unsigned long data) 169*4882a593Smuzhiyun { 170*4882a593Smuzhiyun int cpu; 171*4882a593Smuzhiyun 172*4882a593Smuzhiyun /* Increment the counters */ 173*4882a593Smuzhiyun on_each_cpu(test_each, NULL, 1); 174*4882a593Smuzhiyun /* Read all the counters */ 175*4882a593Smuzhiyun printk("Counters read from CPU %d\n", smp_processor_id()); 176*4882a593Smuzhiyun for_each_online_cpu(cpu) { 177*4882a593Smuzhiyun printk("Read : CPU %d, count %ld\n", cpu, 178*4882a593Smuzhiyun local_read(&per_cpu(counters, cpu))); 179*4882a593Smuzhiyun } 180*4882a593Smuzhiyun mod_timer(&test_timer, jiffies + 1000); 181*4882a593Smuzhiyun } 182*4882a593Smuzhiyun 183*4882a593Smuzhiyun static int __init test_init(void) 184*4882a593Smuzhiyun { 185*4882a593Smuzhiyun /* initialize the timer that will increment the counter */ 186*4882a593Smuzhiyun timer_setup(&test_timer, do_test_timer, 0); 187*4882a593Smuzhiyun mod_timer(&test_timer, jiffies + 1); 188*4882a593Smuzhiyun 189*4882a593Smuzhiyun return 0; 190*4882a593Smuzhiyun } 191*4882a593Smuzhiyun 192*4882a593Smuzhiyun static void __exit test_exit(void) 193*4882a593Smuzhiyun { 194*4882a593Smuzhiyun del_timer_sync(&test_timer); 195*4882a593Smuzhiyun } 196*4882a593Smuzhiyun 197*4882a593Smuzhiyun module_init(test_init); 198*4882a593Smuzhiyun module_exit(test_exit); 199*4882a593Smuzhiyun 200*4882a593Smuzhiyun MODULE_LICENSE("GPL"); 201*4882a593Smuzhiyun MODULE_AUTHOR("Mathieu Desnoyers"); 202*4882a593Smuzhiyun MODULE_DESCRIPTION("Local Atomic Ops"); 203