On 2012-11-08 15:32, Torvald Riegel wrote:
> On Thu, 2012-11-08 at 15:38 +0000, Lai, Konrad wrote:
>> The xabort argument is the only "escape" currently allowed in RTM. So it is 
>> not possible to use a separate Boolean in memory.
> 
> No, that's not what I meant.  The boolean would be used in libitm's
> htm_abort(), which the architecture-specific code (eg,
> config/x86/target.h) would then change into whatever the particular HTM
> uses as abort reasons (eg, true would become 0xff).  That's just to keep
> as much of libitm portable as possible, nothing more.
> 
>> [Roman just posted an example in 
>> http://software.intel.com/en-us/blogs/2012/11/06/exploring-intel-transactional-synchronization-extensions-with-intel-software
>>  ]
>>
>> I don't know "any" large code that uses cancel. Someone claim there is one 
>> in STAMP, and one got speed up if it was removed. I think this discussion 
>> potentially explains why.
> 
> The abort in STAMP is bogus.  They didn't instrument all of the code (if
> you use the manual instrumentation), and the abort is just there to
> "catch" race conditions and other inconsistencies.
> 
> My suggestions for next steps are to move the begin stuff to assembly.
> After that, we can go for the abort branch, if removing it really makes
> a non-negligible performance difference.

I believe this is the sort of patch that Torvald was talking about
for handling abortTransaction with RTM.

Andi, can you please test?


r~
diff --git a/libitm/beginend.cc b/libitm/beginend.cc
index 4369946..8f5c4ef 100644
--- a/libitm/beginend.cc
+++ b/libitm/beginend.cc
@@ -166,18 +166,16 @@ GTM::gtm_thread::begin_transaction (uint32_t prop, const 
gtm_jmpbuf *jb)
     GTM_fatal("pr_undoLogCode not supported");
 
 #if defined(USE_HTM_FASTPATH) && !defined(HTM_CUSTOM_FASTPATH)
-  // HTM fastpath.  Only chosen in the absence of transaction_cancel to allow
-  // using an uninstrumented code path.
-  // The fastpath is enabled only by dispatch_htm's method group, which uses
-  // serial-mode methods as fallback.  Serial-mode transactions cannot execute
-  // concurrently with HW transactions because the latter monitor the serial
-  // lock's writer flag and thus abort if another thread is or becomes a
-  // serial transaction.  Therefore, if the fastpath is enabled, then a
-  // transaction is not executing as a HW transaction iff the serial lock is
-  // write-locked.  This allows us to use htm_fastpath and the serial lock's
-  // writer flag to reliable determine whether the current thread runs a HW
-  // transaction, and thus we do not need to maintain this information in
-  // per-thread state.
+  // HTM fastpath.  The fastpath is enabled only by dispatch_htm's method
+  // group, which uses serial-mode methods as fallback.  Serial-mode
+  // transactions cannot execute concurrently with HW transactions because
+  // the latter monitor the serial lock's writer flag and thus abort if
+  // another thread is or becomes a serial transaction.  Therefore, if the
+  // fastpath is enabled, then a transaction is not executing as a HW
+  // transaction iff the serial lock is write-locked.  This allows us to
+  // use htm_fastpath and the serial lock's writer flag to reliable determine
+  // whether the current thread runs a HW transaction, and thus we do not
+  // need to maintain this information in per-thread state.
   // If an uninstrumented code path is not available, we can still run
   // instrumented code from a HW transaction because the HTM fastpath kicks
   // in early in both begin and commit, and the transaction is not canceled.
@@ -187,7 +185,7 @@ GTM::gtm_thread::begin_transaction (uint32_t prop, const 
gtm_jmpbuf *jb)
   // indeed in serial mode, and HW transactions should never need serial mode
   // for any internal changes (e.g., they never abort visibly to the STM code
   // and thus do not trigger the standard retry handling).
-  if (likely(htm_fastpath && (prop & pr_hasNoAbort)))
+  if (likely(htm_fastpath))
     {
       for (uint32_t t = htm_fastpath; t; t--)
        {
@@ -198,33 +196,41 @@ GTM::gtm_thread::begin_transaction (uint32_t prop, const 
gtm_jmpbuf *jb)
              // Monitor the writer flag in the serial-mode lock, and abort
              // if there is an active or waiting serial-mode transaction.
              if (unlikely(serial_lock.is_write_locked()))
-               htm_abort();
+               htm_abort_retry();
              else
                // We do not need to set a_saveLiveVariables because of HTM.
                return (prop & pr_uninstrumentedCode) ?
                    a_runUninstrumentedCode : a_runInstrumentedCode;
            }
-         // The transaction has aborted.  Don't retry if it's unlikely that
+         // The transaction has aborted.  Retry if it's likely that
          // retrying the transaction will be successful.
-         if (!htm_abort_should_retry(ret))
-           break;
-         // Wait until any concurrent serial-mode transactions have finished.
-         // This is an empty critical section, but won't be elided.
-         if (serial_lock.is_write_locked())
+         if (htm_abort_should_retry(ret))
            {
-             tx = gtm_thr();
-             if (unlikely(tx == NULL))
-               {
-                 // See below.
-                 tx = new gtm_thread();
-                 set_gtm_thr(tx);
-               }
-             serial_lock.read_lock(tx);
-             serial_lock.read_unlock(tx);
-             // TODO We should probably reset the retry count t here, unless
-             // we have retried so often that we should go serial to avoid
-             // starvation.
+             // Wait until any concurrent serial-mode transactions have
+             // finished.  This is an empty critical section, but won't
+             // be elided.
+             if (serial_lock.is_write_locked())
+               {
+                 tx = gtm_thr();
+                 if (unlikely(tx == NULL))
+                   {
+                     // See below.
+                     tx = new gtm_thread();
+                     set_gtm_thr(tx);
+                   }
+                 serial_lock.read_lock(tx);
+                 serial_lock.read_unlock(tx);
+                 // TODO We should probably reset the retry count t here,
+                 // unless we have retried so often that we should go
+                 // serial to avoid starvation.
+               }
            }
+         // Honor an abort from abortTransaction.
+         else if (htm_abort_is_cancel(ret))
+           return a_abortTransaction | a_restoreLiveVariables;
+         // Otherwise quit using HTM and fall back to STM.
+         else
+           break;
        }
     }
 #endif
@@ -438,6 +444,11 @@ GTM::gtm_thread::rollback (gtm_transaction_cp *cp, bool 
aborting)
 void ITM_REGPARM
 _ITM_abortTransaction (_ITM_abortReason reason)
 {
+#if defined(USE_HTM_FASTPATH)
+  if (likely(htm_fastpath && !gtm_thread::serial_lock.is_write_locked()))
+    htm_abort_cancel();
+#endif
+
   gtm_thread *tx = gtm_thr();
 
   assert (reason == userAbort || reason == (userAbort | outerAbort));
diff --git a/libitm/config/x86/target.h b/libitm/config/x86/target.h
index 41ae2eb..1d2e822 100644
--- a/libitm/config/x86/target.h
+++ b/libitm/config/x86/target.h
@@ -125,18 +125,32 @@ htm_commit ()
 }
 
 static inline void
-htm_abort ()
+htm_abort_retry ()
 {
   // ??? According to a yet unpublished ABI rule, 0xff is reserved and
   // supposed to signal a busy lock.  Source: andi.kl...@intel.com
   _xabort(0xff);
 }
 
+static inline void
+htm_abort_cancel ()
+{
+  // ??? What's the unpublished ABI rule for this, Andi?
+  _xabort(0);
+}
+
 static inline bool
 htm_abort_should_retry (uint32_t begin_ret)
 {
   return begin_ret & _XABORT_RETRY;
 }
+
+static inline bool
+htm_abort_is_cancel (uint32_t begin_ret)
+{
+  // return (begin_ret & _XABORT_EXPLICIT) && _XABORT_CODE(begin_ret) == 0;
+  return begin_ret == _XABORT_EXPLICIT;
+}
 #endif
 
 

Reply via email to