# Type stability with type as argument and permutedims

**URL:** <https://discourse.julialang.org/t/type-stability-with-type-as-argument-and-permutedims/108335>\
**Category:** Performance\
**Tags:** type-stability\
**Created:** [January 4, 2024, 11:19am UTC](https://discourse.julialang.org/t/type-stability-with-type-as-argument-and-permutedims/108335 "2024-01-04T11:19:22Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![snowgum](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@snowgum](https://discourse.julialang.org/u/snowgum)\
**Post date:** [January 4, 2024, 11:19am UTC](https://discourse.julialang.org/t/type-stability-with-type-as-argument-and-permutedims/108335/1 "2024-01-04T11:19:23Z")

</div>

I am experiencing poor performance (maybe type unstable?) when having a type as an optional argument to a function, and using `permutedims` inside. I’m having difficulty understanding why the first function is much slower than the second:

```julia
function test1(; FloatT=Float32)
    tmp = Array{FloatT}(undef, 100, 100, 100)
    new = permutedims(tmp, (3, 2, 1))
    for i in eachindex(new)
        new[i] = new[i] / 10
    end
    return new
end

function test2()
    tmp = Array{Float32}(undef, 100, 100, 100)
    new = permutedims(tmp, (3, 2, 1))
    for i in eachindex(new)
        new[i] = new[i] / 10
    end
    return new
end

```

And benchmarks (Julia 1.10):

```julia
julia> @benchmark test1()
BenchmarkTools.Trial: 75 samples with 1 evaluation.
 Range (min … max): 60.314 ms … 127.058 ms ┊ GC (min … max): 0.49% … 49.45%
 Time (median): 60.891 ms ┊ GC (median): 0.91%
 Time (mean ± σ): 66.794 ms ± 17.127 ms ┊ GC (mean ± σ): 9.11% ± 13.86%

  █▂
  ██▆▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▆▆▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▄▄▄ ▁
  60.3 ms Histogram: log(frequency) by time 126 ms <

 Memory estimate: 68.65 MiB, allocs estimate: 3998989.

julia> @benchmark test2()
BenchmarkTools.Trial: 2822 samples with 1 evaluation.
 Range (min … max): 1.246 ms … 9.494 ms ┊ GC (min … max): 0.00% … 80.71%
 Time (median): 1.567 ms ┊ GC (median): 0.00%
 Time (mean ± σ): 1.770 ms ± 527.255 μs ┊ GC (mean ± σ): 11.85% ± 16.25%

       ▁▃▇█▄▃▁
  ▃▂▂▃▅███████▅▄▃▂▂▂▁▂▁▁▂▁▁▁▁▂▁▁▂▂▁▂▂▂▃▃▃▃▃▃▃▃▃▃▃▃▂▂▂▂▃▂▂▂▂▂▂ ▃
  1.25 ms Histogram: frequency by time 3.33 ms <

 Memory estimate: 7.63 MiB, allocs estimate: 4.

```

I’ve tried with `@code_warntype` and Cthulhu but could not find a type instability. If I remove the call to `permutedims`, the functions are equally fast.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 4, 2024, 11:32am UTC](https://discourse.julialang.org/t/type-stability-with-type-as-argument-and-permutedims/108335/2 "2024-01-04T11:32:40Z")

</div>

This is one of these cases, where Julia does not specialize: [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing)

---

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [January 4, 2024, 11:47am UTC](https://discourse.julialang.org/t/type-stability-with-type-as-argument-and-permutedims/108335/3 "2024-01-04T11:47:29Z")

</div>

As a workaround, you may create a function barrier to enforce the specialization:

```julia
julia> function test2(; FloatT=Float32)
           tmp = Array{FloatT}(undef, 100, 100, 100)
           (tmp -> begin
               new = permutedims(tmp, (3, 2, 1))
               for i in eachindex(new)
                   new[i] = new[i] / 10
               end
               return new
           end)(tmp)
       end
test2 (generic function with 1 method)

julia> @btime test2();
  1.889 ms (4 allocations: 7.63 MiB)

```

---

<div class="post-metadata">

**Author:** ![snowgum](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@snowgum](https://discourse.julialang.org/u/snowgum)\
**Post date:** [January 4, 2024, 12:08pm UTC](https://discourse.julialang.org/t/type-stability-with-type-as-argument-and-permutedims/108335/4 "2024-01-04T12:08:48Z")

</div>

Thank you for the replies, it was very helpful. Seems like the easiest solution is to do something like:

```julia
function test3(; t::Type{T}=Float32) where T
    tmp = Array{T}(undef, 100, 100, 100)
    new = permutedims(tmp, (3, 2, 1))
    for i in eachindex(new)
       new[i] = new[i] / 10
    end
    return new
end

```

```julia
@benchmark test3(t=Float32)
BenchmarkTools.Trial: 3033 samples with 1 evaluation.
 Range (min … max): 1.068 ms … 3.514 ms ┊ GC (min … max): 0.00% … 55.37%
 Time (median): 1.488 ms ┊ GC (median): 0.00%
 Time (mean ± σ): 1.647 ms ± 420.597 μs ┊ GC (mean ± σ): 10.16% ± 14.73%

             ▄▆▆█▃
  ▂▂▅▂▂▁▂▃▃▂▃██████▆▄▃▂▂▂▂▂▁▁▁▂▂▂▂▂▂▂▂▂▂▂▂▂▂▃▃▂▃▃▂▃▃▃▃▃▃▃▃▃▃▂ ▃
  1.07 ms Histogram: frequency by time 2.79 ms <

 Memory estimate: 7.63 MiB, allocs estimate: 4.

```
