From patchwork Mon Jun 28 20:28:27 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aldy Hernandez X-Patchwork-Id: 57189 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id E4DFFB6EE8 for ; Tue, 29 Jun 2010 06:28:42 +1000 (EST) Received: (qmail 11885 invoked by alias); 28 Jun 2010 20:28:39 -0000 Received: (qmail 11875 invoked by uid 22791); 28 Jun 2010 20:28:37 -0000 X-SWARE-Spam-Status: No, hits=-5.9 required=5.0 tests=AWL, BAYES_00, KAM_ADVERT2, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_CP, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 28 Jun 2010 20:28:32 +0000 Received: from int-mx05.intmail.prod.int.phx2.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.18]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o5SKSVs8007766 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 28 Jun 2010 16:28:31 -0400 Received: from redhat.com (vpn-9-222.rdu.redhat.com [10.11.9.222]) by int-mx05.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o5SKSRq8028554 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Mon, 28 Jun 2010 16:28:29 -0400 Date: Mon, 28 Jun 2010 16:28:27 -0400 From: Aldy Hernandez To: rth@redhat.com, gcc-patches@gcc.gnu.org Subject: [trans-mem] teach ITM_dropReferences() about the cache Message-ID: <20100628202826.GA13690@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-08-17) Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org 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. 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(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 +#include + +/* 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.