UnrolledUtilities.jl
Compile-time loop unrolling for statically sized iterators, for type-stable and allocation-free code on CPUs and GPUs.
UnrolledUtilities — Module
UnrolledUtilitiesCompile-time loop unrolling for statically sized iterators, such as Tuples, NamedTuples, SVectors, StaticOneTos, and StaticBitVectors. The exported functions are unrolled analogues of functions from Base and Base.Iterators that stay type-stable and free of allocations for long and heterogeneous iterators, which lets them run in GPU kernels and constant-fold results that are used as type parameters.
- Modification and slicing:
unrolled_push,unrolled_append,unrolled_prepend,unrolled_take,unrolled_drop,unrolled_setindex, andunrolled_insert. - Mapping, iteration, and reductions:
unrolled_map,unrolled_foreach,unrolled_any,unrolled_all,unrolled_reduce,unrolled_mapreduce,unrolled_accumulate,unrolled_sum,unrolled_prod,unrolled_cumsum,unrolled_cumprod, andunrolled_count. - Extrema, searching, and indexing:
unrolled_maximum,unrolled_minimum,unrolled_extrema,unrolled_findmax,unrolled_findmin,unrolled_argmax,unrolled_argmin,unrolled_findfirst,unrolled_findlast,unrolled_argfirst,unrolled_arglast, andunrolled_applyat. - Membership, uniqueness, and filtering:
unrolled_in,unrolled_unique,unrolled_allunique,unrolled_allequal,unrolled_filter, andunrolled_split. - Combinators and partitioning:
unrolled_flatten,unrolled_flatmap,unrolled_product,unrolled_cycle, andunrolled_partition.
Installation
using Pkg
Pkg.add("UnrolledUtilities")Quick Example
Functions from Base lose type stability on long heterogeneous Tuples, and Tuples of more than 32 Bools allocate when they are mapped; the unrolled functions and a 300-bit StaticBitVector do neither:
julia> using UnrolledUtilities, Testjulia> items = ntuple(n -> isodd(n) ? (n, n) : (n / 2,), 33);julia> Test.@inferred sum(sum, items);ERROR: return type Float64 does not match inferred return type Union{Float64, Int64}julia> Test.@inferred unrolled_sum(sum, items)714.0julia> const bools = ntuple(isodd, Val(300));julia> const bits = StaticBitVector{300}(isodd);julia> @allocated map(!, bools)2840julia> @allocated unrolled_map(!, bits)0
Contents
- Introduction: what loop unrolling does, and what it costs.
- User Guide: when unrolled functions and the static iterator types outperform their counterparts in
Base. - Cookbook: short recipes for
NamedTuplefields, type parameters, run-time indices, bounds checks, and bitmasks. - Compilation Limits: what the compiler must know for unrolled code to stay type-stable, and how to give it that information.
- API Reference: every exported function and type, and the container type that each function returns.
- Developer Guide: how to make a user-defined iterator type work with the unrolled functions.
- Comparison Tables: measured run times, compilation times, and allocations of unrolled functions against their counterparts in
Base.
Contributing
Issues and pull requests are welcome on GitHub. Development follows the CliMA developer guides. Pkg.test() runs the test suite in a few minutes; the benchmarks behind the comparison tables run when UNROLLED_UTILITIES_BENCHMARK=true is set.