perf-0.2.0: examples/examples.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
import qualified Data.List as List
import qualified Data.Text as Text
import Data.Text.IO (writeFile, readFile)
import qualified Data.Map as Map
import qualified Data.Vector as V
import qualified Data.Vector.Storable as S
import qualified Data.Vector.Unboxed as U
import Formatting
import Options.Generic
import NumHask.Prelude hiding ((%))
import Perf
data Opts = Opts
{ runs :: Maybe Int -- <?> "number of runs"
, sumTo :: Maybe Double -- <?> "sum to this number"
} deriving (Generic, Show)
instance ParseRecord Opts
ticks :: Int -> (a -> b) -> a -> IO ([Cycle], b)
ticks n f a = do
ts <- replicateM' n (tick f a)
pure (fst <$> ts, snd $ List.last ts)
qtick :: Int -> (a -> b) -> a -> IO (Double, b)
qtick n f a = do
ts <- replicateM' n (tick f a)
pure (percentile 0.4 $ fst <$> ts, snd $ List.last ts)
main :: IO ()
main = do
o :: Opts <- getRecord "a random bit of text"
let n = fromMaybe 1000 (runs o)
let a = fromMaybe 10000 (sumTo o)
-- perf
-- prior to Perfification
result <- do
txt <- readFile "examples/examples.hs"
let n = Text.length txt
let x = foldl' (+) 0 [1..n]
putStrLn $ "sum of one to number of characters is: " <>
(show x :: Text)
pure (n, x)
-- post-Perfification
(result', ms) <- runPerfT $ do
txt <- perf "file read" cycles $ readFile "examples/examples.hs"
n <- perf "length" cycles $ pure (Text.length txt)
x <- perf "sum" cycles $ pure (foldl' (+) 0 [1..n])
perf "print to screen" cycles $
putStrLn $ "sum of one to number of characters is: " <>
(show x :: Text)
pure (n, x)
when (result == result') $ print "PerfT preserves computations"
let fmt = sformat ((right 40 ' ' %. stext) %prec 3 % " " % stext)
writeFile "other/perf.md" $
"\nperf cycle measurements\n---\n" <>
code ((\(t,c) -> fmt t c "cycles") <$> Map.toList ms)
-- | tick_
onetick <- tick_
ticks' <- replicateM 10 tick_
manyticks <- replicateM 1000000 tick_
let avticks = average manyticks
let qticks = deciles 10 manyticks
let tick999 = percentile 0.999 manyticks
let tick99999 = percentile 0.99999 manyticks
let tick99 = percentile 0.99 manyticks
let tick40 = percentile 0.4 manyticks
writeFile "other/tick_.md" $
code
[ "one tick_: " <> show onetick <> " cycles"
, "next 10: " <> show ticks'
, "average over 1m: " <> sformat (fixed 2) avticks <> " cycles"
, "99.999% perc: " <> sformat commas (floor tick99999 :: Integer)
, "99.9% perc: " <> sformat (fixed 2) tick999
, "99th perc: " <> sformat (fixed 2) tick99
, "40th perc: " <> sformat (fixed 2) tick40
, "[min, 10th, 20th, .. 90th, max]:"
, mconcat (sformat (" " % prec 4) <$> qticks)
]
-- tick
_ <- warmup 100
let f x = foldl' (+) 0 [1 .. x]
(t, _) <- tick f a
(ts, _) <- Main.ticks n f a
let qt x = (`percentile` x) <$> [0, 0.3, 0.5, 0.9, 0.99, 1]
writeFile "other/tick.md" $
code
[ "sum to " <> show a
, "first measure: " <> show t <> " cycles"
, "average over next " <> show n <> ": " <> sformat (fixed 2) (average ts) <>
" cycles"
, "[min, 30th, median, 90th, 99th, max]:"
, mconcat (sformat (" " % prec 4) <$> qt ts)
]
-- | ticks & friends
(cs, _) <- Perf.ticks n f a
let ft cs t =
sformat
((right 40 ' ' %. stext) % prec 3 % " cycles")
t
(percentile 0.4 cs)
let r1 = ft cs "Perf.ticks n f a"
(cs, _) <- Main.ticks n f a
let r2 = ft cs "Main.ticks n f a"
(cs, _) <- Perf.ticksIO n (pure $ f a)
let r3 = ft cs "Perf.ticksIO n (pure $ f a)"
(c, _) <- Perf.qtick n f a
let fq c t = sformat ((right 40 ' ' %. stext) %prec 3 % " cycles") t c
let r4 = fq c "Perf.qtick n f a"
(c, _) <- Main.qtick n f a
let r5 = fq c "Main.qtick n f a"
cs <- fmap fst <$> replicateM n (tick f a)
let r6 = ft cs "replicateM n (tick f a)"
cs <- fmap fst <$> replicateM' n (tick f a)
let r7 = ft cs "replicateM' n (tick f a)"
cs <- fmap fst <$> replicateM n (tickIO (pure (f a)))
let r8 = ft cs "replicateM n (tickIO (pure (f a)))"
cs <- fmap fst <$> replicateM n (tick (app (f a)) ())
let r9 = ft cs "replicateM n (tick (app (f a)) ())"
cs <- fmap fst <$> replicateM n (tick identity (f a))
let r10 = ft cs "replicateM n (tick identity (f a))"
cs <- fmap fst <$> replicateM n (tick (const (f a)) ())
let r11 = ft cs "replicateM n (tick (const (f a)) ())"
css <-
fmap (fmap fst) <$>
sequence ((replicateM n . tick f) <$> [1, 10, 100, 1000, 10000 :: Int])
let r12 =
"(replicateM n . tick f) <$> [1,10,100,1000,10000]: " <>
mconcat (sformat (" " %prec 3) <$> (percentile 0.4 <$> css))
(ts, _) <- Perf.tickns n f [1, 10, 100, 1000, 10000 :: Int]
let r13 =
"Perf.tickns n f [1,10,100,1000,10000]: " <>
mconcat (sformat (" " %prec 3) <$> (percentile 0.4 <$> ts))
writeFile "other/ticks.md" $
code ["sum to " <> show a, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13]
-- vectors
let sumv :: V.Vector Double -> Double
sumv = V.foldl (+) 0
let asv :: V.Vector Double =
(\x -> V.generate (fromIntegral $ floor x) fromIntegral) a
(t, _) <- Perf.ticks n sumv asv
let rboxed = sformat ("boxed: " %prec 3) (percentile 0.4 t)
let sums :: S.Vector Double -> Double
sums = S.foldl (+) 0
let ass :: S.Vector Double =
(\x -> S.generate (fromIntegral $ floor x) fromIntegral) a
(t, _) <- Perf.ticks n sums ass
let rstorable = sformat ("storable: " %prec 3) (percentile 0.4 t)
let sumu :: U.Vector Double -> Double
sumu = U.foldl (+) 0
let asu :: U.Vector Double =
(\x -> U.generate (fromIntegral $ floor x) fromIntegral) a
(t, _) <- Perf.ticks n sumu asu
let runboxed = sformat ("unboxed: " %prec 3) (percentile 0.4 t)
writeFile "other/vector.md" $
code ["sum to " <> show a, rboxed, rstorable, runboxed]
(t, _) <- Perf.ticks n f a
putStrLn $ sformat ("Perf.Cycle.ticks n f a: " %prec 3) (percentile 0.4 t)
-- perf basics
(result, cs) <- runPerfT $
perf "sum" cycles (pure $ foldl' (+) 0 [0..10000 :: Integer])
putStrLn (show (result, cs) :: Text)
code :: [Text] -> Text
code cs = "\n```\n" <> Text.intercalate "\n" cs <> "\n```\n"