Browse files

Initial commit

  • Loading branch information...
0 parents commit fd8343af775e3ddff156c2b0a3b6c5509677e666 @jaspervdj committed Jun 9, 2011
Showing with 252 additions and 0 deletions.
  1. +1 −0 .ghci
  2. +1 −0 .gitignore
  3. +30 −0 LICENSE
  4. +27 −0 README.markdown
  5. +2 −0 Setup.hs
  6. +50 −0 criterion-to-html.cabal
  7. +32 −0 src/Criterion/ToHtml.hs
  8. +36 −0 src/Criterion/ToHtml/Csv.hs
  9. +38 −0 src/Criterion/ToHtml/Html.hs
  10. +35 −0 src/Criterion/ToHtml/Result.hs
1 .ghci
@@ -0,0 +1 @@
+:set -isrc
1 .gitignore
@@ -0,0 +1 @@
+dist
30 LICENSE
@@ -0,0 +1,30 @@
+Copyright (c)2011, Jasper Van der Jeugt
+
+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 Jasper Van der Jeugt 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.
27 README.markdown
@@ -0,0 +1,27 @@
+criterion-to-html
+=================
+
+What
+----
+
+This is a small program to convert [Criterion][criterion] to HTML reports.
+
+[criterion]: http://hackage.haskell.org/package/criterion
+
+At this point, the HTML reports are (very) minimal, they simply provide a simple
+barplot overview. If there's anything you'd like me to add, please create an
+[issue][issue].
+
+[issue]: http://github.com/jaspervdj/criterion-to-html/issues
+
+Usage
+-----
+
+To generate the CSV file, run your criterion benchmark using the @-u@ flag:
+
+ some-criterion-benchmark -u results.csv
+
+You can then convert the CSV results to some simple HTML plots using this
+program:
+
+ criterion-to-html results.csv
2 Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
50 criterion-to-html.cabal
@@ -0,0 +1,50 @@
+Name: criterion-to-html
+Version: 0.0.0.1
+Synopsis: Convert criterion output to HTML reports
+License: BSD3
+License-file: LICENSE
+Author: Jasper Van der Jeugt
+Maintainer: m@jaspervdj.be
+Category: Development
+Build-type: Simple
+Homepage: http://github.com/jaspervdj/criterion-to-html
+Bug-Reports: http://github.com/jaspervdj/criterion-to-html/issues
+Cabal-version: >= 1.2
+
+Description:
+ A program to convert criterion output (a CSV file) to an HTML which has some
+ quick and dirty plots to compare the results. To generate the CSV file, run
+ your criterion benchmark using the @-u@ flag:
+
+ .
+
+ > some-criterion-benchmark -u results.csv
+
+ .
+
+ You can then convert the CSV results to some simple HTML plots using this
+ program:
+
+ .
+
+ > criterion-to-html results.csv
+
+ .
+
+
+Source-Repository head
+ Type: git
+ Location: git://github.com/jaspervdj/criterion-to-html.git
+
+Executable criterion-to-html
+ Hs-source-dirs: src/
+ Main-is: Criterion/ToHtml.hs
+ Build-depends:
+ base >= 4 && < 5,
+ blaze-html >= 0.4 && < 0.5,
+ bytestring >= 0.9 && < 0.10,
+ filepath >= 1.1 && < 1.3
+ Other-modules:
+ Criterion.ToHtml.Csv,
+ Criterion.ToHtml.Html,
+ Criterion.ToHtml.Result
32 src/Criterion/ToHtml.hs
@@ -0,0 +1,32 @@
+-- | Main module
+--
+module Main
+ ( main
+ ) where
+
+import Control.Applicative ((<$>))
+import System.Environment (getArgs, getProgName)
+import System.FilePath (replaceExtension)
+
+import Text.Blaze.Renderer.Utf8 (renderHtml)
+import qualified Data.ByteString.Lazy as BL
+
+import Criterion.ToHtml.Html
+import Criterion.ToHtml.Result
+
+toHtml' :: FilePath -> FilePath -> IO ()
+toHtml' csv html = do
+ putStrLn $ "Parsing " ++ csv
+ csv' <- parseCriterionCsv <$> readFile csv
+ BL.writeFile html $ renderHtml $ table csv'
+ putStrLn $ "Wrote " ++ html
+
+main :: IO ()
+main = do
+ args <- getArgs
+ progName <- getProgName
+ case args of
+ [csv, html] -> toHtml' csv html
+ [csv] -> toHtml' csv (replaceExtension csv "html")
+ _ -> putStrLn $
+ "Usage: " ++ progName ++ " <csv-file> [out-file]"
36 src/Criterion/ToHtml/Csv.hs
@@ -0,0 +1,36 @@
+-- | Simple CSV parser
+--
+module Criterion.ToHtml.Csv
+ ( Field
+ , Record
+ , Csv
+ , parseCsv
+ ) where
+
+type Field = String
+type Record = [Field]
+type Csv = [Record]
+
+-- | Parse a CSV file
+--
+parseCsv :: String -> Csv
+parseCsv = map parseRecord . lines
+
+-- | Parse a CSV record
+--
+parseRecord :: String -> Record
+parseRecord rec = case parseField rec of
+ (x, ',' : y) -> x : parseRecord y
+ (x, _) -> [x]
+
+-- | Parse a CSV field
+--
+parseField :: String -> (Field, String)
+parseField xs = case xs of
+ ('"' : xs') -> parse' "" xs'
+ _ -> break (== ',') xs
+ where
+ parse' y ('"' : '"' : ys) = parse' ('"' : y) ys
+ parse' y ('"' : ys) = (reverse y, ys)
+ parse' y (y' : ys) = parse' (y' : y) ys
+ parse' y [] = (reverse y, "")
38 src/Criterion/ToHtml/Html.hs
@@ -0,0 +1,38 @@
+-- | Output the results to HTML
+--
+{-# LANGUAGE OverloadedStrings #-}
+module Criterion.ToHtml.Html
+ ( table
+ ) where
+
+import Data.Monoid (mappend)
+import Text.Printf (printf)
+
+import Text.Blaze (Html, toHtml, toValue, preEscapedString, (!))
+import qualified Text.Blaze.Html5 as H
+import qualified Text.Blaze.Html5.Attributes as A
+
+import Criterion.ToHtml.Result
+
+table :: [Result] -> Html
+table results = H.docTypeHtml $ do
+ H.head $ H.title "Criterion results"
+ H.body $ do
+ H.table ! A.style "width: 100%;" $ do
+ H.tr $ do
+ H.th "Name"
+ H.th "Mean"
+ mapM_ row $ normalizeMeans results
+
+row :: (Result, Double) -> Html
+row (Result name _, n) = H.tr $ do
+ H.td $ toHtml name
+ H.td ! A.style "width: 100%" $
+ H.div ! A.style (backgroundColor `mappend` "; " `mappend` width)
+ $ preEscapedString "&nbsp;"
+ where
+ width = toValue $ "width: " ++ show (round (n * 100) :: Int) ++ "%"
+ backgroundColor = toValue
+ (printf "background-color: rgb(%d, %d, %d)" r g b :: String)
+ r, g, b :: Int
+ (r, g, b) = (round (150 * n), round (150 * (1 - n)), 0)
35 src/Criterion/ToHtml/Result.hs
@@ -0,0 +1,35 @@
+-- | Parse Criterion results
+--
+module Criterion.ToHtml.Result
+ ( Result (..)
+ , parseCriterionCsv
+ , normalizeMeans
+ ) where
+
+import Criterion.ToHtml.Csv
+
+-- | A criterion result
+--
+data Result = Result
+ { resultName :: String
+ , resultMean :: Double
+ }
+
+-- | Parse a Criterion CSV file
+--
+parseCriterionCsv :: String -> [Result]
+parseCriterionCsv = map parseCriterionResult . drop 1 . parseCsv
+
+-- | Parse a single result
+--
+parseCriterionResult :: Record -> Result
+parseCriterionResult (name : mean : _) = Result name (read mean)
+parseCriterionResult _ = error
+ "Criterion.ToHtml.Parse.parseCriterionResult: invalid CSV file"
+
+normalizeMeans :: [Result] -> [(Result, Double)]
+normalizeMeans [] = []
+normalizeMeans results = map normalize results
+ where
+ normalize result = (result, resultMean result / max')
+ max' = maximum $ map resultMean results

0 comments on commit fd8343a

Please sign in to comment.