|
| 1 | +{-# LANGUAGE NumericUnderscores #-} |
| 2 | +-- | Logging utilities for reporting heap statistics |
| 3 | +module Development.IDE.Main.HeapStats ( withHeapStats ) where |
| 4 | + |
| 5 | +import GHC.Stats |
| 6 | +import Development.IDE.Types.Logger (Logger, logInfo) |
| 7 | +import Control.Concurrent.Async |
| 8 | +import qualified Data.Text as T |
| 9 | +import Data.Word |
| 10 | +import Control.Monad |
| 11 | +import Control.Concurrent |
| 12 | +import Text.Printf (printf) |
| 13 | + |
| 14 | +-- | Interval at which to report the latest heap statistics. |
| 15 | +heapStatsInterval :: Int |
| 16 | +heapStatsInterval = 60_000_000 -- 60s |
| 17 | + |
| 18 | +-- | Report the live bytes and heap size at the last major collection. |
| 19 | +logHeapStats :: Logger -> IO () |
| 20 | +logHeapStats l = do |
| 21 | + stats <- getRTSStats |
| 22 | + -- live_bytes is the total amount of live memory in a program |
| 23 | + -- (corresponding to the amount on a heap profile) |
| 24 | + let live_bytes = gcdetails_live_bytes (gc stats) |
| 25 | + -- heap_size is the total amount of memory the RTS is using |
| 26 | + -- this corresponds closer to OS memory usage |
| 27 | + heap_size = gcdetails_mem_in_use_bytes (gc stats) |
| 28 | + format :: Word64 -> T.Text |
| 29 | + format m = T.pack (printf "%.2fMB" (fromIntegral @Word64 @Double m / 1e6)) |
| 30 | + message = "Live bytes: " <> format live_bytes <> " " <> |
| 31 | + "Heap size: " <> format heap_size |
| 32 | + logInfo l message |
| 33 | + |
| 34 | +-- | An action which logs heap statistics at the 'heapStatsInterval' |
| 35 | +heapStatsThread :: Logger -> IO r |
| 36 | +heapStatsThread l = forever $ do |
| 37 | + threadDelay heapStatsInterval |
| 38 | + logHeapStats l |
| 39 | + |
| 40 | +-- | A helper function which lauches the 'heapStatsThread' and kills it |
| 41 | +-- appropiately when the inner action finishes. It also checks to see |
| 42 | +-- if `-T` is enabled. |
| 43 | +withHeapStats :: Logger -> IO r -> IO r |
| 44 | +withHeapStats l k = do |
| 45 | + enabled <- getRTSStatsEnabled |
| 46 | + if enabled |
| 47 | + then do |
| 48 | + logInfo l ("Logging heap statistics every " |
| 49 | + <> T.pack (printf "%.2fs" (fromIntegral @Int @Double heapStatsInterval / 1e6))) |
| 50 | + withAsync (heapStatsThread l) (const k) |
| 51 | + else do |
| 52 | + logInfo l "Heap statistics are not enabled (RTS option -T is needed)" |
| 53 | + k |
0 commit comments