diff --git a/benchmarks/Benchmarks.hs b/benchmarks/Benchmarks.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Benchmarks.hs
@@ -0,0 +1,125 @@
+{-# LANGUAGE BangPatterns #-}
+module Main where
+import Control.Exception (SomeException(..))
+
+import Control.DeepSeq (NFData(..))
+import Criterion.Main
+import qualified Control.Concurrent.Async as A
+import qualified Control.Concurrent.Async.Lifted as L
+
+main :: IO ()
+main = defaultMain
+  [ bgroup "async-wait"
+      [ bench "async" $ whnfIO asyncWait_async
+      , bench "lifted-async" $ whnfIO asyncWait_liftedAsync
+      ]
+  , bgroup "async-cancel-waitCatch"
+      [ bench "async" $ nfIO asyncCancelWaitCatch_async
+      , bench "lifted-async" $ nfIO asyncCancelWaitCatch_liftedAsync
+      ]
+  , bgroup "waitAny"
+      [ bench "async" $ whnfIO waitAny_async
+      , bench "lifted-async" $ whnfIO waitAny_liftedAsync
+      ]
+  , bgroup "race"
+      [ bench "async" $ nfIO race_async
+      , bench "lifted-async" $ nfIO race_liftedAsync
+      , bench "async (inlined)" $ nfIO race_async_inlined
+      , bench "lifted-async (inlined)" $ nfIO race_liftedAsync_inlined
+      ]
+  , bgroup "concurrently"
+      [ bench "async" $ nfIO concurrently_async
+      , bench "lifted-async" $ nfIO concurrently_liftedAsync
+      , bench "async (inlined)" $ nfIO concurrently_async_inlined
+      , bench "lifted-async (inlined)" $ nfIO concurrently_liftedAsync_inlined
+      ]
+  , bgroup "mapConcurrently"
+      [ bench "async" $ nfIO mapConcurrently_async
+      , bench "lifted-async" $ nfIO mapConcurrently_liftedAsync
+      ]
+  ]
+
+asyncWait_async :: IO Int
+asyncWait_async = do
+  a <- A.async (return 1)
+  A.wait a
+
+asyncWait_liftedAsync :: IO Int
+asyncWait_liftedAsync = do
+  a <- L.async (return 1)
+  L.wait a
+
+asyncCancelWaitCatch_async :: IO (Either SomeException Int)
+asyncCancelWaitCatch_async = do
+  a <- A.async (return 1)
+  A.cancel a
+  A.waitCatch a
+
+asyncCancelWaitCatch_liftedAsync :: IO (Either SomeException Int)
+asyncCancelWaitCatch_liftedAsync = do
+  a <- L.async (return 1)
+  L.cancel a
+  L.waitCatch a
+
+waitAny_async :: IO Int
+waitAny_async = do
+  as <- mapM (A.async . return) [1..10]
+  (_, n) <- A.waitAny as
+  return n
+
+waitAny_liftedAsync :: IO Int
+waitAny_liftedAsync = do
+  as <- mapM (L.async . return) [1..10]
+  (_, n) <- L.waitAny as
+  return n
+
+race_async :: IO (Either Int Int)
+race_async =
+  A.race (return 1) (return 2)
+
+race_liftedAsync :: IO (Either Int Int)
+race_liftedAsync =
+  L.race (return 1) (return 2)
+
+race_async_inlined :: IO (Either Int Int)
+race_async_inlined =
+  A.withAsync (return 1) $ \a ->
+    A.withAsync (return 2) $ \b ->
+      A.waitEither a b
+
+race_liftedAsync_inlined :: IO (Either Int Int)
+race_liftedAsync_inlined =
+  L.withAsync (return 1) $ \a ->
+    L.withAsync (return 2) $ \b ->
+      L.waitEither a b
+
+concurrently_async :: IO (Int, Int)
+concurrently_async =
+  A.concurrently (return 1) (return 2)
+
+concurrently_liftedAsync :: IO (Int, Int)
+concurrently_liftedAsync =
+  L.concurrently (return 1) (return 2)
+
+concurrently_async_inlined :: IO (Int, Int)
+concurrently_async_inlined =
+  A.withAsync (return 1) $ \a ->
+    A.withAsync (return 2) $ \b ->
+      A.waitBoth a b
+
+concurrently_liftedAsync_inlined :: IO (Int, Int)
+concurrently_liftedAsync_inlined =
+  L.withAsync (return 1) $ \a ->
+    L.withAsync (return 2) $ \b ->
+      L.waitBoth a b
+
+mapConcurrently_async :: IO [Int]
+mapConcurrently_async =
+  A.mapConcurrently return [1..10]
+
+mapConcurrently_liftedAsync :: IO [Int]
+mapConcurrently_liftedAsync =
+  L.mapConcurrently return [1..10]
+
+instance NFData SomeException where
+  rnf (SomeException !e) = ()
diff --git a/lifted-async.cabal b/lifted-async.cabal
--- a/lifted-async.cabal
+++ b/lifted-async.cabal
@@ -1,12 +1,13 @@
 name:                lifted-async
-version:             0.0.0.1
+version:             0.1.0
 synopsis:            Run lifted IO operations asynchronously and wait for their results
 homepage:            https://github.com/maoe/lifted-async
+bug-reports:         https://github.com/maoe/lifted-async/issues
 license:             BSD3
 license-file:        LICENSE
 author:              Mitsutoshi Aoe
 maintainer:          Mitsutoshi Aoe <maoe@foldr.in>
-copyright:           (C) Mitsutoshi Aoe 2012
+copyright:           (C) 2012 Mitsutoshi Aoe
 category:            Concurrency
 build-type:          Simple
 cabal-version:       >= 1.8
@@ -45,6 +46,17 @@
     , test-framework
     , test-framework-hunit
     , test-framework-th
+
+benchmark benchmark-lifted-async
+  type: exitcode-stdio-1.0
+  hs-source-dirs: benchmarks
+  main-is: Benchmarks.hs
+  build-depends:
+      base
+    , async
+    , criterion
+    , deepseq
+    , lifted-async
 
 source-repository head
   type: git
diff --git a/src/Control/Concurrent/Async/Lifted.hs b/src/Control/Concurrent/Async/Lifted.hs
--- a/src/Control/Concurrent/Async/Lifted.hs
+++ b/src/Control/Concurrent/Async/Lifted.hs
@@ -43,7 +43,7 @@
   , A.Concurrently, A.runConcurrently
   ) where
 
-import Control.Monad ((>=>), liftM)
+import Control.Monad ((>=>), liftM, void)
 import Data.Traversable (Traversable(..))
 import GHC.IO (unsafeUnmask)
 import Prelude hiding (mapM)
@@ -98,6 +98,7 @@
   -> (Async (StM m a) -> m b)
   -> m b
 withAsync = withAsyncUsing async
+{-# INLINABLE withAsync #-}
 
 -- | Generalized version of 'A.withAsyncBound'.
 withAsyncBound
@@ -106,6 +107,7 @@
   -> (Async (StM m a) -> m b)
   -> m b
 withAsyncBound = withAsyncUsing asyncBound
+{-# INLINABLE withAsyncBound #-}
 
 -- | Generalized version of 'A.withAsyncOn'.
 withAsyncOn
@@ -115,6 +117,7 @@
   -> (Async (StM m a) -> m b)
   -> m b
 withAsyncOn = withAsyncUsing . asyncOn
+{-# INLINABLE withAsyncOn #-}
 
 -- | Generalized version of 'A.withAsyncWithUnmask'.
 withAsyncWithUnmask
@@ -124,6 +127,7 @@
   -> m b
 withAsyncWithUnmask actionWith =
   withAsyncUsing async (actionWith (liftBaseOp_ unsafeUnmask))
+{-# INLINABLE withAsyncWithUnmask #-}
 
 -- | Generalized version of 'A.withAsyncOnWithUnmask'.
 withAsyncOnWithUnmask
@@ -134,6 +138,7 @@
   -> m b
 withAsyncOnWithUnmask cpu actionWith =
   withAsyncUsing (asyncOn cpu) (actionWith (liftBaseOp_ unsafeUnmask))
+{-# INLINABLE withAsyncOnWithUnmask #-}
 
 withAsyncUsing
   :: MonadBaseControl IO m
@@ -248,7 +253,7 @@
   => Async (StM m a)
   -> Async (StM m b)
   -> m ()
-waitEither_ = (liftBase .) . A.waitEither_
+waitEither_ = (void .) . waitEither
 
 -- | Generalized version of 'A.waitBoth'.
 waitBoth
@@ -261,6 +266,7 @@
   ra <- restoreM sa
   rb <- restoreM sb
   return (ra, rb)
+{-# INLINABLE waitBoth #-}
 
 -- | Generalized version of 'A.link'.
 link :: MonadBase IO m => Async (StM m a) -> m ()
@@ -276,6 +282,7 @@
   withAsync left $ \a ->
   withAsync right $ \b ->
   waitEither a b
+{-# INLINABLE race #-}
 
 -- | Generalized version of 'A.race_'.
 race_ :: MonadBaseControl IO m => m a -> m b -> m ()
@@ -283,6 +290,7 @@
   withAsync left $ \a ->
   withAsync right $ \b ->
   waitEither_ a b
+{-# INLINABLE race_ #-}
 
 -- | Generalized version of 'A.concurrently'.
 concurrently :: MonadBaseControl IO m => m a -> m b -> m (a, b)
@@ -290,6 +298,7 @@
   withAsync left $ \a ->
   withAsync right $ \b ->
   waitBoth a b
+{-# INLINABLE concurrently #-}
 
 -- | Generalized version of 'A.mapConcurrently'.
 mapConcurrently
diff --git a/tests/Test/Async/IO.hs b/tests/Test/Async/IO.hs
--- a/tests/Test/Async/IO.hs
+++ b/tests/Test/Async/IO.hs
@@ -1,7 +1,6 @@
 {-# LANGUAGE TemplateHaskell #-}
 module Test.Async.IO
   ( ioTestGroup
-  , ioTestGroupExtra
   ) where
 import Control.Monad (when)
 import Data.Maybe (isJust, isNothing)
@@ -17,11 +16,6 @@
 ioTestGroup :: Test
 ioTestGroup = $(testGroupGenerator)
 
-ioTestGroupExtra :: Test
-ioTestGroupExtra =
-  testGroup "async cancel rep" $
-    replicate 1000 $ testCase "async cancel" async_cancel
-
 case_async_waitCatch :: Assertion
 case_async_waitCatch = do
   a <- async (return value)
@@ -65,14 +59,16 @@
     Left e  -> fromException e @?= Just ThreadKilled
     Right _ -> assertFailure ""
 
-async_cancel :: Assertion
-async_cancel = do
-  a <- async (return value)
-  cancelWith a TestException
-  r <- waitCatch a
-  case r of
-    Left e -> fromException e @?= Just TestException
-    Right r -> r @?= value
+case_async_cancel :: Assertion
+case_async_cancel = sequence_ $ replicate 1000 run
+  where
+    run = do
+      a <- async (return value)
+      cancelWith a TestException
+      r <- waitCatch a
+      case r of
+        Left e -> fromException e @?= Just TestException
+        Right r -> r @?= value
 
 case_async_poll :: Assertion
 case_async_poll = do
diff --git a/tests/Test/Async/State.hs b/tests/Test/Async/State.hs
--- a/tests/Test/Async/State.hs
+++ b/tests/Test/Async/State.hs
@@ -1,10 +1,10 @@
 {-# LANGUAGE TemplateHaskell #-}
 module Test.Async.State
   ( stateTestGroup
-  , stateTestGroupExtra
   ) where
 import Control.Monad (when)
 import Control.Monad.State
+import Control.Monad.Writer
 import Data.Maybe (isJust, isNothing)
 import Prelude hiding (catch)
 
@@ -16,18 +16,13 @@
 stateTestGroup :: Test
 stateTestGroup = $(testGroupGenerator)
 
-stateTestGroupExtra :: Test
-stateTestGroupExtra =
-  testGroup "async cancel rep" $
-    replicate 1000 $ testCase "async cancel" async_cancel
-
 case_async_waitCatch :: Assertion
 case_async_waitCatch = do
   (r, s) <- flip runStateT value $ do
     a <- async $ modify (+1) >> return value
     waitCatch a
   case r of
-    Left _  -> assertFailure ""
+    Left _  -> assertFailure "An exception must not be raised."
     Right e -> do
       e @?= value
       s @?= value + 1
@@ -49,16 +44,17 @@
     Left e  -> do
       fromException e @?= Just TestException
       s @?= value
-    Right _ -> assertFailure ""
+    Right _ -> assertFailure "An exception must be raised."
 
 case_async_exwait :: Assertion
 case_async_exwait =
   void $ flip runStateT value $ do
     a <- async $ modify (+1) >> throwIO TestException
-    (wait a >> liftIO (assertFailure "")) `catch` \e -> do
-      liftIO $ e @?= TestException
-      s <- get
-      liftIO $ s @?= value
+    (wait a >> liftIO (assertFailure "An exception must be raised"))
+      `catch` \e -> do
+        liftIO $ e @?= TestException
+        s <- get
+        liftIO $ s @?= value
 
 case_withAsync_waitCatch :: Assertion
 case_withAsync_waitCatch =
@@ -66,7 +62,7 @@
     withAsync (modify (+1) >> return value) $ \a -> do
       r <- waitCatch a
       case r of
-        Left _  -> liftIO $ assertFailure ""
+        Left _  -> liftIO $ assertFailure "An exception must not be raised."
         Right e -> do
           liftIO $ e @?= value
           s <- get
@@ -81,30 +77,34 @@
     Left e  -> do
       fromException e @?= Just ThreadKilled
       s @?= value
-    Right _ -> assertFailure ""
+    Right _ -> assertFailure "An exception must be raised."
 
-async_cancel :: Assertion
-async_cancel = do
-  (r, s) <- flip runStateT value $ do
-    a <- async $ modify (+1) >> return value
-    cancelWith a TestException
-    waitCatch a
-  case r of
-    Left e -> do
-      fromException e @?= Just TestException
-      s @?= value
-    Right r -> do
-      r @?= value
-      s @?= value + 1
+case_async_cancel :: Assertion
+case_async_cancel = sequence_ $ replicate 1000 run
+  where
+    run = do
+      (r, s) <- flip runStateT value $ do
+        a <- async $ modify (+1) >> return value
+        cancelWith a TestException
+        waitCatch a
+      case r of
+        Left e -> do
+          fromException e @?= Just TestException
+          s @?= value
+        Right r -> do
+          r @?= value
+          s @?= value + 1
 
 case_async_poll :: Assertion
 case_async_poll =
   void $ flip runStateT value $ do
     a <- async (threadDelay 1000000)
     r <- poll a
-    when (isJust r) $ liftIO $ assertFailure ""
+    when (isJust r) $
+      liftIO $ assertFailure "The result must be nothing."
     r <- poll a   -- poll twice, just to check we don't deadlock
-    when (isJust r) $ liftIO $ assertFailure ""
+    when (isJust r) $
+      liftIO $ assertFailure "The result must be Nothing."
 
 case_async_poll2 :: Assertion
 case_async_poll2 =
@@ -112,6 +112,43 @@
     a <- async (return value)
     wait a
     r <- poll a
-    when (isNothing r) $ liftIO $ assertFailure ""
+    when (isNothing r) $
+      liftIO $ assertFailure "The result must not be Nothing."
     r <- poll a   -- poll twice, just to check we don't deadlock
-    when (isNothing r) $ liftIO $ assertFailure ""
+    when (isNothing r) $
+      liftIO $ assertFailure "The result must not be Nothing."
+
+case_withAsync_waitEither_ :: Assertion
+case_withAsync_waitEither_ = do
+  ((), s) <- flip runStateT value $ do
+    withAsync (modify (+1)) $ \a ->
+      waitEither_ a a
+  liftIO $ s @?= value + 1
+
+case_withAsync_waitBoth1 :: Assertion
+case_withAsync_waitBoth1 = do
+  (_, s) <- flip runStateT value $ do
+    withAsync (return value) $ \a ->
+      withAsync (modify (+1)) $ \b ->
+        waitBoth a b
+  liftIO $ s @?= value + 1
+
+case_withAsync_waitBoth2 :: Assertion
+case_withAsync_waitBoth2 = do
+  (_, s) <- flip runStateT value $ do
+    withAsync (modify (+1)) $ \a ->
+      withAsync (return value) $ \b ->
+        waitBoth a b
+  liftIO $ s @?= value
+
+case_link :: Assertion
+case_link = do
+  r <- try $ flip runStateT value $ do
+    a <- async $ threadDelay 1000000 >> return value
+    link a
+    cancelWith a TestException
+    wait a
+  case r of
+    Left e -> do
+      fromException e @?= Just TestException
+    Right _ -> assertFailure "An exception must be raised."
diff --git a/tests/TestSuite.hs b/tests/TestSuite.hs
--- a/tests/TestSuite.hs
+++ b/tests/TestSuite.hs
@@ -7,7 +7,5 @@
 
 main = defaultMain
   [ ioTestGroup
-  , ioTestGroupExtra
   , stateTestGroup
-  , stateTestGroupExtra
   ]
