# Contiguous Read Non-Contiguous Write vs Non-Contiguous Read Contigous Write Performance

**URL:** https://discourse.julialang.org/t/contiguous-read-non-contiguous-write-vs-non-contiguous-read-contigous-write-performance/128604
**Category:** Performance
**Created:** [May 1, 2025, 10:22pm UTC](https://discourse.julialang.org/t/contiguous-read-non-contiguous-write-vs-non-contiguous-read-contigous-write-performance/128604 "2025-05-01T22:22:39Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![mj2984](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mj2984/32/43833_2.png) [@mj2984](https://discourse.julialang.org/u/mj2984)
#### Post date: [May 1, 2025, 10:22pm UTC](https://discourse.julialang.org/t/contiguous-read-non-contiguous-write-vs-non-contiguous-read-contigous-write-performance/128604/1 "2025-05-01T22:22:40Z")

</div>

```julia
function permutedims_custom(Y,X)
    for idx in range(1,size(Y,2))
        @simd for idy in range(1,size(Y,1))
            @inbounds Y[idy,idx] = X[idx,idy]
        end
    end
end

function permutedims_custom_2(Y,X)
    for idx in range(1,size(Y,1))
        @simd for idy in range(1,size(Y,2))
            @inbounds Y[idx,idy] = X[idy,idx]
        end
    end
end

```

In the above case permutedims\_custom outperforms permutedims\_custom\_2 by a fair margin (3x). The Contiguous write consistently outperforms the other method (even if I put mild customizations on top, like having offsets to create a diagonal stacked variable). Is this common for all type of RAM?

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [May 2, 2025, 1:57am UTC](https://discourse.julialang.org/t/contiguous-read-non-contiguous-write-vs-non-contiguous-read-contigous-write-performance/128604/2 "2025-05-02T01:57:31Z")

</div>

For an out-of-place transpose like this, to get good cache-line utilization you want to do **neither order** : you generally want to “tile” the loops, either by tuning to your cache or by using a cache-oblivious algorithm.

(Optimizing transposition is a heavily studied problem, with a fair amount of literature and code out there if you search.)

See also e.g. [Function on matrix transpose and performance - #4 by stevengj](https://discourse.julialang.org/t/function-on-matrix-transpose-and-performance/20068/4) and the links in that thread.

---

<div class="post-metadata">

### Author: ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)
#### Post date: [May 2, 2025, 9:28am UTC](https://discourse.julialang.org/t/contiguous-read-non-contiguous-write-vs-non-contiguous-read-contigous-write-performance/128604/4 "2025-05-02T09:28:28Z")

</div>

> [@mj2984](#):
>
> Is this common for all type of RAM?

It depends on the cache-architecture, size, and configuration, how prefetching and instructions are scheduled, and a whole lot of details. Without knowledge of these details, one would guess that contiguous reads are better than contiguous writes, because reads must be completed before an operation on the data, whereas writes can be postponed, and memory operations typically occur in whole cache-lines, often 64 contiguous bytes. But a lot of details can interfere with this simple view. In practice one would like to tune the algorithm to the system at hand.

---

<div class="post-metadata">

### Author: ![mj2984](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mj2984/32/43833_2.png) [@mj2984](https://discourse.julialang.org/u/mj2984)
#### Post date: [May 3, 2025, 12:50am UTC](https://discourse.julialang.org/t/contiguous-read-non-contiguous-write-vs-non-contiguous-read-contigous-write-performance/128604/5 "2025-05-03T00:50:39Z")

</div>

Thank you so much. I repeated the experiments with various array sizes.

The 3x speedup was a special case where size(Y,1) was of the order of cache-line width with larger size(Y,2). It essentially acted as its own tiling.

Swapping the inputs favored custom\_2 but the custom here was only 1.5x slower (since there’s other optimizations that is possible). permutedims! speed is comparable to custom in both cases, so I believe the logic should be similar (not as optimized as transpose).
