Haxl/tests/MonadBench.hs
Dylan Yudaken e978f29f64 clean up monadbench a bit (#118)
Summary:
Pull Request resolved: https://github.com/facebook/Haxl/pull/118

* add ability to set reporting flag for benchmarking
* add argument parser
* add a test for using lots of labels

Reviewed By: simonmar

Differential Revision: D20792436

fbshipit-source-id: c87bd8e996397cb2ef229cf59927530a4dac20df
2020-04-24 08:02:52 -07:00

167 lines
5.2 KiB
Haskell

-- Copyright (c) 2014-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is distributed under the terms of a BSD license,
-- found in the LICENSE file.
-- | Benchmarking tool for core performance characteristics of the Haxl monad.
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ApplicativeDo, RecordWildCards #-}
module MonadBench (main) where
import Control.Monad
import Data.List as List
import Data.Maybe
import Data.Time.Clock
import Options.Applicative
import System.Exit
import System.IO
import Text.Printf
import Haxl.Prelude as Haxl
import Prelude()
import Haxl.Core.Memo (newMemoWith, runMemo)
import Haxl.Core
import Haxl.Core.Util
import ExampleDataSource
newtype SimpleWrite = SimpleWrite Text deriving (Eq, Show)
testEnv :: Int -> IO (Env () SimpleWrite)
testEnv report = do
exstate <- ExampleDataSource.initGlobalState
let st = stateSet exstate stateEmpty
env <- initEnv st ()
return env { flags = (flags env) { report = report } }
type Test = (String, Int, Int -> GenHaxl () SimpleWrite ())
testName :: Test -> String
testName (t,_,_) = t
allTests :: [Test]
allTests =
-- parallel, identical queries
[ ("par1", large, \n -> Haxl.sequence_ (replicate n (listWombats 3)))
-- parallel, distinct queries
, ("par2", medium, \n ->
Haxl.sequence_ (map listWombats [1..fromIntegral n]))
-- sequential, identical queries
, ("seqr", huge, \n ->
foldr andThen (return ()) (replicate n (listWombats 3)))
-- sequential, left-associated, distinct queries
, ("seql", medium, \n -> do
_ <- foldl andThen (return []) (map listWombats [1.. fromIntegral n])
return ())
-- No memoization
, ("memo0", small, \n -> Haxl.sequence_ [unionWombats | _ <- [1..n]])
-- One put, N gets.
, ("memo1", medium_large, \n ->
Haxl.sequence_ [memo (42 :: Int) unionWombats | _ <- [1..n]])
-- N puts, N gets.
, ("memo2", small, \n ->
Haxl.sequence_ [memo (i :: Int) unionWombats | i <- [1..n]])
, ("memo3", medium_large, \n -> do
ref <- newMemoWith unionWombats
let c = runMemo ref
Haxl.sequence_ [c | _ <- [1..n]])
, ("memo4", small, \n -> do
let f = unionWombatsTo
Haxl.sequence_ [f x | x <- take n $ cycle [100, 200 .. 1000]])
, ("memo5", medium_large, \n -> do
f <- memoize1 unionWombatsTo
Haxl.sequence_ [f x | x <- take n $ cycle [100, 200 .. 1000]])
, ("memo6", small, \n -> do
let f = unionWombatsFromTo
Haxl.sequence_ [ f x y
| x <- take n $ cycle [100, 200 .. 1000]
, let y = x + 1000
])
, ("memo7", medium_large, \n -> do
f <- memoize2 unionWombatsFromTo
Haxl.sequence_ [ f x y
| x <- take n $ cycle [100, 200 .. 1000]
, let y = x + 1000
])
, ("cc1", medium_large, \n ->
Haxl.sequence_ [ cachedComputation (ListWombats 1000) unionWombats
| _ <- [1..n]
])
, ("tree", 20, \n -> void $ tree n (\_ act -> act))
, ("tree_labels", 20, \n -> void $
tree n (\n act -> withLabel (textShow n) act))
-- parallel writes
, ("write1", large, \n ->
Haxl.sequence_ (replicate n (tellWrite (SimpleWrite "haha"))))
-- sequential writes
, ("write2", huge, \n -> foldr
andThen
(return ())
(replicate n (tellWrite (SimpleWrite "haha"))))
]
where
huge = large * 10
large = medium * 10
medium_large = medium * 4
medium = 200000
small = 1000
data Options = Options
{ test :: String
, nOverride :: Maybe Int
, reportFlag :: Int
}
runTest :: Options -> Test -> IO ()
runTest Options{..} (t, nDef, act) = do
let n = fromMaybe nDef nOverride
env <- testEnv reportFlag
t0 <- getCurrentTime
runHaxl env $ act n
t1 <- getCurrentTime
printf "%12s: %10d reqs: %.2fs\n"
t n (realToFrac (t1 `diffUTCTime` t0) :: Double)
optionsParser :: Parser Options
optionsParser = do
test <- argument str (metavar "TEST")
reportFlag <- option auto (long "report" <> value 0 <> metavar "REPORT")
nOverride <- optional $ argument auto (metavar "NUM")
return Options{..}
main :: IO ()
main = do
opts@Options{..} <- execParser $ info optionsParser mempty
let tests = if test == "all"
then allTests
else filter ((==) test . testName) allTests
when
(null tests)
(do
hPutStrLn stderr $ "syntax: monadbench [all|" ++
intercalate "|" (map testName allTests) ++ "]"
exitWith (ExitFailure 1))
Control.Monad.mapM_ (runTest opts) tests
tree
:: Int
-> (Int -> GenHaxl () SimpleWrite [Id] -> GenHaxl () SimpleWrite [Id])
-> GenHaxl () SimpleWrite [Id]
tree 0 wrap = wrap 0 $ listWombats 0
tree n wrap = wrap n $ concat <$> Haxl.sequence
[ tree (n-1) wrap
, listWombats (fromIntegral n), tree (n-1) wrap
]
unionWombats :: GenHaxl () SimpleWrite [Id]
unionWombats = foldl List.union [] <$> Haxl.mapM listWombats [1..1000]
unionWombatsTo :: Id -> GenHaxl () SimpleWrite [Id]
unionWombatsTo x = foldl List.union [] <$> Haxl.mapM listWombats [1..x]
unionWombatsFromTo :: Id -> Id -> GenHaxl () SimpleWrite [Id]
unionWombatsFromTo x y = foldl List.union [] <$> Haxl.mapM listWombats [x..y]