Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Effectful Juvix tree evaluator #2623

Merged
merged 11 commits into from
Feb 8, 2024
Merged

Effectful Juvix tree evaluator #2623

merged 11 commits into from
Feb 8, 2024

Conversation

janmasrovira
Copy link
Collaborator

@janmasrovira janmasrovira commented Feb 6, 2024

This pr implements two additional versions of the Juvix Tree evaluator. Now we have

  1. The raw implementation that does not use effects. It throws Haskell exceptions for errors. It uses unsafePerformIO for traces. It relies on bang patterns to force strictness and guarantee the expected order of execution (for traces). Avoiding effects allows for improved execution efficiency.
  2. polysemy based implementation.
  3. effectful-core based implementation.

One can specify which evaluator to use thus:

juvix dev tree eval --evaluator XXX test.jvt

where XXX is one of raw, polysemy, effectful.

Preliminary benchmarks

More thorough benchmarks should be run, but here are some preliminary results:

Test032 (Fibonacci 20)

I've adapted test032 so that it main is a single call to fibonacci of 20.

Command:

hyperfine --warmup 2 --runs 10 'juvix dev tree eval test032.jvt --evaluator polysemy' 'juvix dev tree eval test032.jvt --evaluator raw' 'juvix dev tree eval test032.jvt --evaluator e
ffectful'

Output:

Benchmark 1: juvix dev tree eval test032.jvt --evaluator polysemy
  Time (mean ± σ):      2.133 s ±  0.040 s    [User: 2.113 s, System: 0.016 s]
  Range (min … max):    2.088 s …  2.227 s    10 runs

Benchmark 2: juvix dev tree eval test032.jvt --evaluator raw
  Time (mean ± σ):     308.7 ms ±  13.8 ms    [User: 293.6 ms, System: 14.1 ms]
  Range (min … max):   286.5 ms … 330.1 ms    10 runs

Benchmark 3: juvix dev tree eval test032.jvt --evaluator effectful
  Time (mean ± σ):     366.0 ms ±   2.8 ms    [User: 345.4 ms, System: 19.4 ms]
  Range (min … max):   362.5 ms … 372.6 ms    10 runs

Summary
  juvix dev tree eval test032.jvt --evaluator raw ran
    1.19 ± 0.05 times faster than juvix dev tree eval test032.jvt --evaluator effectful
    6.91 ± 0.34 times faster than juvix dev tree eval test032.jvt --evaluator polysemy

Test034 (Higher-order function composition)

A modified version of test034 where main defined as call[exp](3, 12)

Command:

hyperfine --warmup 2 --runs 10 'juvix dev tree eval test034.jvt --evaluator polysemy' 'juvix dev tree eval test034.jvt --evaluator raw' 'juvix dev tree eval test034.jvt --evaluator effectful'

Output:

Benchmark 1: juvix dev tree eval test034.jvt --evaluator polysemy
  Time (mean ± σ):      7.025 s ±  0.184 s    [User: 6.518 s, System: 0.469 s]
  Range (min … max):    6.866 s …  7.327 s    10 runs

Benchmark 2: juvix dev tree eval test034.jvt --evaluator raw
  Time (mean ± σ):     835.6 ms ±   7.4 ms    [User: 757.2 ms, System: 75.9 ms]
  Range (min … max):   824.7 ms … 847.4 ms    10 runs

Benchmark 3: juvix dev tree eval test034.jvt --evaluator effectful
  Time (mean ± σ):      1.578 s ±  0.010 s    [User: 1.427 s, System: 0.143 s]
  Range (min … max):    1.563 s …  1.595 s    10 runs

Summary
  juvix dev tree eval test034.jvt --evaluator raw ran
    1.89 ± 0.02 times faster than juvix dev tree eval test034.jvt --evaluator effectful
    8.41 ± 0.23 times faster than juvix dev tree eval test034.jvt --evaluator polysemy

Test036 (Streams without memoization)

A modified version of test036 where main defined as call[nth](700, call[primes]())

Command:

hyperfine --warmup 2 --runs 5 'juvix dev tree eval test036.jvt --evaluator polysemy' 'juvix dev tree eval test036.jvt --evaluator raw' 'juvix dev tree eval test036.jvt --evaluator effectful'

Output:

Benchmark 1: juvix dev tree eval test036.jvt --evaluator polysemy
  Time (mean ± σ):      1.993 s ±  0.026 s    [User: 1.946 s, System: 0.043 s]
  Range (min … max):    1.969 s …  2.023 s    5 runs

Benchmark 2: juvix dev tree eval test036.jvt --evaluator raw
  Time (mean ± σ):     137.5 ms ±   7.1 ms    [User: 127.5 ms, System: 8.9 ms]
  Range (min … max):   132.8 ms … 149.8 ms    5 runs

Benchmark 3: juvix dev tree eval test036.jvt --evaluator effectful
  Time (mean ± σ):     329.0 ms ±   7.3 ms    [User: 289.3 ms, System: 37.4 ms]
  Range (min … max):   319.9 ms … 336.0 ms    5 runs

Summary
  juvix dev tree eval test036.jvt --evaluator raw ran
    2.39 ± 0.13 times faster than juvix dev tree eval test036.jvt --evaluator effectful
   14.50 ± 0.77 times faster than juvix dev tree eval test036.jvt --evaluator polysemy

@janmasrovira janmasrovira self-assigned this Feb 6, 2024
@janmasrovira janmasrovira force-pushed the sem-tree-evaluator branch 2 times, most recently from 989a8a2 to 33e14c3 Compare February 6, 2024 14:55
@janmasrovira janmasrovira changed the title Sem Juvix tree evaluator Effectful Juvix tree evaluator Feb 6, 2024
@janmasrovira janmasrovira force-pushed the sem-tree-evaluator branch 7 times, most recently from bcf822b to f52cebc Compare February 7, 2024 11:49
@janmasrovira janmasrovira added the enhancement New feature or request label Feb 7, 2024
@janmasrovira janmasrovira marked this pull request as ready for review February 7, 2024 13:58
@lukaszcz lukaszcz self-requested a review February 7, 2024 16:06
v <- eval' _nodeSaveArg
withExtendedTemp v (eval' _nodeSaveBody)

printValue :: InfoTable -> Value -> Text
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is code duplication here. Exactly the same function is available in Evaluator.hs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

ValString s -> s
v -> ppPrint tab v

valueToNode :: Value -> Node
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code duplication

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return val

-- | Catch EvalError and convert it to TreeError.
catchEvalErrorIO :: IO a -> IO (Either TreeError a)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed if errors are not Haskell exceptions. And code duplication.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

(\(ex :: EvalError) -> return (Left (toTreeError ex)))

toTreeError :: EvalError -> TreeError
toTreeError EvalError {..} =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code duplication

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

withExtendedTemp v (eval' _nodeSaveBody)

printValue :: InfoTable -> Value -> Text
printValue tab = \case
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code duplication

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

v -> ppPrint tab v

valueToNode :: Value -> Node
valueToNode = \case
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code duplication

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return val

-- | Catch EvalError and convert it to TreeError.
catchEvalErrorIO :: IO a -> IO (Either TreeError a)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated and not needed for the effects-based version

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

(\(ex :: EvalError) -> return (Left (toTreeError ex)))

toTreeError :: EvalError -> TreeError
toTreeError EvalError {..} =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code duplication

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

eval :: (Output Value :> r, E.Error EvalError :> r) => InfoTable -> Node -> Eff r Value
eval tab = E.runReader emptyEvalCtx . eval'
where
-- eval' :: forall r'. (Members '[Output Value, Reader EvalCtx, Error EvalError] r') => Node -> Sem r' Value
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove comment

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

mapM_ handle l
pure a

-- eval :: (Members '[Output Value, Error EvalError] r) => InfoTable -> Node -> Sem r Value
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove unnecessary comment

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Collaborator

@lukaszcz lukaszcz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid code duplication

@janmasrovira janmasrovira requested a review from lukaszcz February 7, 2024 17:54
@lukaszcz lukaszcz merged commit 8dfe2ba into main Feb 8, 2024
4 checks passed
@lukaszcz lukaszcz deleted the sem-tree-evaluator branch February 8, 2024 09:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants