Unify event logging and debug tracing.
[ghc-hetmet.git] / rts / Sparks.c
1 /* ---------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 2000-2008
4  *
5  * Sparking support for PARALLEL_HASKELL and THREADED_RTS versions of the RTS.
6  *
7  -------------------------------------------------------------------------*/
8
9 #include "PosixSource.h"
10 #include "Rts.h"
11
12 #include "Schedule.h"
13 #include "RtsUtils.h"
14 #include "Trace.h"
15 #include "Prelude.h"
16 #include "Sparks.h"
17
18 #if defined(THREADED_RTS)
19
20 void
21 initSparkPools( void )
22 {
23     /* walk over the capabilities, allocating a spark pool for each one */
24     nat i;
25     for (i = 0; i < n_capabilities; i++) {
26       capabilities[i].sparks = newWSDeque(RtsFlags.ParFlags.maxLocalSparks);
27     }
28 }
29
30 void
31 freeSparkPool (SparkPool *pool)
32 {
33     freeWSDeque(pool);
34 }
35
36 /* -----------------------------------------------------------------------------
37  * 
38  * Turn a spark into a real thread
39  *
40  * -------------------------------------------------------------------------- */
41
42 void
43 createSparkThread (Capability *cap)
44 {
45     StgTSO *tso;
46
47     tso = createIOThread (cap, RtsFlags.GcFlags.initialStkSize, 
48                           &base_GHCziConc_runSparks_closure);
49
50     traceSchedEvent(cap, EVENT_CREATE_SPARK_THREAD, 0, tso->id);
51
52     appendToRunQueue(cap,tso);
53 }
54
55 /* --------------------------------------------------------------------------
56  * newSpark: create a new spark, as a result of calling "par"
57  * Called directly from STG.
58  * -------------------------------------------------------------------------- */
59
60 StgInt
61 newSpark (StgRegTable *reg, StgClosure *p)
62 {
63     Capability *cap = regTableToCapability(reg);
64     SparkPool *pool = cap->sparks;
65
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?
69      */
70     p = UNTAG_CLOSURE(p);
71
72     if (closure_SHOULD_SPARK(p)) {
73         pushWSDeque(pool,p);
74     }   
75
76     cap->sparks_created++;
77
78     return 1;
79 }
80
81 /* -----------------------------------------------------------------------------
82  * 
83  * tryStealSpark: try to steal a spark from a Capability.
84  *
85  * Returns a valid spark, or NULL if the pool was empty, and can
86  * occasionally return NULL if there was a race with another thread
87  * stealing from the same pool.  In this case, try again later.
88  *
89  -------------------------------------------------------------------------- */
90
91 StgClosure *
92 tryStealSpark (Capability *cap)
93 {
94   SparkPool *pool = cap->sparks;
95   StgClosure *stolen;
96
97   do { 
98       stolen = stealWSDeque_(pool); 
99       // use the no-loopy version, stealWSDeque_(), since if we get a
100       // spurious NULL here the caller may want to try stealing from
101       // other pools before trying again.
102   } while (stolen != NULL && !closure_SHOULD_SPARK(stolen));
103
104   return stolen;
105 }
106
107 /* --------------------------------------------------------------------------
108  * Remove all sparks from the spark queues which should not spark any
109  * more.  Called after GC. We assume exclusive access to the structure
110  * and replace  all sparks in the queue, see explanation below. At exit,
111  * the spark pool only contains sparkable closures.
112  * -------------------------------------------------------------------------- */
113
114 void
115 pruneSparkQueue (evac_fn evac, void *user, Capability *cap)
116
117     SparkPool *pool;
118     StgClosurePtr spark, tmp, *elements;
119     nat n, pruned_sparks; // stats only
120     StgWord botInd,oldBotInd,currInd; // indices in array (always < size)
121     const StgInfoTable *info;
122     
123     n = 0;
124     pruned_sparks = 0;
125     
126     pool = cap->sparks;
127     
128     // it is possible that top > bottom, indicating an empty pool.  We
129     // fix that here; this is only necessary because the loop below
130     // assumes it.
131     if (pool->top > pool->bottom)
132         pool->top = pool->bottom;
133
134     // Take this opportunity to reset top/bottom modulo the size of
135     // the array, to avoid overflow.  This is only possible because no
136     // stealing is happening during GC.
137     pool->bottom  -= pool->top & ~pool->moduloSize;
138     pool->top     &= pool->moduloSize;
139     pool->topBound = pool->top;
140
141     debugTrace(DEBUG_sparks,
142                "markSparkQueue: current spark queue len=%ld; (hd=%ld; tl=%ld)",
143                sparkPoolSize(pool), pool->bottom, pool->top);
144
145     ASSERT_WSDEQUE_INVARIANTS(pool);
146
147     elements = (StgClosurePtr *)pool->elements;
148
149     /* We have exclusive access to the structure here, so we can reset
150        bottom and top counters, and prune invalid sparks. Contents are
151        copied in-place if they are valuable, otherwise discarded. The
152        routine uses "real" indices t and b, starts by computing them
153        as the modulus size of top and bottom,
154
155        Copying:
156
157        At the beginning, the pool structure can look like this:
158        ( bottom % size >= top % size , no wrap-around)
159                   t          b
160        ___________***********_________________
161
162        or like this ( bottom % size < top % size, wrap-around )
163                   b         t
164        ***********__________******************
165        As we need to remove useless sparks anyway, we make one pass
166        between t and b, moving valuable content to b and subsequent
167        cells (wrapping around when the size is reached).
168
169                      b      t
170        ***********OOO_______XX_X__X?**********
171                      ^____move?____/
172
173        After this movement, botInd becomes the new bottom, and old
174        bottom becomes the new top index, both as indices in the array
175        size range.
176     */
177     // starting here
178     currInd = (pool->top) & (pool->moduloSize); // mod
179
180     // copies of evacuated closures go to space from botInd on
181     // we keep oldBotInd to know when to stop
182     oldBotInd = botInd = (pool->bottom) & (pool->moduloSize); // mod
183
184     // on entry to loop, we are within the bounds
185     ASSERT( currInd < pool->size && botInd  < pool->size );
186
187     while (currInd != oldBotInd ) {
188       /* must use != here, wrap-around at size
189          subtle: loop not entered if queue empty
190        */
191
192       /* check element at currInd. if valuable, evacuate and move to
193          botInd, otherwise move on */
194       spark = elements[currInd];
195
196       // We have to be careful here: in the parallel GC, another
197       // thread might evacuate this closure while we're looking at it,
198       // so grab the info pointer just once.
199       info = spark->header.info;
200       if (IS_FORWARDING_PTR(info)) {
201           tmp = (StgClosure*)UN_FORWARDING_PTR(info);
202           /* if valuable work: shift inside the pool */
203           if (closure_SHOULD_SPARK(tmp)) {
204               elements[botInd] = tmp; // keep entry (new address)
205               botInd++;
206               n++;
207           } else {
208               pruned_sparks++; // discard spark
209               cap->sparks_pruned++;
210           }
211       } else {
212           if (!(closure_flags[INFO_PTR_TO_STRUCT(info)->type] & _NS)) {
213               elements[botInd] = spark; // keep entry (new address)
214               evac (user, &elements[botInd]);
215               botInd++;
216               n++;
217           } else {
218               pruned_sparks++; // discard spark
219               cap->sparks_pruned++;
220           }
221       }
222       currInd++;
223
224       // in the loop, we may reach the bounds, and instantly wrap around
225       ASSERT( currInd <= pool->size && botInd <= pool->size );
226       if ( currInd == pool->size ) { currInd = 0; }
227       if ( botInd == pool->size )  { botInd = 0;  }
228
229     } // while-loop over spark pool elements
230
231     ASSERT(currInd == oldBotInd);
232
233     pool->top = oldBotInd; // where we started writing
234     pool->topBound = pool->top;
235
236     pool->bottom = (oldBotInd <= botInd) ? botInd : (botInd + pool->size); 
237     // first free place we did not use (corrected by wraparound)
238
239     debugTrace(DEBUG_sparks, "pruned %d sparks", pruned_sparks);
240     
241     debugTrace(DEBUG_sparks,
242                "new spark queue len=%ld; (hd=%ld; tl=%ld)",
243                sparkPoolSize(pool), pool->bottom, pool->top);
244
245     ASSERT_WSDEQUE_INVARIANTS(pool);
246 }
247
248 /* GC for the spark pool, called inside Capability.c for all
249    capabilities in turn. Blindly "evac"s complete spark pool. */
250 void
251 traverseSparkQueue (evac_fn evac, void *user, Capability *cap)
252 {
253     StgClosure **sparkp;
254     SparkPool *pool;
255     StgWord top,bottom, modMask;
256     
257     pool = cap->sparks;
258
259     ASSERT_WSDEQUE_INVARIANTS(pool);
260
261     top = pool->top;
262     bottom = pool->bottom;
263     sparkp = (StgClosurePtr*)pool->elements;
264     modMask = pool->moduloSize;
265
266     while (top < bottom) {
267     /* call evac for all closures in range (wrap-around via modulo)
268      * In GHC-6.10, evac takes an additional 1st argument to hold a
269      * GC-specific register, see rts/sm/GC.c::mark_root()
270      */
271       evac( user , sparkp + (top & modMask) ); 
272       top++;
273     }
274
275     debugTrace(DEBUG_sparks,
276                "traversed spark queue, len=%ld; (hd=%ld; tl=%ld)",
277                sparkPoolSize(pool), pool->bottom, pool->top);
278 }
279
280 /* ----------------------------------------------------------------------------
281  * balanceSparkPoolsCaps: takes an array of capabilities (usually: all
282  * capabilities) and its size. Accesses all spark pools and equally
283  * distributes the sparks among them.
284  *
285  * Could be called after GC, before Cap. release, from scheduler. 
286  * -------------------------------------------------------------------------- */
287 void balanceSparkPoolsCaps(nat n_caps, Capability caps[])
288    GNUC3_ATTRIBUTE(__noreturn__);
289
290 void balanceSparkPoolsCaps(nat n_caps STG_UNUSED, 
291                            Capability caps[] STG_UNUSED) {
292   barf("not implemented");
293 }
294
295 #else
296
297 StgInt
298 newSpark (StgRegTable *reg STG_UNUSED, StgClosure *p STG_UNUSED)
299 {
300     /* nothing */
301     return 1;
302 }
303
304 #endif /* THREADED_RTS */