From: Ashwin Chaugule <ashwinc@codeaurora.org>
To: linux-arm-kernel <linux-arm-kernel@lists.infradead.org>,
linux-arm-msm@vger.kernel.org, dhowells@redhat.com,
catalin.marinas@arm.com
Subject: [RFC] [PATCH] XCHGADD ARM implementation
Date: Tue, 05 Oct 2010 17:05:55 -0400 [thread overview]
Message-ID: <4CAB9333.50400@codeaurora.org> (raw)
[-- Attachment #1: Type: text/plain, Size: 497 bytes --]
The following patch is the ARM implementation for RWSEM_XCHGADD_ALGORITHM.
Based on David's rwsem benchmark from http://lwn.net/Articles/89191/ ,
I see a consistent 5-6% increase in the number of reads and writes taken as
compared to RWSEM_GENERIC_SPINLOCK on a dual core ARMv7. So far I have tested
numrd=1 numwr=1 numdg=1 do_sched=1
numrd=10 numwr=10 numdg=1 do_sched=1
numrd=20 numwr=20 numdg=1 do_sched=1
Can anyone else help to test this patch on other ARM systems ?
Cheers,
Ashwin
[-- Attachment #2: Optimzed-ARM-RWSEM-algorithm.patch --]
[-- Type: text/x-patch, Size: 5928 bytes --]
RWSEM implementation for ARM using atomic functions.
Heavily based on sh/include/asm/rwsem.h
Signed-off-by: Ashwin Chaugule <ashwinc@codeaurora.org>
---
arch/arm/Kconfig | 3 +-
arch/arm/include/asm/rwsem.h | 192 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 193 insertions(+), 2 deletions(-)
create mode 100644 arch/arm/include/asm/rwsem.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 871838b..0149b9f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -129,10 +129,9 @@ config GENERIC_LOCKBREAK
config RWSEM_GENERIC_SPINLOCK
bool
- default y
config RWSEM_XCHGADD_ALGORITHM
- bool
+ def_bool y
config ARCH_HAS_ILOG2_U32
bool
diff --git a/arch/arm/include/asm/rwsem.h b/arch/arm/include/asm/rwsem.h
new file mode 100644
index 0000000..1730ee1
--- /dev/null
+++ b/arch/arm/include/asm/rwsem.h
@@ -0,0 +1,192 @@
+/* rwsem.h: R/W semaphores implemented using ARM atomic functions.
+ *
+ * Written by Ashwin Chaugule (ashwinc@codeaurora.org).
+ *
+ * Derived from arch/sh/asm/rwsem.h
+ *
+ * include/asm-arm/rwsem.h: R/W semaphores for ARM using the stuff
+ * in lib/rwsem.c.
+ *
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef _ASM_ARM_RWSEM_H
+#define _ASM_ARM_RWSEM_H
+
+#ifndef _LINUX_RWSEM_H
+#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
+#endif
+
+#ifdef __KERNEL__
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+ long count;
+#define RWSEM_UNLOCKED_VALUE 0x00000000
+#define RWSEM_ACTIVE_BIAS 0x00000001
+#define RWSEM_ACTIVE_MASK 0x0000ffff
+#define RWSEM_WAITING_BIAS (-0x00010000)
+#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+ spinlock_t wait_lock;
+ struct list_head wait_list;
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ struct lockdep_map dep_map;
+#endif
+};
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
+#else
+# define __RWSEM_DEP_MAP_INIT(lockname)
+#endif
+
+#define __RWSEM_INITIALIZER(name) \
+ { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \
+ LIST_HEAD_INIT((name).wait_list) \
+ __RWSEM_DEP_MAP_INIT(name) }
+
+#define DECLARE_RWSEM(name) \
+ struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
+
+extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
+ struct lock_class_key *key);
+
+#define init_rwsem(sem) \
+do { \
+ static struct lock_class_key __key; \
+ \
+ __init_rwsem((sem), #sem, &__key); \
+} while (0)
+
+/*
+ * lock for reading
+ */
+static inline void __down_read(struct rw_semaphore *sem)
+{
+ if (atomic_inc_return((atomic_t *)(&sem->count)) < 0)
+ rwsem_down_read_failed(sem);
+}
+
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+ int tmp;
+
+ while ((tmp = sem->count) >= 0) {
+ if (tmp == cmpxchg(&sem->count, tmp,
+ tmp + RWSEM_ACTIVE_READ_BIAS)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * lock for writing
+ */
+static inline void __down_write(struct rw_semaphore *sem)
+{
+ int tmp;
+
+ tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
+ (atomic_t *)(&sem->count));
+ if (tmp != RWSEM_ACTIVE_WRITE_BIAS)
+ rwsem_down_write_failed(sem);
+}
+
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+ int tmp;
+
+ tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+ RWSEM_ACTIVE_WRITE_BIAS);
+ return tmp == RWSEM_UNLOCKED_VALUE;
+}
+
+/*
+ * unlock after reading
+ */
+static inline void __up_read(struct rw_semaphore *sem)
+{
+ int tmp;
+
+ tmp = atomic_dec_return((atomic_t *)(&sem->count));
+ if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
+ rwsem_wake(sem);
+}
+
+/*
+ * unlock after writing
+ */
+static inline void __up_write(struct rw_semaphore *sem)
+{
+ if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
+ (atomic_t *)(&sem->count)) < 0)
+ rwsem_wake(sem);
+}
+
+/*
+ * implement atomic add functionality
+ */
+static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
+{
+ atomic_add(delta, (atomic_t *)(&sem->count));
+}
+
+/*
+ * downgrade write lock to read lock
+ */
+static inline void __downgrade_write(struct rw_semaphore *sem)
+{
+ int tmp;
+
+ tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
+ if (tmp < 0)
+ rwsem_downgrade_wake(sem);
+}
+
+static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
+{
+ __down_write(sem);
+}
+
+/*
+ * implement exchange and add functionality
+ */
+static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
+{
+ return atomic_add_return(delta, (atomic_t *)(&sem->count));
+}
+
+static inline int rwsem_is_locked(struct rw_semaphore *sem)
+{
+ return (sem->count != 0);
+}
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_ARM_RWSEM_H */
--
1.7.1
reply other threads:[~2010-10-05 21:05 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=4CAB9333.50400@codeaurora.org \
--to=ashwinc@codeaurora.org \
--cc=catalin.marinas@arm.com \
--cc=dhowells@redhat.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
/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 NNTP newsgroup(s).