microbench (empty) → 0.1
raw patch · 5 files changed
+188/−0 lines, 5 filesdep +basedep +timesetup-changed
Dependencies added: base, time
Files
- LICENSE +26/−0
- Microbench.hs +102/−0
- Setup.lhs +4/−0
- demo.hs +29/−0
- microbench.cabal +27/−0
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright (c) 2008 Evan Martin <martine@danga.com>+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:+* Redistributions of source code must retain the above copyright notice,+ this list of conditions and the following disclaimer.+* Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+* Neither the name of the author nor the names of contributors may be+ used to endorse or promote products derived from this software without+ specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Microbench.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE OverlappingInstances, FlexibleInstances #-}+-- microbench, a tiny microbenchmarking library for Haskell.+-- Copyright (C) 2008 Evan Martin <martine@danga.com>++-- |Microbenchmarking can be used to compare the speed of different+-- approaches to the same operation. Since most code is very fast, to+-- get accurate timing information you must run the operation many times+-- and then divide to get the time per operation.+--+-- This library manages the microbenchmarking process: it finds how many+-- iterations of a function are needed to get a good timing estimate per+-- iteration and prints out a human-readable \"Your code takes /n/+-- nanoseconds to run, and can run /n/ times per second\".+--+-- The only function 'microbench' takes a function that expects an+-- integer parameter (which is the quantity you're trying to measure),+-- and probes the function with increasing parameters until enough time+-- has elapsed to get a good measurement.+--+-- This may be better understood by some example code:+--+-- > sum1 n = sum [1..n]+-- > sum2 n = foldl (+) 0 [1..n]+-- > main = do+-- > microbench "Sum using sum" sum1+-- > microbench "Sum using foldl" sum2+--+-- When run, @sum1@ and @sum2@ are called with varying values of @n@.+-- The output, then, is an estimate of how many integers these+-- approaches could sum per second.+--+-- 'microbench' also accepts a parameter of type @IO ()@ for+-- benchmarking. It does the same probing process, but manages running+-- the operation in a loop.+module Microbench (+ microbench,+ Microbenchable+) where++import Control.Exception+import Debug.Trace+import Data.IORef+import Data.List+import Data.Time.Clock+import Data.Typeable+import Control.Concurrent+import System.IO+import Numeric++-- Want to handle:+-- Int -> a => ok+-- Int -> IO a => ok+-- IO () => loop the action+-- TODO:+-- IO a => loop the action, forcing each result?+-- a => is it possible? I tried for a while but couldn't make it work.+--+-- TODO 2:+-- factor out "setup time" by comparing different outputs for different inputs+-- and a linear model.++-- |Microbenchmarkable computations. Be very wary of adding your own+-- instances of this class, as it's difficult to force GHC to+-- re-evaluate code in a way that makes benchmarking easy.+class Microbenchable a where+ run :: a -> Int -> IO ()++instance Microbenchable (Int -> IO ()) where+ run f n = f n+instance Microbenchable (Int -> a) where+ run f n = do x <- evaluate (f n); return ()+instance Microbenchable (IO ()) where+ run f n = mapM_ (const f) [1..n]++-- This was chosen totally arbitrarily. Perhaps it would be better to make it+-- a parameter, or use some sort of real statistical test.+microbenchTime = 1++-- |@microbench description target@ probes target with different parameters+-- until it's ran enough iterations to have a good estimate at the rate per+-- second of the operation. @description@ is a textual description of the+-- thing being benchmarked. Outputs to stdout.+microbench :: Microbenchable a => String -> a -> IO ()+microbench desc f = do+ hSetBuffering stdout NoBuffering+ putStr $ "* " ++ desc ++ ": "+ start <- getCurrentTime+ time <- probe 1+ putStrLn ""+ putStrLn $ " " ++ showFFloat (Just 3) (time*1000*1000) "ns per iteration / "+ ++ showGFloat (Just 2) (1 / time) " per second."+ where+ probe repeats = do+ putStr "."+ start <- getCurrentTime+ run f repeats+ end <- getCurrentTime+ let delta = end `diffUTCTime` start+ if delta > microbenchTime+ then do return (realToFrac delta / realToFrac repeats)+ else probe (repeats * 2)+
+ Setup.lhs view
@@ -0,0 +1,4 @@+#! /usr/bin/env runhaskell++> import Distribution.Simple+> main = defaultMain
+ demo.hs view
@@ -0,0 +1,29 @@+-- microbench, a tiny microbenchmarking library for Haskell.+-- Copyright (C) 2008 Evan Martin <martine@danga.com>++import Data.IORef+import Data.List (foldl')++import Microbench++b_sum, b_foldl, b_foldl' :: Int -> Int+b_sum n = sum [1..n]+b_foldl n = foldl (+) 0 [1..n]+b_foldl' n = foldl' (+) 0 [1..n]+b_ioref :: Int -> IO ()+b_ioref n = do+ counter <- newIORef 0+ mapM_ (\x -> modifyIORef counter (+x)) [1..n]+ readIORef counter+ return ()++main = do+ putStrLn $ "This demo benchmark measures various ways to sum a list "+ ++ "of integers."+ microbench "sum n ints" b_sum+ microbench "foldl (+) n ints" b_foldl+ microbench "foldl' (+) n ints" b_foldl'+ microbench "sum n ints with an ioref" b_ioref+ microbench "sum 1..10 with an ioref" (b_ioref 10)+ microbench "sum 1..100 with an ioref" (b_ioref 100)+ return ()
+ microbench.cabal view
@@ -0,0 +1,27 @@+Cabal-Version: >= 1.2+Name: microbench+Version: 0.1+Synopsis: Microbenchmark Haskell code+Description:+ Microbenchmarking can be used to compare the speed of different+ approaches to the same operation. Since most code is very fast, to+ get accurate timing information you must run the operation many times+ and then divide to get the time per operation.+ .+ This library manages the microbenchmarking process: it finds how many+ iterations of a function are needed to get a good timing estimate per+ iteration and prints out a human-readable \"Your code takes /n/ nanoseconds+ to run, and can run /n/ times per second\".+Category: Development+License: BSD3+License-File: LICENSE+Author: Evan Martin+Maintainer: martine@danga.com+Copyright: (c) 2008 Evan Martin <martine@danga.com>+Homepage: http://neugierig.org/software/darcs/browse/?r=microbench;a=summary+Extra-Source-Files: demo.hs+Build-Type: Simple++Library+ Build-Depends: base, time+ Exposed-Modules: Microbench