diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
 # Revision history for ghc-trace-events
 
+## v0.1.2 - 2020-06-09
+
+* Revert "Use unsafeUseAsCString in place of useAsCString in Debug.Trace.Text" because it's unsafe
+* Minimize the scope of NOINLINE to get better performance when user tracing is disabled
+
+## v0.1.1 - 2020-06-07 (abondoned)
+
+* Remove redundant checks of userTracingEnabled
+* Optimize Debug.Trace.Text
+
 ## v0.1.0.1 - 2020-04-06
 
 * Support GHC 8.10.1
diff --git a/ghc-trace-events.cabal b/ghc-trace-events.cabal
--- a/ghc-trace-events.cabal
+++ b/ghc-trace-events.cabal
@@ -1,6 +1,6 @@
 cabal-version: 2.2
 name: ghc-trace-events
-version: 0.1.0.1
+version: 0.1.2
 synopsis: Faster traceEvent and traceMarker, and binary object logging for
   eventlog
 description: ghc-trace-events provides faster traceEvent and traceMarker as well
@@ -30,7 +30,7 @@
 license-file: LICENSE
 author: Mitsutoshi Aoe
 maintainer: Mitsutoshi Aoe <me@maoe.name>
-copyright: Copyright (C) 2018-2019 Mitsutoshi Aoe
+copyright: Copyright (C) 2018-2020 Mitsutoshi Aoe
 category: Development, GHC, Trace
 build-type: Simple
 extra-source-files:
@@ -55,6 +55,7 @@
       base
     , bytestring
     , text
+  ghc-options: -Wall
   exposed-modules:
     Debug.Trace.ByteString
     Debug.Trace.Flags
diff --git a/src/Debug/Trace/Binary.hs b/src/Debug/Trace/Binary.hs
--- a/src/Debug/Trace/Binary.hs
+++ b/src/Debug/Trace/Binary.hs
@@ -1,7 +1,13 @@
 {-# LANGUAGE MagicHash #-}
 {-# LANGUAGE UnboxedTuples #-}
+{-|
+Arbitary binary object logging available for GHC 8.8 or later. Unlike the other
+tracing functions 'traceBinaryEvent' takes an arbitrary 'B.ByteString' object as
+opposed to a UTF-8 encoded string.
+-}
 module Debug.Trace.Binary
-  ( traceBinaryEvent
+  ( -- * Binary eventlog tracing
+     traceBinaryEvent
   , traceBinaryEventIO
   ) where
 import Control.Monad (when)
@@ -32,12 +38,15 @@
 -- generates a broken eventlog.
 traceBinaryEvent :: B.ByteString -> a -> a
 traceBinaryEvent bytes a
-  | userTracingEnabled = Unsafe.unsafeDupablePerformIO $ do
-    traceBinaryEventIO bytes
-    return a
+  | userTracingEnabled = traceBinaryEvent' bytes a
   | otherwise = a
-{-# NOINLINE traceBinaryEvent #-}
 
+traceBinaryEvent' :: B.ByteString -> a -> a
+traceBinaryEvent' bytes a = Unsafe.unsafeDupablePerformIO $ do
+  traceBinaryEventIO' bytes
+  return a
+{-# NOINLINE traceBinaryEvent' #-}
+
 -- | The 'traceBinaryEventIO' function emits a binary message to the eventlog,
 -- if eventlog profiling is available and enabled at runtime.
 --
@@ -50,7 +59,10 @@
 -- The input should be shorter than \(2^{16}\) bytes. Otherwise the RTS
 -- generates a broken eventlog.
 traceBinaryEventIO :: B.ByteString -> IO ()
-traceBinaryEventIO bytes = when userTracingEnabled $
+traceBinaryEventIO bytes = when userTracingEnabled $ traceBinaryEventIO' bytes
+
+traceBinaryEventIO' :: B.ByteString -> IO ()
+traceBinaryEventIO' bytes =
   BU.unsafeUseAsCStringLen bytes $ \(Ptr p, I# n) -> IO $ \s ->
     case traceBinaryEvent# p n s of
       s' -> (# s', () #)
diff --git a/src/Debug/Trace/ByteString.hs b/src/Debug/Trace/ByteString.hs
--- a/src/Debug/Trace/ByteString.hs
+++ b/src/Debug/Trace/ByteString.hs
@@ -5,22 +5,25 @@
 'B.ByteString' variant of the tracing functions in "Debug.Trace".
 -}
 module Debug.Trace.ByteString
-  ( traceEvent
+  ( -- * Eventlog tracing
+    -- $eventlog_tracing
+    traceEvent
   , traceEventIO
 
-  , traceMarker
-  , traceMarkerIO
-
   , unsafeTraceEvent
   , unsafeTraceEventIO
 
+  -- * Execution phase markers
+  -- $markers
+  , traceMarker
+  , traceMarkerIO
+
   , unsafeTraceMarker
   , unsafeTraceMarkerIO
   ) where
 import Control.Monad (when)
 import GHC.Exts (Ptr(..), traceEvent#, traceMarker#)
 import GHC.IO (IO(..))
-import qualified GHC.RTS.Flags as Flags
 import qualified System.IO.Unsafe as Unsafe
 
 import qualified Data.ByteString as B
@@ -28,6 +31,17 @@
 
 import Debug.Trace.Flags (userTracingEnabled)
 
+-- $eventlog_tracing
+--
+-- Eventlog tracing is a performance profiling system. These functions emit
+-- extra events into the eventlog. In combination with eventlog profiling
+-- tools these functions can be used for monitoring execution and
+-- investigating performance problems.
+--
+-- Currently only GHC provides eventlog profiling, see the GHC user guide for
+-- details on how to use it. These function exists for other Haskell
+-- implementations but no events are emitted.
+
 -- | 'B.ByteString' variant of 'Debug.Trace.traceEvent'.
 --
 -- \(O(n)\) This function copies the 'B.ByteString' to convert it to a
@@ -40,12 +54,15 @@
 -- generates a broken eventlog.
 traceEvent :: B.ByteString -> a -> a
 traceEvent message a
-  | userTracingEnabled = Unsafe.unsafeDupablePerformIO $ do
-    traceEventIO message
-    return a
+  | userTracingEnabled = traceEvent' message a
   | otherwise = a
-{-# NOINLINE traceEvent #-}
 
+traceEvent' :: B.ByteString -> a -> a
+traceEvent' message a = Unsafe.unsafeDupablePerformIO $ do
+  traceEventIO' message
+  return a
+{-# NOINLINE traceEvent' #-}
+
 -- | 'B.ByteString' variant of 'Debug.Trace.traceEventIO'.
 --
 -- \(O(n)\) This function copies the 'B.ByteString' to convert it to a
@@ -57,81 +74,113 @@
 -- The input should be shorter than \(2^{16}\) bytes. Otherwise the RTS
 -- generates a broken eventlog.
 traceEventIO :: B.ByteString -> IO ()
-traceEventIO message = when userTracingEnabled $
-  B.useAsCString message $ \(Ptr p) -> IO $ \s ->
-    case traceEvent# p s of
-      s' -> (# s', () #)
+traceEventIO message = when userTracingEnabled $ traceEventIO' message
 
--- | 'B.ByteString' variant of 'Debug.Trace.traceMarker'.
+traceEventIO' :: B.ByteString -> IO ()
+traceEventIO' message = B.useAsCString message $ \(Ptr p) -> IO $ \s ->
+  case traceEvent# p s of
+    s' -> (# s', () #)
+
+-- | 'B.ByteString' variant of 'Debug.Trace.traceEvent'.
 --
--- \(O(n)\) This function copies the 'B.ByteString' to convert it to a
--- null-terminated 'Foreign.C.Types.CString'.
+-- \(O(1)\) This function is unsafe in the way that it doesn't ensure the input
+-- string to be null-terminated. It is user's responsibility to null-terminate
+-- the input.
 --
 -- Note that this function doesn't evaluate the 'B.ByteString' if user tracing
 -- in eventlog is disabled.
 --
 -- The input should be shorter than \(2^{16}\) bytes. Otherwise the RTS
 -- generates a broken eventlog.
-traceMarker :: B.ByteString -> a -> a
-traceMarker message a
-  | userTracingEnabled = Unsafe.unsafeDupablePerformIO $ do
-    traceMarkerIO message
-    return a
+unsafeTraceEvent :: B.ByteString -> a -> a
+unsafeTraceEvent message a
+  | userTracingEnabled = unsafeTraceEvent' message a
   | otherwise = a
-{-# NOINLINE traceMarker #-}
 
--- | 'B.ByteString' variant of 'Debug.Trace.traceMarkerIO'.
+unsafeTraceEvent' :: B.ByteString -> a -> a
+unsafeTraceEvent' message a = Unsafe.unsafeDupablePerformIO $ do
+  unsafeTraceEventIO' message
+  return a
+{-# NOINLINE unsafeTraceEvent' #-}
+
+-- | 'B.ByteString' variant of 'Debug.Trace.traceEventIO'.
 --
--- \(O(n)\) This function copies the 'B.ByteString' to convert it to a
--- null-terminated 'Foreign.C.Types.CString'.
+-- \(O(1)\) This function is unsafe in the way that it doesn't ensure the input
+-- string to be null-terminated. It is user's responsibility to null-terminate
+-- the input.
 --
 -- Note that this function doesn't evaluate the 'B.ByteString' if user tracing
 -- in eventlog is disabled.
 --
 -- The input should be shorter than \(2^{16}\) bytes. Otherwise the RTS
 -- generates a broken eventlog.
-traceMarkerIO :: B.ByteString -> IO ()
-traceMarkerIO message = when userTracingEnabled $
-  B.useAsCString message $ \(Ptr p) -> IO $ \s ->
-    case traceMarker# p s of
+unsafeTraceEventIO :: B.ByteString -> IO ()
+unsafeTraceEventIO message =
+  when userTracingEnabled $ unsafeTraceEventIO' message
+
+unsafeTraceEventIO' :: B.ByteString -> IO ()
+unsafeTraceEventIO' message =
+  BU.unsafeUseAsCString message $ \(Ptr p) -> IO $ \s ->
+    case traceEvent# p s of
       s' -> (# s', () #)
 
--- | 'B.ByteString' variant of 'Debug.Trace.traceEvent'.
+-- $markers
 --
--- \(O(1)\) This function is unsafe in the way that it doesn't ensure the input
--- string to be null-terminated. It is user's responsibility to null-terminate
--- the input.
+-- When looking at a profile for the execution of a program we often want to
+-- be able to mark certain points or phases in the execution and see that
+-- visually in the profile.
 --
+-- For example, a program might have several distinct phases with different
+-- performance or resource behaviour in each phase. To properly interpret the
+-- profile graph we really want to see when each phase starts and ends.
+--
+-- Markers let us do this: we can annotate the program to emit a marker at
+-- an appropriate point during execution and then see that in a profile.
+--
+-- Currently this feature is only supported in GHC by the eventlog tracing
+-- system, but in future it may also be supported by the heap profiling or
+-- other profiling tools. These function exists for other Haskell
+-- implementations but they have no effect.
+
+-- | 'B.ByteString' variant of 'Debug.Trace.traceMarker'.
+--
+-- \(O(n)\) This function copies the 'B.ByteString' to convert it to a
+-- null-terminated 'Foreign.C.Types.CString'.
+--
 -- Note that this function doesn't evaluate the 'B.ByteString' if user tracing
 -- in eventlog is disabled.
 --
 -- The input should be shorter than \(2^{16}\) bytes. Otherwise the RTS
 -- generates a broken eventlog.
-unsafeTraceEvent :: B.ByteString -> a -> a
-unsafeTraceEvent message a
-  | userTracingEnabled = Unsafe.unsafeDupablePerformIO $ do
-    unsafeTraceEventIO message
-    return a
+traceMarker :: B.ByteString -> a -> a
+traceMarker message a
+  | userTracingEnabled = traceMarker' message a
   | otherwise = a
-{-# NOINLINE unsafeTraceEvent #-}
 
--- | 'B.ByteString' variant of 'Debug.Trace.traceEventIO'.
+traceMarker' :: B.ByteString -> a -> a
+traceMarker' message a = Unsafe.unsafeDupablePerformIO $ do
+  traceMarkerIO' message
+  return a
+{-# NOINLINE traceMarker' #-}
+
+-- | 'B.ByteString' variant of 'Debug.Trace.traceMarkerIO'.
 --
--- \(O(1)\) This function is unsafe in the way that it doesn't ensure the input
--- string to be null-terminated. It is user's responsibility to null-terminate
--- the input.
+-- \(O(n)\) This function copies the 'B.ByteString' to convert it to a
+-- null-terminated 'Foreign.C.Types.CString'.
 --
 -- Note that this function doesn't evaluate the 'B.ByteString' if user tracing
 -- in eventlog is disabled.
 --
 -- The input should be shorter than \(2^{16}\) bytes. Otherwise the RTS
 -- generates a broken eventlog.
-unsafeTraceEventIO :: B.ByteString -> IO ()
-unsafeTraceEventIO message = when userTracingEnabled $
-  BU.unsafeUseAsCString message $ \(Ptr p) -> IO $ \s ->
-    case traceEvent# p s of
-      s' -> (# s', () #)
+traceMarkerIO :: B.ByteString -> IO ()
+traceMarkerIO message = when userTracingEnabled $ traceMarkerIO' message
 
+traceMarkerIO' :: B.ByteString -> IO ()
+traceMarkerIO' message = B.useAsCString message $ \(Ptr p) -> IO $ \s ->
+  case traceMarker# p s of
+    s' -> (# s', () #)
+
 -- | 'B.ByteString' variant of 'Debug.Trace.traceMarker'.
 --
 -- \(O(1)\) This function is unsafe in the way that it doesn't ensure the input
@@ -145,12 +194,15 @@
 -- generates a broken eventlog.
 unsafeTraceMarker :: B.ByteString -> a -> a
 unsafeTraceMarker message a
-  | userTracingEnabled = Unsafe.unsafeDupablePerformIO $ do
-    unsafeTraceEventIO message
-    return a
+  | userTracingEnabled = unsafeTraceMarker' message a
   | otherwise = a
-{-# NOINLINE unsafeTraceMarker #-}
 
+unsafeTraceMarker' :: B.ByteString -> a -> a
+unsafeTraceMarker' message a = Unsafe.unsafeDupablePerformIO $ do
+  unsafeTraceMarkerIO' message
+  return a
+{-# NOINLINE unsafeTraceMarker' #-}
+
 -- | 'B.ByteString' variant of 'Debug.Trace.traceMarkerIO'.
 --
 -- \(O(1)\) This function is unsafe in the way that it doesn't ensure the input
@@ -163,7 +215,11 @@
 -- The input should be shorter than \(2^{16}\) bytes. Otherwise the RTS
 -- generates a broken eventlog.
 unsafeTraceMarkerIO :: B.ByteString -> IO ()
-unsafeTraceMarkerIO message = when userTracingEnabled $
+unsafeTraceMarkerIO message =
+  when userTracingEnabled $ unsafeTraceMarkerIO' message
+
+unsafeTraceMarkerIO' :: B.ByteString -> IO ()
+unsafeTraceMarkerIO' message =
   BU.unsafeUseAsCString message $ \(Ptr p) -> IO $ \s ->
     case traceMarker# p s of
       s' -> (# s', () #)
diff --git a/src/Debug/Trace/String.hs b/src/Debug/Trace/String.hs
--- a/src/Debug/Trace/String.hs
+++ b/src/Debug/Trace/String.hs
@@ -1,11 +1,15 @@
 {-|
-Drop-in replacements for the event tracing functions in "Debug.Trace" but are
+Drop-in replacement for the event tracing functions in "Debug.Trace" but are
 faster when user tracing is disabled.
 -}
 module Debug.Trace.String
-  ( traceEvent
+  ( -- * Eventlog tracing
+    -- $eventlog_tracing
+    traceEvent
   , traceEventIO
 
+  -- * Execution phase markers
+  -- $markers
   , traceMarker
   , traceMarkerIO
   ) where
@@ -14,6 +18,17 @@
 
 import Debug.Trace.Flags (userTracingEnabled)
 
+-- $eventlog_tracing
+--
+-- Eventlog tracing is a performance profiling system. These functions emit
+-- extra events into the eventlog. In combination with eventlog profiling
+-- tools these functions can be used for monitoring execution and
+-- investigating performance problems.
+--
+-- Currently only GHC provides eventlog profiling, see the GHC user guide for
+-- details on how to use it. These function exists for other Haskell
+-- implementations but no events are emitted.
+
 -- | Drop-in replacement for 'Debug.Trace.traceEvent' but is more efficient
 -- if user tracing in eventlog is disabled.
 --
@@ -37,6 +52,24 @@
 -- generates a broken eventlog.
 traceEventIO :: String -> IO ()
 traceEventIO message = when userTracingEnabled $ Base.traceEventIO message
+
+-- $markers
+--
+-- When looking at a profile for the execution of a program we often want to
+-- be able to mark certain points or phases in the execution and see that
+-- visually in the profile.
+--
+-- For example, a program might have several distinct phases with different
+-- performance or resource behaviour in each phase. To properly interpret the
+-- profile graph we really want to see when each phase starts and ends.
+--
+-- Markers let us do this: we can annotate the program to emit a marker at
+-- an appropriate point during execution and then see that in a profile.
+--
+-- Currently this feature is only supported in GHC by the eventlog tracing
+-- system, but in future it may also be supported by the heap profiling or
+-- other profiling tools. These function exists for other Haskell
+-- implementations but they have no effect.
 
 -- | Drop-in replacement for 'Debug.Trace.traceMarker' but is more efficient
 -- if user tracing in eventlog is disabled.
diff --git a/src/Debug/Trace/Text.hs b/src/Debug/Trace/Text.hs
--- a/src/Debug/Trace/Text.hs
+++ b/src/Debug/Trace/Text.hs
@@ -4,9 +4,13 @@
 'T.Text' variant of the tracing functions in "Debug.Trace".
 -}
 module Debug.Trace.Text
-  ( traceEvent
+  ( -- * Eventlog tracing
+  -- $eventlog_tracing
+    traceEvent
   , traceEventIO
 
+  -- * Execution phase markers
+  -- $markers
   , traceMarker
   , traceMarkerIO
   ) where
@@ -14,7 +18,6 @@
 import Foreign.C.String (CString)
 import GHC.Exts (Ptr(..), traceEvent#, traceMarker#)
 import GHC.IO (IO(..))
-import qualified GHC.RTS.Flags as Flags
 import qualified System.IO.Unsafe as Unsafe
 
 import qualified Data.ByteString as B
@@ -23,6 +26,17 @@
 
 import Debug.Trace.Flags (userTracingEnabled)
 
+-- $eventlog_tracing
+--
+-- Eventlog tracing is a performance profiling system. These functions emit
+-- extra events into the eventlog. In combination with eventlog profiling
+-- tools these functions can be used for monitoring execution and
+-- investigating performance problems.
+--
+-- Currently only GHC provides eventlog profiling, see the GHC user guide for
+-- details on how to use it. These function exists for other Haskell
+-- implementations but no events are emitted.
+
 -- | 'T.Text' variant of 'Debug.Trace.traceEvent'.
 --
 -- \(O(n)\) This function marshals the 'T.Text' into a 'B.ByteString' and
@@ -35,12 +49,15 @@
 -- generates a broken eventlog.
 traceEvent :: T.Text -> a -> a
 traceEvent message a
-  | userTracingEnabled = Unsafe.unsafeDupablePerformIO $ do
-    traceEventIO message
-    return a
+  | userTracingEnabled = traceEvent' message a
   | otherwise = a
-{-# NOINLINE traceEvent #-}
 
+traceEvent' :: T.Text -> a -> a
+traceEvent' message a = Unsafe.unsafeDupablePerformIO $ do
+  traceEventIO' message
+  return a
+{-# NOINLINE traceEvent' #-}
+
 -- | 'T.Text' variant of 'Debug.Trace.traceEventIO'.
 --
 -- \(O(n)\) This function marshals the 'T.Text' into a 'B.ByteString' and
@@ -52,11 +69,31 @@
 -- The input should be shorter than \(2^{16}\) bytes. Otherwise the RTS
 -- generates a broken eventlog.
 traceEventIO :: T.Text -> IO ()
-traceEventIO message = when userTracingEnabled $
-  withCString message $ \(Ptr p) -> IO $ \s ->
-    case traceEvent# p s of
-      s' -> (# s', () #)
+traceEventIO message = when userTracingEnabled $ traceEventIO' message
 
+traceEventIO' :: T.Text -> IO ()
+traceEventIO' message = withCString message $ \(Ptr p) -> IO $ \s ->
+  case traceEvent# p s of
+    s' -> (# s', () #)
+
+-- $markers
+--
+-- When looking at a profile for the execution of a program we often want to
+-- be able to mark certain points or phases in the execution and see that
+-- visually in the profile.
+--
+-- For example, a program might have several distinct phases with different
+-- performance or resource behaviour in each phase. To properly interpret the
+-- profile graph we really want to see when each phase starts and ends.
+--
+-- Markers let us do this: we can annotate the program to emit a marker at
+-- an appropriate point during execution and then see that in a profile.
+--
+-- Currently this feature is only supported in GHC by the eventlog tracing
+-- system, but in future it may also be supported by the heap profiling or
+-- other profiling tools. These function exists for other Haskell
+-- implementations but they have no effect.
+
 -- | 'T.Text' variant of 'Debug.Trace.traceMarker'.
 --
 -- \(O(n)\) This function marshals the 'T.Text' into a 'B.ByteString' and
@@ -69,12 +106,15 @@
 -- generates a broken eventlog.
 traceMarker :: T.Text -> a -> a
 traceMarker message a
-  | userTracingEnabled = Unsafe.unsafeDupablePerformIO $ do
-    traceMarkerIO message
-    return a
+  | userTracingEnabled = traceMarker' message a
   | otherwise = a
-{-# NOINLINE traceMarker #-}
 
+traceMarker' :: T.Text -> a -> a
+traceMarker' message a = Unsafe.unsafeDupablePerformIO $ do
+  traceMarkerIO' message
+  return a
+{-# NOINLINE traceMarker' #-}
+
 -- | 'T.Text' variant of 'Debug.Trace.traceMarkerIO'.
 --
 -- \(O(n)\) This function marshals the 'T.Text' into a 'B.ByteString' and
@@ -86,10 +126,12 @@
 -- The input should be shorter than \(2^{16}\) bytes. Otherwise the RTS
 -- generates a broken eventlog.
 traceMarkerIO :: T.Text -> IO ()
-traceMarkerIO message = when userTracingEnabled $
-  withCString message $ \(Ptr p) -> IO $ \s ->
-    case traceMarker# p s of
-      s' -> (# s', () #)
+traceMarkerIO message = when userTracingEnabled $ traceMarkerIO' message
+
+traceMarkerIO' :: T.Text -> IO ()
+traceMarkerIO' message = withCString message $ \(Ptr p) -> IO $ \s ->
+  case traceMarker# p s of
+    s' -> (# s', () #)
 
 withCString :: T.Text -> (CString -> IO a) -> IO a
 withCString text = B.useAsCString (TE.encodeUtf8 text)
