content: {-
    Copyright (c) Meta Platforms, Inc. and affiliates.
    All rights reserved.
  
    This source code is licensed under the BSD-style license found in the
    LICENSE file in the root directory of this source tree.
  -}
  
  {-# LANGUAGE CPP #-}
  module Util.LogIfSlow (logIfSlow, checkUnsafe) where
  
  import Data.Text (Text)
  import Control.Monad
  import qualified Data.Text as Text
  import Text.Printf
  import Util.Timing (timeItNoGC)
  import Util.Log.Text as Log
  
  -- | Logs a message (via @Util.Log.log info@) if the given operation takes
  -- longer than a specified threshold in seconds.
  --
  logIfSlow
    :: Double    -- ^ threshold in seconds
    -> Text      -- ^ description, for the log message
    -> IO a      -- ^ the operation to time
    -> IO a
  logIfSlow threshold fun io = do
    (t, _, a) <- timeItNoGC io
    when (t > threshold) $
      Log.logInfo $ fun <> " took " <> Text.pack (printf "%.2fs" t)
    return a
  
  -- | Logs a message if an unsafe foreign call takes longer than 1ms,
  -- which indicates that it should probably not be marked "unsafe".
  --
  -- > f = checkUnsafe "c_foo" $ c_foo x y z
  -- > foreign import ccall unsafe "foo" c_foo :: ...
  --
  -- will log a message (via 'Util.Log.info') if the call to @c_foo@ takes
  -- longer than 1ms.
  --
  checkUnsafe :: Text -> IO a -> IO a
  
  #ifdef ENABLE_CHECKUNSAFE
  
  checkUnsafe fun = logIfSlow badUnsafeCallThreshold msg
    where msg = "unsafe foreign call " <> fun
  
  badUnsafeCallThreshold :: Double
  badUnsafeCallThreshold = 0.001
  
  #else
  
  checkUnsafe _ io = io
  {-# INLINE checkUnsafe #-}
  
  #endif
  