public inbox for systemtap@sourceware.org
 help / color / mirror / Atom feed
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 

  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).