linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH]IPC locks breaking down with RCU
@ 2002-10-18  0:14 mingming cao
  2002-10-20 13:14 ` Hugh Dickins
  0 siblings, 1 reply; 37+ messages in thread
From: mingming cao @ 2002-10-18  0:14 UTC (permalink / raw)
  To: torvalds, akpm, Hugh Dickins, linux-kernel; +Cc: cmm, dipankar

[-- Attachment #1: Type: text/plain, Size: 1197 bytes --]

Hi Linus,

This is the latest version of the ipc lock patch.  It breaks down the
three global IPC locks into one lock per IPC ID,  also addresses the
cache line bouncing problem  introduced in the original patch. The
original post could be found at:
http://marc.theaimsgroup.com/?l=linux-kernel&m=102980357802682&w=2
\x18
The original patch breaks down the global IPC locks, yet added another
layer of locking to protect the IPC ID array in case of resizing. Some
concern was raised that the read/write lock may cause cache line
bouncing.

Since write lock is only used when the array is dynamically resized, 
RCU seems perfectly fit for this situation.  By doing so it could reduce
the possible lock contention in some applications where the IPC
resources are heavily used, without introducing cache line bouncing.

Besides the RCU changes, it also remove the redundant ipc_lockall() and
ipc_unlockall() as suggested by Hugh Dickins.

Patch is against 2.5.43 kernel. It requires Dipankar Sarma's
read_barrier_depends RCU helper patch:
http://marc.theaimsgroup.com/?l=linux-kernel&m=103479438017486&w=2

We use the ipc lock on OracleApps and it gave us the best number. 
Please include.

Mingming Cao

[-- Attachment #2: ipclock-rcu-2543.patch --]
[-- Type: text/plain, Size: 5233 bytes --]

Binary files linux-2.5.43/arch/i386/boot/compressed/vmlinux.bin.gz and linux-2.5.43-ipc/arch/i386/boot/compressed/vmlinux.bin.gz differ
diff -urN -X dontdiff linux-2.5.43/include/linux/ipc.h linux-2.5.43-ipc/include/linux/ipc.h
--- linux-2.5.43/include/linux/ipc.h	Tue Oct 15 20:26:43 2002
+++ linux-2.5.43-ipc/include/linux/ipc.h	Wed Oct 16 09:48:28 2002
@@ -56,6 +56,7 @@
 /* used by in-kernel data structures */
 struct kern_ipc_perm
 {
+	spinlock_t	lock;
 	key_t		key;
 	uid_t		uid;
 	gid_t		gid;
diff -urN -X dontdiff linux-2.5.43/ipc/shm.c linux-2.5.43-ipc/ipc/shm.c
--- linux-2.5.43/ipc/shm.c	Tue Oct 15 20:28:22 2002
+++ linux-2.5.43-ipc/ipc/shm.c	Wed Oct 16 09:48:28 2002
@@ -38,8 +38,6 @@
 
 #define shm_lock(id)	((struct shmid_kernel*)ipc_lock(&shm_ids,id))
 #define shm_unlock(id)	ipc_unlock(&shm_ids,id)
-#define shm_lockall()	ipc_lockall(&shm_ids)
-#define shm_unlockall()	ipc_unlockall(&shm_ids)
 #define shm_get(id)	((struct shmid_kernel*)ipc_get(&shm_ids,id))
 #define shm_buildid(id, seq) \
 	ipc_buildid(&shm_ids, id, seq)
@@ -409,14 +407,12 @@
 
 		memset(&shm_info,0,sizeof(shm_info));
 		down(&shm_ids.sem);
-		shm_lockall();
 		shm_info.used_ids = shm_ids.in_use;
 		shm_get_stat (&shm_info.shm_rss, &shm_info.shm_swp);
 		shm_info.shm_tot = shm_tot;
 		shm_info.swap_attempts = 0;
 		shm_info.swap_successes = 0;
 		err = shm_ids.max_id;
-		shm_unlockall();
 		up(&shm_ids.sem);
 		if(copy_to_user (buf, &shm_info, sizeof(shm_info)))
 			return -EFAULT;
diff -urN -X dontdiff linux-2.5.43/ipc/util.c linux-2.5.43-ipc/ipc/util.c
--- linux-2.5.43/ipc/util.c	Tue Oct 15 20:27:54 2002
+++ linux-2.5.43-ipc/ipc/util.c	Wed Oct 16 09:48:28 2002
@@ -92,8 +92,10 @@
 {
 	int id;
 	struct kern_ipc_perm* p;
+	int max_id = ids->max_id;
 
-	for (id = 0; id <= ids->max_id; id++) {
+	read_barrier_depends();
+	for (id = 0; id <= max_id; id++) {
 		p = ids->entries[id].p;
 		if(p==NULL)
 			continue;
@@ -106,8 +108,8 @@
 static int grow_ary(struct ipc_ids* ids, int newsize)
 {
 	struct ipc_id* new;
-	struct ipc_id* old;
 	int i;
+	struct rcu_ipc_array *arg = NULL;
 
 	if(newsize > IPCMNI)
 		newsize = IPCMNI;
@@ -121,14 +123,19 @@
 	for(i=ids->size;i<newsize;i++) {
 		new[i].p = NULL;
 	}
+	arg = (struct rcu_ipc_array *) kmalloc(sizeof(*arg), GFP_KERNEL);
+	if(arg == NULL)
+		return ids->size;
+	arg->entries = ids->entries;
+	arg->size = ids->size;
+	
 	spin_lock(&ids->ary);
-
-	old = ids->entries;
 	ids->entries = new;
-	i = ids->size;
+	wmb();
 	ids->size = newsize;
 	spin_unlock(&ids->ary);
-	ipc_free(old, sizeof(struct ipc_id)*i);
+
+	call_rcu(&arg->rh, ipc_free_callback, arg);
 	return ids->size;
 }
 
@@ -166,7 +173,9 @@
 	if(ids->seq > ids->seq_max)
 		ids->seq = 0;
 
-	spin_lock(&ids->ary);
+	new->lock = SPIN_LOCK_UNLOCKED;
+	rcu_read_lock();
+	spin_lock(&new->lock);
 	ids->entries[id].p = new;
 	return id;
 }
@@ -188,6 +197,7 @@
 	int lid = id % SEQ_MULTIPLIER;
 	if(lid >= ids->size)
 		BUG();
+	rmb();
 	p = ids->entries[lid].p;
 	ids->entries[lid].p = NULL;
 	if(p==NULL)
@@ -239,7 +249,12 @@
 	else
 		kfree(ptr);
 }
-
+static void ipc_free_callback(void * arg)
+{
+	struct rcu_ipc_array *a = (struct rcu_ipc_array *)arg;
+	ipc_free(a->entries, a->size);
+	kfree(arg);
+}
 /**
  *	ipcperms	-	check IPC permissions
  *	@ipcp: IPC permission set
diff -urN -X dontdiff linux-2.5.43/ipc/util.h linux-2.5.43-ipc/ipc/util.h
--- linux-2.5.43/ipc/util.h	Tue Oct 15 20:28:24 2002
+++ linux-2.5.43-ipc/ipc/util.h	Wed Oct 16 09:48:28 2002
@@ -4,6 +4,7 @@
  *
  * ipc helper functions (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
  */
+#include <linux/rcupdate.h>
 
 #define USHRT_MAX 0xffff
 #define SEQ_MULTIPLIER	(IPCMNI)
@@ -12,6 +13,12 @@
 void msg_init (void);
 void shm_init (void);
 
+struct rcu_ipc_array {
+	struct rcu_head rh;
+	struct ipc_id* entries;
+	int size;
+};
+
 struct ipc_ids {
 	int size;
 	int in_use;
@@ -44,11 +51,7 @@
  */
 void* ipc_alloc(int size);
 void ipc_free(void* ptr, int size);
-
-extern inline void ipc_lockall(struct ipc_ids* ids)
-{
-	spin_lock(&ids->ary);
-}
+void ipc_free_callback(void* arg);
 
 extern inline struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id)
 {
@@ -56,32 +59,43 @@
 	int lid = id % SEQ_MULTIPLIER;
 	if(lid >= ids->size)
 		return NULL;
-
+	rmb();
 	out = ids->entries[lid].p;
 	return out;
 }
 
-extern inline void ipc_unlockall(struct ipc_ids* ids)
-{
-	spin_unlock(&ids->ary);
-}
 extern inline struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id)
 {
 	struct kern_ipc_perm* out;
 	int lid = id % SEQ_MULTIPLIER;
-	if(lid >= ids->size)
-		return NULL;
 
-	spin_lock(&ids->ary);
+	rcu_read_lock();
+	if(lid >= ids->size) {
+		rcu_read_unlock();
+		return NULL;
+	}
+	rmb();
 	out = ids->entries[lid].p;
-	if(out==NULL)
-		spin_unlock(&ids->ary);
+	if(out==NULL) {
+		rcu_read_unlock();
+		return NULL;
+	}
+	spin_lock(&out->lock);
 	return out;
 }
 
 extern inline void ipc_unlock(struct ipc_ids* ids, int id)
 {
-	spin_unlock(&ids->ary);
+	int lid = id % SEQ_MULTIPLIER;
+	struct kern_ipc_perm* out;
+
+        if(lid >= ids->size)
+		return;
+	rmb();	
+	out = ids->entries[lid].p;
+	if (out)
+		spin_unlock(&out->lock);
+	rcu_read_unlock();
 }
 
 extern inline int ipc_buildid(struct ipc_ids* ids, int id, int seq)

^ permalink raw reply	[flat|nested] 37+ messages in thread
* Re: [PATCH]IPC locks breaking down with RCU
@ 2002-10-21 19:23 Manfred Spraul
  2002-10-21 20:10 ` Hugh Dickins
  0 siblings, 1 reply; 37+ messages in thread
From: Manfred Spraul @ 2002-10-21 19:23 UTC (permalink / raw)
  To: Hugh Dickins; +Cc: mingming cao, linux-kernel

Hugh wrote:

>I had toyed with the idea of never
>freeing entries once allocated, which is a similarly simple solution;
>

Not possible, the structure size for ipc sem depends on the number of 
semaphores in the semaphore set.

Probably the best approach is to add a "deleted" flag into the ipc_id 
structure, and to check that flag after acquiring the spinlock. And 
perform the actual free operations for the ipc element in a rcu callback.
At which context do the rcu callbacks run? The semaphore sets are 
allocated with vmalloc for large sets, and that function is only 
permitted from process context, not from bh or irq context. According to 
a comment in rcupdate.c, rcu_process_callbacks runs in a tasklet, i.e. 
at bh context.

>I'm happy to be overruled by someone who understands these cacheline
>bounce issues better than we do, but nobody else has spoken up yet.
>  
>
Are there any good documents about cacheline bouncing, or rules how to 
reduce it?

For example, should a spinlock and the data it protects be in the same 
cacheline, or in different cachelines?
I guess that "same cacheline" means that only one cacheline is 
transfered if a cpu acquires the spinlock and touches the data.
But OTHO a spinning cpu would probably force the cacheline into shared 
state, and that'll slow down the data access for the cpu that owns the 
spinlock.

--
    Manfred


^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2002-10-31 17:49 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-10-18  0:14 [PATCH]IPC locks breaking down with RCU mingming cao
2002-10-20 13:14 ` Hugh Dickins
2002-10-20 17:27   ` Hugh Dickins
2002-10-21 18:11     ` mingming cao
2002-10-21 19:00       ` Hugh Dickins
2002-10-24 21:49         ` [PATCH]updated ipc lock patch mingming cao
2002-10-24 22:29           ` Andrew Morton
2002-10-24 22:56             ` Hugh Dickins
2002-10-24 23:30               ` Andrew Morton
2002-10-24 23:59                 ` Hugh Dickins
2002-10-25  0:35                   ` [Lse-tech] " Rick Lindsley
2002-10-25  1:07                     ` Robert Love
2002-10-25  0:07                 ` mingming cao
2002-10-25  0:24                   ` Andrew Morton
2002-10-25  4:18                 ` Rusty Russell
2002-10-25  5:53                   ` mingming cao
2002-10-25  7:27                     ` Rusty Russell
2002-10-25  5:36                 ` Manfred Spraul
2002-10-25 16:53                 ` Rik van Riel
2002-10-24 23:23             ` mingming cao
2002-10-25 14:21               ` [Lse-tech] " Paul Larson
2002-10-25 17:17                 ` mingming cao
2002-10-25 18:20                   ` Paul Larson
2002-10-25 18:51                     ` mingming cao
2002-10-25 19:06                       ` Paul Larson
2002-10-25 20:14                         ` mingming cao
2002-10-25 20:23                       ` Manfred Spraul
2002-10-25  0:38             ` Cliff White
2002-10-31 17:52             ` [Lse-tech] Re: [PATCH]updated ipc lock patch [PERFORMANCE RESULTS] Bill Hartner
2002-10-21 19:18       ` [PATCH]IPC locks breaking down with RCU Dipankar Sarma
2002-10-21 19:36         ` Hugh Dickins
2002-10-21 19:41         ` mingming cao
2002-10-21 20:14           ` Dipankar Sarma
2002-10-21 18:07   ` mingming cao
  -- strict thread matches above, loose matches on Subject: below --
2002-10-21 19:23 Manfred Spraul
2002-10-21 20:10 ` Hugh Dickins
2002-10-21 20:34   ` mingming cao

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