1{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}
4import Control.Monad (forM_)
5import Data.Accessor ((^=))
10import Data.Text (Text)
11import Data.Text.Encoding (decodeUtf8)
12import Graphics.Rendering.Chart
13import Graphics.Rendering.Chart.Gtk (renderableToWindow)
14import System.Environment (getArgs)
16import qualified Data.ByteString as B
17import qualified Data.Map as M
18import qualified Data.Text as T
23 , rowMeanLB :: !Double
24 , rowMeanUB :: !Double
25 , rowStdDev :: !Double
26 , rowStdDevLB :: !Double
27 , rowStdDevUB :: !Double
30parseRow :: Text -> Row
31parseRow = f . T.split ","
32 where f [n,m,ml,mu,s,sl,su] = Row {
43readCSV :: FilePath -> IO [Row]
44readCSV = fmap (map parseRow . tail . T.lines . decodeUtf8) . B.readFile
46groupRows :: [Row] -> M.Map Text [Row]
47groupRows = M.map (sortBy (compare `on` rowName)) . foldr f M.empty
48 where f r m = let (p,s) = T.breakEnd "/" (rowName r)
49 in M.insertWith' (++) (T.init . T.tail $ p)
50 [r { rowName = T.init s}] m
54 groups <- mapM (fmap groupRows . readCSV) args
55 let dd = M.unionsWith (++) . map (M.map (:[])) $ groups
56 forM_ (M.toList dd) $ \(tdesc,rows) -> do
57 let desc = T.unpack tdesc
59 then renderableToWindow (renderMark desc rows) 400 160
60 else renderableToPNGFile (renderMark desc rows) 400 160
61 (printf "time-%s.png" (map clean desc))
63 clean c | isSpace c = '-'
66instance BarsPlotValue LogValue where
67 barsReference = LogValue 1e-300
68 barsAdd (LogValue a) (LogValue b) = LogValue (a * b)
70renderMark :: String -> [[Row]] -> Renderable ()
72 | useLog = toRenderable linLayout
73 | otherwise = toRenderable logLayout
75 useLog = minimum (map minimum values) >= maximum (map maximum values) / 25
76 values = transpose . map (map rowMean) $ rows
77 keys = map git (head rows)
78 where git r = let n = T.unpack . rowName $ r
79 in maybe n id . flip lookup mappings $ n
80 mappings = [("bl", "lazy BS"), ("bs", "strict BS"), ("l", "list"),
81 ("tl", "lazy T"), ("ts", "strict T")]
83 linLayout = layout1_title ^= "Timings for \"" ++ desc ++ "\""
84 $ layout1_plots ^= [ Left (plotBars linBars) ]
85 $ layout1_left_axis ^= linLeftAxis
86 $ layout1_bottom_axis ^= bottomAxis
87 $ defaultLayout1 :: Layout1 Double Double
89 logLayout = layout1_title ^= "Timings for \"" ++ desc ++
91 $ layout1_plots ^= [ Left (plotBars logBars) ]
92 $ layout1_left_axis ^= logLeftAxis
93 $ layout1_bottom_axis ^= bottomAxis
94 $ defaultLayout1 :: Layout1 Double LogValue
96 logLeftAxis = laxis_generate ^= autoScaledLogAxis logSecAxis
97 $ laxis_reverse ^= False
100 linLeftAxis = laxis_generate ^= autoScaledAxis linSecAxis
103 bottomAxis = laxis_generate ^= autoScaledAxis typeAxis
106 linBars = plot_bars_values ^= (zip [0.5,1.5..] values)
109 logBars = plot_bars_values ^= (zip [0.5,1.5..] . map (map LogValue) $ values)
112 typeAxis = la_labelf ^= (ix keys . floor)
113 $ la_nLabels ^= length keys
116 ix (x:xs) n | n <= 0 = x
117 | otherwise = ix xs (n-1)
120 linSecAxis = la_labelf ^= secs
123 logSecAxis = loga_labelf ^= (secs . fromLV)
126 fromLV (LogValue v) = v
128-- | Try to render meaningful time-axis labels.
130-- /FIXME/: Trouble is, we need to know the range of times for this to
131-- work properly, so that we don't accidentally display consecutive
132-- values that appear identical (e.g. \"43 ms, 43 ms\").
133secs :: Double -> String
135 | k < 0 = '-' : secs (-k)
136 | k >= 1e9 = (k/1e9) `with` "Gs"
137 | k >= 1e6 = (k/1e6) `with` "Ms"
138 | k >= 1e4 = (k/1e3) `with` "Ks"
139 | k >= 1 = k `with` "s"
140 | k >= 1e-3 = (k*1e3) `with` "ms"
141 | k >= 1e-6 = (k*1e6) `with` "µs"
142 | k >= 1e-9 = (k*1e9) `with` "ns"
143 | k >= 1e-12 = (k*1e12) `with` "ps"
144 | otherwise = printf "%g s" k
145 where with (t :: Double) (u :: String)
146 | t >= 1e9 = printf "%.4g %s" t u
147 | t >= 1e6 = printf "%.0f %s" t u
148 | t >= 1e5 = printf "%.0f %s" t u
149 | t >= 1e4 = printf "%.0f %s" t u
150 | t >= 1e3 = printf "%.0f %s" t u
151 | t >= 1e2 = printf "%.0f %s" t u
152 | t >= 1e1 = printf "%.0f %s" t u
153 | otherwise = printf "%.0f %s" t u
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list