1
1
mirror of https://github.com/anoma/juvix.git synced 2024-12-02 10:47:32 +03:00
juvix/test/Nockma.hs
Paul Cadman 87c5f0af44
Improve performance of anomaEncode / anomaDecode in the Core evaluator (#2975)
This PR:

* Adds a new implementation of {decode, encode}ByteString functions,
used by anomaEncode and anomaDecode in the Core evaluator
* Adds property tests for roundtripping and benchmarks for the new
functions.

The old implementation used
[bitvec](https://hackage.haskell.org/package/bitvec) to manipulate the
ByteString. This was far too slow. The new implementation uses bit
operations directly on the input integer and ByteArray.

It's now possible to run
[anoma-app-patterns:`Tests/Swap.juvix`](https://github.com/anoma/anoma-app-patterns/blob/feature/tests/Tests/Swap.juvix)
to completion.

For encoding, if the size of the output integer exceeds 64 bits (and
therefore a BigInt must be used) then the new implementation has
quadratic time complexity in the number of input bytes if an
implementation of `ByteString -> Integer` is used as follows:

```
byteStringToIntegerLE :: ByteString -> Integer
byteStringToIntegerLE = BS.foldr (\b acc -> acc `shiftL` 8 .|. fromIntegral b) 0
```

```
byteStringToInteger' :: ByteString -> Integer
byteStringToInteger' = BS.foldl' (\acc b -> acc `shiftL` 8 .|. fromIntegral b) 0

```

I think this is because `shiftL` is expensive for large Integers. To
mitigate this I'm splitting the input ByteString into 1024 byte chunks
and processing each separately. Using this we get 100x speed up at
~0.25Mb input over the non-chunked approach and linear time-complexity
thereafter.

## Benchmarks

The benchmarks for encoding and decoding 250000 bytes:

```
 ByteString Encoding to/from integer
      encode bytes to integer:   OK
        59.1 ms ± 5.3 ms
      decode bytes from integer: OK
        338  ms ±  16 ms
```

The previous implementation would never complete for this input.

Benchmarks for encoding and decoding 2 * 250000 bytes:

```
    ByteString Encoding to/from integer
      encode bytes to integer:   OK
        121  ms ± 8.3 ms
      decode bytes from integer: OK
        651  ms ±  27 ms
```

Benchmarks for encoding and decoding 4 * 250000 bytes:

```
    ByteString Encoding to/from integer
      encode bytes to integer:   OK
        249  ms ±  17 ms
      decode bytes from integer: OK
        1.317 s ±  16 ms
```

---------

Co-authored-by: Lukasz Czajka <lukasz@heliax.dev>
2024-08-30 18:20:18 +01:00

11 lines
324 B
Haskell

module Nockma where
import Base
import Nockma.Compile qualified as Compile
import Nockma.Encoding qualified as Encoding
import Nockma.Eval qualified as Eval
import Nockma.Parse qualified as Parse
allTests :: TestTree
allTests = testGroup "Nockma tests" [Parse.allTests, Eval.allTests, Compile.allTests, Encoding.allTests]