root/rts/posix/OSThreads.c

Revision 085c7fe5d4ea6e7b59f944d46ecfeba3755a315b, 6.2 KB (checked in by Simon Marlow <marlowsd@…>, 3 months ago)

Drop the per-task timing stats, give a summary only (#5897)

We were keeping around the Task struct (216 bytes) for every worker we
ever created, even though we only keep a maximum of 6 workers per
Capability. These Task structs accumulate and cause a space leak in
programs that do lots of safe FFI calls; this patch frees the Task
struct as soon as a worker exits.

One reason we were keeping the Task structs around is because we print
out per-Task timing stats in +RTS -s, but that isn't terribly useful.
What is sometimes useful is knowing how *many* Tasks there were. So
now I'm printing a single-line summary, this is for the program in

TASKS: 2001 (1 bound, 31 peak workers (2000 total), using -N1)

So although we created 2k tasks overall, there were only 31 workers
active at any one time (which is exactly what we expect: the program
makes 30 safe FFI calls concurrently).

This also gives an indication of how many capabilities were being
used, which is handy if you use +RTS -N without an explicit number.

  • Property mode set to 100644
Line 
1/* ---------------------------------------------------------------------------
2 *
3 * (c) The GHC Team, 2001-2005
4 *
5 * Accessing OS threads functionality in a (mostly) OS-independent
6 * manner.
7 *
8 * --------------------------------------------------------------------------*/
9
10#if defined(__linux__) || defined(__GLIBC__)
11/* We want GNU extensions in DEBUG mode for mutex error checking */
12/* We also want the affinity API, which requires _GNU_SOURCE */
13#define _GNU_SOURCE
14#endif
15
16#include "PosixSource.h"
17
18#if defined(freebsd_HOST_OS)
19/* Inclusion of system headers usually requires __BSD_VISIBLE on FreeBSD,
20 * because of some specific types, like u_char, u_int, etc. */
21#define __BSD_VISIBLE   1
22#endif
23
24#include "Rts.h"
25
26#if defined(THREADED_RTS)
27#include "RtsUtils.h"
28#include "Task.h"
29
30#if HAVE_STRING_H
31#include <string.h>
32#endif
33
34#if defined(darwin_HOST_OS) || defined(freebsd_HOST_OS)
35#include <sys/types.h>
36#include <sys/sysctl.h>
37#endif
38
39#if !defined(HAVE_PTHREAD_H)
40#error pthreads.h is required for the threaded RTS on Posix platforms
41#endif
42
43#if defined(HAVE_SCHED_H)
44#include <sched.h>
45#endif
46
47#if defined(HAVE_SYS_CPUSET_H)
48#include <sys/param.h>
49#include <sys/cpuset.h>
50#endif
51
52#ifdef HAVE_UNISTD_H
53#include <unistd.h>
54#endif
55
56#if defined(darwin_HOST_OS)
57#include <mach/mach.h>
58#endif
59
60#ifdef HAVE_SIGNAL_H
61# include <signal.h>
62#endif
63
64/*
65 * This (allegedly) OS threads independent layer was initially
66 * abstracted away from code that used Pthreads, so the functions
67 * provided here are mostly just wrappers to the Pthreads API.
68 *
69 */
70
71void
72initCondition( Condition* pCond )
73{
74  pthread_cond_init(pCond, NULL);
75  return;
76}
77
78void
79closeCondition( Condition* pCond )
80{
81  pthread_cond_destroy(pCond);
82  return;
83}
84
85rtsBool
86broadcastCondition ( Condition* pCond )
87{
88  return (pthread_cond_broadcast(pCond) == 0);
89}
90
91rtsBool
92signalCondition ( Condition* pCond )
93{
94  return (pthread_cond_signal(pCond) == 0);
95}
96
97rtsBool
98waitCondition ( Condition* pCond, Mutex* pMut )
99{
100  return (pthread_cond_wait(pCond,pMut) == 0);
101}
102
103void
104yieldThread(void)
105{
106  sched_yield();
107  return;
108}
109
110void
111shutdownThread(void)
112{
113  pthread_exit(NULL);
114}
115
116int
117createOSThread (OSThreadId* pId, OSThreadProc *startProc, void *param)
118{
119  int result = pthread_create(pId, NULL, (void *(*)(void *))startProc, param);
120  if(!result)
121    pthread_detach(*pId);
122  return result;
123}
124
125OSThreadId
126osThreadId(void)
127{
128  return pthread_self();
129}
130
131rtsBool
132osThreadIsAlive(OSThreadId id STG_UNUSED)
133{
134    // no good way to implement this on POSIX, AFAICT.  Returning true
135    // is safe.
136    return rtsTrue;
137}
138
139void
140initMutex(Mutex* pMut)
141{
142#if defined(DEBUG)
143    pthread_mutexattr_t attr;
144    pthread_mutexattr_init(&attr);
145    pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ERRORCHECK);
146    pthread_mutex_init(pMut,&attr);
147#else
148    pthread_mutex_init(pMut,NULL);
149#endif
150    return;
151}
152void
153closeMutex(Mutex* pMut)
154{
155    pthread_mutex_destroy(pMut);
156}
157
158void
159newThreadLocalKey (ThreadLocalKey *key)
160{
161    int r;
162    if ((r = pthread_key_create(key, NULL)) != 0) {
163        barf("newThreadLocalKey: %s", strerror(r));
164    }
165}
166
167void *
168getThreadLocalVar (ThreadLocalKey *key)
169{
170    return pthread_getspecific(*key);
171    // Note: a return value of NULL can indicate that either the key
172    // is not valid, or the key is valid and the data value has not
173    // yet been set.  We need to use the latter case, so we cannot
174    // detect errors here.
175}
176
177void
178setThreadLocalVar (ThreadLocalKey *key, void *value)
179{
180    int r;
181    if ((r = pthread_setspecific(*key,value)) != 0) {
182        barf("setThreadLocalVar: %s", strerror(r));
183    }
184}
185
186void
187freeThreadLocalKey (ThreadLocalKey *key)
188{
189    int r;
190    if ((r = pthread_key_delete(*key)) != 0) {
191        barf("freeThreadLocalKey: %s", strerror(r));
192    }
193}
194
195static void *
196forkOS_createThreadWrapper ( void * entry )
197{
198    Capability *cap;
199    cap = rts_lock();
200    rts_evalStableIO(&cap, (HsStablePtr) entry, NULL);
201    rts_unlock(cap);
202    return NULL;
203}
204
205int
206forkOS_createThread ( HsStablePtr entry )
207{
208    pthread_t tid;
209    int result = pthread_create(&tid, NULL,
210                                forkOS_createThreadWrapper, (void*)entry);
211    if(!result)
212        pthread_detach(tid);
213    return result;
214}
215
216nat
217getNumberOfProcessors (void)
218{
219    static nat nproc = 0;
220
221    if (nproc == 0) {
222#if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
223        nproc = sysconf(_SC_NPROCESSORS_ONLN);
224#elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF)
225        nproc = sysconf(_SC_NPROCESSORS_CONF);
226#elif defined(darwin_HOST_OS) || defined(freebsd_HOST_OS)
227        size_t size = sizeof(nat);
228        if(0 != sysctlbyname("hw.ncpu",&nproc,&size,NULL,0))
229            nproc = 1;
230#else
231        nproc = 1;
232#endif
233    }
234
235    return nproc;
236}
237
238#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_SETAFFINITY)
239// Schedules the thread to run on CPU n of m.  m may be less than the
240// number of physical CPUs, in which case, the thread will be allowed
241// to run on CPU n, n+m, n+2m etc.
242void
243setThreadAffinity (nat n, nat m)
244{
245    nat nproc;
246    cpu_set_t cs;
247    nat i;
248
249    nproc = getNumberOfProcessors();
250    CPU_ZERO(&cs);
251    for (i = n; i < nproc; i+=m) {
252        CPU_SET(i, &cs);
253    }
254    sched_setaffinity(0, sizeof(cpu_set_t), &cs);
255}
256
257#elif defined(darwin_HOST_OS) && defined(THREAD_AFFINITY_POLICY)
258// Schedules the current thread in the affinity set identified by tag n.
259void
260setThreadAffinity (nat n, nat m GNUC3_ATTRIBUTE(__unused__))
261{
262    thread_affinity_policy_data_t policy;
263
264    policy.affinity_tag = n;
265    thread_policy_set(mach_thread_self(), 
266                      THREAD_AFFINITY_POLICY,
267                      (thread_policy_t) &policy,
268                      THREAD_AFFINITY_POLICY_COUNT);
269}
270
271#elif defined(HAVE_SYS_CPUSET_H) /* FreeBSD 7.1+ */
272void
273setThreadAffinity(nat n, nat m)
274{
275        nat nproc;
276        cpuset_t cs;
277        nat i;
278
279        nproc = getNumberOfProcessors();
280        CPU_ZERO(&cs);
281
282        for (i = n; i < nproc; i += m)
283                CPU_SET(i, &cs);
284
285        cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), &cs);
286}
287
288#else
289void
290setThreadAffinity (nat n GNUC3_ATTRIBUTE(__unused__), 
291                   nat m GNUC3_ATTRIBUTE(__unused__))
292{
293}
294#endif
295
296void
297interruptOSThread (OSThreadId id)
298{
299    pthread_kill(id, SIGPIPE);
300}
301
302#else /* !defined(THREADED_RTS) */
303
304int
305forkOS_createThread ( HsStablePtr entry STG_UNUSED )
306{
307    return -1;
308}
309
310nat getNumberOfProcessors (void)
311{
312    return 1;
313}
314
315#endif
Note: See TracBrowser for help on using the browser.