microecta-0.1.0.0: benchmarks/Benchmarks.hs
{-# LANGUAGE OverloadedStrings #-}
module Main (main) where
import Control.Exception (evaluate)
import qualified Data.Text as Text
import System.CPUTime (getCPUTime)
import System.Environment (getArgs)
import Text.Printf (printf)
import Application.TermSearch.Dataset (typeToFta)
import Application.TermSearch.TermSearch (filterType, reduceFully)
import Application.TermSearch.Type (TypeSkeleton (..))
import Application.TermSearch.Utils (
arrowType,
constFunc,
mkDatatype,
theArrowNode,
typeConst,
)
import Data.ECTA
import Data.ECTA.Internal.ECTA.Operations (reduceEqConstraints)
import Data.ECTA.Paths
import Data.ECTA.Term (Symbol (Symbol))
data Bench = Bench
{ benchName :: String
, benchRepeats :: Int
, benchAction :: Int -> IO Int
}
main :: IO ()
main = do
multiplier <- parseMultiplier <$> getArgs
putStrLn "benchmark,cpu_seconds,repeats,checksum"
mapM_ (runBench multiplier) benchmarks
parseMultiplier :: [String] -> Int
parseMultiplier [] = 1
parseMultiplier (x : _) =
case reads x of
[(n, "")] -> max 1 n
_ -> 1
runBench :: Int -> Bench -> IO ()
runBench multiplier Bench{benchName, benchRepeats, benchAction} = do
start <- getCPUTime
checksum <- loop totalRepeats 0
end <- getCPUTime
let seconds = fromIntegral (end - start) / (10 ^ (12 :: Int) :: Double)
printf "%s,%.6f,%d,%d\n" benchName seconds totalRepeats checksum
where
totalRepeats = benchRepeats * multiplier
loop 0 !acc = return acc
loop n !acc = do
x <- benchAction n
loop (n - 1) (acc + x)
benchmarks :: [Bench]
benchmarks =
[ Bench "getPath/type-search-node" 2000 $ \i ->
forceNode $ getPath (path [2, 0, if i >= 0 then 2 else 1]) typeSearchNode
, Bench "mkEqConstraints/congruence" 600 $ \i ->
forceEqConstraints $ mkEqConstraints (congruencePathSets i)
, Bench "eqConstraintsDescend/wide-sparse" 4000 $ \i ->
forceEqConstraints $ eqConstraintsDescend wideSparseConstraints (i `rem` 16)
, Bench "intersect/finite-constrained" 800 $ \i ->
forceNode $ finiteChoiceNode i `intersect` constrainedChoiceNode i
, Bench "intersect/recursive-types" 300 $ \i ->
forceNode $ recursiveTypeA i `intersect` recursiveTypeB i
, Bench "reduce/recursive-paths" 120 $ \i ->
forceNodes $ reduceEqConstraints recursivePathConstraints EmptyConstraints (recursivePathNodes i)
, Bench "reduce/filter-maybe-int-size-2" 80 $ \i ->
forceNode $ reduceFully (filterMaybeIntSize2 i)
, Bench "reduce/filter-list-int-size-3" 20 $ \i ->
forceNode $ reduceFully (filterListIntSize3 i)
, Bench "enumerate/reduced-filter-maybe-int-size-2" 80 $ \i ->
forceInt $ length (take 64 (getAllTerms (reduceFully (filterMaybeIntSize2 i))))
]
forceNode :: Node -> IO Int
forceNode n = forceInt (nodeCount n + edgeCount n)
forceNodes :: [Node] -> IO Int
forceNodes = forceInt . sum . map (\n -> nodeCount n + edgeCount n)
forceEqConstraints :: EqConstraints -> IO Int
forceEqConstraints =
forceInt
. sum
. map (sum . map (length . unPath) . unPathEClass)
. unsafeGetEclasses
forceInt :: Int -> IO Int
forceInt = evaluate
typeSearchNode :: Node
typeSearchNode =
appNode
(appNode (monoFunctionScope 0) (monoArgumentScope 0))
(monoTermsOfSize 0 2)
filterMaybeIntSize2 :: Int -> Node
filterMaybeIntSize2 i =
filterType
(monoTermsOfSize i 2)
(typeToFta $ TCons "Maybe" [TCons "Int" []])
filterListIntSize3 :: Int -> Node
filterListIntSize3 i =
filterType
(monoTermsOfSize i 3)
(typeToFta $ TCons "List" [TCons "Int" []])
monoTermsOfSize :: Int -> Int -> Node
monoTermsOfSize salt size = union (go size)
where
go 0 = []
go 1 = [monoArgumentScope salt, monoFunctionScope salt]
go n =
[ appNode (union (go i)) (union (go (n - i)))
| i <- [1 .. n - 1]
]
appNode :: Node -> Node -> Node
appNode f x =
Node
[ mkEdge
"app"
[getPath (path [0, 2]) f, theArrowNode, f, x]
( mkEqConstraints
[ [path [1], path [2, 0, 0]]
, [path [3, 0], path [2, 0, 1]]
, [path [0], path [2, 0, 2]]
]
)
]
monoArgumentScope :: Int -> Node
monoArgumentScope salt =
Node
[ constFunc (named "x" salt) (typeConst "Int")
, constFunc (named "y" salt) (typeConst "Int")
, constFunc (named "xs" salt) (mkDatatype "List" [typeConst "Int"])
]
monoFunctionScope :: Int -> Node
monoFunctionScope salt =
Node
[ constFunc (named "idInt" salt) (arrowType intType intType)
, constFunc (named "JustInt" salt) (arrowType intType maybeIntType)
, constFunc (named "headInt" salt) (arrowType listIntType intType)
, constFunc (named "nilInt" salt) listIntType
, constFunc (named "consInt" salt) (arrowType intType (arrowType listIntType listIntType))
]
named :: String -> Int -> Symbol
named prefix salt = Symbol $ Text.pack (prefix ++ show salt)
intType :: Node
intType = typeConst "Int"
maybeIntType :: Node
maybeIntType = mkDatatype "Maybe" [intType]
listIntType :: Node
listIntType = mkDatatype "List" [intType]
congruencePathSets :: Int -> [[Path]]
congruencePathSets salt =
[ [path [i], path [i + 1]]
| i <- [base .. base + 5]
]
++ [ [path [i, 0], path [i, 1]]
| i <- [base .. base + 5]
]
where
base = salt `rem` 3
wideSparseConstraints :: EqConstraints
wideSparseConstraints =
mkEqConstraints
[ [path [i, 0], path [i, 1]]
| i <- [0 .. 15]
]
finiteChoiceNode :: Int -> Node
finiteChoiceNode salt =
Node
[ Edge (named "f" salt) [choiceAB salt, choiceAB salt]
, Edge (named "g" salt) [choiceAB salt, choiceAB salt]
]
constrainedChoiceNode :: Int -> Node
constrainedChoiceNode salt =
Node
[ mkEdge (named "f" salt) [choiceAB salt, choiceAB salt] (mkEqConstraints [[path [0], path [1]]])
, Edge (named "g" salt) [choiceAB salt, choiceAB salt]
]
choiceAB :: Int -> Node
choiceAB salt = Node [Edge (named "a" salt) [], Edge (named "b" salt) []]
recursivePathConstraints :: EqConstraints
recursivePathConstraints = mkEqConstraints [[path [0, 0, 0, 0], path [1, 0, 0]]]
recursivePathNodes :: Int -> [Node]
recursivePathNodes salt = [infiniteFNode salt, infiniteFNode salt]
infiniteFNode :: Int -> Node
infiniteFNode salt = createMu $ \r -> Node [Edge (named "f" salt) [r]]
recursiveTypeA :: Int -> Node
recursiveTypeA salt =
createMu $ \r ->
Node
[ Edge (named "baseType" salt) []
, Edge "->" [theArrowNode, r, r]
, Edge "Maybe" [r]
, Edge "List" [r]
]
recursiveTypeB :: Int -> Node
recursiveTypeB salt =
createMu $ \r ->
Node
[ Edge (named "baseType" salt) []
, Edge "->" [theArrowNode, mkDatatype "List" [r], r]
, Edge "List" [r]
]