diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2014, Nikita Volkov
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/criterion-plus.cabal b/criterion-plus.cabal
new file mode 100644
--- /dev/null
+++ b/criterion-plus.cabal
@@ -0,0 +1,199 @@
+name:
+  criterion-plus
+version:
+  0.1.0
+synopsis:
+  Enhancement of the "criterion" benchmarking library
+description:
+  A dome library over \"criterion\",
+  which enhances it with the following features:
+  .
+  * Support for partial measuring, e.g., exclusion of the setup/teardown phases.
+  .
+  * Generation of multiple unrelated comparison reports.
+  .
+  * A flexible monadic API, 
+  which allows you to benchmark monad transformers and 
+  control which parts you actually want measured.
+  .
+category:
+  Benchmarking
+homepage:
+  https://github.com/nikita-volkov/criterion-plus 
+bug-reports:
+  https://github.com/nikita-volkov/criterion-plus/issues 
+author:
+  Nikita Volkov <nikita.y.volkov@mail.ru>
+maintainer:
+  Nikita Volkov <nikita.y.volkov@mail.ru>
+copyright:
+  (c) 2014, Nikita Volkov
+license:
+  MIT
+license-file:
+  LICENSE
+build-type:
+  Simple
+cabal-version:
+  >=1.10
+
+
+source-repository head
+  type:
+    git
+  location:
+    git://github.com/nikita-volkov/criterion-plus.git
+
+
+library
+  hs-source-dirs:
+    library
+  other-modules:
+    CriterionPlus.Prelude.Basic
+    CriterionPlus.Prelude.Data
+    CriterionPlus.Prelude.Transformers
+    CriterionPlus.Monads
+    CriterionPlus.CSI
+  exposed-modules:
+    CriterionPlus
+  build-depends:
+    -- options:
+    optparse-applicative == 0.8.*,
+    -- criterion:
+    criterion == 0.8.*,
+    statistics == 0.10.*,
+    -- file-system:
+    system-filepath == 0.4.*,
+    system-fileio == 0.3.*,
+    -- data:
+    vector > 0.7 && < 0.11,
+    text,
+    string-conversions == 0.3.*,
+    th-printf == 0.3.*,
+    -- control:
+    monad-control == 0.3.*,
+    transformers-base == 0.4.*,
+    deepseq == 1.3.*,
+    transformers,
+    mtl,
+    -- debugging:
+    loch-th == 0.2.*,
+    placeholders == 0.1.*,
+    -- general:
+    base >= 4.5 && < 5
+  default-extensions:
+    Arrows
+    BangPatterns
+    ConstraintKinds
+    DataKinds
+    DefaultSignatures
+    DeriveDataTypeable
+    DeriveFunctor
+    DeriveGeneric
+    EmptyDataDecls
+    FlexibleContexts
+    FlexibleInstances
+    FunctionalDependencies
+    GADTs
+    GeneralizedNewtypeDeriving
+    ImpredicativeTypes
+    LambdaCase
+    LiberalTypeSynonyms
+    MultiParamTypeClasses
+    MultiWayIf
+    NoImplicitPrelude
+    NoMonomorphismRestriction
+    OverloadedStrings
+    PatternGuards
+    ParallelListComp
+    QuasiQuotes
+    RankNTypes
+    RecordWildCards
+    ScopedTypeVariables
+    StandaloneDeriving
+    TemplateHaskell
+    TupleSections
+    TypeFamilies
+    TypeOperators
+  default-language:
+    Haskell2010
+
+
+test-suite internal-tests
+  type:             
+    exitcode-stdio-1.0
+  hs-source-dirs:   
+    internal-tests
+    library
+  main-is:          
+    InternalTests.hs
+  ghc-options:
+    -O2
+    -threaded
+    "-with-rtsopts=-N"
+  build-depends:
+    -- testing:
+    QuickCheck,
+    HUnit,
+    HTF == 0.11.*,
+    -- options:
+    optparse-applicative == 0.8.*,
+    -- criterion:
+    criterion == 0.8.*,
+    statistics == 0.10.*,
+    -- file-system:
+    system-filepath == 0.4.*,
+    system-fileio == 0.3.*,
+    -- data:
+    vector > 0.7 && < 0.11,
+    text,
+    string-conversions == 0.3.*,
+    th-printf == 0.3.*,
+    -- control:
+    monad-control == 0.3.*,
+    transformers-base == 0.4.*,
+    deepseq == 1.3.*,
+    transformers,
+    mtl,
+    -- debugging:
+    loch-th == 0.2.*,
+    placeholders == 0.1.*,
+    -- general:
+    base >= 4.5 && < 5
+  default-extensions:
+    Arrows
+    BangPatterns
+    ConstraintKinds
+    DataKinds
+    DefaultSignatures
+    DeriveDataTypeable
+    DeriveFunctor
+    DeriveGeneric
+    EmptyDataDecls
+    FlexibleContexts
+    FlexibleInstances
+    FunctionalDependencies
+    GADTs
+    GeneralizedNewtypeDeriving
+    ImpredicativeTypes
+    LambdaCase
+    LiberalTypeSynonyms
+    MultiParamTypeClasses
+    MultiWayIf
+    NoImplicitPrelude
+    NoMonomorphismRestriction
+    OverloadedStrings
+    PatternGuards
+    ParallelListComp
+    QuasiQuotes
+    RankNTypes
+    RecordWildCards
+    ScopedTypeVariables
+    StandaloneDeriving
+    TemplateHaskell
+    TupleSections
+    TypeFamilies
+    TypeOperators
+  default-language:
+    Haskell2010
+
diff --git a/internal-tests/InternalTests.hs b/internal-tests/InternalTests.hs
new file mode 100644
--- /dev/null
+++ b/internal-tests/InternalTests.hs
@@ -0,0 +1,54 @@
+{-# OPTIONS_GHC -F -pgmF htfpp #-}
+
+import Test.Framework
+import Test.QuickCheck.Monadic
+import CriterionPlus.Prelude.Basic
+import CriterionPlus.Prelude.Transformers
+import qualified CriterionPlus.Monads as M
+import qualified Criterion.Environment as C
+import qualified Data.Vector.Unboxed as V
+
+main = htfMain $ htf_thisModulesTests
+
+
+-- * Tests
+-------------------------
+
+test_aMoreComplexPureBenchmarkTakesLonger = do
+  replicateM_ 10 $ do
+    [a, b] <- runStandoff 100 $ do
+      M.subject "shorter" $ do
+        M.nf pureCalc 1
+      M.subject "longer" $ do
+        M.nf pureCalc 4
+    assertEqual LT $ compareResults a b
+
+test_aMoreComplexImpureBenchmarkTakesLonger = do
+  replicateM_ 10 $ do
+    [a, b] <- runStandoff 100 $ do
+      M.subject "shorter" $ do
+        M.nfIO $ return $ pureCalc 1
+      M.subject "longer" $ do
+        M.nfIO $ return $ pureCalc 4
+    assertEqual LT $ compareResults a b
+
+test_timerControlsDontAffectTheResults = unitTestPending ""
+
+
+-- * Utils
+-------------------------
+
+runStandoff :: Int -> M.Standoff a -> IO [M.SubjectReport]
+runStandoff samples = M.runStandoff 1 "test-standoff" env settings where
+  -- env = unsafePerformIO $ M.runBenchmark settings $ M.Benchmark $ lift $ ask
+  env = C.Environment 0 0
+  settings = M.Settings "dist/test" samples
+
+compareResults :: M.SubjectReport -> M.SubjectReport -> Ordering
+compareResults = on compare $ \(_, v, _, _) -> V.sum v
+
+pureCalc :: Int -> [Int]
+pureCalc a = map (+a) $ enumFromTo 0 $ 10^3*a
+
+apxEqual :: Double -> Double -> Bool
+apxEqual a b = a > b * 0.95 && a < b * 1.05
diff --git a/library/CriterionPlus.hs b/library/CriterionPlus.hs
new file mode 100644
--- /dev/null
+++ b/library/CriterionPlus.hs
@@ -0,0 +1,66 @@
+-- |
+-- Using this library you can create executables with benchmarks.
+-- It automatically implants a command-line options parser and info generator.
+-- 
+-- Here is an example of how this library is supposed to be used:
+-- 
+-- > import CriterionPlus
+-- > import qualified SomeMySQLLib as MySQL
+-- > import qualified SomePostgreSQLLib as PostgreSQL
+-- > 
+-- > main = 
+-- >   benchmark $ do
+-- >     standoff "Inserting rows" $ do
+-- >       subject "MySQL" $ do
+-- >         -- Exclude the "setup" phase from measurement:
+-- >         pause
+-- >         connection <- liftIO $ MySQL.openConnection
+-- >         -- Measure what we want:
+-- >         continue
+-- >         liftIO $ MySQL.insertAThousandRows connection
+-- >         -- Exclude the "teardown" phase from measurement:
+-- >         pause
+-- >         liftIO $ MySQL.closeConnection connection
+-- >       subject "PostgreSQL" $ do
+-- >         -- This is how we can exclude the "setup" phase from monad transformers:
+-- >         pause
+-- >         PostgreSQL.runSession $ do
+-- >           lift $ continue
+-- >           PostgreSQL.insertAThousandRows
+-- >           -- Exclude "teardown":
+-- >           lift $ pause
+-- >     -- Each standoff generates an independent report file:
+-- >     standoff "Querying" $ do
+-- >       subject "MySQL" $ error "So on..."
+-- >       subject "PostgreSQL" $ error "So on..."
+-- 
+module CriterionPlus
+(
+  -- * IO
+  benchmark,
+  -- * Benchmark
+  Benchmark,
+  standoff,
+  -- * Standoff
+  Standoff,
+  group,
+  subject,
+  -- * Subject
+  Subject,
+  continue,
+  pause,
+  -- ** Evaluation
+  whnf,
+  nf,
+  nfIO,
+  whnfIO,
+  -- * Shared Types
+  Name,
+)
+where
+
+import CriterionPlus.Monads
+
+
+
+
diff --git a/library/CriterionPlus/CSI.hs b/library/CriterionPlus/CSI.hs
new file mode 100644
--- /dev/null
+++ b/library/CriterionPlus/CSI.hs
@@ -0,0 +1,26 @@
+module CriterionPlus.CSI where
+
+import CriterionPlus.Prelude.Basic
+import CriterionPlus.Prelude.Data
+
+esc = "\ESC["
+csi = "\o033["
+cursorUp n = csi <> (cs $ show n) <> "A"
+cursorDown n = csi <> (cs $ show n) <> "B"
+-- | Moves cursor to beginning of the line n (default 1) lines down.
+cursorNextLine n = csi <> (cs $ show n) <> "E"
+-- | Moves cursor to beginning of the line n (default 1) lines up.
+cursorPreviousLine n = csi <> (cs $ show n) <> "F"
+-- | Moves the cursor to column n.
+cursorHorizontalAbsolute n = csi <> (cs $ show n) <> "G"
+-- | Clears part of the screen. If n is zero (or missing), clear from cursor to end of screen. If n is one, clear from cursor to beginning of the screen. If n is two, clear entire screen (and moves cursor to upper left on MS-DOS ANSI.SYS).
+eraseData n = csi <> (cs $ show n) <> "J"
+-- | Erases part of the line. If n is zero (or missing), clear from cursor to the end of the line. If n is one, clear from cursor to beginning of the line. If n is two, clear entire line. Cursor position does not change.
+eraseInLine n = csi <> (cs $ show n) <> "K"
+eraseLineToEnd = eraseInLine 0
+eraseLineToBeginning = eraseInLine 1
+eraseLine = eraseInLine 2
+saveCursorPosition = csi <> "s"
+restoreCursorPosition = csi <> "u"
+hideCursor = csi <> "?25l"
+showCursor = csi <> "?25h"
diff --git a/library/CriterionPlus/Monads.hs b/library/CriterionPlus/Monads.hs
new file mode 100644
--- /dev/null
+++ b/library/CriterionPlus/Monads.hs
@@ -0,0 +1,311 @@
+-- |
+-- Builder monads.
+module CriterionPlus.Monads where
+
+import CriterionPlus.Prelude.Basic
+import CriterionPlus.Prelude.Data
+import CriterionPlus.Prelude.Transformers
+import qualified Criterion.Config as C
+import qualified Criterion.Report as C
+import qualified Criterion.Types as C
+import qualified Criterion.Environment as C
+import qualified Criterion.Measurement as C
+import qualified Criterion.IO.Printf as C
+import qualified Criterion.Analysis as C
+import qualified Criterion.Monad as C
+import qualified Statistics.Resampling.Bootstrap as S
+import qualified Statistics.Types as S
+import qualified Data.Text as T
+import qualified Data.Vector.Unboxed as V
+import qualified Data.Vector.Unboxed.Mutable as VM
+import qualified Filesystem.Path.CurrentOS as FS
+import qualified Filesystem as FS
+import qualified Options.Applicative as O
+import qualified CriterionPlus.CSI as CSI
+import qualified System.IO
+
+
+-- * Shared Types
+-------------------------
+
+type Name = StrictText
+
+data Settings = 
+  Settings {
+    reportsDir :: FilePath,
+    samplesAmount :: Int
+  }
+
+type Environment = C.Environment
+
+
+-- * IO
+-------------------------
+
+-- |
+-- Parse the command line options and run the benchmark.
+-- 
+benchmark :: Benchmark () -> IO ()
+benchmark b = do
+  settings <- O.execParser $ O.info (O.helper <*> parser) $ O.fullDesc
+  runBenchmark settings b
+  where
+    parser = Settings <$> reportsDir <*> samplesAmount where
+      reportsDir = 
+        O.nullOption $ 
+          O.eitherReader readValue <>
+          O.long "reportsDir" <>
+          O.short 'd' <>
+          O.value "." <>
+          O.showDefault <>
+          O.help "A path to directory to save all the reports in"
+        where
+          readValue s = let
+            p = FS.decodeString s
+            in if unsafePerformIO (FS.isDirectory p)
+              then Right p
+              else Left $ "The path does not exist or is not a directory: " <> s
+      samplesAmount = 
+        O.option $ 
+          O.long "samplesAmount" <>
+          O.short 's' <>
+          O.value 100 <>
+          O.eitherReader (validateValue . read) <>
+          O.showDefault <>
+          O.help "How many times to sample the benchmarks"
+        where
+          validateValue a = if a < 3 
+            then Left "A value is lower than the minimum of 3"
+            else Right a
+
+
+-- * Benchmark
+-------------------------
+
+-- |
+-- A root of the \"criterion-plus\" monad stack.
+-- 
+-- Use this monad to declare 'standoff's.
+-- You can also lift a shared initialization into it using 'liftIO'.
+newtype Benchmark a =
+  Benchmark (StateT Int (ReaderT Environment (ReaderT Settings IO)) a)
+  deriving (Functor, Applicative, Monad, MonadIO)
+
+runBenchmark :: Settings -> Benchmark a -> IO a
+runBenchmark settings (Benchmark m) = do
+  env <- runCriterion settings $ C.measureEnvironment
+  flip runReaderT settings $ flip runReaderT env $ flip evalStateT 1 $ m
+
+-- |
+-- Declare a named comparison of multiple subjects.
+-- This will generate a separate report file.
+standoff :: Name -> Standoff () -> Benchmark ()
+standoff name s = Benchmark $ do
+  i <- state $ id &&& succ
+  env <- lift $ ask
+  settings <- lift $ lift $ ask
+  liftIO $ void $ runStandoff i name env settings s
+
+
+-- * Standoff
+-------------------------
+
+-- |
+-- A monad for declaration of independent comparison,
+-- which will produce a dedicated report file.
+-- 
+-- Use this monad to 'group' and declare 'subject's.
+-- You can also lift a shared initialization into it using 'liftIO'.
+newtype Standoff a =
+  Standoff (StateT [SubjectReport] (ReaderT Group (ReaderT Environment (ReaderT Settings IO))) a)
+  deriving (Functor, Applicative, Monad, MonadIO)
+
+-- | A reverse list of names of nested group declarations.
+type Group = [Name]
+
+runStandoff :: Int -> Name -> Environment -> Settings -> Standoff a -> IO [SubjectReport]
+runStandoff i name env settings (Standoff m) = do
+  reports <- 
+    fmap reverse $
+    flip runReaderT settings $ flip runReaderT env $ flip runReaderT [] $ flip execStateT [] $ m
+  renderHTML settings name reports file
+  return reports
+  where
+    file = (reportsDir settings) <> (FS.decodeString $ uniqueName <> ".html")
+    uniqueName = "standoff-" <> show i
+
+-- |
+-- Put the wrapped computations into a named group.
+-- Can be nested.
+group :: Name -> Standoff () -> Standoff ()
+group name (Standoff m) = Standoff $ local (name :) m
+
+-- |
+-- Execute a named subject.
+subject :: Name -> Subject a -> Standoff ()
+subject name subj = Standoff $ do
+  group <- lift $ ask
+  env <- lift $ lift $ ask
+  settings <- lift $ lift $ lift $ ask
+  report <- liftIO $ runSubject name group env settings subj
+  modify (report :)
+
+
+-- * Subject
+-------------------------
+
+-- |
+-- A monad, which wraps the benchmarking subject and controls its measurement.
+newtype Subject a = 
+  Subject (StateT SampleStartTime (StateT SampleTotalTime IO) a)
+  deriving (Functor, Applicative, Monad, MonadIO, MonadBase IO)
+
+instance MonadBaseControl IO Subject where
+  newtype StM Subject a = SubjectStM (StM (StateT SampleStartTime (StateT SampleTotalTime IO)) a)
+  liftBaseWith run =
+    Subject $ liftBaseWith $ \runStateInBase -> 
+    run $ \(Subject s) -> liftM SubjectStM $ runStateInBase s
+  restoreM (SubjectStM s) = Subject $ restoreM s
+
+
+type SubjectReport = (Name, S.Sample, C.SampleAnalysis, C.Outliers)
+
+type SampleStartTime = Maybe Double
+type SampleTotalTime = Double
+
+runSubject :: Name -> Group -> Environment -> Settings -> Subject a -> IO SubjectReport
+runSubject name group env settings subj = do
+  putStrLnLT $ [lt|\nRunning a subject "%s"|] compositeName
+
+  samplesVec <- collectSamplesVec
+
+  analysis@C.SampleAnalysis{..} <- C.analyseSample 0.95 samplesVec (100 * 1000)
+
+  reportEstimate "mean" anMean
+  reportEstimate "std dev" anStdDev
+  
+  let outliers = C.classifyOutliers samplesVec
+  reportOutliers outliers
+  reportOutliersVariance anOutlierVar 
+
+  return $ (compositeName, samplesVec, analysis, outliers)
+  where
+    reportEstimate header S.Estimate{..} = do
+      putStrLnLT $
+        [lt|%s: %s, lower bound: %s, upper bound: %s, confidence: %.3f|]
+          (header :: LazyText)
+          (C.secs estPoint)
+          (C.secs estLowerBound)
+          (C.secs estUpperBound)
+          (estConfidenceLevel)
+    reportOutliersVariance C.OutlierVariance{..} = do
+      putStrLnLT $ [lt|variance introduced by outliers: %.3f%%|] (ovFraction * 100)
+      putStrLnLT $ [lt|variance is %s by outliers|] $
+        case ovEffect of
+          C.Unaffected -> "unaffected" :: LazyText
+          C.Slight -> "slightly inflated"
+          C.Moderate -> "moderately inflated"
+          C.Severe -> "severely inflated"
+    reportOutliers = runCriterion settings . C.noteOutliers
+    collectSamplesVec = do
+      let amount = samplesAmount settings
+      firstSample <- runSample
+      let useFirstSample = firstSample > 0.2
+      vec <- VM.new amount
+      when useFirstSample $ VM.write vec 0 firstSample
+      forM_ (enumFromTo (if useFirstSample then 1 else 0) (amount - 1)) $ \i -> do
+        printTimeLeft firstSample (amount - i)
+        sample <- runSample
+        VM.write vec i sample
+      V.unsafeFreeze vec
+      where
+        printTimeLeft sample amount = do
+          putStrST $ 
+            [st|Collecting %d more samples in %.1f s.|] 
+              (amount) 
+              (sample * fromIntegral amount)
+          System.IO.hFlush System.IO.stdout
+          putStr (CSI.eraseLineToBeginning <> CSI.cursorHorizontalAbsolute 0)
+        runSample = do
+          performGC
+          (_, time) <- 
+            (continue >> subj >> pause) |> 
+            \(Subject m) -> flip runStateT 0 $ flip runStateT Nothing $ m
+          return $ time - C.envClockCost env
+    compositeName = T.intercalate "/" $ reverse $ name : group
+
+-- | 
+-- Continue the timer.
+-- 
+-- By default it is already running, 
+-- so if you need to eclude something from the beginning of the subject
+-- use 'pause'. E.g.:
+-- 
+-- > subject "MySQL" $ do
+-- >   pause
+-- >   connection <- liftIO $ openConnection
+-- >   continue
+-- >   liftIO $ workWithConnection connection
+-- >   pause
+-- >   liftIO $ closeConnection connection
+-- 
+continue :: Subject ()
+continue = Subject $ do
+  !time <- liftIO $ C.getTime
+  put $ Just time
+
+-- | Pause the timer.
+pause :: Subject ()
+pause = Subject $ do
+  !time <- liftIO $ C.getTime
+  get >>= \case
+    Just startTime -> do
+      lift $ modify (+ (time - startTime))
+      put $ Nothing
+    Nothing -> return ()
+
+-- |
+-- An adaptation of @Criterion.Types.'C.whnf'@.
+whnf :: (MonadIO m) => (a -> b) -> a -> m ()
+whnf f x = liftIO $ void $ evaluate (f x)
+{-# NOINLINE whnf #-}
+
+-- |
+-- An adaptation of @Criterion.Types.'C.nf'@.
+nf :: (MonadIO m, NFData b) => (a -> b) -> a -> m ()
+nf f x = liftIO $ evaluate (rnf (f x))
+{-# NOINLINE nf #-}
+
+-- |
+-- An adaptation of @Criterion.Types.'C.nfIO'@.
+nfIO :: (MonadIO m, NFData a) => IO a -> m ()
+nfIO = liftIO . C.nfIO
+{-# NOINLINE nfIO #-}
+
+-- |
+-- An adaptation of @Criterion.Types.'C.whnfIO'@.
+whnfIO :: (MonadIO m) => IO a -> m ()
+whnfIO = liftIO . C.whnfIO
+{-# NOINLINE whnfIO #-}
+
+
+-- * Criterion Helpers
+-------------------------
+
+runCriterion :: Settings -> C.Criterion a -> IO a
+runCriterion settings = 
+  C.withConfig $ C.defaultConfig {
+    C.cfgSamples = Last $ Just $ (samplesAmount settings)
+  }
+
+renderHTML :: Settings -> Name -> [SubjectReport] -> FilePath -> IO ()
+renderHTML settings name reports file = do
+  C.withConfig config $ C.report reports'
+  where
+    reports' = [C.Report i (cs n) s a o | i <- [0..] | (n, s, a, o) <- reports]
+    config = 
+      C.defaultConfig {
+        C.cfgBanner = Last $ Just $ cs name,
+        C.cfgReport = Last $ Just $ FS.encodeString file,
+        C.cfgSamples = Last $ Just $ samplesAmount settings
+      } 
diff --git a/library/CriterionPlus/Prelude/Basic.hs b/library/CriterionPlus/Prelude/Basic.hs
new file mode 100644
--- /dev/null
+++ b/library/CriterionPlus/Prelude/Basic.hs
@@ -0,0 +1,96 @@
+module CriterionPlus.Prelude.Basic
+( 
+  module Exports,
+
+  traceM,
+  bug,
+  bottom,
+
+  (?:),
+  (|>),
+  (<|),
+  (|$>),
+)
+where
+
+-- base
+-------------------------
+import Prelude as Exports hiding (concat, foldr, mapM_, sequence_, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, mapM, sequence, FilePath, id, (.))
+import Control.Monad as Exports hiding (mapM_, sequence_, forM_, msum, mapM, sequence, forM)
+import Control.Applicative as Exports
+import Control.Arrow as Exports hiding (left, right)
+import Control.Category as Exports
+import Data.Monoid as Exports
+import Data.Foldable as Exports
+import Data.Traversable as Exports hiding (for)
+import Data.Maybe as Exports
+import Data.Either as Exports
+import Data.List as Exports hiding (concat, foldr, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, find, maximumBy, minimumBy, mapAccumL, mapAccumR, foldl')
+import Data.Tuple as Exports
+import Data.Function as Exports hiding ((.), id)
+import Data.Ord as Exports (Down(..))
+import Data.String as Exports
+import Data.Int as Exports
+import Data.Word as Exports
+import Data.Ratio as Exports
+import Data.Fixed as Exports
+import Data.Ix as Exports
+import Data.Data as Exports
+import Text.Read as Exports (readMaybe, readEither)
+import Control.Exception as Exports hiding (tryJust, try, assert)
+import Control.Concurrent as Exports hiding (yield)
+import System.Mem as Exports
+import System.Mem.StableName as Exports
+import System.Timeout as Exports
+import System.Exit as Exports
+import System.IO.Unsafe as Exports
+import System.IO as Exports (Handle, hClose)
+import System.IO.Error as Exports
+import Unsafe.Coerce as Exports
+import GHC.Generics as Exports (Generic)
+import GHC.IO.Exception as Exports
+import Data.IORef as Exports
+import Data.STRef as Exports
+import Control.Monad.ST as Exports
+import Debug.Trace as Exports hiding (traceM)
+
+-- placeholders
+-------------------------
+import Development.Placeholders as Exports
+
+-- deepseq
+-------------------------
+import Control.DeepSeq as Exports
+
+-- custom
+-------------------------
+import qualified Debug.Trace.LocationTH
+
+traceM :: (Monad m) => String -> m ()
+traceM s = trace s $ return ()
+
+bug = [e| $(Debug.Trace.LocationTH.failure) . (msg <>) |]
+  where
+    msg = "A \"criterion-plus\" package bug: " :: String
+
+bottom = [e| $bug "Bottom evaluated" |]
+
+(?:) :: Maybe a -> a -> a
+maybeA ?: b = fromMaybe b maybeA
+{-# INLINE (?:) #-}
+
+(|>) :: a -> (a -> b) -> b
+a |> aToB = aToB a
+{-# INLINE (|>) #-}
+
+(<|) :: (a -> b) -> a -> b
+aToB <| a = aToB a
+{-# INLINE (<|) #-}
+
+-- | 
+-- The following are all the same:
+-- fmap f a == f <$> a == a |> fmap f == a |$> f
+-- 
+-- This operator accomodates the left-to-right operators: >>=, >>>, |>.
+(|$>) = flip fmap
+{-# INLINE (|$>) #-}
diff --git a/library/CriterionPlus/Prelude/Data.hs b/library/CriterionPlus/Prelude/Data.hs
new file mode 100644
--- /dev/null
+++ b/library/CriterionPlus/Prelude/Data.hs
@@ -0,0 +1,40 @@
+module CriterionPlus.Prelude.Data
+(
+  module Exports,
+  putStrLnLT,
+  putStrLnST,
+  putStrLT,
+  putStrST,
+)
+where
+
+-- string-conversions
+-------------------------
+import Data.String.Conversions as Exports hiding (LT, ST)
+
+-- system-filepath
+-------------------------
+import Filesystem.Path as Exports (FilePath)
+
+-- th-printf
+-------------------------
+import Text.Printf.TH as Exports
+
+
+-- Custom
+-------------------------
+import CriterionPlus.Prelude.Basic
+import qualified Data.Text.IO
+import qualified Data.Text.Lazy.IO
+
+putStrLnLT :: LazyText -> IO ()
+putStrLnLT = Data.Text.Lazy.IO.putStrLn
+
+putStrLT :: LazyText -> IO ()
+putStrLT = Data.Text.Lazy.IO.putStr
+
+putStrLnST :: StrictText -> IO ()
+putStrLnST = Data.Text.IO.putStrLn
+
+putStrST :: StrictText -> IO ()
+putStrST = Data.Text.IO.putStr
diff --git a/library/CriterionPlus/Prelude/Transformers.hs b/library/CriterionPlus/Prelude/Transformers.hs
new file mode 100644
--- /dev/null
+++ b/library/CriterionPlus/Prelude/Transformers.hs
@@ -0,0 +1,21 @@
+module CriterionPlus.Prelude.Transformers (module Exports) where
+
+-- mtl
+-------------------------
+import Control.Monad.Identity as Exports hiding (mapM_, sequence_, forM_, msum, mapM, sequence, forM)
+import Control.Monad.State.Strict as Exports hiding (mapM_, sequence_, forM_, msum, mapM, sequence, forM)
+import Control.Monad.Reader as Exports hiding (mapM_, sequence_, forM_, msum, mapM, sequence, forM)
+import Control.Monad.Writer.Strict as Exports hiding (mapM_, sequence_, forM_, msum, mapM, sequence, forM, Any)
+import Control.Monad.RWS.Strict as Exports hiding (mapM_, sequence_, forM_, msum, mapM, sequence, forM, Any)
+import Control.Monad.Error as Exports hiding (mapM_, sequence_, forM_, msum, mapM, sequence, forM)
+import Control.Monad.Trans as Exports
+
+-- transformers-base
+-------------------------
+import Control.Monad.Base as Exports
+
+-- monad-control
+-------------------------
+import Control.Monad.Trans.Control as Exports
+
+
