# Performance optimization：Frequently use permutedims function

**URL:** <https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474>\
**Category:** Performance\
**Tags:** question\
**Created:** [April 28, 2025, 3:15am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474 "2025-04-28T03:15:42Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![quantumdreamer](https://avatars.discourse-cdn.com/v4/letter/q/0ea827/32.png) [@quantumdreamer](https://discourse.julialang.org/u/quantumdreamer)\
**Post date:** [April 28, 2025, 3:15am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/1 "2025-04-28T03:15:42Z")

</div>

Here is my example：

````julia
G = rand(8,256,14,288,6)+rand(8,256,14,288,6)*1im;
@elapsed begin
    G = permutedims(G,[1,2,4,3,5]);
    k = sqrt.(sum(abs2.(reshape(G,589824,1,1,14,6)),dims = 1));
    G .*= k;
    G = permutedims(G,[1,2,4,3,5]);
end
```.
````

---

<div class="post-metadata">

**Author:** ![quantumdreamer](https://avatars.discourse-cdn.com/v4/letter/q/0ea827/32.png) [@quantumdreamer](https://discourse.julialang.org/u/quantumdreamer)\
**Post date:** [April 28, 2025, 3:16am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/2 "2025-04-28T03:16:03Z")

</div>

> [@quantumdreamer](#):
>
> `In my case,codes block like this in a for loop is frequently used,The G array is a matrix used to simulate the input and is not counted in the running time.I don't know how to further optimize it,i would appreciate it if anyone can help me？`

In my case,codes block like this in a for loop is frequently used,The G array is a matrix used to simulate the input and is not counted in the running time.I don’t know how to further optimize it,i would appreciate it if anyone can help me？

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [April 28, 2025, 6:01am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/3 "2025-04-28T06:01:37Z")

</div>

`permutedims` allocates a new array each time you call it. If you call it often, you can make use of `permutedims!` instead, which accepts a preallocated array such that you do not have to allocate a new one each time.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 28, 2025, 7:56am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/4 "2025-04-28T07:56:19Z")

</div>

> [@quantumdreamer](#):
>
> `H .*= k;`

You are not providing the `H` array. Do you need it? It’s hard to suggest improvements without a self-contained example.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 28, 2025, 8:06am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/5 "2025-04-28T08:06:04Z")

</div>

It would be easier to help if you create a fully self-contained function that shows exactly what inputs are given and what outputs are required. Right now, it’s unclear which of the variables are actually needed for output, and which are only temporary helpers that could be removed for performance optimization.

For example, why do you perform permutation twice on `G`, is that intentional? Do you need `k`, and will you output both `G`, `G1`, `H` and `k`? And where does `H` come from?

The only definitive advice I have right now is for a part where you didn’t ask for help:

> [@quantumdreamer](#):
>
> `G = rand(8,256,14,288,6)+rand(8,256,14,288,6)*1im;`

This should instead be

```julia
G = rand(ComplexF64, 8, 256, 14, 288, 6)

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 28, 2025, 8:24am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/6 "2025-04-28T08:24:21Z")

</div>

That said, here are some remarks:

1. If you use `permutedims`, specify the dimensions as a tuple, to avoid allocations: `G = permutedims(G,(1,2,4,3,5));`
2. Never write `sum(abs2.(X))`, instead write `sum(abs2, X)`, the latter avoids the temporary intermediate array.
3. Don’t use `permutedims`, instead specify the dimensions in the `sum` function:

```julia
k2 = sum(abs2, G; dims=(1, 2, 4))

```

1. Don’t calculate the `sqrt` before multiplying with `H`, since that creates a temporary array, instead fuse this calculation into the update: `H .*= sqrt.(k2)`.

That’s a start.

---

<div class="post-metadata">

**Author:** ![quantumdreamer](https://avatars.discourse-cdn.com/v4/letter/q/0ea827/32.png) [@quantumdreamer](https://discourse.julialang.org/u/quantumdreamer)\
**Post date:** [April 28, 2025, 10:59am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/7 "2025-04-28T10:59:38Z")

</div>

I correct my codes.Here, “H” should be changed to “G”

---

<div class="post-metadata">

**Author:** ![quantumdreamer](https://avatars.discourse-cdn.com/v4/letter/q/0ea827/32.png) [@quantumdreamer](https://discourse.julialang.org/u/quantumdreamer)\
**Post date:** [April 28, 2025, 11:16am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/8 "2025-04-28T11:16:43Z")

</div>

> [@quantumdreamer](#):
>
> `G = permutedims(G,[1,2,4,3,5])`

The reason why two permutedims are needed is that when calculating k, the G array is obtained after the first permutedims. I wonder if there is any way to obtain k through the G before permutedims.

---

<div class="post-metadata">

**Author:** ![quantumdreamer](https://avatars.discourse-cdn.com/v4/letter/q/0ea827/32.png) [@quantumdreamer](https://discourse.julialang.org/u/quantumdreamer)\
**Post date:** [April 28, 2025, 11:18am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/9 "2025-04-28T11:18:06Z")

</div>

I have to think about the third point you mentioned. Does it mean that this doesn’t require any permutedims

---

<div class="post-metadata">

**Author:** ![photor](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/photor/32/14343_2.png) [@photor](https://discourse.julialang.org/u/photor)\
**Post date:** [April 28, 2025, 11:35am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/10 "2025-04-28T11:35:15Z")

</div>

You should try Strided.jl .

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 28, 2025, 11:58am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/11 "2025-04-28T11:58:49Z")

</div>

> [@quantumdreamer](#):
>
> The reason why two permutedims are needed is that when calculating k, the G array is obtained after the first permutedims.

So you want to permute it back? You should probably use `invperm` for this. In this particular case, the permutation is its own inverse, but that’s not generally the case.

If you just need `G`, then you could do this:

```julia
function bar!(G)
    k2 = sum(abs2, G; dims=(1,2,4))
    G .*= sqrt.(k2);
    return G
end

```

which is much cleaner and faster, and allocates much less. Also it doesn’t hardcode dimension sizes, which you really should avoid.

Note that this will directly modify the array `G`.

There’s even more stuff you can do to speed this up and completely avoid any temporary arrays, but this is a simple solution.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 28, 2025, 12:05pm UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/12 "2025-04-28T12:05:39Z")

</div>

This version completely avoids allocations, but is roughly the same speed:

```julia
function baz!(G)
    for slice in eachslice(G; dims=(3, 5))
        slice .*= sqrt(sum(abs2, slice))
    end
    return G
end

```

---

<div class="post-metadata">

**Author:** ![quantumdreamer](https://avatars.discourse-cdn.com/v4/letter/q/0ea827/32.png) [@quantumdreamer](https://discourse.julialang.org/u/quantumdreamer)\
**Post date:** [April 29, 2025, 1:24am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/13 "2025-04-29T01:24:20Z")

</div>

Yes,It’s a good. I already try “@Strided”,but sometimes its performance is not good enough.

---

<div class="post-metadata">

**Author:** ![quantumdreamer](https://avatars.discourse-cdn.com/v4/letter/q/0ea827/32.png) [@quantumdreamer](https://discourse.julialang.org/u/quantumdreamer)\
**Post date:** [April 29, 2025, 1:27am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/14 "2025-04-29T01:27:26Z")

</div>

This is exactly what I want. Thank you for your help. This can indeed avoid unnecessary performance overhead

---

<div class="post-metadata">

**Author:** ![quantumdreamer](https://avatars.discourse-cdn.com/v4/letter/q/0ea827/32.png) [@quantumdreamer](https://discourse.julialang.org/u/quantumdreamer)\
**Post date:** [April 29, 2025, 3:09am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/15 "2025-04-29T03:09:25Z")

</div>

```julia
function foo(G)
    H = reshape(permutedims(G,(1,2,4,3,5)),8,256,288,14,6,1)
    H = permutedims(H,(2,1,6,5,3,4))
    return H
end
G = rand(ComplexF64,8,256,14,288,6);
H = foo(G);

```

---

<div class="post-metadata">

**Author:** ![quantumdreamer](https://avatars.discourse-cdn.com/v4/letter/q/0ea827/32.png) [@quantumdreamer](https://discourse.julialang.org/u/quantumdreamer)\
**Post date:** [April 29, 2025, 3:11am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/16 "2025-04-29T03:11:04Z")

</div>

Could you help me take a look at this by the way? I have no clue at all.@DNF

---

<div class="post-metadata">

**Author:** ![quantumdreamer](https://avatars.discourse-cdn.com/v4/letter/q/0ea827/32.png) [@quantumdreamer](https://discourse.julialang.org/u/quantumdreamer)\
**Post date:** [April 29, 2025, 3:23am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/17 "2025-04-29T03:23:44Z")

</div>

```julia
function bar2(G)
    out = similar(G, 256, 8, 1, 6, 288, 14)
    @inbounds for i5=1:6, i4=1:288, i3=1:14, i2=1:256, i1=1:8
        out[i2,i1,1,i5,i4,i3] = G[i1,i2,i3,i4,i5] # 注意索引对应关系
    end
    return out
end

```

This is how I do it at present.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 29, 2025, 5:30am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/18 "2025-04-29T05:30:09Z")

</div>

I don’t know how to improve on the performance of this code, but I would not use hardcoded ranges like that, it’s dangerous when combined with `@inbounds`. Use `size` or `axes` to get the ranges.

But the takeaway from my previous answer was that you didn’t need permutedims or reshape at all! Perhaps you don’t need it now either, but since I don’t know what you what this for, I cannot suggest any alternative.

---

<div class="post-metadata">

**Author:** ![quantumdreamer](https://avatars.discourse-cdn.com/v4/letter/q/0ea827/32.png) [@quantumdreamer](https://discourse.julialang.org/u/quantumdreamer)\
**Post date:** [April 30, 2025, 1:06am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/19 "2025-04-30T01:06:05Z")

</div>

OK,thank you for your advice.

---

<div class="post-metadata">

**Author:** ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)\
**Post date:** [April 30, 2025, 11:37am UTC](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474/20 "2025-04-30T11:37:32Z")

</div>

Also this works but the winner is `baz!`

```julia
using BenchmarkTools

function a(G)
    G = permutedims(G,[1,2,4,3,5]);
    k = sqrt.(sum(abs2.(reshape(G,589824,1,1,14,6)),dims = 1));
    G .*= k;
    G = permutedims(G,[1,2,4,3,5]);
end

function b(G)
    G = PermutedDimsArray(G,[1,2,4,3,5]);
    G .*= sqrt.(sum(abs2, reshape(G,589824,1,1,14,6),dims = 1));
    G = PermutedDimsArray(G,[1,2,4,3,5]);
end

function baz!(G)
    for slice in eachslice(G; dims=(3, 5))
        slice .*= sqrt(sum(abs2, slice))
    end
    return G
end

G = rand(8,256,14,288,6)+rand(8,256,14,288,6)*1im;

@btime a($G)
@btime b($G)
@btime baz!($G)

  1.105 s (30 allocations: 1.85 GiB)
  572.395 ms (27 allocations: 2.25 KiB)
  290.433 ms (0 allocations: 0 bytes)

```

[Next page](https://discourse.julialang.org/t/performance-optimization-frequently-use-permutedims-function/128474.md?page=2)
