criterion 0.1 → 0.1.2
raw patch · 5 files changed
+162/−31 lines, 5 files
Files
- Criterion/Plot.hs +48/−27
- README +17/−0
- criterion.cabal +12/−4
- examples/Fibber.hs +37/−0
- examples/Judy.hs +48/−0
Criterion/Plot.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE CPP, ScopedTypeVariables #-} -- | -- Module : Criterion.Plot@@ -19,13 +19,10 @@ ) where import Criterion.Config-import Data.Accessor ((^=)) import Data.Array.Vector import Data.Char (isSpace, toLower) import Data.Foldable (forM_) import Data.List (group, intersperse)-import Graphics.Rendering.Chart hiding (Plot,c)-import Graphics.Rendering.Chart.Gtk (renderableToWindow) import Statistics.KernelDensity (Points, fromPoints) import Statistics.Types (Sample) import System.FilePath (pathSeparator)@@ -33,6 +30,14 @@ import Text.Printf (printf) import qualified Criterion.MultiMap as M +#ifdef HAVE_CHART+import Data.Accessor ((^=))+import Graphics.Rendering.Chart hiding (Plot,c)+import Graphics.Rendering.Chart.Gtk (renderableToWindow)+#else+import Criterion.IO (printError)+#endif+ plotWith :: Plot -> Config -> (PlotOutput -> IO ()) -> IO () plotWith p cfg plot = case M.lookup p (cfgPlot cfg) of@@ -51,6 +56,7 @@ forM_ (fromU $ indexedU times) $ \(x :*: y) -> putRow h [show x, show y] +#ifdef HAVE_CHART plotTiming (PDF x y) desc times = renderableToPDFFile (renderTiming desc times) x y (mangle $ printf "%s timings %dx%d.pdf" desc x y)@@ -65,6 +71,11 @@ plotTiming (Window x y) desc times = renderableToWindow (renderTiming desc times) x y+#else+plotTiming output _desc _times =+ printError "ERROR: output type %s not supported on this platform\n"+ (show output)+#endif -- | Plot kernel density estimate. plotKDE :: PlotOutput -- ^ The kind of output desired.@@ -79,6 +90,7 @@ forM_ (zip (fromU pdf) (fromU (fromPoints points))) $ \(x, y) -> putRow h [show x, show y] +#ifdef HAVE_CHART plotKDE (PDF x y) desc points pdf = renderableToPDFFile (renderKDE desc points pdf) x y (mangle $ printf "%s densities %dx%d.pdf" desc x y)@@ -93,7 +105,13 @@ plotKDE (Window x y) desc points pdf = renderableToWindow (renderKDE desc points pdf) x y+#else+plotKDE output _desc _points _pdf =+ printError "ERROR: output type %s not supported on this platform\n"+ (show output)+#endif +#ifdef HAVE_CHART renderTiming :: String -> Sample -> Renderable () renderTiming desc times = toRenderable layout where@@ -110,7 +128,9 @@ bottomAxis = laxis_title ^= "number of samples" $ defaultLayoutAxis - bars = plot_bars_values ^= (zip [0..] . map (:[]) . fromU $ times)+ bars = plot_bars_values ^= (zip [0.5,1.5..] . map (:[]) . fromU $ times)+ $ plot_bars_item_styles ^= [ (solidFillStyle c, Nothing) | c <- defaultColorSeq ]+ $ plot_bars_spacing ^= BarsFixGap 0 $ defaultPlotBars renderKDE :: String -> Points -> UArr Double -> Renderable ()@@ -141,28 +161,6 @@ secAxis = la_labelf ^= secs $ defaultLinearAxis -writeTo :: FilePath -> (Handle -> IO a) -> IO a-writeTo path = withBinaryFile path WriteMode--escapeCSV :: String -> String-escapeCSV xs | any (`elem`xs) escapes = '"' : concatMap esc xs ++ "\""- | otherwise = xs- where esc '"' = "\"\""- esc c = [c]- escapes = "\"\r\n,"--putRow :: Handle -> [String] -> IO ()-putRow h s = hPutStr h (concat (intersperse "," (map escapeCSV s)) ++ "\r\n")---- | Get rid of spaces and other potentially troublesome characters--- from output.-mangle :: String -> FilePath-mangle = concatMap (replace ((==) '-' . head) "-")- . group- . map (replace isSpace '-' . replace (==pathSeparator) '-' . toLower)- where replace p r c | p c = r- | otherwise = c- -- | Try to render meaningful time-axis labels. -- -- /FIXME/: Trouble is, we need to know the range of times for this to@@ -189,3 +187,26 @@ | t >= 1e2 = printf "%.0f %s" t u | t >= 1e1 = printf "%.1f %s" t u | otherwise = printf "%.2f %s" t u+#endif++writeTo :: FilePath -> (Handle -> IO a) -> IO a+writeTo path = withBinaryFile path WriteMode++escapeCSV :: String -> String+escapeCSV xs | any (`elem`xs) escapes = '"' : concatMap esc xs ++ "\""+ | otherwise = xs+ where esc '"' = "\"\""+ esc c = [c]+ escapes = "\"\r\n,"++putRow :: Handle -> [String] -> IO ()+putRow h s = hPutStr h (concat (intersperse "," (map escapeCSV s)) ++ "\r\n")++-- | Get rid of spaces and other potentially troublesome characters+-- from output.+mangle :: String -> FilePath+mangle = concatMap (replace ((==) '-' . head) "-")+ . group+ . map (replace isSpace '-' . replace (==pathSeparator) '-' . toLower)+ where replace p r c | p c = r+ | otherwise = c
README view
@@ -8,6 +8,23 @@ and take a look at the programs in the examples directory. +Building and installing+-----------------------++To build and install criterion, just run++ cabal install criterion++On Mac OS X, the Chart library that criterion uses is not available,+so you'll have to build without it.++ cabal install criterion -f-chart+ +This will lose you the ability to generate charts, but you'll still be+able to generate CSV files and import them into your favourite+spreadsheet, or gnuplot, or whatnot.++ Get involved! -------------
criterion.cabal view
@@ -1,5 +1,5 @@ name: criterion-version: 0.1+version: 0.1.2 synopsis: Benchmarking, Performance, Testing license: BSD3 license-file: LICENSE@@ -9,7 +9,8 @@ category: Development, Performance build-type: Simple cabal-version: >= 1.2-extra-source-files: README+extra-source-files:+ README examples/Fibber.hs examples/Judy.hs description: This library provides a powerful but simple way to measure the performance of Haskell code. It provides both a framework for@@ -20,6 +21,9 @@ The fastest way to get started is to read the documentation and examples in the Criterion.Main module. +flag Chart+ Description: enable use of the Chart package+ library exposed-modules: Criterion@@ -34,11 +38,9 @@ Criterion.Types build-depends:- Chart, base < 5, bytestring >= 0.9 && < 1.0, containers,- data-accessor, filepath, parallel, parsec,@@ -46,6 +48,12 @@ time, uvector, uvector-algorithms >= 0.2++ if flag(chart)+ build-depends:+ Chart,+ data-accessor+ cpp-options: -DHAVE_CHART -- gather extensive profiling data for now ghc-prof-options: -auto-all
+ examples/Fibber.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE ScopedTypeVariables #-}++import Criterion.Main++fib :: Int -> Int+fib 0 = 0+fib 1 = 1+fib n = fib (n-1) + fib (n-2)++fact :: Int -> Integer+fact n | n < 0 = error "negative!"+ | otherwise = go (fromIntegral n)+ where go i | i == 0 = 1+ | otherwise = i * go (i-1)++fio :: Int -> IO Integer+fio n | n < 0 = error "negative!"+ | otherwise = go (fromIntegral n)+ where go i | i == 0 = return 1+ | otherwise = do+ j <- go (i-1)+ return $! i * j++main = defaultMain [+ bgroup "fib" [ bench "fib 10" $ \n -> fib (10+n-n)+ , bench "fib 35" $ \n -> fib (35+n-n)+ , bench "fib 37" $ \n -> fib (37+n-n)+ ],+ bgroup "fact" [ bench "fact 100" $ \n -> fact (100+n-n)+ , bench "fact 1000" $ \n -> fact (1000+n-n)+ , bench "fact 3000" $ \n -> fact (3000+n-n)+ ],+ bgroup "fio" [ bench "fio 100" (fio 100)+ , bench "fio 1000" (fio 1000)+ , bench "fio 3000" (fio 3000)+ ]+ ]
+ examples/Judy.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE FlexibleInstances, ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-full-laziness #-}++-- cabal install judy++import Control.Monad (forM_)+import Criterion.Config+import Criterion.Main+import Criterion.Types+import qualified Data.IntMap as I+import qualified Data.Judy as J+import qualified Data.Map as M+import qualified Data.IntMap as I+import Data.List (foldl')++-- Work around the fact that the GC won't run finalizers aggressively+-- enough for us.+myConfig = defaultConfig { cfgPerformGC = ljust True }++main = defaultMainWith myConfig [+ bgroup "judy" [+ bench "insert 1M" (testit 1000000)+ , bench "insert 10M" (testit 10000000)+ , bench "insert 100M" (testit 100000000)+ ],+ bgroup "map" [+ bench "insert 100k" (testmap 100000)+ , bench "insert 1M" (testmap 1000000)+ ],+ bgroup "intmap" [+ bench "insert 100k" (testintmap 100000)+ , bench "insert 1M" (testintmap 1000000)+ ]+ ]++testit n = do+ j <- J.new :: IO (J.JudyL Int)+ forM_ [1..n] $ \n -> J.insert n (fromIntegral n :: Int) j+ v <- J.lookup 100 j+ v `seq` return ()++testmap :: Int -> Int -> M.Map Int Int+testmap n i =+ foldl' (\m k -> M.insert k 1 m) M.empty [0..(n+i-i)]++testintmap :: Int -> Int -> I.IntMap Int+testintmap n i =+ foldl' (\m k -> I.insert k 1 m) I.empty [0..(n+i-i)]