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: Tue, 09 Jan 2007 03:20:00 -0000 [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:20 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-12-21 0:22 [PATCH 0/10] local_t : adding and standardising atomic primitives Mathieu Desnoyers
2006-12-21 0:22 ` [PATCH 1/10] local_t : architecture agnostic Mathieu Desnoyers
2006-12-21 0:24 ` [PATCH 2/10] local_t : alpha Mathieu Desnoyers
2006-12-21 0:25 ` [PATCH 3/10] local_t : i386 Mathieu Desnoyers
2006-12-21 19:47 ` [Ltt-dev] [PATCH 3/10] local_t : i386, local_add_return fix Mathieu Desnoyers
2006-12-21 0:26 ` [PATCH 4/10] local_t : ia64 Mathieu Desnoyers
2006-12-21 0:27 ` [PATCH 6/10] local_t : parisc Mathieu Desnoyers
2006-12-21 0:27 ` [PATCH 5/10] local_t : ia64 Mathieu Desnoyers
2006-12-21 18:56 ` [Ltt-dev] [PATCH 5/10] local_t : MIPS Mathieu Desnoyers
2006-12-21 0:28 ` [PATCH 7/10] local_t : powerpc Mathieu Desnoyers
2006-12-21 14:04 ` [Ltt-dev] " Mathieu Desnoyers
2007-01-24 10:00 ` Paul Mackerras
2007-01-24 10:43 ` Gabriel Paubert
2007-01-24 17:05 ` Mathieu Desnoyers
2006-12-21 0:29 ` [PATCH 8/10] local_t : s390 Mathieu Desnoyers
2006-12-21 0:41 ` [PATCH 9/10] local_t : sparc64 Mathieu Desnoyers
2006-12-21 3:01 ` [PATCH 10/10] local_t : x86_64 Mathieu Desnoyers
2006-12-21 19:55 ` [Ltt-dev] [PATCH 10/10] local_t : x86_64 : local_add_return Mathieu Desnoyers
2006-12-26 19:48 ` [PATCH 0/10] local_t : adding and standardising atomic primitives Pavel Machek
2007-01-09 3:20 ` Mathieu Desnoyers [this message]
2007-01-09 21:02 ` [PATCH] local_t : Documentation Andrew Morton
2007-01-09 22:11 ` Mathieu Desnoyers
2007-01-09 22:12 ` Andrew Morton
2007-01-09 22:38 ` Pavel Machek
2007-01-09 22:41 ` Pavel Machek
2007-01-09 23:27 ` [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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).