packages feed

ghcide-1.6.0.0: src/Development/IDE/Main/HeapStats.hs

{-# LANGUAGE NumericUnderscores #-}
-- | Logging utilities for reporting heap statistics
module Development.IDE.Main.HeapStats ( withHeapStats ) where

import           Control.Concurrent
import           Control.Concurrent.Async
import           Control.Monad
import qualified Data.Text                    as T
import           Data.Word
import           Development.IDE.Types.Logger (Logger, logInfo)
import           GHC.Stats
import           Text.Printf                  (printf)

-- | Interval at which to report the latest heap statistics.
heapStatsInterval :: Int
heapStatsInterval = 60_000_000 -- 60s

-- | Report the live bytes and heap size at the last major collection.
logHeapStats :: Logger -> IO ()
logHeapStats l = do
  stats <- getRTSStats
  -- live_bytes is the total amount of live memory in a program
  -- (corresponding to the amount on a heap profile)
  let live_bytes = gcdetails_live_bytes (gc stats)
  -- heap_size is the total amount of memory the RTS is using
  -- this corresponds closer to OS memory usage
      heap_size  = gcdetails_mem_in_use_bytes (gc stats)
      format :: Word64 -> T.Text
      format m = T.pack (printf "%.2fMB" (fromIntegral @Word64 @Double m / 1e6))
      message = "Live bytes: " <> format live_bytes  <> " " <>
                "Heap size: " <> format heap_size
  logInfo l message

-- | An action which logs heap statistics at the 'heapStatsInterval'
heapStatsThread :: Logger -> IO r
heapStatsThread l = forever $ do
  threadDelay heapStatsInterval
  logHeapStats l

-- | A helper function which lauches the 'heapStatsThread' and kills it
-- appropiately when the inner action finishes. It also checks to see
-- if `-T` is enabled.
withHeapStats :: Logger -> IO r -> IO r
withHeapStats l k = do
  enabled <- getRTSStatsEnabled
  if enabled
    then do
      logInfo l ("Logging heap statistics every "
                  <> T.pack (printf "%.2fs" (fromIntegral @Int @Double heapStatsInterval / 1e6)))
      withAsync (heapStatsThread l) (const k)
    else do
      logInfo l "Heap statistics are not enabled (RTS option -T is needed)"
      k