packages feed

chronograph (empty) → 0.1.0.0

raw patch · 5 files changed

+232/−0 lines, 5 filesdep +basedep +deepseqdep +ghc-primsetup-changed

Dependencies added: base, deepseq, ghc-prim, time

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2012, John Lato++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 John Lato nor the names of other+      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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ chronograph.cabal view
@@ -0,0 +1,42 @@+-- Initial chronograph.cabal generated by cabal init.  For further+-- documentation, see http://haskell.org/cabal/users-guide/++name:                chronograph+version:             0.1.0.0+synopsis:            measure timings of data evaluation+description:         The 'Chronograph' data structure adds a measure field+                     to an existing Haskell expression.  This field will be the+                     time necessary to evaluate the expression using an+                     arbitrary evaluation strategy (WHNF by default).+                     .+                     Chronograph preserves laziness, so that the work of+                     performing the evaluation is only done after the result is+                     demanded.+                     .+                     If you want to benchmark your program, you should look to+                     other packages like Criterion that perform statistical+                     analysis of your results so you can determine how reliable+                     they are.  Chronograph just takes measurements, leaving+                     the interpretation entirely to you.+license:             BSD3+license-file:        LICENSE+author:              John Lato+maintainer:          jwlato@gmail.com+copyright:           John W. Lato, 2012+category:            Testing+build-type:          Simple+cabal-version:       >=1.8++extra-source-files:  examples/Chrono.hs++library+  exposed-modules:     Data.Chronograph+  build-depends:       base >=4.5 && < 5.0,+                       ghc-prim >=0.2 && < 0.4,+                       deepseq ==1.3.*,+                       time ==1.4.*+  hs-source-dirs:      src++source-repository head+  type: git+  location: https://github.com/JohnLato/chronograph
+ examples/Chrono.hs view
@@ -0,0 +1,35 @@+-- | A simple example of how to use Chronograph.  We want to count the lines in+-- a file, and measure how long it takes.++module Main where++import Control.Applicative+import System.Environment+import Data.Chronograph++import Text.Printf++main :: IO ()+main = do+    args <- getArgs+    putStrLn "pure Chronograph"+    mapM_ procFile args+    putStrLn "IO Chronograph"+    mapM_ procIO args++procFile :: FilePath -> IO ()+procFile fp = do+    doc <- readFile fp+    let wc = length $ lines doc+    putStrLn $ formatOutput fp (chrono wc)+    +formatOutput :: FilePath -> Chronograph Int -> String+formatOutput fp chr = printf "%s :: %d, %s" fp (val chr) (show $ measure chr)++fileLinesIO :: FilePath -> IO Int+fileLinesIO fp = length . lines <$> readFile fp++procIO :: FilePath -> IO ()+procIO fp = do+  wc <- chronoIO $ fileLinesIO fp+  putStrLn $ formatOutput fp wc
+ src/Data/Chronograph.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE NamedFieldPuns #-}++ -- |+ -- Measure data and IO evaluation time in a lightweight manner.+ --+ -- A 'Chronograph a' has two parts, the value 'a' and the measurement of+ -- evaluation time.  A Chronograph is lazy, so 'a' is only evaluted on demand.+ --+ -- This example counts the lines in a number of files, and records the+ -- evaluation time taken for each one.+ --+ -- >  import System.Environment+ -- >  import Control.Applicative+ -- >  import Data.Chronograph+ -- >+ -- >  import Text.Printf+ -- >+ -- >  formatOutput :: FilePath -> Chronograph Int -> String+ -- >  formatOutput fp chr = printf "%s :: %d, %s" fp (val chr) (show $ measure chr)+ -- >+ -- >  procFile :: FilePath -> IO ()+ -- >  procFile fp = do+ -- >      doc <- readFile fp+ -- >      let wc = length $ lines doc+ -- >      putStrLn $ formatOutput fp (chrono wc)+ --+ -- 'chrono' creates a chronograph that evaluates its input as far as 'seq' would.+ -- In this case the input 'wc' is an Int, so 'chrono' fully evaluates it.+ -- deepseq-style evaluation is performed by 'chronoNF', and custom evaluation+ -- strategies can be implemented with 'chronoBy'.+ --+ -- although 'wc' is a pure value, IO is lazily performed in its evalution.+ -- This IO cost is included in 'chrono's measurement.+ --+ -- You can explicitly include timings of IO actions as well:+ --+ -- >  fileLinesIO :: FilePath -> IO Int+ -- >  fileLinesIO fp = length . lines <$> readFile fp+ -- >+ -- >  procIO :: FilePath -> IO ()+ -- >  procIO fp = do+ -- >    wc <- chronoIO $ fileLinesIO fp+ -- >    putStrLn $ formatOutput fp wc+ --+ -- >  main :: IO ()+ -- >  main = do+ -- >      args <- getArgs+ -- >      putStrLn "pure Chronograph"+ -- >      mapM_ procFile args+ -- >      putStrLn "IO Chronograph"+ -- >      mapM_ procIO args+ --+module Data.Chronograph (+  Chronograph (..)+-- * chrono pure stuff+, chrono+, chronoNF+, chronoBy+-- * chrono IO stuff+, chronoJustIO+, chronoIO+, chronoNFIO+, chronoIOBy+) where++import Control.DeepSeq+import Data.Time (NominalDiffTime, getCurrentTime, diffUTCTime)+import GHC.Generics+import System.IO.Unsafe (unsafePerformIO)++data Chronograph a = Chronograph+    { val :: a+    , measure :: NominalDiffTime+    } deriving (Show, Generic)++----------------------------------------------------------+-- chrono pure functions++-- | Add a 'Chronograph' to measure evaluation to weak head normal form.+chrono :: a -> Chronograph a+chrono = chronoBy (`seq` ())++-- | Add a 'Chronograph' to measure evaluation to normal form.+chronoNF :: NFData a => a -> Chronograph a+chronoNF = chronoBy rnf++-- | Add a 'Chronograph' to measure evalution time with the provided strategy.+chronoBy :: (a -> ()) -> a -> Chronograph a+chronoBy eval x =+    let measure = unsafePerformIO $ do+                    t0 <- getCurrentTime+                    t1 <- eval x `seq` getCurrentTime+                    return (t1 `diffUTCTime` t0)+    in Chronograph {val = measure `seq` x, measure }++----------------------------------------------------------+-- chrono IO computations++-- | Add a 'Chronograph' to measure IO time (no additional evaluation is+-- performed, although the IO action itself may perform some evaluation)+chronoJustIO :: IO a -> IO (Chronograph a)+chronoJustIO = chronoIOBy (const ())++-- | Add a 'Chronograph' to measure time of IO and evaluation to weak head+-- normal form.+chronoIO :: IO a -> IO (Chronograph a)+chronoIO = chronoIOBy (`seq` ())++-- | Add a 'Chronograph' to measure time of IO and evaluation to normal form.+chronoNFIO :: NFData a => IO a -> IO (Chronograph a)+chronoNFIO = chronoIOBy rnf++-- | Add a 'Chronograph' to measure time of IO and evaluation with the+-- provided strategy.+chronoIOBy :: (a -> ()) -> IO a -> IO (Chronograph a)+chronoIOBy eval mx = do+    t0 <- getCurrentTime+    val  <- mx+    t1 <- eval val `seq` getCurrentTime+    let measure = t1 `diffUTCTime` t0++    return $ Chronograph {val, measure}