diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -42,7 +42,8 @@
 `tasty-bench` is a native Haskell library and works everywhere, where GHC
 does, including WASM. We support a full range of architectures (`i386`, `amd64`, `armhf`,
 `arm64`, `ppc64le`, `s390x`) and operating systems (Linux, Windows, macOS,
-FreeBSD, OpenBSD, NetBSD), plus any GHC from 7.0 to 9.10.
+FreeBSD, OpenBSD, NetBSD), plus any GHC from 8.0 to 9.10
+(and earlier releases stretch back to GHC 7.0).
 
 ## How is it possible?
 
@@ -393,6 +394,13 @@
 
   ```
   <stdout>: commitBuffer: invalid argument (cannot encode character '\177')
+  ```
+
+  or
+
+  ```
+  Uncaught exception ghc-internal:GHC.Internal.IO.Exception.IOException:
+  <stdout>: commitBuffer: invalid argument (cannot encode character '\956')
   ```
 
   it means that your locale does not support UTF-8. `tasty-bench` makes an effort
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,8 @@
+# 0.4.1
+
+* Force GC before collecting `RTSStats`, otherwise measurements are inaccurate.
+* Restore locale encoding after `defaultMain`.
+
 # 0.4
 
 * Switch `nf`, `nfIO` and `nfAppIO` to evaluate outputs to a normal form
diff --git a/src/Test/Tasty/Bench.hs b/src/Test/Tasty/Bench.hs
--- a/src/Test/Tasty/Bench.hs
+++ b/src/Test/Tasty/Bench.hs
@@ -27,7 +27,7 @@
 GHC does, including WASM. We support a full range of architectures
 (@i386@, @amd64@, @armhf@, @arm64@, @ppc64le@, @s390x@) and operating
 systems (Linux, Windows, macOS, FreeBSD, OpenBSD, NetBSD), plus any GHC
-from 7.0 to 9.10.
+from 8.0 to 9.10 (and earlier releases stretch back to GHC 7.0).
 
 === How is it possible?
 
@@ -366,6 +366,11 @@
 
     > <stdout>: commitBuffer: invalid argument (cannot encode character '\177')
 
+    or
+
+    > Uncaught exception ghc-internal:GHC.Internal.IO.Exception.IOException:
+    > <stdout>: commitBuffer: invalid argument (cannot encode character '\956')
+
     it means that your locale does not support UTF-8. @tasty-bench@
     makes an effort to force locale to UTF-8, but sometimes, when
     benchmarks are a part of a larger application, it’s
@@ -648,7 +653,6 @@
 
 {-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE CPP #-}
-{-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
@@ -707,9 +711,8 @@
 import Control.Applicative
 import Control.Arrow (first, second)
 import Control.DeepSeq (NFData, force, rnf)
-import Control.Exception (bracket, evaluate)
+import Control.Exception (bracket, bracket_, evaluate)
 import Control.Monad (void, unless, guard, (>=>), when)
-import Data.Data (Typeable)
 import Data.Foldable (foldMap, traverse_)
 import Data.Int (Int64)
 import Data.IORef
@@ -720,12 +723,9 @@
 import Data.Traversable (forM)
 import Data.Word (Word64)
 import GHC.Conc
-#if MIN_VERSION_base(4,5,0)
 import GHC.IO.Encoding
-#endif
-#if MIN_VERSION_base(4,6,0)
 import GHC.Stats
-#endif
+import GHC.Types (SPEC(..))
 import System.CPUTime
 import System.Exit
 import System.IO
@@ -734,17 +734,8 @@
 import Text.Printf
 
 #ifdef MIN_VERSION_tasty
-#if !MIN_VERSION_base(4,8,0)
-import Data.Monoid (Monoid(..))
-#endif
-#if MIN_VERSION_base(4,9,0)
 import Data.Semigroup (Semigroup(..))
-#endif
-#if MIN_VERSION_containers(0,5,0)
 import qualified Data.IntMap.Strict as IM
-#else
-import qualified Data.IntMap as IM
-#endif
 import Data.IntMap (IntMap)
 import Data.Sequence (Seq, (<|))
 import qualified Data.Sequence as Seq
@@ -771,15 +762,6 @@
 import Data.Word (Word32)
 #endif
 
-#if MIN_VERSION_ghc_prim(0,3,1)
-import GHC.Types (SPEC(..))
-#else
-import GHC.Exts (SpecConstrAnnotation(..))
-
-data SPEC = SPEC | SPEC2
-{-# ANN type SPEC ForceSpecConstr #-}
-#endif
-
 #ifndef MIN_VERSION_tasty
 data Timeout
   = Timeout
@@ -822,7 +804,6 @@
   -- ^ @since 0.4
   , Fractional
   -- ^ @since 0.4
-  , Typeable
   )
 
 -- | Whether to measure CPU time or wall-clock time.
@@ -852,7 +833,6 @@
   -- ^ Measure CPU time.
   | WallTime
   -- ^ Measure wall-clock time.
-  deriving (Typeable)
 
 #ifdef MIN_VERSION_tasty
 instance IsOption RelStDev where
@@ -885,7 +865,6 @@
   -- ^ @since 0.4
   , Fractional
   -- ^ @since 0.4
-  , Typeable
   )
 
 instance IsOption FailIfSlower where
@@ -918,7 +897,6 @@
   -- ^ @since 0.4
   , Fractional
   -- ^ @since 0.4
-  , Typeable
   )
 
 instance IsOption FailIfFaster where
@@ -957,23 +935,19 @@
     -- | @since 0.3
     Benchmarkable
   { unBenchmarkable :: Word64 -> IO () -- ^ Run benchmark given number of times.
-  } deriving (Typeable)
+  }
 
 #ifdef MIN_VERSION_tasty
 
 -- | 'defaultMain' forces 'setLocaleEncoding' to 'utf8', but users might
 -- be running benchmarks outside of it (e. g., via 'defaultMainWithIngredients').
 supportsUnicode :: Bool
-#if MIN_VERSION_base(4,5,0)
 supportsUnicode = take 3 (textEncodingName enc) == "UTF"
 #if defined(mingw32_HOST_OS)
   && unsafePerformIO getConsoleOutputCP == 65001
 #endif
   where
     enc = unsafePerformIO getLocaleEncoding
-#else
-supportsUnicode = False
-#endif
 {-# NOINLINE supportsUnicode #-}
 
 mu :: Char
@@ -1103,10 +1077,8 @@
 hasGCStats :: Bool
 #if MIN_VERSION_base(4,10,0)
 hasGCStats = unsafePerformIO getRTSStatsEnabled
-#elif MIN_VERSION_base(4,6,0)
-hasGCStats = unsafePerformIO getGCStatsEnabled
 #else
-hasGCStats = False
+hasGCStats = unsafePerformIO getGCStatsEnabled
 #endif
 
 getAllocsAndCopied :: IO (Word64, Word64, Word64)
@@ -1114,10 +1086,8 @@
   if not hasGCStats then pure (0, 0, 0) else
 #if MIN_VERSION_base(4,10,0)
     (\s -> (allocated_bytes s, copied_bytes s, max_mem_in_use_bytes s)) <$> getRTSStats
-#elif MIN_VERSION_base(4,6,0)
-    (\s -> (int64ToWord64 $ bytesAllocated s, int64ToWord64 $ bytesCopied s, int64ToWord64 $ peakMegabytesAllocated s * 1024 * 1024)) <$> getGCStats
 #else
-    pure (0, 0, 0)
+    (\s -> (int64ToWord64 $ bytesAllocated s, int64ToWord64 $ bytesCopied s, int64ToWord64 $ peakMegabytesAllocated s * 1024 * 1024)) <$> getGCStats
 #endif
 
 getWallTimeSecs :: IO Double
@@ -1140,6 +1110,7 @@
   (startAllocs, startCopied, startMaxMemInUse) <- getAllocsAndCopied
   act n
   endTime <- getTimePicoSecs'
+  performMinorGC -- perform GC to update RTSStats
   (endAllocs, endCopied, endMaxMemInUse) <- getAllocsAndCopied
   let meas = Measurement
         { measTime   = endTime - startTime
@@ -1341,14 +1312,22 @@
 defaultMain :: [Benchmark] -> IO ()
 defaultMain bs = do
   let act = defaultMain' bs
-#if MIN_VERSION_base(4,5,0)
-  setLocaleEncoding utf8
-#endif
+  bracketUtf8 act
+
+bracketUtf8 :: IO a -> IO a
+bracketUtf8 act = do
+  prevLocaleEnc <- getLocaleEncoding
 #if defined(mingw32_HOST_OS)
   codePage <- getConsoleOutputCP
-  bracket (setConsoleOutputCP 65001) (const $ setConsoleOutputCP codePage) (const act)
+  bracket_
+    (setLocaleEncoding utf8 >> setConsoleOutputCP 65001)
+    (setLocaleEncoding prevLocaleEnc >> setConsoleOutputCP codePage)
+    act
 #else
-  act
+  bracket_
+    (setLocaleEncoding utf8)
+    (setLocaleEncoding prevLocaleEnc)
+    act
 #endif
 
 defaultMain' :: [Benchmark] -> IO ()
@@ -1738,7 +1717,6 @@
   -- ^ @since 0.4
   , Ord
   -- ^ @since 0.4
-  , Typeable
   )
 
 instance IsOption (Maybe CsvPath) where
@@ -1817,7 +1795,6 @@
   -- ^ @since 0.4
   , Ord
   -- ^ @since 0.4
-  , Typeable
   )
 
 instance IsOption (Maybe SvgPath) where
@@ -1956,7 +1933,6 @@
   -- ^ @since 0.4
   , Ord
   -- ^ @since 0.4
-  , Typeable
   )
 
 instance IsOption (Maybe BaselinePath) where
@@ -2056,23 +2032,14 @@
 data Unique a = None | Unique !a | NotUnique
   deriving (Functor)
 
-appendUnique :: Unique a -> Unique a -> Unique a
-appendUnique None a = a
-appendUnique a None = a
-appendUnique _ _ = NotUnique
-
-#if MIN_VERSION_base(4,9,0)
 instance Semigroup (Unique a) where
-  (<>) = appendUnique
-#endif
+  None <> a = a
+  a <> None = a
+  _ <> _ = NotUnique
 
 instance Monoid (Unique a) where
   mempty = None
-#if MIN_VERSION_base(4,9,0)
   mappend = (<>)
-#else
-  mappend = appendUnique
-#endif
 
 modifyConsoleReporter
     :: [OptionDescription]
@@ -2185,7 +2152,7 @@
 word64ToDouble :: Word64 -> Double
 word64ToDouble = fromIntegral
 
-#if !MIN_VERSION_base(4,10,0) && MIN_VERSION_base(4,6,0)
+#if !MIN_VERSION_base(4,10,0)
 int64ToWord64 :: Int64 -> Word64
 int64ToWord64 = fromIntegral
 #endif
diff --git a/tasty-bench.cabal b/tasty-bench.cabal
--- a/tasty-bench.cabal
+++ b/tasty-bench.cabal
@@ -1,5 +1,5 @@
 name:          tasty-bench
-version:       0.4
+version:       0.4.1
 cabal-version: 1.18
 build-type:    Simple
 license:       MIT
@@ -25,7 +25,7 @@
   example.svg
   README.md
 
-tested-with: GHC == 9.10.1, GHC == 9.8.2, GHC == 9.6.6, GHC == 9.4.8, GHC == 9.2.8, GHC==9.0.2, GHC==8.10.7, GHC==8.8.4, GHC==8.6.5, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2
+tested-with: GHC == 9.12.1, GHC == 9.10.1, GHC == 9.8.4, GHC == 9.6.6, GHC == 9.4.8, GHC == 9.2.8, GHC==9.0.2, GHC==8.10.7, GHC==8.8.4, GHC==8.6.5, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2
 
 source-repository head
   type: git
@@ -42,23 +42,16 @@
   exposed-modules:  Test.Tasty.Bench
   hs-source-dirs:   src
   default-language: Haskell2010
-  ghc-options:      -O2 -Wall -fno-warn-unused-imports
-  if impl(ghc < 7.10)
-    ghc-options:    -fcontext-stack=30
-  if impl(ghc >= 8.0)
-    ghc-options:    -Wcompat -Widentities
+  ghc-options:      -O2 -Wall -fno-warn-unused-imports -Wcompat -Widentities
 
   build-depends:
     base >= 4.3 && < 5,
     deepseq >= 1.1 && < 1.6,
-    ghc-prim < 0.12
+    ghc-prim < 0.14
   if flag(tasty)
     build-depends:
-      containers >= 0.4 && < 0.8,
+      containers >= 0.5 && < 0.8,
       tasty >= 1.4 && < 1.6
-  if impl(ghc < 7.8)
-    build-depends:
-      tagged >= 0.2 && < 0.9
   if impl(ghc < 8.4)
     build-depends:
       time >= 1.2 && < 1.13
