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 (Tuple
s, NamedTuple
s, StaticArray
s, 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 Tuple
s with elements of different types:
julia> nonuniform_itr = ((1, 2), (1, 2, 3));
julia> @allocated () in nonuniform_itr
80
julia> @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 tomap
unrolled_any([f], itr)
—similar toany
unrolled_all([f], itr)
—similar toall
unrolled_foreach(f, itrs...)
—similar toforeach
unrolled_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 toaccumulate
unrolled_in(item, itr)
—similar toin
unrolled_unique([f], itr)
—similar tounique
unrolled_allunique([f], itr)
—similar toallunique
unrolled_allequal([f], itr)
—similar toallequal
unrolled_sum([f], itr; [init])
—similar tosum
, but withinit = 0
whenitr
is emptyunrolled_prod([f], itr; [init])
—similar toprod
, but withinit = 1
whenitr
is emptyunrolled_cumsum([f], itr)
—similar tocumsum
, but with an optionalf
unrolled_cumprod([f], itr)
—similar tocumprod
, but with an optionalf
unrolled_count([f], itr)
—similar tocount
unrolled_maximum([f], itr)
—similar tomaximum
unrolled_minimum([f], itr)
—similar tominimum
unrolled_extrema([f], itr)
—similar toextrema
unrolled_findmax([f], itr)
—similar tofindmax
unrolled_findmin([f], itr)
—similar tofindmin
unrolled_argmax([f], itr)
—similar toargmax
unrolled_argmin([f], itr)
—similar toargmin
unrolled_findfirst([f], itr)
—similar tofindfirst
unrolled_findlast([f], itr)
—similar tofindlast
unrolled_filter(f, itr)
—similar tofilter
unrolled_flatten(itr)
—similar toIterators.flatten
unrolled_flatmap(f, itrs...)
—similar toIterators.flatmap
unrolled_product(itrs...)
—similar toIterators.product
unrolled_cycle(itr, ::Val{N})
—similar toIterators.cycle
, but with a static value ofN
unrolled_partition(itr, ::Val{N})
—similar toIterators.partition
, but with a static value ofN
unrolled_take(itr, ::Val{N})
—similar toIterators.take
(i.e.,itr[1:N]
), but with a static value ofN
unrolled_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.,Tuple
andNamedTuple
) - statically sized iterators from
StaticArrays
(e.g.,SVector
andMVector
) - 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.OneTo
StaticBitVector
—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.