diff --git a/crdt.cabal b/crdt.cabal
--- a/crdt.cabal
+++ b/crdt.cabal
@@ -1,10 +1,10 @@
 name: crdt
-version: 10.3
+version: 10.4
           -- ^ ComVer
 category: Distributed Systems
 copyright:
-    2017 Yuriy Syrovetskiy, Nikolay Loginov;
-    2018 Yuriy Syrovetskiy
+    2017        Yuriy Syrovetskiy, Nikolay Loginov;
+    2018-2019   Yuriy Syrovetskiy
 maintainer: Yuriy Syrovetskiy <cblp@cblp.su>
 license: BSD3
 license-file: LICENSE
@@ -22,7 +22,7 @@
 
 library
     hs-source-dirs: lib
-    build-depends:  base >= 4.8 && < 4.12
+    build-depends:  base >= 4.8 && < 4.13
                   , binary
                   , bytestring
                   , containers >= 0.5.9
diff --git a/lib/CRDT/LamportClock.hs b/lib/CRDT/LamportClock.hs
--- a/lib/CRDT/LamportClock.hs
+++ b/lib/CRDT/LamportClock.hs
@@ -1,7 +1,4 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE NamedFieldPuns #-}
 
 module CRDT.LamportClock
     ( Pid (..)
@@ -19,12 +16,11 @@
     , getMacAddress
     ) where
 
-import           Control.Concurrent.STM (TVar, atomically, modifyTVar',
-                                         readTVar, writeTVar)
 import           Control.Monad.IO.Class (MonadIO, liftIO)
-import           Control.Monad.Reader (ReaderT, ask, runReaderT)
+import           Control.Monad.Reader (ReaderT (..))
 import           Control.Monad.State.Strict (StateT)
 import           Control.Monad.Trans (lift)
+import           Data.IORef (IORef, atomicModifyIORef')
 import           Data.Time.Clock.POSIX (getPOSIXTime)
 import           Data.Word (Word64)
 import           Numeric.Natural (Natural)
@@ -69,33 +65,27 @@
 getTime :: Clock m => m LamportTime
 getTime = getTimes 1
 
--- TODO(cblp, 2018-01-06) benchmark and compare with 'atomicModifyIORef'
-newtype LamportClock a = LamportClock (ReaderT (TVar LocalTime) IO a)
+newtype LamportClock a = LamportClock (ReaderT (IORef LocalTime) IO a)
     deriving (Applicative, Functor, Monad, MonadIO)
 
-runLamportClock :: TVar LocalTime -> LamportClock a -> IO a
+runLamportClock :: IORef LocalTime -> LamportClock a -> IO a
 runLamportClock var (LamportClock action) = runReaderT action var
 
 instance Process LamportClock where
     getPid = Pid <$> liftIO getMacAddress
 
 instance Clock LamportClock where
-    advance time = LamportClock $ do
-        timeVar <- ask
-        lift $ atomically $ modifyTVar' timeVar $ max time
+    advance time = LamportClock $ ReaderT $ \timeVar ->
+        atomicModifyIORef' timeVar $ \t0 -> (max time t0, ())
 
     getTimes n' = LamportTime <$> getTimes' <*> getPid
       where
         n = max n' 1
-        getTimes' = LamportClock $ do
-            timeVar <- ask
-            lift $ do
-                realTime <- getRealLocalTime
-                atomically $ do
-                    timeCur <- readTVar timeVar
-                    let timeRangeStart = max realTime (timeCur + 1)
-                    writeTVar timeVar $ timeRangeStart + n - 1
-                    pure timeRangeStart
+        getTimes' = LamportClock $ ReaderT $ \timeVar -> do
+            realTime <- getRealLocalTime
+            atomicModifyIORef' timeVar $ \timeCur ->
+                let timeRangeStart = max realTime (timeCur + 1)
+                in (timeRangeStart + n - 1, timeRangeStart)
 
 instance Process m => Process (ReaderT r m) where
     getPid = lift getPid
