Opened 8 years ago

Closed 8 years ago

#5773 closed bug (fixed)

main = forever (putStrLn =<< getLine) continuously saturates a CPU when compiled

Reported by: lpsmith Owned by:
Priority: highest Milestone: 7.4.1
Component: Compiler Version: 7.4.1-rc1
Keywords: Cc:
Operating System: Linux Architecture: x86_64 (amd64)
Type of failure: Runtime performance bug Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:


$ ghc --make copycat.hs
$ ./copycat

Attachments (2)

copycat.hs (74 bytes) - added by lpsmith 8 years ago.
PGListener.hs (1.3 KB) - added by lpsmith 8 years ago.

Download all attachments as: .zip

Change History (14)

Changed 8 years ago by lpsmith

Attachment: copycat.hs added

comment:1 Changed 8 years ago by lpsmith

The problem appears to be in getLine; you can remove forever and still consume 100% of a CPU (until you type something in and the program exits of course.)

comment:2 Changed 8 years ago by lpsmith

Playing around with this issue a little bit more, getLine and hGet from Data.ByteString.Char8 also saturate the CPU when they block. However I do have some code that uses threadWaitRead and a C library to fetch some input (specifically, the asynchronous notification mechanism of PostgreSQL via libpq), which does not exhibit this problem.

comment:3 Changed 8 years ago by igloo

difficulty: Unknown
Milestone: 7.4.1
Owner: set to simonmar
Priority: normalhighest

Thanks for the report.

This is a regression: It works in 7.2 and 7.0.

Simon, do you know what's up?

I skimmed 6b1098511aaabd2c9503ee7be6da1944466f9cb4, and while I don't think it's relevant, shouldn't the tv_nsec and tv_usec fields in these hunks have the complete seconds removed?:

-        it.it_value.tv_sec = itimer_interval / 1000;
-        it.it_value.tv_nsec = (itimer_interval % 1000) * 1000000;
+        it.it_value.tv_sec  = TimeToSeconds(itimer_interval);
+        it.it_value.tv_nsec = TimeToNS(itimer_interval);
-        it.it_value.tv_sec = itimer_interval / 1000;
-        it.it_value.tv_usec = (itimer_interval % 1000) * 1000;
+        it.it_value.tv_sec = TimeToSeconds(itimer_interval);
+        it.it_value.tv_usec = TimeToUS(itimer_interval);

comment:4 Changed 8 years ago by lpsmith

Ok, I was mistaken. The program I though I compiled with ghc-7.4.1-rc1 I actually compiled with ghc-7.0.3, and so the program I used to test threadWaitRead also saturates the CPU. Although it may not be of any great interest to the bug-hunters, I'll attach the program, it's a straightforward port of a sample program from the PostgreSQL source distribution to the bindings.

So it seems to be a problem with blocking IO in general. I find it curious that none of my test programs exhibit this problem when run inside GHCi.

Changed 8 years ago by lpsmith

Attachment: PGListener.hs added

comment:5 Changed 8 years ago by igloo

GHCi is linked with -threaded by default, which uses a different implementation of this stuff.

comment:6 Changed 8 years ago by lpsmith

Oh, right, I didn't notice that the program I was writing when I ran into this bug wasn't not being linked -threaded. And this problem does go away when I do that. Thanks!

comment:7 Changed 8 years ago by marlowsd@…

commit fac8ecbbafde17dd92439c41747223c43e9d2b80

Author: Simon Marlow <>
Date:   Mon Jan 16 09:49:24 2012 +0000

    Fix bug causing polling instead of blocking in the non-threaded RTS (#5773)
    This was a regression introduced accidentally in
    6b1098511aaabd2c9503ee7be6da1944466f9cb4.  We were previously passing
    a large time value to select() to simulate blocking, and this broke
    due to a change from unsigned to signed arithmetic.  I've refactored
    it to be less fragile now - we just pass NULL as the timeval parameter
    to select(), which is the correct way to do blocking.

 rts/posix/Select.c |   35 +++++++++++++++++------------------
 1 files changed, 17 insertions(+), 18 deletions(-)

comment:8 Changed 8 years ago by simonmar

Status: newmerge

Thanks for the report - a good one to find before the release.

comment:9 Changed 8 years ago by igloo

Resolution: fixed
Status: mergeclosed

comment:10 Changed 8 years ago by simonmar

Owner: simonmar deleted
Resolution: fixed
Status: closednew

The fix is faulty, I'm just validating a fix for the fix.

comment:11 Changed 8 years ago by simonmar

Status: newmerge

comment:12 Changed 8 years ago by igloo

Resolution: fixed
Status: mergeclosed
Note: See TracTickets for help on using tickets.