packages feed

acc-0.1: benchmark/Main.hs

module Main where

import Prelude
import Criterion
import Criterion.Main
import qualified Acc
import qualified Data.Foldable as Foldable
import qualified Data.Sequence as Seq
import qualified Data.DList as DList
import qualified Data.Vector as Vector


main =
  defaultMain [
    sumBgroup "1"
      (replicate 1000 1)
      (foldMapToRight)
    ,
    sumBgroup "2"
      (replicate 1000 1)
      (foldMapToLeft)
    ,
    sumBgroup "sum/foldr',foldr'"
      (Vector.fromList (replicate 100 (Vector.fromList (replicate @Int 100 1))))
      (\ singleton -> foldr' (\ a b -> foldr' (mappend . singleton) mempty a <> b) mempty)
    ,
    sumBgroup "sum/foldl',foldl'"
      (Vector.fromList (replicate 100 (Vector.fromList (replicate @Int 100 1))))
      (\ singleton -> foldl' (\ a b -> a <> foldl' (\ a -> mappend a . singleton) mempty b) mempty)
    ,
    bgroup "thousand-elements" [
      bgroup "foldl'" $ let
        !input =
          force $ enumFromTo 0 999 :: [Int]
        in [
          bench "Acc" $ let
            work input =
              let
                acc =
                  foldl' (<>) mempty $ fmap (pure @Acc.Acc) input
                in Foldable.toList acc
            in nf work input
          ,
          bench "Seq" $ let
            work input =
              let
                seq =
                  foldl' (<>) mempty $ fmap Seq.singleton input
                in Foldable.toList seq
            in nf work input
          ,
          bench "DList" $ let
            work input =
              let
                seq =
                  foldl' (<>) mempty $ fmap DList.singleton input
                in Foldable.toList seq
            in nf work input
          ]
      ,
      bgroup "foldr" $ let
        !input =
          force $ enumFromTo 0 999 :: [Int]
        in [
          bench "Acc" $ let
            work input =
              let
                acc =
                  foldr (<>) mempty $ fmap (pure @Acc.Acc) input
                in Foldable.toList acc
            in nf work input
          ,
          bench "Seq" $ let
            work input =
              let
                seq =
                  foldr (<>) mempty $ fmap Seq.singleton input
                in Foldable.toList seq
            in nf work input
          ,
          bench "DList" $ let
            work input =
              let
                seq =
                  foldr (<>) mempty $ fmap DList.singleton input
                in Foldable.toList seq
            in nf work input
          ]
      ,
      bgroup "foldr'" $ let
        !input =
          force $ enumFromTo 0 999 :: [Int]
        in [
          bench "Acc" $ let
            work input =
              let
                acc =
                  foldr' (<>) mempty $ fmap (pure @Acc.Acc) input
                in Foldable.toList acc
            in nf work input
          ,
          bench "Seq" $ let
            work input =
              let
                seq =
                  foldr' (<>) mempty $ fmap Seq.singleton input
                in Foldable.toList seq
            in nf work input
          ,
          bench "DList" $ let
            work input =
              let
                seq =
                  foldr' (<>) mempty $ fmap DList.singleton input
                in Foldable.toList seq
            in nf work input
          ]
      ,
      bgroup "foldr, force intermediate" $ let
        !input =
          force $ enumFromTo 0 999 :: [Int]
        in [
          bench "Acc" $ let
            work input =
              let
                acc =
                  foldr (<>) mempty $ fmap (pure @Acc.Acc) input
                in Foldable.toList $!! acc
            in nf work input
          ,
          bench "Seq" $ let
            work input =
              let
                seq =
                  foldr (<>) mempty $ fmap Seq.singleton input
                in Foldable.toList $!! seq
            in nf work input
          ,
          bench "DList" $ let
            work input =
              let
                seq =
                  foldr (<>) mempty $ fmap DList.singleton input
                in Foldable.toList $!! seq
            in nf work input
          ]
      ,
      bgroup "foldMap" $ let
        !input =
          force $ enumFromTo 0 999 :: [Int]
        in [
          bench "Acc" $ let
            work input =
              let
                acc =
                  foldMap (pure @Acc.Acc) input
                in Foldable.toList acc
            in nf work input
          ,
          bench "Seq" $ let
            work input =
              let
                seq =
                  foldMap Seq.singleton input
                in Foldable.toList seq
            in nf work input
          ,
          bench "DList" $ let
            work input =
              let
                seq =
                  foldMap DList.singleton input
                in Foldable.toList seq
            in nf work input
          ]
      ,
      bgroup "foldMap'" $ let
        !input =
          force $ enumFromTo 0 999 :: [Int]
        in [
          bench "Acc" $ let
            work input =
              let
                acc =
                  foldMap' (pure @Acc.Acc) input
                in Foldable.toList acc
            in nf work input
          ,
          bench "Seq" $ let
            work input =
              let
                seq =
                  foldMap' Seq.singleton input
                in Foldable.toList seq
            in nf work input
          ,
          bench "DList" $ let
            work input =
              let
                seq =
                  foldMap' DList.singleton input
                in Foldable.toList seq
            in nf work input
          ]
      ]
    ,
    bgroup "groups" [
      bgroup "foldl'" [
        bench "acc" $ let
          input :: [Acc.Acc Int]
          !input =
            enumFromTo 0 99 & fmap pure &
            foldl' (<>) mempty &
            replicate 10 &
            force
          work =
            Foldable.toList . foldl' (<>) mempty
          in nf work input
        ,
        bench "seq" $ let
          input :: [Seq Int]
          !input =
            enumFromTo 0 99 & fmap pure &
            foldl' (<>) mempty &
            replicate 10 &
            force
          work =
            Foldable.toList . foldl' (<>) mempty
          in nf work input
        ,
        bench "dlist" $ let
          input :: [DList Int]
          !input =
            enumFromTo 0 99 & fmap pure &
            foldl' (<>) mempty &
            replicate 10 &
            force
          work =
            Foldable.toList . foldl' (<>) mempty
          in nf work input
        ]
      ]
    ]

sumBgroup :: NFData input => String -> input -> (forall f. (Foldable f, Monoid (f Int)) => (Int -> f Int) -> input -> f Int) -> Benchmark
sumBgroup name (force -> !input) build =
  bgroup name [
    sumBench "Acc" (pure @Acc.Acc)
    ,
    sumBench "Seq" Seq.singleton
    ,
    sumBench "DList" DList.singleton
    ,
    sumBench "List" (pure @[])
    ]
  where
    sumBench :: (Foldable f, Monoid (f Int)) => String -> (Int -> f Int) -> Benchmark
    sumBench name singleton =
      bench name (nf (Foldable.sum . build singleton) input)



{-| Best for Acc. -}
{-# NOINLINE foldMapToRight #-}
foldMapToRight :: Monoid m => (a -> m) -> [a] -> m
foldMapToRight pure =
  foldl' (\ a b -> pure b <> a) mempty

{-| Worst for Acc. -}
{-# NOINLINE foldMapToLeft #-}
foldMapToLeft :: Monoid m => (a -> m) -> [a] -> m
foldMapToLeft pure =
  foldl' (\ a b -> a <> pure b) mempty