Re: [PATCH] percpu: preemptless __per_cpu_counter_add

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 14 Apr 2011, Tejun Heo wrote:

> Hello,
>
> On Wed, Apr 13, 2011 at 03:22:36PM -0500, Christoph Lameter wrote:
> > +	do {
> > +		count = this_cpu_read(*fbc->counters);
> > +
> > +		new = count + amount;
> > +		/* In case of overflow fold it into the global counter instead */
> > +		if (new >= batch || new <= -batch) {
> > +			spin_lock(&fbc->lock);
> > +			fbc->count += __this_cpu_read(*fbc->counters) + amount;
> > +			spin_unlock(&fbc->lock);
> > +			amount = 0;
> > +			new = 0;
> > +		}
> > +
> > +	} while (this_cpu_cmpxchg(*fbc->counters, count, new) != count);
>
> Is this correct?  If the percpu count changes in the middle, doesn't
> the count get added twice?  Can you please use the cmpxchg() only in
> the fast path?  ie.

Oh gosh this is the old version. The fixed version should do this
differently.

We need to update the counter that is cpu specific as well otherwise it
will overflow again soon. Hmmm... Yes, it could be done while holding the
spinlock which disables preempt.



Subject: [PATCH] percpu: preemptless __per_cpu_counter_add

Use this_cpu_cmpxchg to avoid preempt_disable/enable in __percpu_add.

Signed-off-by: Christoph Lameter <cl@xxxxxxxxx>

---
 lib/percpu_counter.c |   32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

Index: linux-2.6/lib/percpu_counter.c
===================================================================
--- linux-2.6.orig/lib/percpu_counter.c	2011-04-13 15:19:54.000000000 -0500
+++ linux-2.6/lib/percpu_counter.c	2011-04-13 15:20:04.000000000 -0500
@@ -71,19 +71,27 @@ EXPORT_SYMBOL(percpu_counter_set);

 void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch)
 {
-	s64 count;
+	s64 count, new;

-	preempt_disable();
-	count = __this_cpu_read(*fbc->counters) + amount;
-	if (count >= batch || count <= -batch) {
-		spin_lock(&fbc->lock);
-		fbc->count += count;
-		__this_cpu_write(*fbc->counters, 0);
-		spin_unlock(&fbc->lock);
-	} else {
-		__this_cpu_write(*fbc->counters, count);
-	}
-	preempt_enable();
+	do {
+		count = this_cpu_read(*fbc->counters);
+
+		new = count + amount;
+		/* In case of overflow fold it into the global counter instead */
+		if (new >= batch || new <= -batch) {
+			spin_lock(&fbc->lock);
+			count = __this_cpu_read(*fbc->counters);
+			fbc->count += count + amount;
+			spin_unlock(&fbc->lock);
+			/*
+			 * If cmpxchg fails then we need to subtract the amount that
+			 * we found in the percpu value.
+			 */
+			amount = -count;
+			new = 0;
+		}
+
+	} while (this_cpu_cmpxchg(*fbc->counters, count, new) != count);
 }
 EXPORT_SYMBOL(__percpu_counter_add);

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@xxxxxxxxxx  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@xxxxxxxxx";> email@xxxxxxxxx </a>


[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]