[commit: ghc] master: STM: Only wake up once (a23661d)

Simon Marlow marlowsd at gmail.com
Wed Jan 30 12:01:08 CET 2013


Repository : ssh://darcs.haskell.org//srv/darcs/ghc

On branch  : master

http://hackage.haskell.org/trac/ghc/changeset/a23661d242e8dd55007c4aee8a053f35de7705bd

>---------------------------------------------------------------

commit a23661d242e8dd55007c4aee8a053f35de7705bd
Author: Ben Gamari <bgamari.foss at gmail.com>
Date:   Mon Jan 28 11:15:08 2013 -0500

    STM: Only wake up once
    
    Previously, threads blocked on an STM retry would be sent a wakeup
    message each time an unpark was requested. This could result in the
    accumulation of a large number of wake-up messages, which would slow
    wake-up once the sleeping thread is finally scheduled.
    
    Here, we introduce a new closure type, STM_AWOKEN, which marks a TSO
    which has been sent a wake-up message, allowing us to send only one
    wakeup.

>---------------------------------------------------------------

 includes/Cmm.h              |    1 +
 includes/rts/storage/TSO.h  |    4 +++-
 includes/stg/MiscClosures.h |    2 ++
 rts/STM.c                   |   16 +++++++++++-----
 rts/StgMiscClosures.cmm     |   12 ++++++++++++
 5 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/includes/Cmm.h b/includes/Cmm.h
index 5ef6c2d..41e7b89 100644
--- a/includes/Cmm.h
+++ b/includes/Cmm.h
@@ -744,6 +744,7 @@
 
 #define NO_TREC                   stg_NO_TREC_closure
 #define END_TSO_QUEUE             stg_END_TSO_QUEUE_closure
+#define STM_AWOKEN                stg_STM_AWOKEN_closure
 #define END_INVARIANT_CHECK_QUEUE stg_END_INVARIANT_CHECK_QUEUE_closure
 
 #define recordMutableCap(p, gen)                                        \
diff --git a/includes/rts/storage/TSO.h b/includes/rts/storage/TSO.h
index 82f5a75..e9c2655 100644
--- a/includes/rts/storage/TSO.h
+++ b/includes/rts/storage/TSO.h
@@ -218,7 +218,8 @@ void dirty_STACK (Capability *cap, StgStack *stack);
 	
         BlockedOnMVar          the MVAR             the MVAR's queue
 
-	BlockedOnSTM           END_TSO_QUEUE        STM wait queue(s)
+        BlockedOnSTM           END_TSO_QUEUE        STM wait queue(s)
+        BlockedOnSTM           STM_AWOKEN           run queue
 	
         BlockedOnMsgThrowTo    MessageThrowTo *     TSO->blocked_exception
 
@@ -252,5 +253,6 @@ void dirty_STACK (Capability *cap, StgStack *stack);
 
 /* this is the NIL ptr for a TSO queue (e.g. runnable queue) */
 #define END_TSO_QUEUE  ((StgTSO *)(void*)&stg_END_TSO_QUEUE_closure)
+#define STM_AWOKEN     ((StgTSO *)(void*)&stg_STM_AWOKEN_closure)
 
 #endif /* RTS_STORAGE_TSO_H */
diff --git a/includes/stg/MiscClosures.h b/includes/stg/MiscClosures.h
index 61e6b09..0eccfbf 100644
--- a/includes/stg/MiscClosures.h
+++ b/includes/stg/MiscClosures.h
@@ -114,6 +114,7 @@ RTS_ENTRY(stg_MUT_ARR_PTRS_FROZEN0);
 RTS_ENTRY(stg_MUT_VAR_CLEAN);
 RTS_ENTRY(stg_MUT_VAR_DIRTY);
 RTS_ENTRY(stg_END_TSO_QUEUE);
+RTS_ENTRY(stg_STM_AWOKEN);
 RTS_ENTRY(stg_MSG_TRY_WAKEUP);
 RTS_ENTRY(stg_MSG_THROWTO);
 RTS_ENTRY(stg_MSG_BLACKHOLE);
@@ -142,6 +143,7 @@ RTS_ENTRY(stg_NO_TREC);
 /* closures */
 
 RTS_CLOSURE(stg_END_TSO_QUEUE_closure);
+RTS_CLOSURE(stg_STM_AWOKEN_closure);
 RTS_CLOSURE(stg_NO_FINALIZER_closure);
 RTS_CLOSURE(stg_dummy_ret_closure);
 RTS_CLOSURE(stg_forceIO_closure);
diff --git a/rts/STM.c b/rts/STM.c
index 62ced25..7400d57 100644
--- a/rts/STM.c
+++ b/rts/STM.c
@@ -380,13 +380,19 @@ static void unpark_tso(Capability *cap, StgTSO *tso) {
 
     // Unblocking a TSO from BlockedOnSTM is done under the TSO lock,
     // to avoid multiple CPUs unblocking the same TSO, and also to
-    // synchronise with throwTo().
+    // synchronise with throwTo(). The first time the TSO is unblocked
+    // we mark this fact by setting block_info.closure == STM_AWOKEN.
+    // This way we can avoid sending further wakeup messages in the
+    // future.
     lockTSO(tso);
-    if (tso -> why_blocked == BlockedOnSTM) {
-	TRACE("unpark_tso on tso=%p", tso);
-        tryWakeupThread(cap,tso);
+    if (tso->why_blocked == BlockedOnSTM && tso->block_info.closure == STM_AWOKEN) {
+      TRACE("unpark_tso already woken up tso=%p", tso);
+    } else if (tso -> why_blocked == BlockedOnSTM) {
+      TRACE("unpark_tso on tso=%p", tso);
+      tso->block_info.closure = STM_AWOKEN;
+      tryWakeupThread(cap,tso);
     } else {
-	TRACE("spurious unpark_tso on tso=%p", tso);
+      TRACE("spurious unpark_tso on tso=%p", tso);
     }
     unlockTSO(tso);
 }
diff --git a/rts/StgMiscClosures.cmm b/rts/StgMiscClosures.cmm
index 4341013..28a41ad 100644
--- a/rts/StgMiscClosures.cmm
+++ b/rts/StgMiscClosures.cmm
@@ -547,6 +547,18 @@ INFO_TABLE_CONSTR(stg_END_TSO_QUEUE,0,0,0,CONSTR_NOCAF_STATIC,"END_TSO_QUEUE","E
 CLOSURE(stg_END_TSO_QUEUE_closure,stg_END_TSO_QUEUE);
 
 /* ----------------------------------------------------------------------------
+   STM_AWOKEN
+
+   This is a static nullary constructor (like []) that we use to mark a
+   thread waiting on an STM wakeup
+   ------------------------------------------------------------------------- */
+
+INFO_TABLE_CONSTR(stg_STM_AWOKEN,0,0,0,CONSTR_NOCAF_STATIC,"STM_AWOKEN","STM_AWOKEN")
+{ foreign "C" barf("STM_AWOKEN object entered!") never returns; }
+
+CLOSURE(stg_STM_AWOKEN_closure,stg_STM_AWOKEN);
+
+/* ----------------------------------------------------------------------------
    Arrays
 
    These come in two basic flavours: arrays of data (StgArrWords) and arrays of





More information about the ghc-commits mailing list