X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2FSparks.c;h=8f52a611699c07f6d9403a452640feaeb7e74975;hb=17a596022d01987d5ffe7db0742aa8db267b8cc3;hp=ac11172a9d958299166be02b01e45c351a2f40ac;hpb=cf9650f2a1690c04051c716124bb0350adc74ae7;p=ghc-hetmet.git diff --git a/rts/Sparks.c b/rts/Sparks.c index ac11172..8f52a61 100644 --- a/rts/Sparks.c +++ b/rts/Sparks.c @@ -53,9 +53,9 @@ /* internal helpers ... */ -StgWord roundUp2(StgWord val); - -StgWord roundUp2(StgWord val) { +static StgWord +roundUp2(StgWord val) +{ StgWord rounded = 1; /* StgWord is unsigned anyway, only catch 0 */ @@ -69,25 +69,6 @@ StgWord roundUp2(StgWord val) { return rounded; } -INLINE_HEADER -rtsBool casTop(StgPtr addr, StgWord old, StgWord new); - -#if !defined(THREADED_RTS) -/* missing def. in non THREADED RTS, and makes no sense anyway... */ -StgWord cas(StgPtr addr,StgWord old,StgWord new); -StgWord cas(StgPtr addr,StgWord old,StgWord new) { - barf("cas: not implemented without multithreading"); - old = new = *addr; /* to avoid gcc warnings */ -} -#endif - -INLINE_HEADER -rtsBool casTop(StgWord* addr, StgWord old, StgWord new) { - StgWord res = cas((StgPtr) addr, old, new); - return ((res == old)); -} - -/* or simply like this */ #define CASTOP(addr,old,new) ((old) == cas(((StgPtr)addr),(old),(new))) /* ----------------------------------------------------------------------------- @@ -97,8 +78,9 @@ rtsBool casTop(StgWord* addr, StgWord old, StgWord new) { * -------------------------------------------------------------------------- */ /* constructor */ -SparkPool* initPool(StgWord size) { - +static SparkPool* +initPool(StgWord size) +{ StgWord realsize; SparkPool *q; @@ -136,14 +118,17 @@ initSparkPools( void ) } void -freeSparkPool(SparkPool *pool) { +freeSparkPool (SparkPool *pool) +{ /* should not interfere with concurrent findSpark() calls! And nobody should use the pointer any more. We cross our fingers...*/ stgFree(pool->elements); stgFree(pool); } -/* reclaimSpark(cap): remove a spark from the write end of the queue. +/* ----------------------------------------------------------------------------- + * + * reclaimSpark: remove a spark from the write end of the queue. * Returns the removed spark, and NULL if a race is lost or the pool * empty. * @@ -151,9 +136,12 @@ freeSparkPool(SparkPool *pool) { * concurrently stealing threads by using cas to modify the top field. * This routine should NEVER be called by a task which does not own * the capability. Can this be checked here? - */ -StgClosure* reclaimSpark(Capability *cap) { - SparkPool *deque = cap->sparks; + * + * -------------------------------------------------------------------------- */ + +StgClosure * +reclaimSpark (SparkPool *deque) +{ /* also a bit tricky, has to avoid concurrent steal() calls by accessing top with cas, when there is only one element left */ StgWord t, b; @@ -196,19 +184,17 @@ StgClosure* reclaimSpark(Capability *cap) { /* ----------------------------------------------------------------------------- * - * findSpark: find a spark on the current Capability that we can fork - * into a thread. + * tryStealSpark: try to steal a spark from a Capability. * - * May be called by concurrent threads, which synchronise on top - * variable. Returns a spark, or NULL if pool empty or race lost. + * Returns a valid spark, or NULL if the pool was empty, and can + * occasionally return NULL if there was a race with another thread + * stealing from the same pool. In this case, try again later. * -------------------------------------------------------------------------- */ -StgClosurePtr steal(SparkPool *deque); - -/* steal an element from the read end. Synchronises multiple callers - by failing with NULL return. Returns NULL when deque is empty. */ -StgClosurePtr steal(SparkPool *deque) { +static StgClosurePtr +steal(SparkPool *deque) +{ StgClosurePtr* pos; StgClosurePtr* arraybase; StgWord sz; @@ -231,43 +217,39 @@ StgClosurePtr steal(SparkPool *deque) { /* now decide whether we have won */ if ( !(CASTOP(&(deque->top),t,t+1)) ) { - /* lost the race, someon else has changed top in the meantime */ - stolen = NULL; + /* lost the race, someon else has changed top in the meantime */ + return NULL; } /* else: OK, top has been incremented by the cas call */ - ASSERT_SPARK_POOL_INVARIANTS(deque); - /* return NULL or stolen element */ + /* return stolen element */ return stolen; } StgClosure * -findSpark (Capability *cap) +tryStealSpark (SparkPool *pool) { - SparkPool *deque = (cap->sparks); StgClosure *stolen; - ASSERT_SPARK_POOL_INVARIANTS(deque); - do { - /* keep trying until good spark found or pool looks empty. - TODO is this a good idea? */ + stolen = steal(pool); + } while (stolen != NULL && !closure_SHOULD_SPARK(stolen)); - stolen = steal(deque); - - } while ( ( !stolen /* nothing stolen*/ - || !closure_SHOULD_SPARK(stolen)) /* spark not OK */ - && !looksEmpty(deque)); /* run empty, give up */ - - /* return stolen element */ return stolen; } -/* "guesses" whether a deque is empty. Can return false negatives in - presence of concurrent steal() calls, and false positives in - presence of a concurrent pushBottom().*/ -rtsBool looksEmpty(SparkPool* deque) { +/* ----------------------------------------------------------------------------- + * + * "guesses" whether a deque is empty. Can return false negatives in + * presence of concurrent steal() calls, and false positives in + * presence of a concurrent pushBottom(). + * + * -------------------------------------------------------------------------- */ + +rtsBool +looksEmpty(SparkPool* deque) +{ StgWord t = deque->top; StgWord b = deque->bottom; /* try to prefer false negatives by reading top first */ @@ -288,6 +270,7 @@ createSparkThread (Capability *cap, StgClosure *p) tso = createGenThread (cap, RtsFlags.GcFlags.initialStkSize, p); appendToRunQueue(cap,tso); + cap->sparks_converted++; } /* ----------------------------------------------------------------------------- @@ -297,11 +280,12 @@ createSparkThread (Capability *cap, StgClosure *p) * -------------------------------------------------------------------------- */ #define DISCARD_NEW -void pushBottom(SparkPool* deque, StgClosurePtr elem); /* enqueue an element. Should always succeed by resizing the array (not implemented yet, silently fails in that case). */ -void pushBottom(SparkPool* deque, StgClosurePtr elem) { +static void +pushBottom (SparkPool* deque, StgClosurePtr elem) +{ StgWord t; StgClosurePtr* pos; StgWord sz = deque->moduloSize; @@ -349,12 +333,16 @@ void pushBottom(SparkPool* deque, StgClosurePtr elem) { } -/* this is called as a direct C-call from Stg => we need to keep the - pool in a register (???) */ +/* -------------------------------------------------------------------------- + * newSpark: create a new spark, as a result of calling "par" + * Called directly from STG. + * -------------------------------------------------------------------------- */ + StgInt newSpark (StgRegTable *reg, StgClosure *p) { - SparkPool *pool = (reg->rCurrentTSO->cap->sparks); + Capability *cap = regTableToCapability(reg); + SparkPool *pool = cap->sparks; /* I am not sure whether this is the right thing to do. * Maybe it is better to exploit the tag information @@ -368,6 +356,8 @@ newSpark (StgRegTable *reg, StgClosure *p) pushBottom(pool,p); } + cap->sparks_created++; + ASSERT_SPARK_POOL_INVARIANTS(pool); return 1; } @@ -381,13 +371,14 @@ newSpark (StgRegTable *reg, StgClosure *p) * the spark pool only contains sparkable closures. * -------------------------------------------------------------------------- */ -static void -pruneSparkQueue (Capability *cap) +void +pruneSparkQueue (evac_fn evac, void *user, Capability *cap) { SparkPool *pool; - StgClosurePtr spark, evacspark, *elements; + StgClosurePtr spark, tmp, *elements; nat n, pruned_sparks; // stats only StgWord botInd,oldBotInd,currInd; // indices in array (always < size) + const StgInfoTable *info; PAR_TICKY_MARK_SPARK_QUEUE_START(); @@ -450,13 +441,31 @@ pruneSparkQueue (Capability *cap) botInd, otherwise move on */ spark = elements[currInd]; - /* if valuable work: shift inside the pool */ - if ( closure_SHOULD_SPARK(spark) ) { - elements[botInd] = spark; // keep entry (new address) - botInd++; - n++; - } else { - pruned_sparks++; // discard spark + // We have to be careful here: in the parallel GC, another + // thread might evacuate this closure while we're looking at it, + // so grab the info pointer just once. + info = spark->header.info; + if (IS_FORWARDING_PTR(info)) { + tmp = (StgClosure*)UN_FORWARDING_PTR(info); + /* if valuable work: shift inside the pool */ + if (closure_SHOULD_SPARK(tmp)) { + elements[botInd] = tmp; // keep entry (new address) + botInd++; + n++; + } else { + pruned_sparks++; // discard spark + cap->sparks_pruned++; + } + } else { + if (!(closure_flags[INFO_PTR_TO_STRUCT(info)->type] & _NS)) { + elements[botInd] = spark; // keep entry (new address) + evac (user, &elements[botInd]); + botInd++; + n++; + } else { + pruned_sparks++; // discard spark + cap->sparks_pruned++; + } } currInd++; @@ -486,15 +495,6 @@ pruneSparkQueue (Capability *cap) ASSERT_SPARK_POOL_INVARIANTS(pool); } -void -pruneSparkQueues (void) -{ - nat i; - for (i = 0; i < n_capabilities; i++) { - pruneSparkQueue(&capabilities[i]); - } -} - /* GC for the spark pool, called inside Capability.c for all capabilities in turn. Blindly "evac"s complete spark pool. */ void @@ -528,7 +528,6 @@ traverseSparkQueue (evac_fn evac, void *user, Capability *cap) } /* ---------------------------------------------------------------------------- - * balanceSparkPoolsCaps: takes an array of capabilities (usually: all * capabilities) and its size. Accesses all spark pools and equally * distributes the sparks among them. @@ -537,7 +536,8 @@ traverseSparkQueue (evac_fn evac, void *user, Capability *cap) * -------------------------------------------------------------------------- */ void balanceSparkPoolsCaps(nat n_caps, Capability caps[]); -void balanceSparkPoolsCaps(nat n_caps, Capability caps[]) { +void balanceSparkPoolsCaps(nat n_caps STG_UNUSED, + Capability caps[] STG_UNUSED) { barf("not implemented"); }