root/rts/Capability.h

Revision 8536f09c2f310a95297b339de6084f77cc4044c1, 13.0 KB (checked in by Duncan Coutts <duncan@…>, 8 weeks ago)

Calculate the total memory allocated on a per-capability basis

In addition to the existing global method. For now we just do
it both ways and assert they give the same grand total. At some
stage we can simplify the global method to just take the sum of
the per-cap counters.

  • Property mode set to 100644
Line 
1/* ---------------------------------------------------------------------------
2 *
3 * (c) The GHC Team, 2001-2006
4 *
5 * Capabilities
6 *
7 * For details on the high-level design, see
8 *   http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Scheduler
9 *
10 * A Capability holds all the state an OS thread/task needs to run
11 * Haskell code: its STG registers, a pointer to its TSO, a nursery
12 * etc. During STG execution, a pointer to the Capabilitity is kept in
13 * a register (BaseReg).
14 *
15 * Only in a THREADED_RTS build will there be multiple capabilities,
16 * in the non-threaded RTS there is one global capability, called
17 * MainCapability.
18 *
19 * --------------------------------------------------------------------------*/
20
21#ifndef CAPABILITY_H
22#define CAPABILITY_H
23
24#include "sm/GC.h" // for evac_fn
25#include "Task.h"
26#include "Sparks.h"
27
28#include "BeginPrivate.h"
29
30struct Capability_ {
31    // State required by the STG virtual machine when running Haskell
32    // code.  During STG execution, the BaseReg register always points
33    // to the StgRegTable of the current Capability (&cap->r).
34    StgFunTable f;
35    StgRegTable r;
36
37    nat no;  // capability number.
38
39    // The Task currently holding this Capability.  This task has
40    // exclusive access to the contents of this Capability (apart from
41    // returning_tasks_hd/returning_tasks_tl).
42    // Locks required: cap->lock.
43    Task *running_task;
44
45    // true if this Capability is running Haskell code, used for
46    // catching unsafe call-ins.
47    rtsBool in_haskell;
48
49    // Has there been any activity on this Capability since the last GC?
50    nat idle;
51
52    rtsBool disabled;
53
54    // The run queue.  The Task owning this Capability has exclusive
55    // access to its run queue, so can wake up threads without
56    // taking a lock, and the common path through the scheduler is
57    // also lock-free.
58    StgTSO *run_queue_hd;
59    StgTSO *run_queue_tl;
60
61    // Tasks currently making safe foreign calls.  Doubly-linked.
62    // When returning, a task first acquires the Capability before
63    // removing itself from this list, so that the GC can find all
64    // the suspended TSOs easily.  Hence, when migrating a Task from
65    // the returning_tasks list, we must also migrate its entry from
66    // this list.
67    InCall *suspended_ccalls;
68
69    // One mutable list per generation, so we don't need to take any
70    // locks when updating an old-generation thunk.  This also lets us
71    // keep track of which closures this CPU has been mutating, so we
72    // can traverse them using the right thread during GC and avoid
73    // unnecessarily moving the data from one cache to another.
74    bdescr **mut_lists;
75    bdescr **saved_mut_lists; // tmp use during GC
76
77    // block for allocating pinned objects into
78    bdescr *pinned_object_block;
79    // full pinned object blocks allocated since the last GC
80    bdescr *pinned_object_blocks;
81
82    // Context switch flag.  When non-zero, this means: stop running
83    // Haskell code, and switch threads.
84    int context_switch;
85
86    // Interrupt flag.  Like the context_switch flag, this also
87    // indicates that we should stop running Haskell code, but we do
88    // *not* switch threads.  This is used to stop a Capability in
89    // order to do GC, for example.
90    //
91    // The interrupt flag is always reset before we start running
92    // Haskell code, unlike the context_switch flag which is only
93    // reset after we have executed the context switch.
94    int interrupt;
95
96#if defined(THREADED_RTS)
97    // Worker Tasks waiting in the wings.  Singly-linked.
98    Task *spare_workers;
99    nat n_spare_workers; // count of above
100
101    // This lock protects:
102    //    running_task
103    //    returning_tasks_{hd,tl}
104    //    wakeup_queue
105    //    inbox
106    Mutex lock;
107
108    // Tasks waiting to return from a foreign call, or waiting to make
109    // a new call-in using this Capability (NULL if empty).
110    // NB. this field needs to be modified by tasks other than the
111    // running_task, so it requires cap->lock to modify.  A task can
112    // check whether it is NULL without taking the lock, however.
113    Task *returning_tasks_hd; // Singly-linked, with head/tail
114    Task *returning_tasks_tl;
115
116    // Messages, or END_TSO_QUEUE.
117    // Locks required: cap->lock
118    Message *inbox;
119
120    SparkPool *sparks;
121
122    // Stats on spark creation/conversion
123    SparkCounters spark_stats;
124#endif
125    // Total words allocated by this cap since rts start
126    lnat total_allocated;
127
128    // Per-capability STM-related data
129    StgTVarWatchQueue *free_tvar_watch_queues;
130    StgInvariantCheckQueue *free_invariant_check_queues;
131    StgTRecChunk *free_trec_chunks;
132    StgTRecHeader *free_trec_headers;
133    nat transaction_tokens;
134} // typedef Capability is defined in RtsAPI.h
135  // Capabilities are stored in an array, so make sure that adjacent
136  // Capabilities don't share any cache-lines:
137#ifndef mingw32_HOST_OS
138  ATTRIBUTE_ALIGNED(64)
139#endif
140  ;
141
142
143#if defined(THREADED_RTS)
144#define ASSERT_TASK_ID(task) ASSERT(task->id == osThreadId())
145#else
146#define ASSERT_TASK_ID(task) /*empty*/
147#endif
148
149// These properties should be true when a Task is holding a Capability
150#define ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task)                     \
151  ASSERT(cap->running_task != NULL && cap->running_task == task);       \
152  ASSERT(task->cap == cap);                                             \
153  ASSERT_PARTIAL_CAPABILITY_INVARIANTS(cap,task)
154
155// Sometimes a Task holds a Capability, but the Task is not associated
156// with that Capability (ie. task->cap != cap).  This happens when
157// (a) a Task holds multiple Capabilities, and (b) when the current
158// Task is bound, its thread has just blocked, and it may have been
159// moved to another Capability.
160#define ASSERT_PARTIAL_CAPABILITY_INVARIANTS(cap,task)  \
161  ASSERT(cap->run_queue_hd == END_TSO_QUEUE ?           \
162            cap->run_queue_tl == END_TSO_QUEUE : 1);    \
163  ASSERT(myTask() == task);                             \
164  ASSERT_TASK_ID(task);
165
166#if defined(THREADED_RTS)
167rtsBool checkSparkCountInvariant (void);
168#endif
169
170// Converts a *StgRegTable into a *Capability.
171//
172INLINE_HEADER Capability *
173regTableToCapability (StgRegTable *reg)
174{
175    return (Capability *)((void *)((unsigned char*)reg - STG_FIELD_OFFSET(Capability,r)));
176}
177
178// Initialise the available capabilities.
179//
180void initCapabilities (void);
181
182// Add and initialise more Capabilities
183//
184Capability * moreCapabilities (nat from, nat to);
185
186// Release a capability.  This is called by a Task that is exiting
187// Haskell to make a foreign call, or in various other cases when we
188// want to relinquish a Capability that we currently hold.
189//
190// ASSUMES: cap->running_task is the current Task.
191//
192#if defined(THREADED_RTS)
193void releaseCapability           (Capability* cap);
194void releaseAndWakeupCapability  (Capability* cap);
195void releaseCapability_ (Capability* cap, rtsBool always_wakeup); 
196// assumes cap->lock is held
197#else
198// releaseCapability() is empty in non-threaded RTS
199INLINE_HEADER void releaseCapability  (Capability* cap STG_UNUSED) {};
200INLINE_HEADER void releaseAndWakeupCapability  (Capability* cap STG_UNUSED) {};
201INLINE_HEADER void releaseCapability_ (Capability* cap STG_UNUSED, 
202                                       rtsBool always_wakeup STG_UNUSED) {};
203#endif
204
205// declared in includes/rts/Threads.h:
206// extern Capability MainCapability;
207
208// declared in includes/rts/Threads.h:
209// extern nat n_capabilities;
210
211extern nat enabled_capabilities;
212
213// Array of all the capabilities
214//
215extern Capability *capabilities;
216
217// The Capability that was last free.  Used as a good guess for where
218// to assign new threads.
219//
220extern Capability *last_free_capability;
221
222//
223// Indicates that the RTS wants to synchronise all the Capabilities
224// for some reason.  All Capabilities should stop and return to the
225// scheduler.
226//
227#define SYNC_GC_SEQ 1
228#define SYNC_GC_PAR 2
229#define SYNC_OTHER  3
230extern volatile StgWord pending_sync;
231
232// Acquires a capability at a return point.  If *cap is non-NULL, then
233// this is taken as a preference for the Capability we wish to
234// acquire.
235//
236// OS threads waiting in this function get priority over those waiting
237// in waitForCapability().
238//
239// On return, *cap is non-NULL, and points to the Capability acquired.
240//
241void waitForReturnCapability (Capability **cap/*in/out*/, Task *task);
242
243EXTERN_INLINE void recordMutableCap (StgClosure *p, Capability *cap, nat gen);
244
245EXTERN_INLINE void recordClosureMutated (Capability *cap, StgClosure *p);
246
247#if defined(THREADED_RTS)
248
249// Gives up the current capability IFF there is a higher-priority
250// thread waiting for it.  This happens in one of two ways:
251//
252//   (a) we are passing the capability to another OS thread, so
253//       that it can run a bound Haskell thread, or
254//
255//   (b) there is an OS thread waiting to return from a foreign call
256//
257// On return: *pCap is NULL if the capability was released.  The
258// current task should then re-acquire it using waitForCapability().
259//
260void yieldCapability (Capability** pCap, Task *task);
261
262// Acquires a capability for doing some work.
263//
264// On return: pCap points to the capability.
265//
266void waitForCapability (Task *task, Mutex *mutex, Capability **pCap);
267
268// Wakes up a worker thread on just one Capability, used when we
269// need to service some global event.
270//
271void prodOneCapability (void);
272void prodCapability (Capability *cap, Task *task);
273
274// Similar to prodOneCapability(), but prods all of them.
275//
276void prodAllCapabilities (void);
277
278// Attempt to gain control of a Capability if it is free.
279//
280rtsBool tryGrabCapability (Capability *cap, Task *task);
281
282// Try to find a spark to run
283//
284StgClosure *findSpark (Capability *cap);
285
286// True if any capabilities have sparks
287//
288rtsBool anySparks (void);
289
290INLINE_HEADER rtsBool emptySparkPoolCap (Capability *cap);
291INLINE_HEADER nat     sparkPoolSizeCap  (Capability *cap);
292INLINE_HEADER void    discardSparksCap  (Capability *cap);
293
294#else // !THREADED_RTS
295
296// Grab a capability.  (Only in the non-threaded RTS; in the threaded
297// RTS one of the waitFor*Capability() functions must be used).
298//
299extern void grabCapability (Capability **pCap);
300
301#endif /* !THREADED_RTS */
302
303// Waits for a capability to drain of runnable threads and workers,
304// and then acquires it.  Used at shutdown time.
305//
306void shutdownCapability (Capability *cap, Task *task, rtsBool wait_foreign);
307
308// Shut down all capabilities.
309//
310void shutdownCapabilities(Task *task, rtsBool wait_foreign);
311
312// cause all capabilities to context switch as soon as possible.
313void contextSwitchAllCapabilities(void);
314INLINE_HEADER void contextSwitchCapability(Capability *cap);
315
316// cause all capabilities to stop running Haskell code and return to
317// the scheduler as soon as possible.
318void interruptAllCapabilities(void);
319INLINE_HEADER void interruptCapability(Capability *cap);
320
321// Free all capabilities
322void freeCapabilities (void);
323
324// For the GC:
325void markCapability (evac_fn evac, void *user, Capability *cap,
326                     rtsBool no_mark_sparks USED_IF_THREADS);
327
328void markCapabilities (evac_fn evac, void *user);
329
330void traverseSparkQueues (evac_fn evac, void *user);
331
332/* -----------------------------------------------------------------------------
333   Messages
334   -------------------------------------------------------------------------- */
335
336#ifdef THREADED_RTS
337
338INLINE_HEADER rtsBool emptyInbox(Capability *cap);
339
340#endif // THREADED_RTS
341
342/* -----------------------------------------------------------------------------
343 * INLINE functions... private below here
344 * -------------------------------------------------------------------------- */
345
346EXTERN_INLINE void
347recordMutableCap (StgClosure *p, Capability *cap, nat gen)
348{
349    bdescr *bd;
350
351    // We must own this Capability in order to modify its mutable list.
352    //    ASSERT(cap->running_task == myTask());
353    // NO: assertion is violated by performPendingThrowTos()
354    bd = cap->mut_lists[gen];
355    if (bd->free >= bd->start + BLOCK_SIZE_W) {
356        bdescr *new_bd;
357        new_bd = allocBlock_lock();
358        new_bd->link = bd;
359        bd = new_bd;
360        cap->mut_lists[gen] = bd;
361    }
362    *bd->free++ = (StgWord)p;
363}
364
365EXTERN_INLINE void
366recordClosureMutated (Capability *cap, StgClosure *p)
367{
368    bdescr *bd;
369    bd = Bdescr((StgPtr)p);
370    if (bd->gen_no != 0) recordMutableCap(p,cap,bd->gen_no);
371}
372
373
374#if defined(THREADED_RTS)
375INLINE_HEADER rtsBool
376emptySparkPoolCap (Capability *cap) 
377{ return looksEmpty(cap->sparks); }
378
379INLINE_HEADER nat
380sparkPoolSizeCap (Capability *cap) 
381{ return sparkPoolSize(cap->sparks); }
382
383INLINE_HEADER void
384discardSparksCap (Capability *cap) 
385{ discardSparks(cap->sparks); }
386#endif
387
388INLINE_HEADER void
389stopCapability (Capability *cap)
390{
391    // setting HpLim to NULL tries to make the next heap check will
392    // fail, which will cause the thread to return to the scheduler.
393    // It may not work - the thread might be updating HpLim itself
394    // at the same time - so we also have the context_switch/interrupted
395    // flags as a sticky way to tell the thread to stop.
396    cap->r.rHpLim = NULL;
397}
398
399INLINE_HEADER void
400interruptCapability (Capability *cap)
401{
402    stopCapability(cap);
403    cap->interrupt = 1;
404}
405
406INLINE_HEADER void
407contextSwitchCapability (Capability *cap)
408{
409    stopCapability(cap);
410    cap->context_switch = 1;
411}
412
413#ifdef THREADED_RTS
414
415INLINE_HEADER rtsBool emptyInbox(Capability *cap)
416{
417    return (cap->inbox == (Message*)END_TSO_QUEUE);
418}
419
420#endif
421
422#include "EndPrivate.h"
423
424#endif /* CAPABILITY_H */
Note: See TracBrowser for help on using the browser.