Skip to content

Heap profiler doesn't collect samples when process is idle

Consider this program which runs for 10 seconds, mostly blocked in a safe foreign call:

-- hi.hs
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C.Types
import Control.Concurrent
import Control.Monad
foreign import ccall "sleep" c_sleep :: CInt -> IO ()

force_activity = False
main = do
    putStrLn "Hello"
    when force_activity $ void $ forkIO $ forever $ threadDelay 1000
    c_sleep 10
    putStrLn "World"

When running with a 10ms sample period, we would expect 1000 samples. However, in practice we see only three:

$ ghc -threaded hi.hs -rtsopts -prof -eventlog
$ time ./hi +RTS -l -i0.01 -p -hc
Hello
World

real    0m10.013s
user    0m0.041s
sys     0m0.172s
$ ghc-events show /home/ben/hi.eventlog | grep 'start heap prof sample'
304981792: start heap prof sample 0
606904028: start heap prof sample 0
10003624192: start heap prof sample 0

This could be considered either a bug or a feature: since there is no activity there is no allocation and consequently the census should be unchanged. However, this behavior can be somewhat surprising.

One might think that setting force_activity=True would help as it would spur periodic activity. However, even then the number of samples is quite a bit smaller than expected:

$ nix run .#ghc-events -- show /home/ben/hi.eventlog | grep 'start heap prof sample' | wc -l
41

Brought to my attention by @maralorn.

Edited by Ben Gamari
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information