Skip to content

Commit

Permalink
Add support for non-Tuple iterators, improve docs and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dennisYatunin committed Sep 4, 2024
1 parent 91a30eb commit 5ec4815
Show file tree
Hide file tree
Showing 18 changed files with 1,857 additions and 441 deletions.
7 changes: 7 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ version = "0.1.2"

[compat]
julia = "1.10"
StaticArrays = "1"

[weakdeps]
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

[extensions]
UnrolledUtilitiesStaticArraysExt = "StaticArrays"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
Expand Down
1 change: 1 addition & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
UnrolledUtilities = "0fe1646c-419e-43be-ac14-22321958931b"
26 changes: 15 additions & 11 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,32 @@ using Documenter

include(joinpath("..", "test", "test_and_analyze.jl"))

comparison_table_file = joinpath("docs", "src", "comparison_table.md")

open(comparison_table_file, "w") do io
println(io, "# Comparison Table\n```@raw html")
println(io, "<div style=\"width: max(80vw, 100%)\">") # use 80% of viewport
print_comparison_table(io, true)
println(io, "</div>")
println(io, "```")
comparison_tables_file = joinpath("docs", "src", "comparison_tables.md")
preamble_file = joinpath("docs", "src", "comparison_tables_preamble.md")
cp(preamble_file, comparison_tables_file; force = true)
open(comparison_tables_file, "a") do io
for (title, comparison_table_dict) in comparison_table_dicts
print_comparison_table(title, comparison_table_dict, io)
end
end

makedocs(;
sitename = "UnrolledUtilities.jl",
modules = [UnrolledUtilities],
pages = ["Home" => "index.md", "Comparison Table" => "comparison_table.md"],
pages = [
"Home" => "index.md",
"User Guide" => "user_guide.md",
"Developer Guide" => "developer_guide.md",
"Comparison Tables" => basename(comparison_tables_file),
],
format = Documenter.HTML(
prettyurls = get(ENV, "CI", nothing) == "true",
size_threshold_ignore = ["comparison_table.md"],
size_threshold_ignore = [basename(comparison_tables_file)],
),
clean = true,
)

rm(comparison_table_file)
rm(comparison_tables_file)

deploydocs(
repo = "github.com/CliMA/UnrolledUtilities.jl.git",
Expand Down
60 changes: 60 additions & 0 deletions docs/src/comparison_tables_preamble.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
The following autogenerated tables contain a representative set of potential use
cases for this package, along with measurements that summarize each case's
performance, compilation, and memory usage:
- run time (best of several trial measurements)
- compilation time (as reported by the compiler)
- overall level of optimization (type stability, constant propagation, etc.) and
allocations during run time (as reported by the garbage collector)
- total allocations during compilation and first run (as reported by the garbage
collector and, when possible, the Julia process's resident set size estimator)

The rows of the tables are highlighted as follows:
- ```@raw html
<span style="color:darkturquoise">light blue </span>
```
indicates an improvement in performance due to better optimization and either
an improvement or no change in compilation time and total allocations
- ```@raw html
<span style="color:royalblue">dark blue </span>
```
indicates an improvement in performance due to better optimization and either
slower compilation or more total allocations
- ```@raw html
<span style="color:mediumseagreen">green </span>
```
indicates either faster run time or fewer allocations during run time and
either an improvement or no change in compilation time and total allocations
- ```@raw html
<span style="color:khaki">yellow </span>
```
indicates either faster run time or fewer allocations during run time and
either slower compilation or more total allocations
- ```@raw html
<span style="color:mediumorchid">magenta </span>
```
indicates no change in performance and either an improvement or no change in
compilation time and total allocations
- ```@raw html
<span style="color:silver">light gray </span>
```
indicates no change in performance and either faster compilation with more
total allocations or slower compilation with fewer total allocations
- ```@raw html
<span style="color:gray">dark gray </span>
```
indicates no change in performance and no change in compilation time and total
allocations
- ```@raw html
<span style="color:indianred">red </span>
```
indicates a deterioration in performance, or no change in performance and
either slower compilation or more total allocations

Rows highlighted in gray present no clear advantage to unrolling, while those
highlighted in red present a clear disadvantage. It is recommended that you only
unroll when your use case is similar to a row in one of the remaining
categories, each of which demonstrates some advantage to unrolling.

The tables are also printed out by this package's test suite, so they can be
compared across different operating systems by consulting the
[CI pipeline](https://github.com/CliMA/UnrolledUtilities.jl/actions/workflows/ci.yml).
55 changes: 55 additions & 0 deletions docs/src/developer_guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
```@meta
CurrentModule = UnrolledUtilities
```

## Unrollable Iterator Interface

The functions exported by this package can be used with any statically sized
iterators, as long as those iterators are compatible with following interface:

```@docs
generic_getindex
output_type_for_promotion
AmbiguousOutputType
NoOutputType
ConditionalOutputType
output_promote_rule
constructor_from_tuple
```

## Extending the Interface

To unroll over a statically sized iterator of some user-defined type `T`, follow
these steps:
- Add a method for either `getindex(::T, n)` or `generic_getindex(::T, n)`
- If every unrolled function that needs to construct an iterator when given an
iterator of type `T` can return a `Tuple` instead, stop here; otherwise, to
return a non-Tuple iterator whenever possible, follow these steps:
- Add a method for `output_type_for_promotion(::T) = O`, where `O` can be
`T`, a supertype of `T`, or some other `Type` or `AmbiguousOutputType`
- If an output of type `O` can be used together with an output of type `O′`,
add a method for `output_promote_rule(O, O′)`
- If an output of type `O` can be efficiently constructed from a `Tuple`,
add a method for `constructor_from_tuple(O)`; otherwise, add a method for
each unrolled function that can efficiently generate an output of type `O`
without temporarily storing it as a `Tuple`

## Internals

*TODO: This is still under development.*

The unrolled functions have been written in a way that makes them very
likely to get fully optimized out through constant propagation when the
iterators have singleton element types (and when the result of calling `f`
and/or `op` on these elements is inferrable). However, they can also be much
more expensive to compile than their counterparts from `Base` and
`Base.Iterators`, in which case they should not be used unless there is a clear
performance benefit. Two notable exceptions to this are `unrolled_take` and
`unrolled_drop`, which are faster to compile than their non-static versions.

```@docs
rec_unroll
```

For more information, see the benchmarks for
[Generative vs. Recursive Unrolling](@ref).
Loading

0 comments on commit 5ec4815

Please sign in to comment.