X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=rts%2FCapability.h;h=d380af9cff5d3a952feebd7bfe85dcf08ceeeab7;hp=9446a7e7794b06526f898675d8938caacddc84c3;hb=b2524b3960999fffdb3767900f58825903f6560f;hpb=b7ea7671c442a0223f34593dc8a1182b15dde0bf diff --git a/rts/Capability.h b/rts/Capability.h index 9446a7e..d380af9 100644 --- a/rts/Capability.h +++ b/rts/Capability.h @@ -4,29 +4,29 @@ * * Capabilities * - * The notion of a capability is used when operating in multi-threaded - * environments (which the THREADED_RTS build of the RTS does), to - * hold all the state an OS thread/task needs to run Haskell code: - * its STG registers, a pointer to its TSO, a nursery etc. During - * STG execution, a pointer to the capabilitity is kept in a - * register (BaseReg). + * For details on the high-level design, see + * http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Scheduler * - * Only in an THREADED_RTS build will there be multiple capabilities, - * in the non-threaded builds there is one global capability, namely + * A Capability holds all the state an OS thread/task needs to run + * Haskell code: its STG registers, a pointer to its TSO, a nursery + * etc. During STG execution, a pointer to the Capabilitity is kept in + * a register (BaseReg). + * + * Only in a THREADED_RTS build will there be multiple capabilities, + * in the non-threaded RTS there is one global capability, called * MainCapability. * - * This header file contains the functions for working with capabilities. - * (the main, and only, consumer of this interface is the scheduler). - * * --------------------------------------------------------------------------*/ #ifndef CAPABILITY_H #define CAPABILITY_H -#include "RtsFlags.h" +#include "sm/GC.h" // for evac_fn #include "Task.h" #include "Sparks.h" +#include "BeginPrivate.h" + struct Capability_ { // State required by the STG virtual machine when running Haskell // code. During STG execution, the BaseReg register always points @@ -59,13 +59,18 @@ struct Capability_ { // the suspended TSOs easily. Hence, when migrating a Task from // the returning_tasks list, we must also migrate its entry from // this list. - Task *suspended_ccalling_tasks; + InCall *suspended_ccalls; // One mutable list per generation, so we don't need to take any - // locks when updating an old-generation thunk. These - // mini-mut-lists are moved onto the respective gen->mut_list at - // each GC. + // locks when updating an old-generation thunk. This also lets us + // keep track of which closures this CPU has been mutating, so we + // can traverse them using the right thread during GC and avoid + // unnecessarily moving the data from one cache to another. bdescr **mut_lists; + bdescr **saved_mut_lists; // tmp use during GC + + // block for allocating pinned objects into + bdescr *pinned_object_block; // Context switch flag. We used to have one global flag, now one // per capability. Locks required : none (conflicts are harmless) @@ -74,6 +79,7 @@ struct Capability_ { #if defined(THREADED_RTS) // Worker Tasks waiting in the wings. Singly-linked. Task *spare_workers; + nat n_spare_workers; // count of above // This lock protects running_task, returning_tasks_{hd,tl}, wakeup_queue. Mutex lock; @@ -86,18 +92,17 @@ struct Capability_ { Task *returning_tasks_hd; // Singly-linked, with head/tail Task *returning_tasks_tl; - // A list of threads to append to this Capability's run queue at - // the earliest opportunity. These are threads that have been - // woken up by another Capability. - StgTSO *wakeup_queue_hd; - StgTSO *wakeup_queue_tl; + // Messages, or END_TSO_QUEUE. + Message *inbox; SparkPool *sparks; // Stats on spark creation/conversion nat sparks_created; + nat sparks_dud; nat sparks_converted; - nat sparks_pruned; + nat sparks_gcd; + nat sparks_fizzled; #endif // Per-capability STM-related data @@ -109,7 +114,10 @@ struct Capability_ { } // typedef Capability is defined in RtsAPI.h // Capabilities are stored in an array, so make sure that adjacent // Capabilities don't share any cache-lines: - ATTRIBUTE_ALIGNED(64); +#ifndef mingw32_HOST_OS + ATTRIBUTE_ALIGNED(64) +#endif + ; #if defined(THREADED_RTS) @@ -140,7 +148,7 @@ struct Capability_ { INLINE_HEADER Capability * regTableToCapability (StgRegTable *reg) { - return (Capability *)((void *)((unsigned char*)reg - sizeof(StgFunTable))); + return (Capability *)((void *)((unsigned char*)reg - STG_FIELD_OFFSET(Capability,r))); } // Initialise the available capabilities. @@ -166,14 +174,14 @@ INLINE_HEADER void releaseCapability_ (Capability* cap STG_UNUSED, rtsBool always_wakeup STG_UNUSED) {}; #endif -#if !IN_STG_CODE -// one global capability -extern Capability MainCapability; -#endif +// declared in includes/rts/Threads.h: +// extern Capability MainCapability; + +// declared in includes/rts/Threads.h: +// extern nat n_capabilities; // Array of all the capabilities // -extern nat n_capabilities; extern Capability *capabilities; // The Capability that was last free. Used as a good guess for where @@ -182,6 +190,8 @@ extern Capability *capabilities; extern Capability *last_free_capability; // GC indicator, in scope for the scheduler +#define PENDING_GC_SEQ 1 +#define PENDING_GC_PAR 2 extern volatile StgWord waiting_for_gc; // Acquires a capability at a return point. If *cap is non-NULL, then @@ -195,7 +205,9 @@ extern volatile StgWord waiting_for_gc; // void waitForReturnCapability (Capability **cap/*in/out*/, Task *task); -INLINE_HEADER void recordMutableCap (StgClosure *p, Capability *cap, nat gen); +EXTERN_INLINE void recordMutableCap (StgClosure *p, Capability *cap, nat gen); + +EXTERN_INLINE void recordClosureMutated (Capability *cap, StgClosure *p); #if defined(THREADED_RTS) @@ -218,33 +230,27 @@ void yieldCapability (Capability** pCap, Task *task); // void waitForCapability (Task *task, Mutex *mutex, Capability **pCap); -// Wakes up a thread on a Capability (probably a different Capability -// from the one held by the current Task). -// -void wakeupThreadOnCapability (Capability *my_cap, Capability *other_cap, - StgTSO *tso); - // Wakes up a worker thread on just one Capability, used when we // need to service some global event. // void prodOneCapability (void); +void prodCapability (Capability *cap, Task *task); // Similar to prodOneCapability(), but prods all of them. // void prodAllCapabilities (void); -// Waits for a capability to drain of runnable threads and workers, -// and then acquires it. Used at shutdown time. -// -void shutdownCapability (Capability *cap, Task *task, rtsBool wait_foreign); - // Attempt to gain control of a Capability if it is free. // rtsBool tryGrabCapability (Capability *cap, Task *task); -// Try to steal a spark from other Capabilities +// Try to find a spark to run +// +StgClosure *findSpark (Capability *cap); + +// True if any capabilities have sparks // -rtsBool stealWork (Capability *cap); +rtsBool anySparks (void); INLINE_HEADER rtsBool emptySparkPoolCap (Capability *cap); INLINE_HEADER nat sparkPoolSizeCap (Capability *cap); @@ -259,29 +265,52 @@ extern void grabCapability (Capability **pCap); #endif /* !THREADED_RTS */ +// Waits for a capability to drain of runnable threads and workers, +// and then acquires it. Used at shutdown time. +// +void shutdownCapability (Capability *cap, Task *task, rtsBool wait_foreign); + +// Shut down all capabilities. +// +void shutdownCapabilities(Task *task, rtsBool wait_foreign); + // cause all capabilities to context switch as soon as possible. void setContextSwitches(void); +INLINE_HEADER void contextSwitchCapability(Capability *cap); // Free all capabilities void freeCapabilities (void); -// FOr the GC: -void markSomeCapabilities (evac_fn evac, void *user, nat i0, nat delta, - rtsBool prune_sparks); +// For the GC: +void markCapability (evac_fn evac, void *user, Capability *cap, + rtsBool no_mark_sparks USED_IF_THREADS); + void markCapabilities (evac_fn evac, void *user); + void traverseSparkQueues (evac_fn evac, void *user); /* ----------------------------------------------------------------------------- + Messages + -------------------------------------------------------------------------- */ + +#ifdef THREADED_RTS + +INLINE_HEADER rtsBool emptyInbox(Capability *cap);; + +#endif // THREADED_RTS + +/* ----------------------------------------------------------------------------- * INLINE functions... private below here * -------------------------------------------------------------------------- */ -INLINE_HEADER void +EXTERN_INLINE void recordMutableCap (StgClosure *p, Capability *cap, nat gen) { bdescr *bd; // We must own this Capability in order to modify its mutable list. - ASSERT(cap->running_task == myTask()); + // ASSERT(cap->running_task == myTask()); + // NO: assertion is violated by performPendingThrowTos() bd = cap->mut_lists[gen]; if (bd->free >= bd->start + BLOCK_SIZE_W) { bdescr *new_bd; @@ -293,6 +322,15 @@ recordMutableCap (StgClosure *p, Capability *cap, nat gen) *bd->free++ = (StgWord)p; } +EXTERN_INLINE void +recordClosureMutated (Capability *cap, StgClosure *p) +{ + bdescr *bd; + bd = Bdescr((StgPtr)p); + if (bd->gen_no != 0) recordMutableCap(p,cap,bd->gen_no); +} + + #if defined(THREADED_RTS) INLINE_HEADER rtsBool emptySparkPoolCap (Capability *cap) @@ -307,4 +345,27 @@ discardSparksCap (Capability *cap) { return discardSparks(cap->sparks); } #endif +INLINE_HEADER void +contextSwitchCapability (Capability *cap) +{ + // setting HpLim to NULL ensures that the next heap check will + // fail, and the thread will return to the scheduler. + cap->r.rHpLim = NULL; + // But just in case it didn't work (the target thread might be + // modifying HpLim at the same time), we set the end-of-block + // context-switch flag too: + cap->context_switch = 1; +} + +#ifdef THREADED_RTS + +INLINE_HEADER rtsBool emptyInbox(Capability *cap) +{ + return (cap->inbox == (Message*)END_TSO_QUEUE); +} + +#endif + +#include "EndPrivate.h" + #endif /* CAPABILITY_H */