GHC Threads affinity

Simon Marlow marlowsd at
Mon Sep 11 12:14:25 UTC 2017

On 10 September 2017 at 04:03, Michael Baikov <manpacket at> wrote:

> Greetings
> Currently GHC supports two kinds of threads - pinned to a specific
> capability (bound threads) and those it can migrate between any
> capabilities (unbound threads). For purposes of achieving lower latency in
> Haskell applications it would be nice to have something in between -
> threads GHC can migrate but within a certain subset of capabilities only.

That's not correct actually: a bound thread is associated with a particular
OS thread, but it can migrate between capabilities just like unbound

> I'm developing a program that contains several kinds of threads - those
> that do little work and sensitive to latency and those that can spend more
> CPU time and less latency sensitive. I looked into several cases of
> increased latency in those sensitive threads (using GHC eventlog) and in
> all cases sensitive threads were waiting for non-sensitive threads to
> finish working. I was able to reduce worst case latency by factor of 10 by
> pinning all the threads in the program to specific capability but manually
> distributing threads (60+ of them) between capabilities (several different
> machines with different numbers of cores available) seems very fragile.
> World stopping GC is still a problem but at least in my case is much less
> frequently so.

If you have a fixed set of threads you might just want to use -N<threads>
-qn<cores>, and then pin every thread to a different capability.  This
gives you 1:1 scheduling at the GHC level, delegating the scheduling job to
the OS.  You will also want to use nursery chunks with something like -n2m,
so you don't waste too much nursery space on the idle capabilities.

Even if your set of threads isn't fixed you might be able to use a hybrid
scheme with -N<large> -qn<cores> and pin the high-priority threads on their
own capability, while putting all the low-priority threads on a single
capability, or a few separate ones.

It would be nice to be able to allow GHC runtime to migrate a thread
> between a subset of capabilities using interface similar to this one:
> -- creates a thread that is allowed to migrate between capabilities
> according to following rule: ghc is allowed to run this thread on Nth
> capability if Nth `mod` size_of_word bit in mask is set.
> forkOn' :: Int -> IO () -> IO ThreadId
> forkOn' mask act = undefined
> This should allow to define up to 64 (32) distinct groups and allow user
> to break down their threads into bigger number of potentially intersecting
> groups by specifying things like capability 0 does latency sensitive
> things, caps 1..5 - less  sensitive things, caps 6-7 bulk things.

We could do this, but it would add some complexity to the scheduler and
load balancer (which has already been quite hard to get right, I fixed a
handful of bugs there recently). I'd be happy review a patch if you want to
try it though.


Anything obvious I'm missing? Any recommendations to how to implement this?

> _______________________________________________
> ghc-devs mailing list
> ghc-devs at
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the ghc-devs mailing list