Skip to content

Commit

Permalink
update benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
ztellman committed Mar 27, 2017
1 parent a453a20 commit 9da9afb
Show file tree
Hide file tree
Showing 22 changed files with 11 additions and 13 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

__This library is still alpha quality, use with caution__

This library provides high-quality Java implementations of mutable and immutable data structures exposing a common API, and sharing these design principles:
This library provides high-quality Java implementations of mutable and immutable data structures, each sharing a common API and these design principles:

* efficient random access
* efficient splitting and merging of collections
* customizable equality semantics
* contiguous memory used wherever possible
* performance equivalent to, or better than, existing alternatives

Some of these properties, such as uniformly efficient random access and split/merge, are simply not available elsewhere. Even if these are not required, other JVM libraries in this space tend to bring a large amount of tangential code along for the ride. For instance, the collections in the [Functional Java](https://github.com/functionaljava/functionaljava) library assume and encourage the use of all the surrounding abstractions. Clojure's data structures, while implemented in Java, are hard-coded to use Clojure's equality semantics.
Some of these properties, such as uniformly efficient random access and splits, are simply not available elsewhere. Even if these are not required, other JVM libraries in this space tend to bring a large amount of tangential code along for the ride. For instance, the collections in the [Functional Java](https://github.com/functionaljava/functionaljava) library assume and encourage the use of all the surrounding abstractions. Clojure's data structures, while implemented in Java, are hard-coded to use Clojure's equality semantics.

These libraries are all-or-nothing propositions: they work great as long as you also adopt the surrounding ecosystem. Historically, given the lack of functional primitives in Java's standard library, this made a lot of sense. With the introduction of lambdas, streams, et al in Java 8, however, this is no longer required.
These libraries are all-or-nothing propositions: they work great as long as you also adopt the surrounding ecosystem. Historically, given the lack of functional primitives in Java's standard library, this made a lot of sense. With the introduction of lambdas, streams, et al in Java 8, however, this is no longer true.

This library builds only on the primitives provided by the Java 8 standard library. Rather than using the existing collection interfaces in `java.util` such as `List` or `Map`, it provides its own interfaces (`IList`, `IMap`, `ISet`) that provide functional semantics - each update to a collection returns a reference to a new collection. Each interface provides a method (`toList`, `toMap`, `toSet`) for coercing the collection to a read-only version of the standard Java interfaces.

Expand All @@ -22,7 +22,7 @@ This library builds only on the primitives provided by the Java 8 standard libra
* [Map](http://lacuna.io/docs/bifurcan/io/lacuna/bifurcan/Map.html) is an immutable hash-map, which also allows for custom hash and equality semantics. It ensures that all equivalent collections have an equivalent layout in memory, which makes checking for equality and performing set operations (`merge`, `union`, `difference`, `intersection`) significantly faster.
* [LinearSet](http://lacuna.io/docs/bifurcan/io/lacuna/bifurcan/LinearSet.html) and [Set](http://lacuna.io/docs/bifurcan/io/lacuna/bifurcan/Set.html) are built atop their respective map implementations, and have similar properties.
* [LinearList](http://lacuna.io/docs/bifurcan/io/lacuna/bifurcan/LinearList.html) is a mutable list, which allows for elements to be added or removed from both ends of the collection, and allows random reads and writes within the list.
* [List](http://lacuna.io/docs/bifurcan/io/lacuna/bifurcan/List.html) is an immutable list, which also allows for modification at both ends, and random reads and writes. Due to its [relaxed radix structure](https://infoscience.epfl.ch/record/169879/files/RMTrees.pdf), it also allows for near constant-time slices and concatenation.
* [List](http://lacuna.io/docs/bifurcan/io/lacuna/bifurcan/List.html) is an immutable list, which also allows for modification at both ends, as well as random reads and writes. Due to its [relaxed radix structure](https://infoscience.epfl.ch/record/169879/files/RMTrees.pdf), it also allows for near constant-time slices and concatenation.
* [IntMap](http://lacuna.io/docs/bifurcan/io/lacuna/bifurcan/IntMap.html) is an immutable sorted map of integers onto arbitrary values, and can be used as an efficient sparse vector.

Full benchmarks for these collections [can be found here](https://github.com/lacuna/bifurcan/blob/master/doc/benchmarks.md). Full documentation [can be found here](http://lacuna.io/docs/bifurcan/io/lacuna/bifurcan/package-summary.html).
Expand All @@ -36,11 +36,11 @@ IList<Long> list = Lists.from(1_000_000, i -> i);
// creates a set representing that same range
ISet<Long> set = Sets.from(list, i -> 0 <= i && i < 1_000_000);

// creates a map of that range onto its corresponding square number
IMap<Long, Long> = Maps.from(set, i -> i * i);
// creates a map of the numbers onto their corresponding square
IMap<Long, Long> map = Maps.from(set, i -> i * i);
```

Each of these collections is identical to its concrete, immutable equivalent. They can be updated, in which case only the changes to the underlying collection will be stored in memory.
Each of these collections are identical to their concrete, immutable equivalent. They can be updated, in which case only the changes to the underlying collection will be stored in memory.

### "linear" and "forked" collections

Expand Down
2 changes: 1 addition & 1 deletion benchmarks/benchmarks.edn

Large diffs are not rendered by default.

Binary file modified benchmarks/images/clone.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/concat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/list_construct.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/list_iterate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/list_lookup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/map_construct.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/map_difference.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/map_equals.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/map_intersection.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/map_iterate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/map_lookup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/map_union.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/set_construct.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/set_difference.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/set_equals.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/set_intersection.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/set_iterate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/set_lookup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified benchmarks/images/set_union.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 3 additions & 5 deletions doc/benchmarks.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
These benchmarks are generated using [Criterium](https://github.com/hugoduncan/criterium), which provides a median value based on repeated trials. These measurements are isolated from the effects of JIT or GC.

The numbers given here are scaled by the size of the collection, because otherwise the most noticeable feature of these benchmarks would be "larger collections take longer to create/iterate/etc". This means, however, that the numbers provided here are the mean duration of the median sample, and do not reflect the variation that might be seen in real-world usage.
The numbers given here are scaled by the size of the collection, because otherwise the most noticeable feature of these benchmarks would be "larger collections take longer to create/iterate/etc". This means, however, that the numbers provided here are the mean duration of the median sample, and do not reflect any variation that might be seen in real-world usage.

With that said, this is still as useful as pretty much any other data structure benchmark. The single largest factor in the performance of any in-memory data structure is whether it's in the cache, and the repeated operations of a benchmark guarantee a warm cache. This may reflect some real-world workloads, but not others. The performance for 1OOk+ element collections, which are too big to fit in cache, give some hint as to the effects of a cold cache, but also reflect the other costs of a larger collection.

Expand All @@ -12,12 +12,10 @@ Unlike Java's `HashMap` and `HashSet`, Bifurcan's `LinearMap` and `LinearSet` st

## Lists

Unlike Clojure and Java's lists, Bifurcan's lists can efficiently remove and add from both ends of the collection.
`List` and `LinearList` are more or less equivalent to Clojure's `PersistentVector` and Java's `ArrayList`, respectively. Unlike their counterparts, however, both allow for near constant-time slicing and concatenation.

![](../benchmarks/images/list_construct.png)

Bifurcan's `List` provides equivalent performance in iteration and random lookups to Clojure's vector, but unlike Clojure it also allows for near constant-time slices and concats.

![](../benchmarks/images/list_iterate.png)

![](../benchmarks/images/list_lookup.png)
Expand Down Expand Up @@ -50,7 +48,7 @@ However, both `Map` and `IntMap` also use their structure to perform equality ch

## Sets

The behavior for sets broadly mirrors that of the maps.
Since the sets are implemented in terms of their corresponding map, the behavior is much the same as above.

![](../benchmarks/images/set_construct.png)

Expand Down

0 comments on commit 9da9afb

Please sign in to comment.