summaryrefslogtreecommitdiff
path: root/rts/Sparks.h
diff options
context:
space:
mode:
authorberthold@mathematik.uni-marburg.de <unknown>2008-09-15 13:28:46 +0000
committerberthold@mathematik.uni-marburg.de <unknown>2008-09-15 13:28:46 +0000
commitcf9650f2a1690c04051c716124bb0350adc74ae7 (patch)
treef2e622b8eea04515fc4a19d24a1ecb57a654b33d /rts/Sparks.h
parent7eeac4d143e9287d7c2e27ba23b84d175df49962 (diff)
downloadhaskell-cf9650f2a1690c04051c716124bb0350adc74ae7.tar.gz
Work stealing for sparks
Spark stealing support for PARALLEL_HASKELL and THREADED_RTS versions of the RTS. Spark pools are per capability, separately allocated and held in the Capability structure. The implementation uses Double-Ended Queues (deque) and cas-protected access. The write end of the queue (position bottom) can only be used with mutual exclusion, i.e. by exactly one caller at a time. Multiple readers can steal()/findSpark() from the read end (position top), and are synchronised without a lock, based on a cas of the top position. One reader wins, the others return NULL for a failure. Work stealing is called when Capabilities find no other work (inside yieldCapability), and tries all capabilities 0..n-1 twice, unless a theft succeeds. Inside schedulePushWork, all considered cap.s (those which were idle and could be grabbed) are woken up. Future versions should wake up capabilities immediately when putting a new spark in the local pool, from newSpark(). Patch has been re-recorded due to conflicting bugfixes in the sparks.c, also fixing a (strange) conflict in the scheduler.
Diffstat (limited to 'rts/Sparks.h')
-rw-r--r--rts/Sparks.h69
1 files changed, 42 insertions, 27 deletions
diff --git a/rts/Sparks.h b/rts/Sparks.h
index 8e0ba90f3d..dbbf268988 100644
--- a/rts/Sparks.h
+++ b/rts/Sparks.h
@@ -9,17 +9,45 @@
#ifndef SPARKS_H
#define SPARKS_H
+#if defined(PARALLEL_HASKELL)
+#error Sparks.c using new internal structure, needs major overhaul!
+#endif
+
+/* typedef for SparkPool in RtsTypes.h */
+
#if defined(THREADED_RTS)
+
+/* INVARIANTS, in this order: bottom/top consistent, reasonable size,
+ topBound consistent, space pointer, space accessible to us */
+#define ASSERT_SPARK_POOL_INVARIANTS(p) \
+ ASSERT((p)->bottom >= (p)->top); \
+ ASSERT((p)->size > 0); \
+ ASSERT((p)->size > (p)->bottom - (p)->top); \
+ ASSERT((p)->topBound <= (p)->top); \
+ ASSERT((p)->elements != NULL); \
+ ASSERT(*((p)->elements) || 1); \
+ ASSERT(*((p)->elements - 1 + ((p)->size)) || 1);
+
+// missing in old interface. Currently called by initSparkPools
+// internally.
+SparkPool* initPool(StgWord size);
+
+// special case: accessing our own pool, at the write end
+// otherwise, we can always steal from our pool as the others do...
+StgClosure* reclaimSpark(Capability *cap);
+
+rtsBool looksEmpty(SparkPool* deque);
+
+// rest: same as old interface
StgClosure * findSpark (Capability *cap);
void initSparkPools (void);
-void freeSparkPool (StgSparkPool *pool);
+void freeSparkPool (SparkPool *pool);
void createSparkThread (Capability *cap, StgClosure *p);
void pruneSparkQueues (void);
void traverseSparkQueue(evac_fn evac, void *user, Capability *cap);
-INLINE_HEADER void discardSparks (StgSparkPool *pool);
-INLINE_HEADER nat sparkPoolSize (StgSparkPool *pool);
-INLINE_HEADER rtsBool emptySparkPool (StgSparkPool *pool);
+INLINE_HEADER void discardSparks (SparkPool *pool);
+INLINE_HEADER nat sparkPoolSize (SparkPool *pool);
INLINE_HEADER void discardSparksCap (Capability *cap);
INLINE_HEADER nat sparkPoolSizeCap (Capability *cap);
@@ -32,46 +60,33 @@ INLINE_HEADER rtsBool emptySparkPoolCap (Capability *cap);
#if defined(PARALLEL_HASKELL) || defined(THREADED_RTS)
-INLINE_HEADER rtsBool
-emptySparkPool (StgSparkPool *pool)
-{
- return (pool->hd == pool->tl);
-}
+INLINE_HEADER rtsBool
+emptySparkPool (SparkPool *pool)
+{ return looksEmpty(pool); }
INLINE_HEADER rtsBool
emptySparkPoolCap (Capability *cap)
-{ return emptySparkPool(&cap->r.rSparks); }
+{ return looksEmpty(cap->sparks); }
INLINE_HEADER nat
-sparkPoolSize (StgSparkPool *pool)
+sparkPoolSize (SparkPool *pool)
{
- if (pool->hd <= pool->tl) {
- return (pool->tl - pool->hd);
- } else {
- return (pool->lim - pool->hd + pool->tl - pool->base);
- }
+ return (pool->bottom - pool->top);
}
INLINE_HEADER nat
sparkPoolSizeCap (Capability *cap)
-{ return sparkPoolSize(&cap->r.rSparks); }
+{ return sparkPoolSize(cap->sparks); }
INLINE_HEADER void
-discardSparks (StgSparkPool *pool)
+discardSparks (SparkPool *pool)
{
- pool->hd = pool->tl;
+ pool->top = pool->bottom = 0;
}
INLINE_HEADER void
discardSparksCap (Capability *cap)
-{ return discardSparks(&cap->r.rSparks); }
-
-
-#elif defined(THREADED_RTS)
-
-INLINE_HEADER rtsBool
-emptySparkPoolCap (Capability *cap STG_UNUSED)
-{ return rtsTrue; }
+{ return discardSparks(cap->sparks); }
#endif