[GHC] #9221: (super!) linear slowdown of parallel builds on 40 core machine

GHC ghc-devs at haskell.org
Sun Dec 31 03:07:54 UTC 2017


#9221: (super!) linear slowdown of parallel builds on 40 core machine
-------------------------------------+-------------------------------------
        Reporter:  carter            |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:  8.4.1
       Component:  Compiler          |              Version:  7.8.2
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  Compile-time      |  Unknown/Multiple
  performance bug                    |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:  #910, #8224       |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by nh2):

 Hey, a question about `sched_yield()`:

 I just read the [http://man7.org/linux/man-pages/man2/sched_yield.2.html
 man page] for `sched_yield()` again. It says:

 > `sched_yield()` is intended for use with read-time scheduling policies
 (i.e., `SCHED_FIFO` or `SCHED_RR`).  Use of `sched_yield()` with
 nondeterministic scheduling policies such as `SCHED_OTHER` is unspecified
 and very likely means your application design is broken.

 Does GHC set the `FIFO` or`RR` policy? If not, then according to that our
 "application design is broken".

 I also found some interesting info on
 http://www.informit.com/articles/article.aspx?p=101760&seqNum=5 (emphasis
 mine):

 > Linux provides the `sched_yield()` system call as a mechanism for a
 process to explicitly yield the processor to other waiting processes. It
 works by removing the process from the active array (where it currently
 is, because it is running) and inserting it into the expired array. This
 has the effect of not only preempting the process and putting it at the
 end of its priority list, but putting it on the expired list —
 **guaranteeing it will not run for a while**. Because real-time tasks
 never expire, they are a special case. Therefore, they are merely moved to
 the end of their priority list (and not inserted into the expired array).
 **In earlier versions of Linux, the semantics of the `sched_yield()` call
 were quite different; at best, the task was only moved to the end of their
 priority list**. The yielding was often not for a very long time.
 Nowadays, applications and even kernel code should be certain they truly
 want to give up the processor before calling `sched_yield()`.

 A similar article on LWN: https://lwn.net/Articles/31462/

 > This call used to simply move the process to the end of the run queue;
 now it moves the process to the "expired" queue, effectively cancelling
 the rest of the process's time slice. So a process calling `sched_yield()`
 now must wait until all other runnable processes in the system have used
 up their time slices before it will get the processor again.

 The article goes on to explain that this resulted bad performance
 especially for

 > threaded applications [that] implement busy-wait loops with
 `sched_yield()`

 Might this be relevant here?

 Also, can someone explain me why GHC is using `sched_yield()` at all? If
 the purpose is to wait until other GC threads are done, wouldn't `futex()`
 be enough? Or is that what's explained in
 https://ghcmutterings.wordpress.com/2010/01/25/yielding-more-improvements-
 in-parallel-performance/ ?

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9221#comment:84>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list