UnrolledUtilities.jl
A toolkit for low-level optimization of Julia code in which iterator sizes are known during compilation.
This package can be used with all statically sized iterators (Tuples, NamedTuples, StaticArrays, etc.), including ones that are very long or ones that have elements of different types, both of which are cases that Julia's standard library often handles inefficiently. For example, the standard libary function in performs worse than this package's unrolled_in for Tuples with elements of different types:
julia> nonuniform_itr = ((1, 2), (1, 2, 3));julia> @allocated () in nonuniform_itr80julia> @allocated unrolled_in((), nonuniform_itr)0
The loop unrolling automatically performed by this package offers the following benefits for statically sized iterators:
- better support for static compilation
- compilation of executables
- compilation of GPU kernels
- better performance (usually)
- reduced run times
- reduced memory footprints while code is running
- better compilation efficiency (occasionally)
- reduced compilation times
- reduced memory footprints while code is compiling
To find out more about loop unrolling and when it is useful, see the Introduction.
Package Features
This package exports a number of analogues to functions from Base and Base.Iterators, each of which has been optimized for statically sized iterators (in terms of both performance and compilation time):
unrolled_push(itr, item)—similar topush!, but non-mutatingunrolled_append(itr, itrs...)—similar toappend!, but non-mutatingunrolled_prepend(itr, itrs...)—similar toprepend!, but non-mutatingunrolled_map(f, itrs...)—similar tomapunrolled_any([f], itr)—similar toanyunrolled_all([f], itr)—similar toallunrolled_foreach(f, itrs...)—similar toforeachunrolled_reduce(op, itr; [init])—similar toreduce(i.e.,foldl)unrolled_mapreduce(f, op, itrs...; [init])—similar tomapreduce(i.e.,mapfoldl)unrolled_accumulate(op, itr; [init])—similar toaccumulateunrolled_in(item, itr)—similar toinunrolled_unique([f], itr)—similar touniqueunrolled_allunique([f], itr)—similar toalluniqueunrolled_allequal([f], itr)—similar toallequalunrolled_sum([f], itr; [init])—similar tosum, but withinit = 0whenitris emptyunrolled_prod([f], itr; [init])—similar toprod, but withinit = 1whenitris emptyunrolled_cumsum([f], itr)—similar tocumsum, but with an optionalfunrolled_cumprod([f], itr)—similar tocumprod, but with an optionalfunrolled_count([f], itr)—similar tocountunrolled_maximum([f], itr)—similar tomaximumunrolled_minimum([f], itr)—similar tominimumunrolled_extrema([f], itr)—similar toextremaunrolled_findmax([f], itr)—similar tofindmaxunrolled_findmin([f], itr)—similar tofindminunrolled_argmax([f], itr)—similar toargmaxunrolled_argmin([f], itr)—similar toargminunrolled_findfirst([f], itr)—similar tofindfirstunrolled_findlast([f], itr)—similar tofindlastunrolled_filter(f, itr)—similar tofilterunrolled_flatten(itr)—similar toIterators.flattenunrolled_flatmap(f, itrs...)—similar toIterators.flatmapunrolled_product(itrs...)—similar toIterators.productunrolled_cycle(itr, ::Val{N})—similar toIterators.cycle, but with a static value ofNunrolled_partition(itr, ::Val{N})—similar toIterators.partition, but with a static value ofNunrolled_take(itr, ::Val{N})—similar toIterators.take(i.e.,itr[1:N]), but with a static value ofNunrolled_drop(itr, ::Val{N})—similar toIterators.drop(i.e.,itr[(N + 1):end]), but with a static value ofN
In addition, this package exports several functions that do not have analogues in Base or Base.Iterators:
unrolled_applyat(f, n, itrs...)—similar tof(itrs[1][n], itrs[2][n], ...)unrolled_argfirst(f, itr)—similar toitr[findfirst(f, itr)]unrolled_arglast(f, itr)—similar toitr[findlast(f, itr)]unrolled_split(f, itr)—similar to(filter(f, itr), filter(!f, itr)), but without duplicate calls tof
These unrolled functions are compatible with the following types of iterators:
- statically sized iterators from
Base(e.g.,TupleandNamedTuple) - statically sized iterators from
StaticArrays(e.g.,SVectorandMVector) - lazy iterators from
Base(e.g., the results of generator expressions,Iterators.map,Iterators.reverse,enumerate, andzip) that are used as wrappers for statically sized iterators
They are also compatible with two new types of statically sized iterators exported by this package:
StaticOneTo—similar toBase.OneToStaticBitVector—similar toBitVector
See the User Guide for additional information about these new types of iterators.
See the Developer Guide to learn how user-defined iterator types can be made compatible with unrolled functions.