diff options
author | Simon Marlow <marlowsd@gmail.com> | 2012-03-02 10:53:34 +0000 |
---|---|---|
committer | Simon Marlow <marlowsd@gmail.com> | 2012-03-02 11:44:17 +0000 |
commit | 085c7fe5d4ea6e7b59f944d46ecfeba3755a315b (patch) | |
tree | 3de7e3e6306dbf9a8869862266a35a2d0d75d11f /rts/Task.c | |
parent | 27d7d930ff8741f980245da1b895ceaa5294e257 (diff) | |
download | haskell-085c7fe5d4ea6e7b59f944d46ecfeba3755a315b.tar.gz |
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.
Diffstat (limited to 'rts/Task.c')
-rw-r--r-- | rts/Task.c | 100 |
1 files changed, 45 insertions, 55 deletions
diff --git a/rts/Task.c b/rts/Task.c index 36dd0a94b9..f4a37bf6ff 100644 --- a/rts/Task.c +++ b/rts/Task.c @@ -26,7 +26,12 @@ // Task lists and global counters. // Locks required: all_tasks_mutex. Task *all_tasks = NULL; -static nat taskCount; + +nat taskCount; +nat workerCount; +nat currentWorkerCount; +nat peakWorkerCount; + static int tasksInitialized = 0; static void freeTask (Task *task); @@ -64,8 +69,11 @@ void initTaskManager (void) { if (!tasksInitialized) { - taskCount = 0; - tasksInitialized = 1; + taskCount = 0; + workerCount = 0; + currentWorkerCount = 0; + peakWorkerCount = 0; + tasksInitialized = 1; #if defined(THREADED_RTS) #if !defined(MYTASK_USE_TLV) newThreadLocalKey(¤tTaskKey); @@ -87,7 +95,7 @@ freeTaskManager (void) ACQUIRE_LOCK(&all_tasks_mutex); for (task = all_tasks; task != NULL; task = next) { - next = task->all_link; + next = task->all_next; if (task->stopped) { freeTask(task); } else { @@ -164,9 +172,6 @@ freeTask (Task *task) static Task* newTask (rtsBool worker) { -#if defined(THREADED_RTS) - Time currentElapsedTime, currentUserTime; -#endif Task *task; #define ROUND_TO_CACHE_LINE(x) ((((x)+63) / 64) * 64) @@ -186,26 +191,25 @@ newTask (rtsBool worker) task->wakeup = rtsFalse; #endif -#if defined(THREADED_RTS) - currentUserTime = getThreadCPUTime(); - currentElapsedTime = getProcessElapsedTime(); - task->mut_time = 0; - task->mut_etime = 0; - task->gc_time = 0; - task->gc_etime = 0; - task->muttimestart = currentUserTime; - task->elapsedtimestart = currentElapsedTime; -#endif - task->next = NULL; ACQUIRE_LOCK(&all_tasks_mutex); - task->all_link = all_tasks; + task->all_prev = NULL; + task->all_next = all_tasks; + if (all_tasks != NULL) { + all_tasks->all_prev = task; + } all_tasks = task; taskCount++; - + if (worker) { + workerCount++; + currentWorkerCount++; + if (currentWorkerCount > peakWorkerCount) { + peakWorkerCount = currentWorkerCount; + } + } RELEASE_LOCK(&all_tasks_mutex); return task; @@ -314,14 +318,15 @@ discardTasksExcept (Task *keep) // Wipe the task list, except the current Task. ACQUIRE_LOCK(&all_tasks_mutex); for (task = all_tasks; task != NULL; task=next) { - next = task->all_link; + next = task->all_next; if (task != keep) { debugTrace(DEBUG_sched, "discarding task %ld", (long)TASK_ID(task)); freeTask(task); } } all_tasks = keep; - keep->all_link = NULL; + keep->all_next = NULL; + keep->all_prev = NULL; RELEASE_LOCK(&all_tasks_mutex); } @@ -337,7 +342,7 @@ void updateCapabilityRefs (void) ACQUIRE_LOCK(&all_tasks_mutex); - for (task = all_tasks; task != NULL; task=task->all_link) { + for (task = all_tasks; task != NULL; task=task->all_next) { if (task->cap != NULL) { task->cap = &capabilities[task->cap->no]; } @@ -353,34 +358,6 @@ void updateCapabilityRefs (void) } -void -taskTimeStamp (Task *task USED_IF_THREADS) -{ -#if defined(THREADED_RTS) - Time currentElapsedTime, currentUserTime; - - currentUserTime = getThreadCPUTime(); - currentElapsedTime = getProcessElapsedTime(); - - task->mut_time = - currentUserTime - task->muttimestart - task->gc_time; - task->mut_etime = - currentElapsedTime - task->elapsedtimestart - task->gc_etime; - - if (task->gc_time < 0) { task->gc_time = 0; } - if (task->gc_etime < 0) { task->gc_etime = 0; } - if (task->mut_time < 0) { task->mut_time = 0; } - if (task->mut_etime < 0) { task->mut_etime = 0; } -#endif -} - -void -taskDoneGC (Task *task, Time cpu_time, Time elapsed_time) -{ - task->gc_time += cpu_time; - task->gc_etime += elapsed_time; -} - #if defined(THREADED_RTS) void @@ -391,9 +368,22 @@ workerTaskStop (Task *task) ASSERT(task->id == id); ASSERT(myTask() == task); - task->cap = NULL; - taskTimeStamp(task); - task->stopped = rtsTrue; + ACQUIRE_LOCK(&all_tasks_mutex); + + if (task->all_prev) { + task->all_prev->all_next = task->all_next; + } else { + all_tasks = task->all_next; + } + if (task->all_next) { + task->all_next->all_prev = task->all_prev; + } + + currentWorkerCount--; + + RELEASE_LOCK(&all_tasks_mutex); + + freeTask(task); } #endif @@ -491,7 +481,7 @@ void printAllTasks(void) { Task *task; - for (task = all_tasks; task != NULL; task = task->all_link) { + for (task = all_tasks; task != NULL; task = task->all_next) { debugBelch("task %p is %s, ", taskId(task), task->stopped ? "stopped" : "alive"); if (!task->stopped) { if (task->cap) { |