Opened 14 months ago

Last modified 9 months ago

#15485 infoneeded bug

GHC uses 300% CPU when calling into blocking C call

Reported by: oconnore Owned by:
Priority: normal Milestone: 8.6.1
Component: Runtime System Version: 8.4.3
Keywords: Cc: osa1, lelf
Operating System: Unknown/Multiple Architecture: x86_64 (amd64)
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

Hello,

I'm trying to write a program that modifies /etc/passwd safely, and so I wrote a function that looks like this:

lockPwd f = bracket main recover (\_ -> f)
  where
    mode = unionFileModes ownerReadMode ownerWriteMode
    main = do
      fd <- openFd "/etc/.pwd.lock" WriteOnly (Just mode) defaultFileFlags
      putStrLn "waiting to set lock"
      waitToSetLock fd (WriteLock, AbsoluteSeek, 0, 0)
      putStrLn "got lock"
      return fd
    recover = flip setLock (Unlock, AbsoluteSeek, 0, 0)

When I run it, my fans go wild, and CPU usage hits 300%.

/u/gelisam did some more in depth investigation here: https://www.reddit.com/r/haskell/comments/94wbfc/systemunixiowaittosetlock_call_results_in_300_cpu/e3p7sks/

Googling confirms that the parallel gc is using spin locks. So I think what is happening is that the waitToSetLock call makes the current thread unavailable for garbage collection (I don't know if that means the thread is "descheduled" as in the linked issue), which then causes the other threads to spin-lock while waiting for that thread at the next parallel GC. The problem still occurs with the latest release, GHC 8.4.3, and I could not find an existing issue describing the problem, so please file a ticket.

Maybe an argument could be made that this waitToSetLock call should be converted to be interruptible, but it also seems like I should be able to make my haskell program block patiently if I want it to.

Change History (3)

comment:1 Changed 12 months ago by osa1

Cc: osa1 added

I'll try to reproduce this.

comment:2 Changed 12 months ago by osa1

Status: newinfoneeded

oconnore, would it be possible for you to provide a reproducer? I looked at the /r/haskell thread but I still have no idea how to reproduce this. A cabal package would work (please avoid stack if possible, it adds extra friction).

comment:3 Changed 9 months ago by lelf

Cc: lelf added
Note: See TracTickets for help on using tickets.