1
1
mirror of https://github.com/anoma/juvix.git synced 2025-01-05 22:46:08 +03:00
juvix/test/Base.hs
Jan Mas Rovira 3a4cbc742d
Replace polysemy by effectful (#2663)
The following benchmark compares juvix 0.6.0 with polysemy and a new
version (implemented in this pr) which replaces polysemy by effectful.

# Typecheck standard library without caching
```
hyperfine --warmup 2 --prepare 'juvix-polysemy clean' 'juvix-polysemy typecheck Stdlib/Prelude.juvix' 'juvix-effectful typecheck Stdlib/Prelude.juvix'
Benchmark 1: juvix-polysemy typecheck Stdlib/Prelude.juvix
  Time (mean ± σ):      3.924 s ±  0.143 s    [User: 3.787 s, System: 0.084 s]
  Range (min … max):    3.649 s …  4.142 s    10 runs

Benchmark 2: juvix-effectful typecheck Stdlib/Prelude.juvix
  Time (mean ± σ):      2.558 s ±  0.074 s    [User: 2.430 s, System: 0.084 s]
  Range (min … max):    2.403 s …  2.646 s    10 runs

Summary
  juvix-effectful typecheck Stdlib/Prelude.juvix ran
    1.53 ± 0.07 times faster than juvix-polysemy typecheck Stdlib/Prelude.juvix
```

# Typecheck standard library with caching
```
hyperfine --warmup 1 'juvix-effectful typecheck Stdlib/Prelude.juvix' 'juvix-polysemy typecheck Stdlib/Prelude.juvix' --min-runs 20
Benchmark 1: juvix-effectful typecheck Stdlib/Prelude.juvix
  Time (mean ± σ):      1.194 s ±  0.068 s    [User: 0.979 s, System: 0.211 s]
  Range (min … max):    1.113 s …  1.307 s    20 runs

Benchmark 2: juvix-polysemy typecheck Stdlib/Prelude.juvix
  Time (mean ± σ):      1.237 s ±  0.083 s    [User: 0.997 s, System: 0.231 s]
  Range (min … max):    1.061 s …  1.476 s    20 runs

Summary
  juvix-effectful typecheck Stdlib/Prelude.juvix ran
    1.04 ± 0.09 times faster than juvix-polysemy typecheck Stdlib/Prelude.juvix
```
2024-03-21 12:09:34 +00:00

117 lines
3.4 KiB
Haskell

module Base
( module Test.Tasty,
module Test.Tasty.HUnit,
module Juvix.Prelude,
module Base,
module Juvix.Extra.Paths,
module Juvix.Prelude.Env,
module Juvix.Compiler.Pipeline.Run,
module Juvix.Compiler.Pipeline.EntryPoint.IO,
)
where
import Control.Monad.Extra as Monad
import Data.Algorithm.Diff
import Data.Algorithm.DiffOutput
import Juvix.Compiler.Internal.Translation.FromInternal.Analysis.Termination
import Juvix.Compiler.Pipeline.EntryPoint.IO
import Juvix.Compiler.Pipeline.Loader.PathResolver
import Juvix.Compiler.Pipeline.Run
import Juvix.Data.Effect.TaggedLock
import Juvix.Extra.Paths hiding (rootBuildDir)
import Juvix.Prelude hiding (assert)
import Juvix.Prelude.Env
import Test.Tasty
import Test.Tasty.HUnit hiding (assertFailure)
import Test.Tasty.HUnit qualified as HUnit
data AssertionDescr
= Single Assertion
| Steps ((String -> IO ()) -> Assertion)
data TestDescr = TestDescr
{ _testName :: String,
_testRoot :: Path Abs Dir,
-- | relative to root
_testAssertion :: AssertionDescr
}
newtype WASMInfo = WASMInfo
{ _wasmInfoActual :: Path Abs File -> IO Text
}
makeLenses ''TestDescr
data StdlibMode
= StdlibInclude
| StdlibExclude
deriving stock (Show, Eq)
data CompileMode
= WASI StdlibMode
| WASM WASMInfo
mkTest :: TestDescr -> TestTree
mkTest TestDescr {..} = case _testAssertion of
Single assertion -> testCase _testName (withCurrentDir _testRoot assertion)
Steps steps -> testCaseSteps _testName (withCurrentDir _testRoot . steps)
assertEqDiffText :: String -> Text -> Text -> Assertion
assertEqDiffText = assertEqDiff unpack
assertEqDiff :: (Eq a) => (a -> String) -> String -> a -> a -> Assertion
assertEqDiff show_ msg a b
| a == b = return ()
| otherwise = do
putStrLn (pack $ ppDiff (getGroupedDiff pa pb))
putStrLn "End diff"
Monad.fail msg
where
pa = lines $ show_ a
pb = lines $ show_ b
assertEqDiffShow :: (Eq a, Show a) => String -> a -> a -> Assertion
assertEqDiffShow = assertEqDiff show
assertCmdExists :: Path Rel File -> Assertion
assertCmdExists cmd =
assertBool ("Command: " <> toFilePath cmd <> " is not present on $PATH")
. isJust
=<< findExecutable cmd
testTaggedLockedToIO :: (MonadIO m) => Sem PipelineAppEffects a -> m a
testTaggedLockedToIO =
runM
. runTaggedLock LockModeExclusive
testRunIO ::
forall a m.
(MonadIO m) =>
EntryPoint ->
Sem (PipelineEff PipelineAppEffects) a ->
m (ResolverState, PipelineResult a)
testRunIO e = testTaggedLockedToIO . runIO defaultGenericOptions e
testDefaultEntryPointIO :: (MonadIO m) => Path Abs Dir -> Path Abs File -> m EntryPoint
testDefaultEntryPointIO cwd mainFile = testTaggedLockedToIO (defaultEntryPointIO cwd mainFile)
testDefaultEntryPointNoFileIO :: Path Abs Dir -> IO EntryPoint
testDefaultEntryPointNoFileIO cwd = testTaggedLockedToIO (defaultEntryPointNoFileIO cwd)
testRunIOEither ::
EntryPoint ->
Sem (PipelineEff PipelineAppEffects) a ->
IO (Either JuvixError (ResolverState, PipelineResult a))
testRunIOEither entry = testTaggedLockedToIO . runIOEither entry
testRunIOEitherTermination ::
EntryPoint ->
Sem (Termination ': PipelineEff PipelineAppEffects) a ->
IO (Either JuvixError (ResolverState, PipelineResult a))
testRunIOEitherTermination entry =
testRunIOEither entry
. evalTermination iniTerminationState
assertFailure :: (MonadIO m) => String -> m a
assertFailure = liftIO . HUnit.assertFailure