Skip to content

Commit

Permalink
WIP README
Browse files Browse the repository at this point in the history
  • Loading branch information
radeusgd committed Apr 6, 2021
1 parent 68b825c commit 86a95a7
Show file tree
Hide file tree
Showing 8 changed files with 5,527 additions and 0 deletions.
247 changes: 247 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
# Microbenchmarks

> This README is currently a work in progress.
This section describes the comparison of performance of Enso and other popular languages (currently that includes Java, JS and Python).

## Results

Below follows a short description of each benchmark (including references to the source code) and a presentation of its results.

### Sum

The goal of this benchmark is to measure the base performance of a loop with arithmetic, by summing numbers from one to ten million.

The Enso implementation used tail recursion, as shown below.

```
sum : Integer -> Integer
sum n =
go acc i =
if i > n then acc else
@Tail_Call go acc+i i+1
res = go 0 1
res
```

In other languages, this was implemented using a while loop.
See the implementations in [Python](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/python/implementations.py#L1-L7), [JS](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/js/implementations.js#L1-L9) and [Java](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/java/microbenchmarks/src/main/java/org/enso/microbenchmarks/Implementations.java#L5-L13).

<img align="left" src="images/sum.svg" width="50%">

<br/>

| language | time | error |
|:-----------|----------:|------------:|
| Java | 4.04504 | 0.000693 |
| Enso | 11.3328 | 0.00967667 |
| JS | 12.94 | 0.00392667 |
| Python | 821.581 | 17.8992 |

> The error is approximated by computing the interval within which 99% of measurements fit.
<br/>

### Vector Allocation

This benchmark measures the time it takes to allocate a vector (a linear array) and fill it with complex objects. The objects used in this and all following benchmarks were 2-dimensional points represented using a simple structure (an atom or a class, depending on a language).

The created vectors consist of one million elements.

```
type Point x y
alloc_vector : Integer -> Vector
alloc_vector n =
Vector.new n (x -> Point x x)
```

See the implementations in [Python](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/python/implementations.py#L9-L15), [JS](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/js/implementations.js#L11-L24) and Java ([the allocation function](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/java/microbenchmarks/src/main/java/org/enso/microbenchmarks/Implementations.java#L15-L22) and the [`Point` class](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/java/microbenchmarks/src/main/java/org/enso/microbenchmarks/Point.java)).

<img align="left" src="images/alloc_vector.svg" width="50%">

<br/><br/>

| language | time | error |
|:-----------|---------:|----------:|
| Java | 88.9622 | 0.467679 |
| JS | 139.051 | 1.55461 |
| Enso | 151.249 | 13.4023 |
| Python | 860.448 | 9.79263 |

<br/>

### Vector Sum

This benchmark measures the time it takes to sum elements of a vector. The vector is the same as created by the benchmark above - it computes `Point`s and the sum of both of their coordinates is computed.

```
sum_vector : Vector -> Integer
sum_vector vec =
go acc i =
if i >= vec.length then acc else
v = vec.at i
@Tail_Call go (acc + v.x + v.y) i+1
res = go 0 0
res
```

See the implementations in [Python](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/python/implementations.py#L17-L21), [JS](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/js/implementations.js#L26-L34) and [Java](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/java/microbenchmarks/src/main/java/org/enso/microbenchmarks/Implementations.java#L24-L31).

<img align="left" src="images/sum_vector.svg" width="50%">

<br/><br/>

| language | time | error |
|:-----------|---------:|---------:|
| JS | 3.73833 | 0.160482 |
| Java | 6.48289 | 0.079613 |
| Enso | 15.2125 | 0.404855 |
| Python | 97.8382 | 0.188951 |

<br/>

### List Allocation

This benchmark measures the time it takes to allocate a linked list data structure containing complex objects (the same `Point` structure is used as in the previous benchmarks).

The created lists consist of one million elements.

```
type List
type Cons head tail
type Nil
alloc_list : Integer -> List
alloc_list n =
go acc n =
if n == 0 then Cons (Point 0 0) acc else
@Tail_Call go (Cons (Point n n) acc) n-1
res = go Nil n
res
```

In other languages the list is implemented as a structure containing the head and a pointer to the tail and the empty list is represented as `null` (or `None` in case of Python) to avoid, usually more expensive, `instanceof` checks.
See the implementations in [Python](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/python/implementations.py#L23-L32), [JS](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/js/implementations.js#L36-L49) and Java ([the allocation function](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/java/microbenchmarks/src/main/java/org/enso/microbenchmarks/Implementations.java#L33-L39) and the [`Cons` class](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/java/microbenchmarks/src/main/java/org/enso/microbenchmarks/Cons.java)).

<img align="left" src="images/alloc_list.svg" width="50%">

<br/><br/>

| language | time | error |
| :----------- | ---------: | ---------: |
| Enso | 194.425 | 67.7076 |
| JS | 208.974 | 1.25082 |
| Java | 254.009 | 13.0299 |
| Python | 2283.15 | 11.6015 |

<br/>

### List Sum

This benchmark measures the time it takes to sum elements of a linked list as created above (it is analogous to the Vector Sum benchmark). It checks the general performance of list traversal.

```
sum_list : List -> Integer
sum_list list =
go acc list = case list of
Nil -> acc
Cons h t ->
@Tail_Call go acc+h.x+h.y t
res = go 0 list
res
```

See the implementations in [Python](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/python/implementations.py#L34-L40), [JS](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/js/implementations.js#L51-L59) and [Java](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/java/microbenchmarks/src/main/java/org/enso/microbenchmarks/Implementations.java#L41-L48).

<img align="left" src="images/sum_list.svg" width="50%">

<br/><br/>

| language | time | error |
|:-----------|----------:|---------:|
| Java | 7.26603 | 0.070526 |
| JS | 9.04733 | 0.137573 |
| Enso | 17.1443 | 0.928918 |
| Python | 154.862 | 0.646967 |

<br/>

### Full Binary Tree Allocation

This benchmark measures the time it takes to allocate a full binary tree.

This one and its corresponding summing benchmark compare the performance of creating and traversing more complex data structures using non-tail recursion (because in the other benchmarks mostly relied on while-loops in imperative languages and tail-recursion in Enso). Of course it is possible to avoid recursion in these examples, for example by simulating a stack, but the recursive solution is the most natural one here.

It also shows an example of using mutable `State` to keep track of the indexes in each node and shows that Enso's `State` monad has comparable performance to regular mutable state of other languages.

The allocated trees have a depth of 17, which means that they consist of 2^17 = 131072 elements (including the leafs).

```
type Tree
type Leaf
type Node left elem right
alloc_full_tree : Integer -> Tree
alloc_full_tree depth =
go remaining_depth =
if remaining_depth == 0 then Leaf else
l = go remaining_depth-1
i = State.get Integer
State.put Integer i+1
e = Point i i
r = go remaining_depth-1
Node l e r
res = State.run Integer 0 <| go depth
res
```

In other languages, the leaf is represented as `null` (or `None`), similarly as explained in [List Allocation](#list-allocation). The state is implemented using a mutable variable within the closure of a helper function (in case of Python and JS) and using mutable member elements within a helper class (in case of Java).
See the implementations in [Python](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/python/implementations.py#L42-L60), [JS](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/js/implementations.js#L61-L83) and Java ([the allocation function](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/java/microbenchmarks/src/main/java/org/enso/microbenchmarks/Implementations.java#L50-L78) and the [`Tree` class](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/java/microbenchmarks/src/main/java/org/enso/microbenchmarks/Tree.java)).

<img align="left" src="images/alloc_full_tree.svg" width="50%">

<br/><br/>

| language | time | error |
| :----------- | ----------: | --------: |
| Java | 2.49132 | 0.05542 |
| JS | 7.7585 | 0.28599 |
| Enso | 11.822 | 1.88513 |
| Python | 307.699 | 4.37348 |

<br/>

### Tree Sum

This benchmark measures the time it takes to sum elements of a binary tree. It checks the performance of traversal of more complex data structures and recursion.

```
sum_tree : Tree -> Integer
sum_tree tree = case tree of
Leaf -> 0
Node l e r -> here.sum_tree l + e.x + e.y + here.sum_tree r
```

See the implementations in [Python](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/python/implementations.py#L62-L68), [JS](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/js/implementations.js#L85-L94) and [Java](https://github.com/enso-org/benchmarks/blob/wip/rw/initial-microbenchmarks/java/microbenchmarks/src/main/java/org/enso/microbenchmarks/Implementations.java#L80-L88).

<img align="left" src="images/sum_tree.svg" width="50%">

<br/><br/>

| language | time | error |
|:-----------|---------:|---------:|
| Java | 1.29162 | 0.012507 |
| JS | 2.0155 | 0.042925 |
| Enso | 4.911 | 1.31693 |
| Python | 47.9598 | 1.23146 |

<br/>

## Additional Notes

## How To Run The Benchmarks

# Enso-R vs Gnu-R

TODO
Loading

0 comments on commit 86a95a7

Please sign in to comment.