diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,10 +1,2 @@
-A contention-free STM hash map for Haskell.
-
-"Contention-free" means that the map will never cause spurious conflicts.
-A transaction operating on the map will only ever have to retry if
-another transaction is operating on the same key at the same time.
-
-This is an implementation of the *transactional trie*,
-which is basically a *lock-free concurrent hash trie* lifted into STM.
-For a detailed discussion, including an evaluation of its performance,
-see Chapter 4 of [my master's thesis](https://github.com/mcschroeder/thesis).
+# ttrie
+A contention-free STM hash map for Haskell
diff --git a/benchmarks/Bench.hs b/benchmarks/Bench.hs
deleted file mode 100644
--- a/benchmarks/Bench.hs
+++ /dev/null
@@ -1,200 +0,0 @@
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE OverloadedStrings #-}
-module Main where
-
-import BenchGen
-import Control.Applicative
-import Control.Concurrent.Async
-import Control.Concurrent.STM
-import Control.Concurrent.STM.Stats
-import Control.DeepSeq
-import Control.Exception (evaluate)
-import Control.Monad
-import Control.Monad.IO.Class
-import CriterionPlus
-import qualified Data.Map as Map
-import Data.Text (Text)
-import qualified Data.Text as T
-import GHC.Generics
-import GHC.Stats
-import System.Environment
-import System.Mem
-import System.Random.MWC
-import System.Random.MWC.CondensedTable
-import Text.Printf
-
-import qualified Control.Concurrent.STM.Map as TTrie
-import qualified STMContainers.Map as STMCont
-import qualified Data.HashMap.Strict as HashMap
-
-------------------------------------------------------------------------------
-
-main :: IO ()
-main = do
-    (arg1:arg2:arg3:arg4:arg5:args) <- getArgs
-    printf "threads = %s\n"         arg1
-    printf "numTransactions = %s\n" arg2
-    printf "sizes = %s\n"           arg3
-    printf "numPrefill = %s\n"      arg4
-    printf "ops = %s\n"             arg5
-    let threads            = read arg1 :: [Int]
-        numTransactions    = read arg2
-        sizes              = mkTable $ read arg3
-        numPrefill         = read arg4
-        (ins,upd,look,del) = read arg5
-        config = Config
-            { operations = mkTable [ (Insert, ins + upd)
-                                   , (Lookup, look)
-                                   , (Delete, del)
-                                   ]
-            , keys = \op -> case op of
-                Insert -> mkTable [(remember key, ins), (remember (reuse key), upd)]
-                Lookup -> mkTable [(reuse key, 1)]
-                Delete -> mkTable [(forget (reuse key), 1)]
-            }
-
-    (ks,txs) <- genTransactions numPrefill numTransactions sizes config
-    withArgs args $ benchmark
-                  $ standoff (T.pack arg5)
-                  $ mapM_ (supergroup ks txs numTransactions)
-                  $ threads
-
-supergroup :: [Key] -> [Transaction] -> Int -> Int -> Standoff ()
-supergroup ks txs numTransactions t =
-    group (T.pack $ printf "%d/%d" t n) $ do
-        runAll "unordered-containers" hashmapPrefill hashmapEval
-        runAll "stm-containers"       stmcontPrefill stmcontEval
-        runAll "ttrie"                ttriePrefill  ttrieEval
-  where
-    n = numTransactions `div` t
-    ops = split n txs
-    runAll name prefill eval = do
-        runTime name prefill eval ks ops
-        liftIO $ runRetries (printf "%d/%d/%s" t n name) prefill eval ks ops
-        liftIO $ runAlloc prefill eval ks ops
-
-split :: Int -> [a] -> [[a]]
-split n [] = []
-split n xs = let (ys,zs) = splitAt n xs in ys : split n zs
-
-------------------------------------------------------------------------------
-
-type EvalFunc c = Op -> Key -> c -> STM ()
-type PrefillFunc c = [Key] -> IO c
-
-runTime :: String -> PrefillFunc c -> EvalFunc c -> [Key] -> [[Transaction]] -> Standoff ()
-runTime name prefill eval ks ops = subject (T.pack name) $ do
-    pause
-    c <- liftIO $ prefill ks
-    continue
-    liftIO $ run_ atomically ops eval c
-
-runRetries :: String -> PrefillFunc c -> EvalFunc c -> [Key] -> [[Transaction]] -> IO ()
-runRetries name prefill eval ks ops = do
-    printf "commits: "
-    c <- prefill ks
-    let atomically' = trackSTMConf defaultTrackSTMConf
-                        { tryThreshold = Nothing
-                        , globalTheshold = Nothing
-                        }
-    run_ (atomically' name) ops eval c
-    stats <- getSTMStats
-    let Just (commits, retries) = Map.lookup name stats
-    printf "%d\nretries: %d\n" commits retries
-
-runAlloc :: PrefillFunc c -> EvalFunc c -> [Key] -> [[Transaction]] -> IO ()
-runAlloc prefill eval ks ops = do
-    printf "allocated bytes: "
-    c <- prefill ks
-    performGC
-    before <- getGCStats
-    run_ atomically ops eval c
-    performGC
-    after <- getGCStats
-    let bytes = bytesAllocated after - bytesAllocated before
-    printf "%d\n" bytes
-
-run_ :: (STM () -> IO ()) -> [[Transaction]] -> EvalFunc c -> c -> IO ()
-run_ atom ops f c = void $ mapConcurrently (mapM_ txEval) ops
-  where txEval = atom . mapM_ (\(op,k) -> f op k c)
-
-------------------------------------------------------------------------------
-
-type Key = Text
-type Transaction = [(Op,Key)]
-
-data Op = Lookup | Insert | Delete
-    deriving (Eq, Show, Generic)
-
-instance NFData Op
-
-key :: Generator IO k Key
-key = do
-    n <- liftGen $ genFromTable length
-    T.pack <$> replicateM n (liftGen $ genFromTable alphabet)
-  where
-    length = mkTable $ zip [7..20] (repeat 1)
-    alphabet = mkTable $ zip ['a'..'z'] (repeat 1)
-
-genTransactions :: Int -> Int -> CondensedTableV Int -> Config IO Op Key -> IO ([Key],[Transaction])
-genTransactions numPrefill numTransactions sizes config = do
-    gen <- create
-    runGenerator gen $ do
-        liftIO $ printf "Generating %d random keys to prefill...\n" numPrefill
-        ks <- replicateM numPrefill (remember key)
-        liftIO $ printf "Generating %d random transactions...\n" numTransactions
-        txs <- replicateM numTransactions $ do
-            size <- liftGen $ genFromTable sizes
-            generateOperations config size
-        return (ks,txs)
-
-------------------------------------------------------------------------------
--- Evaluation and Prefill functions
-
-instance (NFData k, NFData v) => NFData (TTrie.Map k v)
-
-ttriePrefill :: PrefillFunc (TTrie.Map Key ())
-ttriePrefill ks = do
-  m <- atomically $ TTrie.empty
-  forM_ ks $ \k -> atomically $ TTrie.insert k () m
-  evaluate (rnf m)
-  return m
-
-ttrieEval :: EvalFunc (TTrie.Map Key ())
-ttrieEval Lookup k = void . TTrie.lookup k
-ttrieEval Insert k = TTrie.insert k ()
-ttrieEval Delete k = TTrie.delete k
-
-instance (NFData k, NFData v) => NFData (STMCont.Map k v)
-
-stmcontPrefill :: PrefillFunc (STMCont.Map Key ())
-stmcontPrefill ks = do
-  m <- atomically $ STMCont.new
-  forM_ ks $ \k -> atomically $ STMCont.insert () k m
-  evaluate (rnf m)
-  return m
-
-stmcontEval :: EvalFunc (STMCont.Map Key ())
-stmcontEval Lookup k = void . STMCont.lookup k
-stmcontEval Insert k = STMCont.insert () k
-stmcontEval Delete k = STMCont.delete k
-
-instance (NFData a) => NFData (TVar a)
-
-hashmapPrefill :: PrefillFunc (TVar (HashMap.HashMap Key (TVar ())))
-hashmapPrefill ks = do
-  elems <- forM ks (\k -> newTVarIO () >>= \v -> return (k,v))
-  m <- newTVarIO $ HashMap.fromList elems
-  evaluate (rnf m)
-  return m
-
-hashmapEval :: EvalFunc (TVar (HashMap.HashMap Key (TVar ())))
-hashmapEval Lookup k m = do
-  v <- HashMap.lookup k <$> readTVar m
-  case v of
-    Just v -> void $ readTVar v
-    Nothing -> return ()
-hashmapEval Insert k m = do
-  v <- newTVar ()
-  modifyTVar' m (HashMap.insert k v)
-hashmapEval Delete k m = modifyTVar' m (HashMap.delete k)
diff --git a/benchmarks/Bench1.hs b/benchmarks/Bench1.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Bench1.hs
@@ -0,0 +1,26 @@
+module Main where
+
+import BenchGen
+import Common
+import System.Environment
+import Text.Printf
+
+main :: IO ()
+main = do
+    (arg1:arg2:arg3:arg4:args) <- getArgs
+    printf "threads = %s\nnumTransactions = %s\nsizes = %s\nops = %s\n" arg1 arg2 arg3 arg4
+    let threads = read arg1
+        numTransactions = read arg2
+        sizes = mkTable $ read arg3
+        (inserts,lookups,updates,deletes) = read arg4
+        config = Config
+            { operations = mkTable [ (Insert, inserts + updates)
+                                   , (Lookup, lookups)
+                                   , (Delete, deletes)
+                                   ]
+            , keys = \op -> case op of
+                Insert -> mkTable [(remember key, inserts), (remember (reuse key), updates)]
+                Lookup -> mkTable [(key,                0), (reuse key,                  1)]
+                Delete -> mkTable [(forget key,         0), (forget (reuse key),         1)]
+            }
+    withArgs args $ runAll threads numTransactions sizes config
diff --git a/benchmarks/BenchGen.hs b/benchmarks/BenchGen.hs
--- a/benchmarks/BenchGen.hs
+++ b/benchmarks/BenchGen.hs
@@ -4,7 +4,6 @@
 
 import Control.Applicative
 import Control.Monad
-import Control.Monad.IO.Class
 import Control.Monad.Primitive
 import Control.Monad.Trans.Class
 import Control.Monad.Trans.State.Strict
@@ -19,9 +18,6 @@
 
 newtype Generator m k a = Generator { unG :: StateT (Gen (PrimState m), Set k) m a }
   deriving (Functor, Applicative, Monad)
-
-instance MonadIO m => MonadIO (Generator m k) where
-    liftIO = Generator . liftIO
 
 runGenerator :: PrimMonad m => Gen (PrimState m) -> Generator m k a -> m a
 runGenerator gen (Generator m) = evalStateT m (gen, Set.empty)
diff --git a/benchmarks/Common.hs b/benchmarks/Common.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Common.hs
@@ -0,0 +1,122 @@
+{-# LANGUAGE DeriveGeneric #-}
+module Common where
+
+import BenchGen
+
+import Control.Applicative
+import Control.Concurrent.Async
+import Control.Concurrent.STM
+import Control.Concurrent.STM.Stats
+import Control.DeepSeq
+import Control.Monad
+import Criterion.Main
+import qualified Data.Map as Map
+import Data.Text (Text)
+import qualified Data.Text as T
+import GHC.Generics
+import System.Random.MWC
+import System.Random.MWC.CondensedTable
+import Text.Printf
+
+import qualified Control.Concurrent.STM.Map as TTrie
+import qualified STMContainers.Map as STMCont
+import qualified Data.HashMap.Strict as HashMap
+
+------------------------------------------------------------------------------
+
+data Op = Lookup | Insert | Delete
+    deriving (Eq, Show, Generic)
+
+instance NFData Op
+
+key :: Generator IO k Text
+key = do
+    n <- liftGen $ genFromTable length
+    T.pack <$> replicateM n (liftGen $ genFromTable alphabet)
+  where
+    length = mkTable $ zip [7..20] (repeat 1)
+    alphabet = mkTable $ zip ['a'..'z'] (repeat 1)
+
+------------------------------------------------------------------------------
+
+runAll :: [Int] -> Int -> CondensedTableV Int -> Config IO Op Text -> IO ()
+runAll numThreads numTransactions sizes config = do
+    txs <- genTransactions numTransactions sizes config
+    runBenchmarks txs numTransactions numThreads
+    collectRetryStats txs numTransactions numThreads
+
+genTransactions :: Int -> CondensedTableV Int -> Config IO Op Text -> IO [[(Op, Text)]]
+genTransactions numTransactions sizes config = do
+    printf "Generating %d random transactions...\n" numTransactions
+    gen <- create
+    runGenerator gen $ do
+        replicateM numTransactions $ do
+            size <- liftGen $ genFromTable sizes
+            generateOperations config size
+
+runBenchmarks :: [[(Op, Text)]] -> Int -> [Int] -> IO ()
+runBenchmarks txs numTransactions numThreads =
+    defaultMain $! flip map numThreads
+         $ \n -> env (return $! split (numTransactions `div` n) txs)
+         $ \ ~ops -> bgroup (printf "%d/%d" n (numTransactions `div` n))
+         [ bench "unordered-containers" $ whnfIO $ run ops hashmapEval =<< newTVarIO HashMap.empty
+         , bench "unordered-containers2" $ whnfIO $ run ops hashmapEval2 =<< newTVarIO HashMap.empty
+         , bench "stm-containers"       $ whnfIO $ run ops stmcontEval =<< STMCont.newIO
+         , bench "ttrie"                $ whnfIO $ run ops ttrieEval =<< atomically TTrie.empty
+         ]
+  where
+    run ops f c = mapConcurrently (mapM_ txEval) ops
+      where txEval = atomically . mapM_ (\(op,k) -> f op k c)
+
+collectRetryStats :: [[(Op, Text)]] -> Int -> [Int] -> IO ()
+collectRetryStats txs numTransactions numThreads =
+    flip mapM_ numThreads $ \n -> do
+        let ops = split (numTransactions `div` n) txs
+            str = printf "%d/%d" n (numTransactions `div` n)
+        run (str++"/unordered-containers") ops hashmapEval =<< newTVarIO HashMap.empty
+        run (str++"/unordered-containers2") ops hashmapEval2 =<< newTVarIO HashMap.empty
+        run (str++"/stm-containers")       ops stmcontEval =<< STMCont.newIO
+        run (str++"/ttrie")                ops ttrieEval =<< atomically TTrie.empty
+  where
+    run name ops f c = do
+        printf "collecting retry statistics for %s\n" name
+        mapConcurrently (mapM_ txEval) ops
+        printStats name
+      where
+        txEval = atomically' name . mapM_ (\(op,k) -> f op k c)
+        atomically' = trackSTMConf defaultTrackSTMConf
+                            { tryThreshold = Nothing
+                            , globalTheshold = Nothing
+                            }
+        printStats name = do
+            stats <- getSTMStats
+            let Just (commits, retries) = Map.lookup name stats
+            printf "Commits\t%d\nRetries\t%d\n\n" commits retries
+
+split n [] = []
+split n xs = let (ys,zs) = splitAt n xs in ys : split n zs
+
+------------------------------------------------------------------------------
+-- Evaluation functions
+
+ttrieEval Lookup k = void . TTrie.lookup k
+ttrieEval Insert k = TTrie.insert k ()
+ttrieEval Delete k = TTrie.delete k
+
+stmcontEval Lookup k = void . STMCont.lookup k
+stmcontEval Insert k = STMCont.insert () k
+stmcontEval Delete k = STMCont.delete k
+
+hashmapEval Lookup k m = do
+    v <- HashMap.lookup k <$> readTVar m
+    case v of
+        Nothing -> return ()
+        Just v -> readTVar v >> return ()
+hashmapEval Insert k m = do
+    v <- newTVar ()
+    modifyTVar' m (HashMap.insert k v)
+hashmapEval Delete k m = modifyTVar' m (HashMap.delete k)
+
+hashmapEval2 Lookup k m = HashMap.lookup k <$> readTVar m >> return ()
+hashmapEval2 Insert k m = modifyTVar' m (HashMap.insert k ())
+hashmapEval2 Delete k m = modifyTVar' m (HashMap.delete k)
diff --git a/benchmarks/run.sh b/benchmarks/run.sh
--- a/benchmarks/run.sh
+++ b/benchmarks/run.sh
@@ -1,30 +1,62 @@
-#!/bin/bash
+#!/bin/sh
 
 main() {
-    THREADS="[1,2,4,6,8,10,12,14,16]"
-    TX_SIZE="[(1,1),(2,1),(3,1),(4,1),(5,1)]"
-    NUM_TX="200000"
-    NUM_PREFILL="1000000"
+    THREADS="[1,2,4,6,8,12,16,24,32,48,64,96,128]"
+    NUM_TX="250000"
 
-    mkdir -p "results/1"
-    bench $THREADS $NUM_TX "[(1,1)]" 0       "(1,0,0,0)" "results/1/insert"
-    bench $THREADS $NUM_TX "[(1,1)]" $NUM_TX "(0,1,0,0)" "results/1/update"
-    bench $THREADS $NUM_TX "[(1,1)]" $NUM_TX "(0,0,1,0)" "results/1/lookup"
-    bench $THREADS $NUM_TX "[(1,1)]" $NUM_TX "(0,0,0,1)" "results/1/delete"
+    # weights for the transaction's size distribution
+    TX_SIZES[0]="[(1,5),(2,5),(3,4),(4,4),(5,3),(6,3),(7,2),(8,2),(9,1),(10,1)]"
+    TX_SIZES[1]="[(1,2),(2,3),(3,4),(4,4),(5,5),(6,4),(7,3),(8,2),(9,1),(10,1)]"
+    TX_SIZES[2]="[(1,1),(2,1),(3,2),(4,2),(5,3),(6,3),(7,4),(8,4),(9,5),(10,5)]"
 
-    mkdir -p "results/5"
-    bench $THREADS $NUM_TX $TX_SIZE 0            "(70,10,10,10)" "results/update/5/insert"
-    bench $THREADS $NUM_TX $TX_SIZE $NUM_PREFILL "(10,70,10,10)" "results/update/5/update"
-    bench $THREADS $NUM_TX $TX_SIZE $NUM_PREFILL "(10,10,70,10)" "results/update/5/lookup"
-    bench $THREADS $NUM_TX $TX_SIZE $NUM_PREFILL "(10,10,10,70)" "results/update/5/delete"    
-    bench $THREADS $NUM_TX $TX_SIZE $NUM_PREFILL "(25,25,25,25)" "results/update/5/balanced-prefill"
+    # distributions of (lookup,insert,update,delete)
+    OP_DISTS[0]="(20,60,15,5)"
+    OP_DISTS[1]="(20,15,60,5)"
+    OP_DISTS[2]="(80,10,5,5)"
+    OP_DISTS[3]="(40,20,15,5)"
 
-#    sudo shutdown -h now
+    TX_SIZES_NAMES=("small" "medium" "large")
+    OP_DISTS_NAMES=("insert" "update" "lookup" "balanced")
+
+    for i in ${!TX_SIZES[@]}; do
+        TX_SIZE=${TX_SIZES[$i]}
+        for j in ${!OP_DISTS[@]}; do
+            OP=${OP_DIST[$j]}
+
+            mkdir -p "results"
+            ni=${TX_SIZES_NAMES[$i]}
+            nj=${OP_DISTS_NAMES[$j]}
+            n="results/$ni-$nj"
+
+            unbuffer cabal bench bench1 --benchmark-options="$THREADS $NUM_TX $TX_SIZE $OP_DIST --regress allocated:iters +RTS -T" | 
+            tee "$n.txt"
+            
+            cat "$n.txt" | extract_times | transpose > "$n-time.dat"
+            cat "$n.txt" | extract_allocations | transpose > "$n-alloc.dat"
+            cat "$n.txt" | extract_retries | transpose > "$n-retries.dat"
+        done
+    done
 }
 
-bench() {
-    unbuffer cabal bench bench --benchmark-options="$1 $2 $3 $4 $5 +RTS -T" | tee "$6.txt"
-#    curl -F $6.txt=@$6.txt https://XXXXXXXXXXXXXXX@neocities.org/api/upload
+extract_retries() {
+    grep -E "collecting|Retries" | 
+    sed -E 'N;s/[^0-9]*([0-9]+)\/[0-9]+\/(.*)\n[^0-9]*([0-9\.e]*)/\2 \1 \3/g'
+}
+
+extract_times() {
+    grep -E "benchmarking|time" | 
+    sed -E "s/time *([0-9\.]*) s.*/\1/g" | 
+    sed -E "s/time *([0-9]*)\.([0-9]*) ms.*/0.\1\2/g" | 
+    sed -E "N;s/[^0-9]*([0-9]+)\/[0-9]+\/(.*)\n(.*)/\2 \1 \3/g"
+}
+
+extract_allocations() {
+    grep -E "benchmarking|iters" | 
+    sed -E "N;s/[^0-9]*([0-9]+)\/[0-9]+\/(.*)\n[^0-9]*([0-9\.e]*).*/\2 \1 \3/g"
+}
+
+transpose() {
+    awk '{names[$1]++; threads[0]=0; threads[$2]++; results[$1,0]="\""$1"\""; results[$1,$2]=$3}END{for (t in threads) { printf "%s",t; for (n in names) printf " %s",results[n,t]; printf "\n" }}' | sort -n
 }
 
 main "$@"
diff --git a/src/Control/Concurrent/STM/Map.hs b/src/Control/Concurrent/STM/Map.hs
--- a/src/Control/Concurrent/STM/Map.hs
+++ b/src/Control/Concurrent/STM/Map.hs
@@ -1,27 +1,13 @@
 {-# LANGUAGE PatternGuards #-}
 {-# OPTIONS_GHC -funbox-strict-fields #-}
-
------------------------------------------------------------------------
--- | A contention-free STM hash map.
--- \"Contention-free\" means that the map will never cause spurious conflicts.
--- A transaction operating on the map will only ever have to retry if
--- another transaction is operating on the same key at the same time.
------------------------------------------------------------------------
-
 module Control.Concurrent.STM.Map
     ( Map
-
-      -- * Construction
     , empty
-
-      -- * Modification
     , insert
-    , delete
-    , unsafeDelete
-
-      -- * Query
     , lookup
+    , delete
     , phantomLookup
+    , unsafeDelete
     ) where
 
 import Control.Applicative ((<$>))
@@ -53,38 +39,27 @@
 
 -----------------------------------------------------------------------
 
--- | /O(1)/. Construct an empty map.
+-- | /O(1)/. The empty map.
 empty :: STM (Map k v)
 empty = unsafeIOToSTM $ Map <$> newIORef (Array emptyArray)
 {-# INLINE empty #-}
 
--- | /O(log n)/. Associate the given value with the given key.
--- If the key is already present in the map, the old value is replaced.
 insert :: (Eq k, Hashable k) => k -> v -> Map k v -> STM ()
 insert k v m = do var <- getTVar k m
                   writeTVar var (Just v)
+
 {-# INLINABLE insert #-}
 
--- | /O(log n)/. Return the value associated with the given key, or 'Nothing'.
---
--- __Note__: This might increase the map's memory consumption
--- by putting the key into the map.
--- If that is not acceptable, use 'phantomLookup'.
 lookup :: (Eq k, Hashable k) => k -> Map k v -> STM (Maybe v)
 lookup k m = do var <- getTVar k m
                 readTVar var
+
 {-# INLINABLE lookup #-}
 
--- | /O(log n)/. Remove the value associated with a given key from the map,
--- if present.
---
--- __Note__: This does not actually remove the key from the map.
--- In fact, it might actually increase the map's memory consumption
--- by putting the key into the map.
--- To completely delete an entry, including its key, use 'unsafeDelete'.
 delete :: (Eq k, Hashable k) => k -> Map k v -> STM ()
 delete k m = do var <- getTVar k m
                 writeTVar var Nothing
+
 {-# INLINABLE delete #-}
 
 -----------------------------------------------------------------------
@@ -137,20 +112,6 @@
 {-# INLINE getTVar #-}
 
 
--- | /O(log n)/. Return the value associated with the given key, or 'Nothing'.
---
--- In contrast to 'lookup', this will never increase the map's memory consumption.
--- However, it might allow /phantom reads/ to occur.
--- Consider the following situation:
---
--- > f = atomically $ do v1 <- phantomLookup k m
--- >                     v2 <- phantomLookup k m
--- >                     return (v1 == v2)
---
--- Under certain circumstances @f@ might actually return @False@, in particular
--- if the first @phantomLookup@ happens on an empty map
--- and some other transaction inserts a value for @k@ before the second call
--- to @phantomLookup@.
 phantomLookup :: (Eq k, Hashable k) => k -> Map k v -> STM (Maybe v)
 phantomLookup k (Map root) = go root 0 undefined
   where
@@ -172,9 +133,6 @@
 {-# INLINABLE phantomLookup #-}
 
 
--- | /O(log n)/. This will completely remove a given key
--- and its associated value from the map, if present.
--- This is not an atomic operation, however. __Use with caution!__
 unsafeDelete :: (Eq k, Hashable k) => k -> Map k v -> IO ()
 unsafeDelete k m@(Map root) = do
     ok <- go root 0 undefined
diff --git a/ttrie.cabal b/ttrie.cabal
--- a/ttrie.cabal
+++ b/ttrie.cabal
@@ -1,16 +1,7 @@
 name:                ttrie
-version:             0.1
+version:             0.1.0.0
 synopsis:            Contention-free STM hash map
-description:
-  A contention-free STM hash map.
-  \"Contention-free\" means that the map will never cause spurious conflicts.
-  A transaction operating on the map will only ever have to retry if
-  another transaction is operating on the same key at the same time.
-  .
-  This is an implementation of the /transactional trie/,
-  which is basically a /lock-free concurrent hash trie/ lifted into STM.
-  For a detailed discussion, including an evaluation of its performance,
-  see Chapter 4 of <https://github.com/mcschroeder/thesis my master's thesis>.
+-- description:
 homepage:            http://github.com/mcschroeder/ttrie
 bug-reports:         http://github.com/mcschroeder/ttrie/issues
 license:             MIT
@@ -23,29 +14,26 @@
 extra-source-files:  README.md, benchmarks/run.sh
 cabal-version:       >=1.10
 
-source-repository head
-  type: git
-  location: https://github.com/mcschroeder/ttrie.git
-
 library
   hs-source-dirs:      src
   exposed-modules:     Control.Concurrent.STM.Map
   other-modules:       Data.SparseArray
-  default-language:    Haskell2010
-  ghc-options:         -Wall
+
   build-depends:       base >=4.7 && <4.8
-                     , atomic-primops >=0.6
-                     , hashable >=1.2
-                     , primitive >=0.5
+                     , atomic-primops ==0.6.*
+                     , hashable ==1.2.*
+                     , primitive ==0.5.*
                      , stm >=2
 
-benchmark bench
+  default-language:    Haskell2010
+  ghc-options:         -Wall
+
+
+benchmark bench1
   hs-source-dirs:      benchmarks
-  main-is:             Bench.hs
-  other-modules:       BenchGen
+  main-is:             Bench1.hs
+  other-modules:       BenchGen, Common
   type:                exitcode-stdio-1.0
-  default-language:    Haskell2010
-  ghc-options:         -O2 -threaded -with-rtsopts=-N
   build-depends:
-    base, async, bifunctors, containers, criterion-plus, deepseq, mwc-random, primitive, stm, stm-containers, stm-stats, text, transformers, ttrie, unordered-containers, vector
-
+    base, async, criterion >= 1.0, deepseq, hashable, stm, stm-containers, stm-stats, text, ttrie, unordered-containers, mwc-random, containers, transformers, vector, primitive, bifunctors
+  ghc-options: -O2 -threaded -with-rtsopts=-N
