Patchwork [trans-mem] teach ITM_dropReferences() about the cache

login
register
mail settings
Submitter Aldy Hernandez
Date June 28, 2010, 8:28 p.m.
Message ID <20100628202826.GA13690@redhat.com>
Download mbox | patch
Permalink /patch/57189/
State New
Headers show

Comments

Aldy Hernandez - June 28, 2010, 8:28 p.m.
Here's the rest of the _ITM_dropReferences() implementation.

What we do here is force a write-through of the current cached value of a
given chunk of memory, so that when we cancel out of a transaction the
local value permeates through.  The rest of the transaction cached
memory gets rolled back as usual.  See included testcase for an example.

Since there's no set size for the chunk of memory, I use the same
approach as we do with the transactional memcpy() implementation-- just
a bit simpler.

How do you like them apples?

	* method-wbetl.cc (class wbetl_dispatch): Add trydropreference.
	(validate): Add comment.
	(trydropreference): New.
	* method-readonly.cc (class readonly_dispatch): Add
	trydropreference.
	* alloc_c.cc (_ITM_dropReferences): Remove const attribute.
	Call trydropreference().
	* libitm.h (_ITM_dropReferences): Remove const attribute.
	* method-serial.cc (class serial_dispatch): Add trydropreference.
	* libitm_i.h (struct gtm_dispatch): Add trydropreference.
Richard Henderson - June 28, 2010, 8:40 p.m.
On 06/28/2010 01:28 PM, Aldy Hernandez wrote:
> Here's the rest of the _ITM_dropReferences() implementation.
> 
> What we do here is force a write-through of the current cached value of a
> given chunk of memory, so that when we cancel out of a transaction the
> local value permeates through.  The rest of the transaction cached
> memory gets rolled back as usual.  See included testcase for an example.
> 
> Since there's no set size for the chunk of memory, I use the same
> approach as we do with the transactional memcpy() implementation-- just
> a bit simpler.
> 
> How do you like them apples?
> 
> 	* method-wbetl.cc (class wbetl_dispatch): Add trydropreference.
> 	(validate): Add comment.
> 	(trydropreference): New.
> 	* method-readonly.cc (class readonly_dispatch): Add
> 	trydropreference.
> 	* alloc_c.cc (_ITM_dropReferences): Remove const attribute.
> 	Call trydropreference().
> 	* libitm.h (_ITM_dropReferences): Remove const attribute.
> 	* method-serial.cc (class serial_dispatch): Add trydropreference.
> 	* libitm_i.h (struct gtm_dispatch): Add trydropreference.


Ok.


r~

Patch

Index: method-wbetl.cc
===================================================================
--- method-wbetl.cc	(revision 161331)
+++ method-wbetl.cc	(working copy)
@@ -90,6 +90,7 @@  class wbetl_dispatch : public gtm_dispat
   virtual void rollback();
   virtual void reinit();
   virtual void fini();
+  virtual bool trydropreference (void *, size_t);
 };
 
 /* Check if W is one of our write locks.  */
@@ -131,6 +132,8 @@  wbetl_dispatch::validate ()
 	{
 	  w_entry *w = (w_entry *) gtm_stmlock_get_addr (l);
 
+	  // If someone has locked us, it better be by someone in the
+	  // current thread.
 	  if (!local_w_entry_p (w))
 	    return false;
 	}
@@ -521,6 +524,83 @@  wbetl_dispatch::fini ()
   delete this;
 }
 
+/* Attempt to drop any internal references to PTR.  Return TRUE if successful.
+
+   This is an adaptation of the transactional memcpy function.
+
+   What we do here is flush out the current transactional content of
+   PTR to real memory, and remove the write mask bits associated with
+   it so future commits will ignore this piece of memory.  */
+
+bool
+wbetl_dispatch::trydropreference (void *ptr, size_t size)
+{
+  if (size == 0)
+    return true;
+
+  if (!validate ())
+    return false;
+
+  uintptr_t isrc = (uintptr_t)ptr;
+  // The position in the source cacheline where *PTR starts.
+  uintptr_t sofs = isrc & (CACHELINE_SIZE - 1);
+  gtm_cacheline *src
+    = reinterpret_cast<gtm_cacheline *>(isrc & -CACHELINE_SIZE);
+  unsigned char *dst = (unsigned char *)ptr;
+  gtm_dispatch::mask_pair pair;
+
+  // If we're trying to drop a reference, we should already have a
+  // write lock on it.  If we don't have one, there's no work to do.
+  if (!gtm_stmlock_owned_p (*gtm_get_stmlock (src)))
+    return true;
+
+  // We copy the data in three stages:
+
+  // (a) Copy stray bytes at the beginning that are smaller than a
+  // cacheline.
+  if (sofs != 0)
+    {
+      size_t sleft = CACHELINE_SIZE - sofs;
+      size_t min = (size <= sleft ? size : sleft);
+
+      // WaW will give us the current locked entry.
+      pair = this->write_lock (src, WaW);
+
+      // *jedi mind wave*...these aren't the droids you're looking for.
+      *pair.mask &= ~((((gtm_cacheline_mask)1 << min) - 1) << sofs);
+
+      memcpy (dst, &pair.line->b[sofs], min);
+      dst += min;
+      src++;
+      size -= min;
+    }
+
+  // (b) Copy subsequent cacheline sized chunks.
+  while (size >= CACHELINE_SIZE)
+    {
+      pair = this->write_lock(src, WaW);
+      *pair.mask = 0;
+      memcpy (dst, src, CACHELINE_SIZE);
+      dst += CACHELINE_SIZE;
+      src++;
+      size -= CACHELINE_SIZE;
+    }
+
+  // (c) Copy anything left over.
+  if (size != 0)
+    {
+      pair = this->write_lock(src, WaW);
+      *pair.mask &= ~(((gtm_cacheline_mask)1 << size) - 1);
+      memcpy (dst, pair.line, size);
+    }
+
+  // No need to drop locks, since we're going to abort the transaction
+  // anyhow.
+
+  return true;
+}
+
+
 wbetl_dispatch::wbetl_dispatch ()
   : gtm_dispatch (false, false)
 {
Index: method-readonly.cc
===================================================================
--- method-readonly.cc	(revision 161318)
+++ method-readonly.cc	(working copy)
@@ -42,6 +42,7 @@  class readonly_dispatch : public gtm_dis
   virtual void rollback();
   virtual void reinit();
   virtual void fini();
+  virtual bool trydropreference (void *ptr, size_t size) { return true; }
 };
 
 inline
Index: alloc_c.cc
===================================================================
--- alloc_c.cc	(revision 161326)
+++ alloc_c.cc	(working copy)
@@ -61,9 +61,11 @@  _ITM_free (void *ptr)
 
 __attribute__((transaction_pure))
 void ITM_REGPARM
-_ITM_dropReferences (const void *ptr, size_t len)
+_ITM_dropReferences (void *ptr, size_t len)
 {
   gtm_transaction *tx = gtm_tx();
+  if (!gtm_disp()->trydropreference (ptr, len))
+    tx->restart (RESTART_VALIDATE_READ);
   tx->drop_references_local (ptr, len);
   tx->drop_references_allocations (ptr);
 }
Index: libitm.h
===================================================================
--- libitm.h	(revision 161326)
+++ libitm.h	(working copy)
@@ -153,7 +153,7 @@  extern void _ITM_addUserUndoAction(_ITM_
 extern int _ITM_getThreadnum(void) ITM_REGPARM;
 
 __attribute__((transaction_pure))
-extern void _ITM_dropReferences (const void *, size_t) ITM_REGPARM;
+extern void _ITM_dropReferences (void *, size_t) ITM_REGPARM;
 
 
 /* The following typedefs exist to make the macro expansions below work
Index: method-serial.cc
===================================================================
--- method-serial.cc	(revision 161318)
+++ method-serial.cc	(working copy)
@@ -64,6 +64,7 @@  class serial_dispatch : public gtm_dispa
   virtual void rollback() { abort(); }
   virtual void reinit() { }
   virtual void fini() { }
+  virtual bool trydropreference (void *ptr, size_t size) { return true; }
 };
 
 } // anon namespace
Index: testsuite/libitm.c/dropref-2.c
===================================================================
--- testsuite/libitm.c/dropref-2.c	(revision 0)
+++ testsuite/libitm.c/dropref-2.c	(revision 0)
@@ -0,0 +1,35 @@ 
+#include <stdlib.h>
+#include <libitm.h>
+
+/* Test that _ITM_dropReferences() forces a commit of given chunk.  */
+
+unsigned char pp[100];
+
+int main()
+{
+  int i;
+
+  for(i=0; i < 100; ++i)
+    pp[i]=0x22;
+
+  __transaction {
+    for(i=0; i < 100; ++i)
+      pp[i]=0x33;
+
+    /* This should write-through pp[0..49]...  */
+    _ITM_dropReferences (pp, 50);
+
+    /* ...while this should revert everything but pp[0..49].  */
+    __transaction_cancel;
+  }
+
+  for(i=0; i < 50; ++i)
+    if (pp[i] != 0x33)
+      abort();
+
+  for(i=50; i < 100; ++i)
+    if (pp[i] != 0x22)
+      abort();
+
+  return 0;
+}
Index: libitm_i.h
===================================================================
--- libitm_i.h	(revision 161326)
+++ libitm_i.h	(working copy)
@@ -114,6 +114,7 @@  struct gtm_dispatch
   virtual bool trycommit() = 0;
   virtual void rollback() = 0;
   virtual void reinit() = 0;
+  virtual bool trydropreference(void *, size_t) = 0;
 
   // Use fini instead of dtor to support a static subclasses that uses
   // a unique object and so we don't want to destroy it from common code.