1 /* ---------------------------------------------------------------------------
3 * (c) The GHC Team, 2000-2008
5 * Sparking support for PARALLEL_HASKELL and THREADED_RTS versions of the RTS.
7 -------------------------------------------------------------------------*/
9 #include "PosixSource.h"
18 #if defined(THREADED_RTS)
21 initSparkPools( void )
23 /* walk over the capabilities, allocating a spark pool for each one */
25 for (i = 0; i < n_capabilities; i++) {
26 capabilities[i].sparks = newWSDeque(RtsFlags.ParFlags.maxLocalSparks);
31 freeSparkPool (SparkPool *pool)
36 /* -----------------------------------------------------------------------------
38 * Turn a spark into a real thread
40 * -------------------------------------------------------------------------- */
43 createSparkThread (Capability *cap)
47 tso = createIOThread (cap, RtsFlags.GcFlags.initialStkSize,
48 (StgClosure *)runSparks_closure);
50 traceEventCreateSparkThread(cap, tso->id);
52 appendToRunQueue(cap,tso);
55 /* --------------------------------------------------------------------------
56 * newSpark: create a new spark, as a result of calling "par"
57 * Called directly from STG.
58 * -------------------------------------------------------------------------- */
61 newSpark (StgRegTable *reg, StgClosure *p)
63 Capability *cap = regTableToCapability(reg);
64 SparkPool *pool = cap->sparks;
66 /* I am not sure whether this is the right thing to do.
67 * Maybe it is better to exploit the tag information
68 * instead of throwing it away?
72 if (closure_SHOULD_SPARK(p)) {
74 cap->sparks_created++;
82 /* -----------------------------------------------------------------------------
84 * tryStealSpark: try to steal a spark from a Capability.
86 * Returns a valid spark, or NULL if the pool was empty, and can
87 * occasionally return NULL if there was a race with another thread
88 * stealing from the same pool. In this case, try again later.
90 -------------------------------------------------------------------------- */
93 tryStealSpark (Capability *cap)
95 SparkPool *pool = cap->sparks;
99 stolen = stealWSDeque_(pool);
100 // use the no-loopy version, stealWSDeque_(), since if we get a
101 // spurious NULL here the caller may want to try stealing from
102 // other pools before trying again.
103 } while (stolen != NULL && !closure_SHOULD_SPARK(stolen));
108 /* --------------------------------------------------------------------------
109 * Remove all sparks from the spark queues which should not spark any
110 * more. Called after GC. We assume exclusive access to the structure
111 * and replace all sparks in the queue, see explanation below. At exit,
112 * the spark pool only contains sparkable closures.
113 * -------------------------------------------------------------------------- */
116 pruneSparkQueue (Capability *cap)
119 StgClosurePtr spark, tmp, *elements;
120 nat n, pruned_sparks; // stats only
121 StgWord botInd,oldBotInd,currInd; // indices in array (always < size)
122 const StgInfoTable *info;
129 // it is possible that top > bottom, indicating an empty pool. We
130 // fix that here; this is only necessary because the loop below
132 if (pool->top > pool->bottom)
133 pool->top = pool->bottom;
135 // Take this opportunity to reset top/bottom modulo the size of
136 // the array, to avoid overflow. This is only possible because no
137 // stealing is happening during GC.
138 pool->bottom -= pool->top & ~pool->moduloSize;
139 pool->top &= pool->moduloSize;
140 pool->topBound = pool->top;
142 debugTrace(DEBUG_sparks,
143 "markSparkQueue: current spark queue len=%ld; (hd=%ld; tl=%ld)",
144 sparkPoolSize(pool), pool->bottom, pool->top);
146 ASSERT_WSDEQUE_INVARIANTS(pool);
148 elements = (StgClosurePtr *)pool->elements;
150 /* We have exclusive access to the structure here, so we can reset
151 bottom and top counters, and prune invalid sparks. Contents are
152 copied in-place if they are valuable, otherwise discarded. The
153 routine uses "real" indices t and b, starts by computing them
154 as the modulus size of top and bottom,
158 At the beginning, the pool structure can look like this:
159 ( bottom % size >= top % size , no wrap-around)
161 ___________***********_________________
163 or like this ( bottom % size < top % size, wrap-around )
165 ***********__________******************
166 As we need to remove useless sparks anyway, we make one pass
167 between t and b, moving valuable content to b and subsequent
168 cells (wrapping around when the size is reached).
171 ***********OOO_______XX_X__X?**********
174 After this movement, botInd becomes the new bottom, and old
175 bottom becomes the new top index, both as indices in the array
179 currInd = (pool->top) & (pool->moduloSize); // mod
181 // copies of evacuated closures go to space from botInd on
182 // we keep oldBotInd to know when to stop
183 oldBotInd = botInd = (pool->bottom) & (pool->moduloSize); // mod
185 // on entry to loop, we are within the bounds
186 ASSERT( currInd < pool->size && botInd < pool->size );
188 while (currInd != oldBotInd ) {
189 /* must use != here, wrap-around at size
190 subtle: loop not entered if queue empty
193 /* check element at currInd. if valuable, evacuate and move to
194 botInd, otherwise move on */
195 spark = elements[currInd];
197 // We have to be careful here: in the parallel GC, another
198 // thread might evacuate this closure while we're looking at it,
199 // so grab the info pointer just once.
200 if (GET_CLOSURE_TAG(spark) != 0) {
201 // Tagged pointer is a value, so the spark has fizzled. It
202 // probably never happens that we get a tagged pointer in
203 // the spark pool, because we would have pruned the spark
204 // during the previous GC cycle if it turned out to be
205 // evaluated, but it doesn't hurt to have this check for
208 cap->sparks_fizzled++;
210 info = spark->header.info;
211 if (IS_FORWARDING_PTR(info)) {
212 tmp = (StgClosure*)UN_FORWARDING_PTR(info);
213 /* if valuable work: shift inside the pool */
214 if (closure_SHOULD_SPARK(tmp)) {
215 elements[botInd] = tmp; // keep entry (new address)
219 pruned_sparks++; // discard spark
220 cap->sparks_fizzled++;
222 } else if (HEAP_ALLOCED(spark)) {
223 if ((Bdescr((P_)spark)->flags & BF_EVACUATED)) {
224 if (closure_SHOULD_SPARK(spark)) {
225 elements[botInd] = spark; // keep entry (new address)
229 pruned_sparks++; // discard spark
230 cap->sparks_fizzled++;
233 pruned_sparks++; // discard spark
237 if (INFO_PTR_TO_STRUCT(info)->type == THUNK_STATIC) {
238 if (*THUNK_STATIC_LINK(spark) != NULL) {
239 elements[botInd] = spark; // keep entry (new address)
243 pruned_sparks++; // discard spark
247 pruned_sparks++; // discard spark
248 cap->sparks_fizzled++;
255 // in the loop, we may reach the bounds, and instantly wrap around
256 ASSERT( currInd <= pool->size && botInd <= pool->size );
257 if ( currInd == pool->size ) { currInd = 0; }
258 if ( botInd == pool->size ) { botInd = 0; }
260 } // while-loop over spark pool elements
262 ASSERT(currInd == oldBotInd);
264 pool->top = oldBotInd; // where we started writing
265 pool->topBound = pool->top;
267 pool->bottom = (oldBotInd <= botInd) ? botInd : (botInd + pool->size);
268 // first free place we did not use (corrected by wraparound)
270 debugTrace(DEBUG_sparks, "pruned %d sparks", pruned_sparks);
272 debugTrace(DEBUG_sparks,
273 "new spark queue len=%ld; (hd=%ld; tl=%ld)",
274 sparkPoolSize(pool), pool->bottom, pool->top);
276 ASSERT_WSDEQUE_INVARIANTS(pool);
279 /* GC for the spark pool, called inside Capability.c for all
280 capabilities in turn. Blindly "evac"s complete spark pool. */
282 traverseSparkQueue (evac_fn evac, void *user, Capability *cap)
286 StgWord top,bottom, modMask;
290 ASSERT_WSDEQUE_INVARIANTS(pool);
293 bottom = pool->bottom;
294 sparkp = (StgClosurePtr*)pool->elements;
295 modMask = pool->moduloSize;
297 while (top < bottom) {
298 /* call evac for all closures in range (wrap-around via modulo)
299 * In GHC-6.10, evac takes an additional 1st argument to hold a
300 * GC-specific register, see rts/sm/GC.c::mark_root()
302 evac( user , sparkp + (top & modMask) );
306 debugTrace(DEBUG_sparks,
307 "traversed spark queue, len=%ld; (hd=%ld; tl=%ld)",
308 sparkPoolSize(pool), pool->bottom, pool->top);
311 /* ----------------------------------------------------------------------------
312 * balanceSparkPoolsCaps: takes an array of capabilities (usually: all
313 * capabilities) and its size. Accesses all spark pools and equally
314 * distributes the sparks among them.
316 * Could be called after GC, before Cap. release, from scheduler.
317 * -------------------------------------------------------------------------- */
318 void balanceSparkPoolsCaps(nat n_caps, Capability caps[])
319 GNUC3_ATTRIBUTE(__noreturn__);
321 void balanceSparkPoolsCaps(nat n_caps STG_UNUSED,
322 Capability caps[] STG_UNUSED) {
323 barf("not implemented");
329 newSpark (StgRegTable *reg STG_UNUSED, StgClosure *p STG_UNUSED)
335 #endif /* THREADED_RTS */