{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE RebindableSyntax #-}
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Perf.Cycle
(
Cycle,
tick_,
warmup,
tick,
tick',
tickIO,
tickNoinline,
ticks,
ticksIO,
ns,
tickWHNF,
tickWHNF',
tickWHNFIO,
ticksWHNF,
ticksWHNFIO,
)
where
import Control.DeepSeq (NFData (..), force)
import qualified Control.Foldl as L (fold, genericLength, premap, sum)
import Control.Monad (replicateM)
import Data.Foldable (toList)
import Data.Sequence (Seq (..))
import GHC.Word (Word64)
import System.CPUTime.Rdtsc
import Prelude
type Cycle = Word64
tick_ :: IO Cycle
tick_ :: IO Cycle
tick_ = do
Cycle
t <- IO Cycle
rdtsc
Cycle
t' <- IO Cycle
rdtsc
Cycle -> IO Cycle
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Cycle
t' Cycle -> Cycle -> Cycle
forall a. Num a => a -> a -> a
- Cycle
t)
warmup :: Int -> IO Double
warmup :: Int -> IO Double
warmup Int
n = do
[Cycle]
ts <- Int -> IO Cycle -> IO [Cycle]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM Int
n IO Cycle
tick_
Double -> IO Double
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Double -> IO Double) -> Double -> IO Double
forall a b. (a -> b) -> a -> b
$ [Cycle] -> Double
forall a (f :: * -> *). (Integral a, Foldable f) => f a -> Double
average [Cycle]
ts
tick' :: (NFData b) => (a -> b) -> a -> IO (Cycle, b)
tick' :: (a -> b) -> a -> IO (Cycle, b)
tick' a -> b
f a
a = do
!Cycle
t <- IO Cycle
rdtsc
!b
a' <- b -> IO b
forall (f :: * -> *) a. Applicative f => a -> f a
pure (b -> b
forall a. NFData a => a -> a
force (b -> b) -> b -> b
forall a b. (a -> b) -> a -> b
$ a -> b
f a
a)
!Cycle
t' <- IO Cycle
rdtsc
(Cycle, b) -> IO (Cycle, b)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Cycle
t' Cycle -> Cycle -> Cycle
forall a. Num a => a -> a -> a
- Cycle
t, b
a')
{-# INLINE tick' #-}
tick :: (NFData b) => (a -> b) -> a -> IO (Cycle, b)
tick :: (a -> b) -> a -> IO (Cycle, b)
tick !a -> b
f !a
a = (a -> b) -> a -> IO (Cycle, b)
forall b a. NFData b => (a -> b) -> a -> IO (Cycle, b)
tick' a -> b
f a
a
{-# INLINE tick #-}
tickNoinline :: (NFData b) => (a -> b) -> a -> IO (Cycle, b)
tickNoinline :: (a -> b) -> a -> IO (Cycle, b)
tickNoinline !a -> b
f !a
a = (a -> b) -> a -> IO (Cycle, b)
forall b a. NFData b => (a -> b) -> a -> IO (Cycle, b)
tick' a -> b
f a
a
{-# NOINLINE tickNoinline #-}
tickIO :: (NFData a) => IO a -> IO (Cycle, a)
tickIO :: IO a -> IO (Cycle, a)
tickIO IO a
a = do
Cycle
t <- IO Cycle
rdtsc
!a
a' <- a -> a
forall a. NFData a => a -> a
force (a -> a) -> IO a -> IO a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO a
a
Cycle
t' <- IO Cycle
rdtsc
(Cycle, a) -> IO (Cycle, a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Cycle
t' Cycle -> Cycle -> Cycle
forall a. Num a => a -> a -> a
- Cycle
t, a
a')
tickIONoinline :: (NFData a) => IO a -> IO (Cycle, a)
tickIONoinline :: IO a -> IO (Cycle, a)
tickIONoinline = IO a -> IO (Cycle, a)
forall a. NFData a => IO a -> IO (Cycle, a)
tickIO
{-# NOINLINE tickIONoinline #-}
ticks :: NFData b => Int -> (a -> b) -> a -> IO ([Cycle], b)
ticks :: Int -> (a -> b) -> a -> IO ([Cycle], b)
ticks Int
n0 a -> b
f a
a = (a -> b) -> a -> Int -> Seq Cycle -> IO ([Cycle], b)
forall t t t.
(Ord t, Num t) =>
t -> t -> t -> Seq Cycle -> IO ([Cycle], b)
go a -> b
f a
a Int
n0 Seq Cycle
forall a. Seq a
Empty
where
go :: t -> t -> t -> Seq Cycle -> IO ([Cycle], b)
go t
f' t
a' t
n Seq Cycle
ts
| t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
<= t
0 = ([Cycle], b) -> IO ([Cycle], b)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Seq Cycle -> [Cycle]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Seq Cycle
ts, a -> b
f a
a)
| Bool
otherwise = do
(Cycle
t, b
_) <- (a -> b) -> a -> IO (Cycle, b)
forall b a. NFData b => (a -> b) -> a -> IO (Cycle, b)
tickNoinline a -> b
f a
a
t -> t -> t -> Seq Cycle -> IO ([Cycle], b)
go t
f' t
a' (t
n t -> t -> t
forall a. Num a => a -> a -> a
- t
1) (Seq Cycle
ts Seq Cycle -> Cycle -> Seq Cycle
forall a. Seq a -> a -> Seq a
:|> Cycle
t)
{-# NOINLINE ticks #-}
ticksIO :: (NFData a) => Int -> IO a -> IO ([Cycle], a)
ticksIO :: Int -> IO a -> IO ([Cycle], a)
ticksIO Int
n0 IO a
a = IO a -> Int -> Seq Cycle -> IO ([Cycle], a)
forall t a.
(Ord t, Num t, NFData a) =>
IO a -> t -> Seq Cycle -> IO ([Cycle], a)
go IO a
a Int
n0 Seq Cycle
forall a. Seq a
Empty
where
go :: IO a -> t -> Seq Cycle -> IO ([Cycle], a)
go IO a
a' t
n Seq Cycle
ts
| t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
<= t
0 = do
a
a'' <- IO a
a'
([Cycle], a) -> IO ([Cycle], a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Seq Cycle -> [Cycle]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Seq Cycle
ts, a
a'')
| Bool
otherwise = do
(Cycle
t, a
_) <- IO a -> IO (Cycle, a)
forall a. NFData a => IO a -> IO (Cycle, a)
tickIONoinline IO a
a'
IO a -> t -> Seq Cycle -> IO ([Cycle], a)
go IO a
a' (t
n t -> t -> t
forall a. Num a => a -> a -> a
- t
1) (Seq Cycle
ts Seq Cycle -> Cycle -> Seq Cycle
forall a. Seq a -> a -> Seq a
:|> Cycle
t)
{-# NOINLINE ticksIO #-}
ns :: (a -> IO ([Cycle], b)) -> [a] -> IO ([[Cycle]], [b])
ns :: (a -> IO ([Cycle], b)) -> [a] -> IO ([[Cycle]], [b])
ns a -> IO ([Cycle], b)
t [a]
as = do
[([Cycle], b)]
cs <- [IO ([Cycle], b)] -> IO [([Cycle], b)]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence ([IO ([Cycle], b)] -> IO [([Cycle], b)])
-> [IO ([Cycle], b)] -> IO [([Cycle], b)]
forall a b. (a -> b) -> a -> b
$ a -> IO ([Cycle], b)
t (a -> IO ([Cycle], b)) -> [a] -> [IO ([Cycle], b)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [a]
as
([[Cycle]], [b]) -> IO ([[Cycle]], [b])
forall (f :: * -> *) a. Applicative f => a -> f a
pure (([Cycle], b) -> [Cycle]
forall a b. (a, b) -> a
fst (([Cycle], b) -> [Cycle]) -> [([Cycle], b)] -> [[Cycle]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [([Cycle], b)]
cs, ([Cycle], b) -> b
forall a b. (a, b) -> b
snd (([Cycle], b) -> b) -> [([Cycle], b)] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [([Cycle], b)]
cs)
average :: (Integral a, Foldable f) => f a -> Double
average :: f a -> Double
average = Fold a Double -> f a -> Double
forall (f :: * -> *) a b. Foldable f => Fold a b -> f a -> b
L.fold ((a -> Double) -> Fold Double Double -> Fold a Double
forall a b r. (a -> b) -> Fold b r -> Fold a r
L.premap a -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Double -> Double -> Double
forall a. Fractional a => a -> a -> a
(/) (Double -> Double -> Double)
-> Fold Double Double -> Fold Double (Double -> Double)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Fold Double Double
forall a. Num a => Fold a a
L.sum Fold Double (Double -> Double)
-> Fold Double Double -> Fold Double Double
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Fold Double Double
forall b a. Num b => Fold a b
L.genericLength))
tickWHNF :: (a -> b) -> a -> IO (Cycle, b)
tickWHNF :: (a -> b) -> a -> IO (Cycle, b)
tickWHNF !a -> b
f !a
a = (a -> b) -> a -> IO (Cycle, b)
forall a b. (a -> b) -> a -> IO (Cycle, b)
tickWHNF' a -> b
f a
a
tickWHNFNoinline :: (a -> b) -> a -> IO (Cycle, b)
tickWHNFNoinline :: (a -> b) -> a -> IO (Cycle, b)
tickWHNFNoinline !a -> b
f !a
a = (a -> b) -> a -> IO (Cycle, b)
forall a b. (a -> b) -> a -> IO (Cycle, b)
tickWHNF' a -> b
f a
a
{-# NOINLINE tickWHNFNoinline #-}
tickWHNF' :: (a -> b) -> a -> IO (Cycle, b)
tickWHNF' :: (a -> b) -> a -> IO (Cycle, b)
tickWHNF' a -> b
f a
a = do
!Cycle
t <- IO Cycle
rdtsc
!b
a' <- b -> IO b
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> b
f a
a)
!Cycle
t' <- IO Cycle
rdtsc
(Cycle, b) -> IO (Cycle, b)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Cycle
t' Cycle -> Cycle -> Cycle
forall a. Num a => a -> a -> a
- Cycle
t, b
a')
tickWHNFIO :: IO a -> IO (Cycle, a)
tickWHNFIO :: IO a -> IO (Cycle, a)
tickWHNFIO IO a
a = do
Cycle
t <- IO Cycle
rdtsc
!a
a' <- IO a
a
Cycle
t' <- IO Cycle
rdtsc
(Cycle, a) -> IO (Cycle, a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Cycle
t' Cycle -> Cycle -> Cycle
forall a. Num a => a -> a -> a
- Cycle
t, a
a')
tickWHNFIONoinline :: IO a -> IO (Cycle, a)
tickWHNFIONoinline :: IO a -> IO (Cycle, a)
tickWHNFIONoinline = IO a -> IO (Cycle, a)
forall a. IO a -> IO (Cycle, a)
tickWHNFIO
{-# NOINLINE tickWHNFIONoinline #-}
ticksWHNF :: Int -> (a -> b) -> a -> IO ([Cycle], b)
ticksWHNF :: Int -> (a -> b) -> a -> IO ([Cycle], b)
ticksWHNF Int
n0 a -> b
f a
a = (a -> b) -> a -> Int -> Seq Cycle -> IO ([Cycle], b)
forall t t t.
(Ord t, Num t) =>
t -> t -> t -> Seq Cycle -> IO ([Cycle], b)
go a -> b
f a
a Int
n0 Seq Cycle
forall a. Seq a
Empty
where
go :: t -> t -> t -> Seq Cycle -> IO ([Cycle], b)
go t
f' t
a' t
n Seq Cycle
ts
| t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
<= t
0 = ([Cycle], b) -> IO ([Cycle], b)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Seq Cycle -> [Cycle]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Seq Cycle
ts, a -> b
f a
a)
| Bool
otherwise = do
(Cycle
t, b
_) <- (a -> b) -> a -> IO (Cycle, b)
forall a b. (a -> b) -> a -> IO (Cycle, b)
tickWHNFNoinline a -> b
f a
a
t -> t -> t -> Seq Cycle -> IO ([Cycle], b)
go t
f' t
a' (t
n t -> t -> t
forall a. Num a => a -> a -> a
- t
1) (Seq Cycle
ts Seq Cycle -> Cycle -> Seq Cycle
forall a. Seq a -> a -> Seq a
:|> Cycle
t)
{-# NOINLINE ticksWHNF #-}
ticksWHNFIO :: Int -> IO a -> IO ([Cycle], a)
ticksWHNFIO :: Int -> IO a -> IO ([Cycle], a)
ticksWHNFIO Int
n0 IO a
a = IO a -> Int -> Seq Cycle -> IO ([Cycle], a)
forall t a.
(Ord t, Num t) =>
IO a -> t -> Seq Cycle -> IO ([Cycle], a)
go IO a
a Int
n0 Seq Cycle
forall a. Seq a
Empty
where
go :: IO a -> t -> Seq Cycle -> IO ([Cycle], a)
go IO a
a' t
n Seq Cycle
ts
| t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
<= t
0 = do
a
a'' <- IO a
a'
([Cycle], a) -> IO ([Cycle], a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Seq Cycle -> [Cycle]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Seq Cycle
ts, a
a'')
| Bool
otherwise = do
(Cycle
t, a
_) <- IO a -> IO (Cycle, a)
forall a. IO a -> IO (Cycle, a)
tickWHNFIONoinline IO a
a'
IO a -> t -> Seq Cycle -> IO ([Cycle], a)
go IO a
a' (t
n t -> t -> t
forall a. Num a => a -> a -> a
- t
1) (Seq Cycle
ts Seq Cycle -> Cycle -> Seq Cycle
forall a. Seq a -> a -> Seq a
:|> Cycle
t)
{-# NOINLINE ticksWHNFIO #-}