Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does GHC have a stack for each thread?

Tags:

haskell

ghc

It's my understanding that GHC gives each thread a stack. Why is this necessary? Doesn't GHC compile to CPS? Isn't a thread expressed concisely as a closure?

like image 798
dan_waterworth Avatar asked Jun 22 '11 07:06

dan_waterworth


1 Answers

There are several aspects to your question.

The key reference for the design decisions in the GHC runtime is the paper ''Runtime Support for Multicore Haskell''.

Recall that

The GHC runtime system supports millions of lightweight threads by multiplexing them onto a handful of operating system threads, roughly one for each physical CPU.

And:

Each Haskell thread runs on a finite-sized stack, which is allocated in the heap. The state of a thread, together with its stack, is kept in a heap-allocated thread state object (TSO). The size of a TSO is around 15 words plus the stack, and constitutes the whole state of a Haskell thread. A stack may grow by copying the TSO into a larger area, and may subsequently shrink again

GHC does not compile via CPS. Each thread make recursive calls, and they must allocate to the stack. By representing the stack as a heap-allocated object, things are made simpler.

A thread is more than a closure.

As a thread executes, it starts allocating to the heap and stack. Thus:

The stack of a thread, and hence its TSO, is mutable. When a thread executes, the stack will accumulate pointers to new objects, and so if the TSO resides in an old generation it must be added to the remembered set [of the GC].

Garbage collecting objects pointed at by stacks can be optimized to ensure GC takes place on the same physical thread as the thread.

Furthermore, when the garbage collector runs, it is highly desirable that the TSOs that have been executed on a given CPU are traversed by the garbage collector on the same CPU, because the TSO and data it refers to are likely to be in the local cache of that CPU.

So, GHC has a stack for each thread because the compilation mandates that threads have access to a stack and a heap. By giving each thread its own stack, threads can execute in parallel more efficiently. Threads are more than "just a closure", since they have a mutable stack.

like image 153
Don Stewart Avatar answered Oct 09 '22 13:10

Don Stewart