perf-0.3.1.0: examples/examples.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Main where
import qualified Data.Text as Text
import Data.Text.IO (writeFile)
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
import Data.Scientific
data Opts = Opts
{ runs :: Maybe Int -- <?> "number of runs"
, sumTo :: Maybe Int -- <?> "sum to this number"
, sumsTo :: Maybe [Int] -- <?> "sum to these numbers"
, flipMaybe :: Maybe Bool
} deriving (Generic, Show)
instance ParseField [Int]
instance ParseRecord Opts
ticksInFile :: (NFData b) => Int -> (a -> b) -> a -> IO ([Cycle], b)
ticksInFile n0 f a = go f a n0 []
where
go f a n ts
| n <= 0 = pure (ts, f a)
| otherwise = do
(t,_) <- tick f a
go f a (n - 1) (t:ts)
fLambda :: Int -> Int
fLambda = \x -> foldl' (+) 0 [1 .. x]
fMono :: Int -> Int
fMono x = foldl' (+) 0 [1 .. x]
fPoly :: (Enum b, Num b, Additive b) => b -> b
fPoly x = foldl' (+) 0 [1 .. x]
prec :: Int -> Format r (Scientific -> r)
prec n = scifmt Exponent (Just n)
int2Sci :: ToInteger a => a -> Scientific
int2Sci n = scientific (fromIntegral n) 0
formatone :: (ToInteger a) => Text -> Int -> a -> Text
formatone t p x =
sformat
((right 24 ' ' %. stext) %
(left 8 ' ' %. prec p) % " cycles") t (int2Sci x)
runone :: (ToInteger a) => Text -> Int -> IO (a, b) -> IO Text
runone label p t = formatone label p . fst <$> t
main :: IO ()
main = do
o :: Opts <- getRecord "a random bit of text"
let n = fromMaybe 1000 (runs o)
let a = fromMaybe 1000 (sumTo o)
let !a' = fromIntegral a
let !a'' = a'+1
let !a''' = a'+1
let as = [1, 10, 100, 1000 :: Int]
let fm = fromMaybe True (flipMaybe o)
writeFile "other/run.md" $
code
[ sformat ((right 24 ' ' %. stext)%prec 1) "number of runs:" (int2Sci n)
, sformat ((right 24 ' ' %. stext)%prec 1) "accumulate to:" (int2Sci a)
, sformat ((right 24 ' ' %. stext)%stext) "function:" "foldl' (+) 0"
]
let formatRun :: [Cycle] -> Text -> Int -> Text
formatRun cs label p =
sformat
((right 24 ' ' %. stext) % stext %
(left 7 ' ' %. prec p) % " cycles")
label
(Text.intercalate " " $ sformat (left 7 ' ' %. prec p) .
int2Sci <$>
take 5 cs)
(fromFloatDigits $ percentile 0.4 cs)
let formatRunHeader =
sformat
((right 24 ' ' %. stext) %
(left 7 ' ' %. stext) %
(left 8 ' ' %. stext) %
(left 8 ' ' %. stext) %
(left 8 ' ' %. stext) %
(left 8 ' ' %. stext) %
(left 8 ' ' %. stext))
"run"
"first"
"2nd"
"3rd"
"4th"
"5th"
"40th %"
let run label p t = (\x -> formatRun x label p) . fst <$> t
_ <- warmup 100
-- | 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) . fromFloatDigits <$> qticks)
]
-- tick
(t, resultPrime) <- tick fMono a'
print resultPrime
(t2,_) <- tick fMono a'
writeFile "other/tick.md" $
code
[ "sum to " <> show a
, "first measure: " <> show t <> " cycles"
, "second measure: " <> show t2 <> " cycles"
]
-- | various versions of tick
rpure <- run "ticks" 2 $ ticks n fMono a'
rpurePoly <- run "ticks (poly)" 2 $ ticks n fPoly a
rpureLambda <- run "ticks (lambda)" 2 $ ticks n fLambda a'
rio <- run "ticksIO" 2 $ ticksIO n (pure $ fMono a'')
rioPoly <- run "ticksIO (poly)" 2 $ ticksIO n (pure $ fPoly a)
rioLambda <- run "ticksIO (lambda)" 2 $ ticksIO n (pure $ fLambda a')
writeFile "other/ticks.md" $
code [ "sum to " <> show a <> " n = " <> show n <> " prime run: " <>
sformat (prec 3) (int2Sci t)
, formatRunHeader
, rpure
, rpureLambda
, rpurePoly
, rio
, rioLambda
, rioPoly
]
-- | overall ticks cost
let formatGap :: Int -> (Cycle, ([Cycle],b)) -> Text
formatGap a (co, (ci, _)) =
sformat
("n = " %(left 7 ' ' %. prec 3)%" outside: "%(left 7 ' ' %. prec 3)%" inside: "%(left 7 ' ' %. prec 3)%" gap: "%(left 7 ' ' %. prec 3))
(int2Sci a) (int2Sci co) (int2Sci $ sum ci) (int2Sci $ co - sum ci)
let runGap t a = formatGap a <$> tickIO t
gaps <- sequence $ (\a -> runGap (ticks n fPoly a) a) <$> as
writeFile "other/ticksCost.md" $ code gaps
-- | ns
css <-
fmap (fmap fst) <$>
sequence ((replicateM n . tick fMono) <$> as)
let r12 =
"(replicateM n . tick fMono) <$> as: " <>
mconcat (sformat (" " %prec 3) <$> (fromFloatDigits . percentile 0.4 <$> css))
(ts, _) <-ns (ticks n fMono) as
let r13 =
"ns (ticks n fMono) as: " <>
mconcat (sformat (" " %prec 3) <$> (fromFloatDigits . percentile 0.4 <$> ts))
writeFile "other/tickns.md" $
code ["sum to's " <> show as, r13, r12]
-- | vectors
let asl :: [Int]
asl = [1 .. a]
let suml :: [Int] -> Int
suml = foldl' (+) 0
rlist <- run "ticks list" 2 $ ticks n suml asl
let sumv :: V.Vector Int -> Int
sumv = V.foldl (+) 0
let asv :: V.Vector Int =
V.generate a identity
rboxed <- run "ticks boxed" 2 $ ticks n sumv asv
let sums :: S.Vector Int -> Int
sums = S.foldl (+) 0
let ass :: S.Vector Int =
S.generate a identity
rstorable <- run "ticks storable" 2 $ ticks n sums ass
let sumu :: U.Vector Int -> Int
sumu = U.foldl (+) 0
let asu :: U.Vector Int =
U.generate a identity
runboxed <- run "ticks unboxed" 2 $ ticks n sumu asu
writeFile "other/vector.md" $
code ["sum to " <> show a, rlist, rboxed, rstorable, runboxed]
-- WHNF
let just' x
| fm = Just x
| otherwise = Nothing
rnf <- runone "tick" 2 $ tick (fmap fMono) (just' a')
rwhnf <- runone "tickWHNF" 2 $ tick (fmap fMono) (just' a')
rnfs <- run "ticks" 2 $ ticks n (fmap fMono) (just' a')
rwhnfs <- run "ticksWHNF" 2 $ ticksWHNF n (fmap fMono) (just' a')
rnfio <- runone "tickIO" 2 $ tickIO (pure $ fmap fMono (just' a'))
rwhnfio <- runone "tickWHNFIO" 2 $ tickWHNFIO (pure $ fmap fMono (just' a'))
rnfsio <- run "ticksIO" 2 $ ticksIO n (pure $ fmap fMono (just' a'''))
rwhnfsio <- run "ticksWHNFIO" 2 $ ticksWHNFIO n (pure $ fmap fMono (just' a'))
writeFile "other/whnf.md" $
code ["sum to " <> show a,
rnf, rwhnf, rnfs, rwhnfs, rnfio, rwhnfio, rnfsio, rwhnfsio]
{-
-- perf basics
(result, cs) <- runPerfT $
perf "sum" cycles (pure $ foldl' (+) 0 [0 .. floor a :: Integer])
putStrLn (show (result, cs) :: Text)
-- PerfT example
-- 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 preserving 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)
-}
code :: [Text] -> Text
code cs = "\n```\n" <> Text.intercalate "\n" cs <> "\n```\n"