@@ -13,7 +13,7 @@ import Control.Concurrent.Extra (Var, modifyVar_, newVar,
1313 readVar , threadDelay )
1414import Control.Exception (evaluate )
1515import Control.Exception.Safe (catch , SomeException )
16- import Control.Monad (unless , forM_ , forever , (>=>) )
16+ import Control.Monad (void , when , unless , forM_ , forever , (>=>) )
1717import Control.Monad.Extra (whenJust )
1818import Control.Seq (r0 , seqList , seqTuple2 , using )
1919import Data.Dynamic (Dynamic )
@@ -28,12 +28,13 @@ import Development.IDE.Core.RuleTypes (GhcSession (GhcSession),
2828import Development.IDE.Types.Logger (logInfo , Logger , logDebug )
2929import Development.IDE.Types.Shake (Key (.. ), Value , Values )
3030import Development.Shake (Action , actionBracket , liftIO )
31+ import Ide.PluginUtils (installSigUsr1Handler )
3132import Foreign.Storable (Storable (sizeOf ))
3233import HeapSize (recursiveSize , runHeapsize )
3334import Language.Haskell.LSP.Types (NormalizedFilePath ,
3435 fromNormalizedFilePath )
3536import Numeric.Natural (Natural )
36- import OpenTelemetry.Eventlog (addEvent , beginSpan , endSpan ,
37+ import OpenTelemetry.Eventlog (Synchronicity ( Asynchronous ), Instrument , addEvent , beginSpan , endSpan ,
3738 mkValueObserver , observe ,
3839 setTag , withSpan , withSpan_ )
3940
@@ -71,36 +72,47 @@ otTracedAction key file success act = actionBracket
7172 unless (success res) $ setTag sp " error" " 1"
7273 return res)
7374
74- startTelemetry :: Logger -> Var Values -> IO ()
75- startTelemetry logger stateRef = do
75+ startTelemetry :: Bool -> Logger -> Var Values -> IO ()
76+ startTelemetry allTheTime logger stateRef = do
7677 instrumentFor <- getInstrumentCached
7778 mapCountInstrument <- mkValueObserver " values map count"
7879
79- _ <- regularly (1 * seconds) $
80- withSpan_ " Measure length" $
81- readVar stateRef
82- >>= observe mapCountInstrument . length
83-
84- _ <- regularly (1 * seconds) $ do
85- values <- readVar stateRef
86- let keys = nub
87- $ Key GhcSession : Key GhcSessionDeps
88- : [ k | (_,k) <- HMap. keys values
89- -- do GhcSessionIO last since it closes over stateRef itself
90- , k /= Key GhcSessionIO ]
91- ++ [Key GhcSessionIO ]
92- ! groupedForSharing <- evaluate (keys `using` seqList r0)
93- measureMemory logger [groupedForSharing] instrumentFor stateRef
94- `catch` \ (e:: SomeException ) ->
95- logInfo logger (" MEMORY PROFILING ERROR: " <> fromString (show e))
96- return ()
80+ installSigUsr1Handler $ do
81+ logInfo logger " SIGUSR1 received: performing memory measurement"
82+ performMeasurement logger stateRef instrumentFor mapCountInstrument
83+
84+ when allTheTime $ void $ regularly (1 * seconds) $
85+ performMeasurement logger stateRef instrumentFor mapCountInstrument
9786 where
9887 seconds = 1000000
9988
10089 regularly :: Int -> IO () -> IO (Async () )
10190 regularly delay act = async $ forever (act >> threadDelay delay)
10291
103- {-# ANN startTelemetry ("HLint: ignore Use nubOrd" :: String) #-}
92+
93+ performMeasurement ::
94+ Logger ->
95+ Var (HMap. HashMap (NormalizedFilePath , Key ) (Value Dynamic )) ->
96+ (Maybe Key -> IO OurValueObserver ) ->
97+ Instrument 'Asynchronous a m' ->
98+ IO ()
99+ performMeasurement logger stateRef instrumentFor mapCountInstrument = do
100+ withSpan_ " Measure length" $ readVar stateRef >>= observe mapCountInstrument . length
101+
102+ values <- readVar stateRef
103+ let keys = Key GhcSession
104+ : Key GhcSessionDeps
105+ : [ k | (_,k) <- HMap. keys values
106+ -- do GhcSessionIO last since it closes over stateRef itself
107+ , k /= Key GhcSession
108+ , k /= Key GhcSessionDeps
109+ , k /= Key GhcSessionIO
110+ ] ++ [Key GhcSessionIO ]
111+ groupedForSharing <- evaluate (keys `using` seqList r0)
112+ measureMemory logger [groupedForSharing] instrumentFor stateRef
113+ `catch` \ (e:: SomeException ) ->
114+ logInfo logger (" MEMORY PROFILING ERROR: " <> fromString (show e))
115+
104116
105117type OurValueObserver = Int -> IO ()
106118
0 commit comments