From: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
To: Pavel Machek <pavel@suse.cz>
Cc: linux-kernel@vger.kernel.org, Andrew Morton <akpm@osdl.org>,
Ingo Molnar <mingo@redhat.com>,
Greg Kroah-Hartman <gregkh@suse.de>,
Christoph Hellwig <hch@infradead.org>,
ltt-dev@shafik.org, systemtap@sources.redhat.com,
Douglas Niehaus <niehaus@eecs.ku.edu>,
"Martin J. Bligh" <mbligh@mbligh.org>,
Thomas Gleixner <tglx@linutronix.de>
Subject: [PATCH] local_t : Documentation
Date: Mon, 8 Jan 2007 22:14:46 -0500 [thread overview]
Message-ID: <20070109031446.GA29426@Krystal> (raw)
In-Reply-To: <20061223093358.GF3960@ucw.cz>
* Pavel Machek (pavel@suse.cz) wrote:
> Hi!
>
> > These patches extend and standardise local_t operations on each architectures,
> > allowing a rich set of atomic operations to be done on per-cpu data with
> > minimal performance impact. On some architectures, there seems to be no
> > difference between the SMP and UP operation (same memory barriers, same
> > LOCking), local.h simply includes asm-generic/local.h, which removes duplicated
> > code.
>
> Could you provide some Documentation/? Knowing when local_t can be
> used is kind-of important.
> Pavel
Hi Pavel,
Thanks for this appropriate comment. I totally agree that there is a need for
documentation about how local_t variables should be used. Here is the patch
that adds Documentation/local_ops.txt. Comments are welcome.
Regards,
Mathieu
diff --git a/Documentation/local_ops.txt b/Documentation/local_ops.txt
new file mode 100644
index 0000000..dfeec94
--- /dev/null
+++ b/Documentation/local_ops.txt
@@ -0,0 +1,148 @@
+ Semantics and Behavior of Local Atomic Operations
+
+ Mathieu Desnoyers
+
+
+ This document explains the purpose of the local atomic operations, how
+to implement them for any given architecture and shows how they can be used
+properly. It also stresses on the precautions that must be taken when reading
+those local variables across CPUs when the order of memory writes matters.
+
+
+
+* Purpose of local atomic operations
+
+Local atomic operations are meant to provide fast and highly reentrant per CPU
+counters. They minimize the performance cost of standard atomic operations by
+removing the LOCK prefix and memory barriers normally required to synchronize
+across CPUs.
+
+Having fast per CPU atomic counters is interesting in many cases : it does not
+require disabling interrupts to protect from interrupt handlers and it permits
+coherent counters in NMI handlers. It is especially useful for tracing purposes
+and for various performance monitoring counters.
+
+
+* Implementation for a given architecture
+
+It can be done by slightly modifying the standard atomic operations : only
+their UP variant must be kept. It typically means removing LOCK prefix (on
+i386 and x86_64) and any SMP sychronization barrier. If the architecture does
+not have a different behavior between SMP and UP, including asm-generic/local.h
+in your archtecture's local.h is sufficient.
+
+
+* How to use local atomic operations
+
+#include <linux/percpu.h>
+#include <asm/local.h>
+
+static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);
+
+
+* Counting
+
+In preemptible context, use get_cpu_var() and put_cpu_var() around local atomic
+operations : it makes sure that preemption is disabled around write access to
+the per cpu variable. For instance :
+
+ local_inc(&get_cpu_var(counters));
+ put_cpu_var(counters);
+
+If you are already in a preemption-safe context, you can directly use
+__get_cpu_var() instead.
+
+ local_inc(&__get_cpu_var(counters));
+
+
+
+* Reading the counters
+
+Those local counters can be read from foreign CPUs to sum the count. Note that
+the data seen by local_read across CPUs must be considered to be out of order
+relatively to other memory writes happening on the CPU that owns the data.
+
+ long sum = 0;
+ for_each_online_cpu(cpu)
+ sum += local_read(&per_cpu(counters, cpu));
+
+If you want to use a remote local_read to synchronize access to a resource
+between CPUs, explicit smp_wmb() and smp_rmb() memory barriers must be used
+respectively on the writer and the reader CPUs. It would be the case if you use
+the local_t variable as a counter of bytes written in a buffer : there should
+be a smp_wmb() between the buffer write and the counter increment and also a
+smp_rmb() between the counter read and the buffer read.
+
+
+Here is a sample module which implements a basic per cpu counter using local.h.
+
+--- BEGIN ---
+/* test-local.c
+ *
+ * Sample module for local.h usage.
+ */
+
+
+#include <asm/local.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+
+static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);
+
+static struct timer_list test_timer;
+
+/* IPI called on each CPU. */
+static void test_each(void *info)
+{
+ /* Increment the counter from a non preemptible context */
+ printk("Increment on cpu %d\n", smp_processor_id());
+ local_inc(&__get_cpu_var(counters));
+
+ /* This is what incrementing the variable would look like within a
+ * preemptible context (it disables preemption) :
+ *
+ * local_inc(&get_cpu_var(counters));
+ * put_cpu_var(counters);
+ */
+}
+
+static void do_test_timer(unsigned long data)
+{
+ int cpu;
+
+ /* Increment the counters */
+ on_each_cpu(test_each, NULL, 0, 1);
+ /* Read all the counters */
+ printk("Counters read from CPU %d\n", smp_processor_id());
+ for_each_online_cpu(cpu) {
+ printk("Read : CPU %d, count %ld\n", cpu,
+ local_read(&per_cpu(counters, cpu)));
+ }
+ del_timer(&test_timer);
+ test_timer.expires = jiffies + 1000;
+ add_timer(&test_timer);
+}
+
+static int __init test_init(void)
+{
+ /* initialize the timer that will increment the counter */
+ init_timer(&test_timer);
+ test_timer.function = do_test_timer;
+ test_timer.expires = jiffies + 1;
+ add_timer(&test_timer);
+
+ return 0;
+}
+
+static void __exit test_exit(void)
+{
+ del_timer_sync(&test_timer);
+}
+
+module_init(test_init);
+module_exit(test_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Local Atomic Ops");
+--- END ---
--
OpenPGP public key: http://krystal.dyndns.org:8080/key/compudj.gpg
Key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
next prev parent reply other threads:[~2007-01-09 3:14 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-12-21 0:15 [PATCH 0/10] local_t : adding and standardising atomic primitives Mathieu Desnoyers
2006-12-21 0:20 ` [PATCH 1/10] local_t : architecture agnostic Mathieu Desnoyers
2006-12-21 0:21 ` [PATCH 2/10] local_t : alpha Mathieu Desnoyers
2006-12-21 0:22 ` [PATCH 3/10] local_t : i386 Mathieu Desnoyers
2006-12-21 19:44 ` [Ltt-dev] [PATCH 3/10] local_t : i386, local_add_return fix Mathieu Desnoyers
2006-12-21 0:23 ` [PATCH 4/10] local_t : ia64 Mathieu Desnoyers
2006-12-21 0:25 ` [PATCH 5/10] " Mathieu Desnoyers
2006-12-21 14:04 ` [Ltt-dev] [PATCH 5/10] local_t : MIPS Mathieu Desnoyers
2006-12-21 0:25 ` [PATCH 6/10] local_t : parisc Mathieu Desnoyers
2006-12-21 0:27 ` [PATCH 7/10] local_t : powerpc Mathieu Desnoyers
2006-12-21 0:27 ` Mathieu Desnoyers
2006-12-21 3:34 ` [Ltt-dev] " Mathieu Desnoyers
2007-01-24 9:08 ` Paul Mackerras
2007-01-24 9:08 ` Paul Mackerras
2007-01-24 10:43 ` Gabriel Paubert
2007-01-24 10:43 ` Gabriel Paubert
2007-01-24 17:00 ` Mathieu Desnoyers
2007-01-24 17:00 ` Mathieu Desnoyers
2006-12-21 0:27 ` [PATCH 8/10] local_t : s390 Mathieu Desnoyers
2006-12-21 0:28 ` [PATCH 9/10] local_t : sparc64 Mathieu Desnoyers
2006-12-21 0:29 ` [PATCH 10/10] local_t : x86_64 Mathieu Desnoyers
2006-12-21 19:46 ` [Ltt-dev] [PATCH 10/10] local_t : x86_64 : local_add_return Mathieu Desnoyers
2006-12-23 9:33 ` [PATCH 0/10] local_t : adding and standardising atomic primitives Pavel Machek
2007-01-09 3:14 ` Mathieu Desnoyers [this message]
2007-01-09 21:01 ` [PATCH] local_t : Documentation Andrew Morton
2007-01-09 22:06 ` Mathieu Desnoyers
2007-01-09 22:11 ` Andrew Morton
2007-01-09 22:38 ` Pavel Machek
2007-01-09 22:41 ` Pavel Machek
2007-01-09 23:21 ` [PATCH] local_t : Documentation - update Mathieu Desnoyers
2007-01-09 23:45 ` Pavel Machek
2007-01-10 0:39 ` Mathieu Desnoyers
2007-01-10 1:06 ` [Ltt-dev] " Mathieu Desnoyers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070109031446.GA29426@Krystal \
--to=mathieu.desnoyers@polymtl.ca \
--cc=akpm@osdl.org \
--cc=gregkh@suse.de \
--cc=hch@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=ltt-dev@shafik.org \
--cc=mbligh@mbligh.org \
--cc=mingo@redhat.com \
--cc=niehaus@eecs.ku.edu \
--cc=pavel@suse.cz \
--cc=systemtap@sources.redhat.com \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.