packages feed

grapesy-1.0.0: kvstore/KVStore/Util/Profiling.hs

{-# LANGUAGE CPP #-}

-- | Profiling utilities
--
-- Function 'markEvent' is normally just an alias for 'traceEventIO'. However,
-- when grapey is compiled with the @strace@ flag enabled, 'markEvent' also
-- writes the string to /dev/null using a posix @write@ call. This will show
-- up in the output of @strace@, thereby making it possible to relate strace
-- events to user events.
module KVStore.Util.Profiling (
    markEvent
  , markNonStreaming
  ) where

import Debug.Trace (traceEventIO)
import Control.Exception (bracket_)
import Network.GRPC.Common.StreamType
import Network.GRPC.Common
import Network.GRPC.Server.StreamType (ServerHandler')
import Network.GRPC.Server.StreamType qualified as Server

#ifdef STRACE
import Control.Monad
import System.IO.Unsafe (unsafePerformIO)
import System.Posix
#endif

{-------------------------------------------------------------------------------
  markEvent
-------------------------------------------------------------------------------}

#ifdef STRACE

devNull :: Fd
{-# NOINLINE devNull #-}
devNull = unsafePerformIO $ do
#if MIN_VERSION_unix(2,8,0)
   openFd "/dev/null" WriteOnly defaultFileFlags
#else
   openFd "/dev/null" WriteOnly Nothing defaultFileFlags
#endif

markEvent :: String -> IO ()
markEvent str' = do
    -- We also write to /dev/null; the benefit of doing this is that this will
    -- show up in the strace output, allowing us to relate events to syscalls.
    _bytesWritten <- fdWrite devNull str
    when (fromIntegral _bytesWritten /= length str) $
      error "markEvent: fdWrite failed to write complete string"
    traceEventIO str
  where
    str = str' ++ "\n"

#else

markEvent :: String -> IO ()
markEvent = traceEventIO

#endif

{-------------------------------------------------------------------------------
  Derived
-------------------------------------------------------------------------------}

markNonStreaming ::
     SupportsStreamingType rpc NonStreaming
  => String
  -> (Input rpc -> IO (Output rpc))
  -> ServerHandler' NonStreaming IO rpc
markNonStreaming label handler = Server.mkNonStreaming $ \inp ->
    bracket_ (markEvent $ "HANDLER start " ++ label)
             (markEvent $ "HANDLER stop  " ++ label)
             (handler inp)