# Big overhead with the new lazy reshape/reinterpret

**URL:** https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635
**Category:** Internals & Design
**Created:** [December 8, 2017, 8:02pm UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635 "2017-12-08T20:02:20Z")
**Posts on this page:** 16
**Page:** 2

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [May 22, 2018, 5:06pm UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/21 "2018-05-22T17:06:38Z")

</div>

No, I think `array.c` should do all the thinking for reinterpreting arrays in some `Base.unsafe_reinterpret`. That is, this kind of reinterpret is the job for someone who knows all the array flags, all the multi-threaded and multiprocessor special cases, who knows which array to lock when, etc. Think of the following:

```julia
julia> A=[1,2,3];
julia> B=reinterpret(UInt64, A);
julia> push!(A, 1);
ERROR: cannot resize array with shared data
julia> push!(B, 1);

```

I am sceptical that allowing `push!` to `B` is a good idea. But some author of `array.c` thought about this, and every end-user resorting to pointer games is definitely worse than core people giving us the best and safest thing that can be done with zero-overhead, and all the segfaults we asked for when zero-overhead is not possible.

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [May 22, 2018, 5:11pm UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/22 "2018-05-22T17:11:33Z")

</div>

The amount of code is not always a good sign of how much will happen in the runtime. It has been confirmed that this all used to optimize away but now fails to do so.

---

<div class="post-metadata">

### Author: ![ExpandingMan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/expandingman/32/866_2.png) [@ExpandingMan](https://discourse.julialang.org/u/ExpandingMan)
#### Post date: [May 22, 2018, 5:13pm UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/23 "2018-05-22T17:13:22Z")

</div>

> [@kristoffer.carlsson](#):
>
> The amount of code is not always a good sign of how much will happen in the runtime. It has been confirmed that this all used to optimize away but now fails to do so.

Fair enough, but I remember coming to the conclusion that in many cases this would not be a no-op (it’s been quite a while since I’ve looked at it carefully, so maybe I don’t know what I’m talking about).

I don’t _ever_ remember a time when there weren’t problems with this though, at what point did it get broken?

---

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [May 22, 2018, 5:35pm UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/24 "2018-05-22T17:35:19Z")

</div>

Even if true, this does not make a `Base.unsafe_reinterpret` obsolete. Alone the fact that  
`y? reinterpret(some_T, x): something::Array{some_T}` is now type-unstable makes it necessary to sometimes really reinterpret memory regions, not julia objects. And the old reinterpret code is perfectly fine for this job, and so much better than `unsafe_wrap` hacks that will break on first contact with arrays that have nonzero `offset`.

---

<div class="post-metadata">

### Author: ![ExpandingMan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/expandingman/32/866_2.png) [@ExpandingMan](https://discourse.julialang.org/u/ExpandingMan)
#### Post date: [May 22, 2018, 5:57pm UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/25 "2018-05-22T17:57:37Z")

</div>

Having an `unsafe_reinterpret` that is basically just a safe copy of an `unsafe_wrap`ed array does seem like it would be a useful thing. Basically my current workaround of the `reinterpret` slowness is to do this by default, but also to allow `view`s of `unsafe_wrap`ed arrays when it is guaranteed safe.

---

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [May 22, 2018, 6:14pm UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/26 "2018-05-22T18:14:32Z")

</div>

After you `unsafe_wrap` an array it is indistinguishable from a “proper” array. That’s what the old reinterpret does. But a one-liner that grabs the pointer and unsafe wraps it is not optimal: In principle you should handle offsets, lock arrays against resizing and possibly handle other array flags. Views of `unsafe_wrap` arrays are OK by default. Consider:

```julia
julia> zz=[];
       for i=1:50_000
       n=rand(1:30)
       A=zeros(UInt32,n*n+1);
       deleteat!(A,1);
       #B=unsafe_wrap(Array,pointer(A),(n,n))
       B=reinterpret(UInt32,A,(n,n))
       push!(zz,B);
       (i%1000 == 0)&& gc()
       end;
julia> all(iszero.(zz))
true

julia> zz=[];
       for i=1:50_000
       n=rand(1:30)
       A=zeros(UInt32,n*n+1);
       deleteat!(A,1);
       B=unsafe_wrap(Array,pointer(A),(n,n))
       #B=reinterpret(UInt32,A,(n,n))
       push!(zz,B);
       (i%1000 == 0)&& gc()
       end;

julia> all(iszero.(zz))
false

```

edit: So we see that we corrupted memory in the second variant (all on 0.62). Expecting users to handle these subtleties is slightly harsh, imo.

---

<div class="post-metadata">

### Author: ![Keno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/keno/32/285_2.png) [@Keno](https://discourse.julialang.org/u/Keno)
#### Post date: [May 23, 2018, 2:04am UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/27 "2018-05-23T02:04:44Z")

</div>

[https://github.com/JuliaLang/julia/pull/27213](https://github.com/JuliaLang/julia/pull/27213)

---

<div class="post-metadata">

### Author: ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)
#### Post date: [May 23, 2018, 6:24am UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/28 "2018-05-23T06:24:05Z")

</div>

You are the man! Thank you so much Keno!

---

<div class="post-metadata">

### Author: ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)
#### Post date: [May 23, 2018, 10:11am UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/29 "2018-05-23T10:11:52Z")

</div>

Some benchmaks:

```julia
using StaticArrays
m = rand(3, 1_000_000);
v = reinterpret(SVector{3,Float64}, m, (1_000_000,));
sum(v);

```

v0.6.2

```julia
julia> @time sum(v);
  0.002449 seconds (5 allocations: 192 bytes)

```

current master:

```julia
julia> @time sum(v);
  0.016592 seconds (9 allocations: 320 bytes)

```

Keno’s PR #27213:

```julia
julia> @time sum(v);
  0.002688 seconds (9 allocations: 320 bytes)

```

Nice!

---

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [May 23, 2018, 11:49am UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/30 "2018-05-23T11:49:35Z")

</div>

Awesome!

And the new pointerref / pointerset intrinsics for controlling tbaa are also really cool, thanks a lot!

---

<div class="post-metadata">

### Author: ![ExpandingMan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/expandingman/32/866_2.png) [@ExpandingMan](https://discourse.julialang.org/u/ExpandingMan)
#### Post date: [May 23, 2018, 1:25pm UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/31 "2018-05-23T13:25:40Z")

</div>

Wow, awesome @keno! All that work on the optimizer and then a `reinterpret` PR almost immediately, you are one prolific coder! I’m sure all of us will hugely appreciate whatever improvement this can offer.

---

<div class="post-metadata">

### Author: ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)
#### Post date: [August 18, 2018, 12:47am UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/32 "2018-08-18T00:47:59Z")

</div>

Keno’s updated PR #28707 has just been merged! As of 8 hours ago, v1.1.0-DEV shows this

```julia
julia> using StaticArrays, BenchmarkTools
julia> a = rand(3, 10^4); b = reshape(reinterpret(SVector{3, Float64}, a), (size(a, 2),))
julia> @btime $b[5][2];
  1.347 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

### Author: ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)
#### Post date: [August 18, 2018, 4:52am UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/33 "2018-08-18T04:52:31Z")

</div>

How does it compare to a normal array?

---

<div class="post-metadata">

### Author: ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)
#### Post date: [August 18, 2018, 7:57pm UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/34 "2018-08-18T19:57:18Z")

</div>

I’m not sure I know what you mean. Are you thinking about reinterpreting an `Array` of `Array`s? In that case, I’d think you cannot use `reinterpret`, which is actually for `Array`s of bitstypes

```julia
julia> isbitstype(eltype([[1,2],[3,4]]))
false
julia> isbitstype(eltype([SVector(1,2),SVector(3,4)]))
true

```

You might be looking for `hcat` and friends. Maybe I misunderstood?

---

<div class="post-metadata">

### Author: ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)
#### Post date: [August 18, 2018, 8:51pm UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/35 "2018-08-18T20:51:45Z")

</div>

No, I mean compared to `getindex` for a normal array `b[5]` where `b::Vector{SVector{3, Float64}}`. In v0.6 this would have been the output of the `reshape(reinterpret(..))`. So I am interested in knowing the cost of these 2 operations in v1.1.0-DEV.

I am asking because I don’t have access to a Linux machine currently and building v1.1.0-DEV on Windows didn’t work for me.

---

<div class="post-metadata">

### Author: ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)
#### Post date: [August 18, 2018, 9:02pm UTC](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635/36 "2018-08-18T21:02:19Z")

</div>

Ah, sorry, yes, they’re the same now. You cannot go much lower than this, I guess.

```julia
julia> b=[SVector{3}(rand(3)) for i in 1:10^4];
julia> @btime $b[5][2];
  1.347 ns (0 allocations: 0 bytes)

```

It’s interesting that, despite the above, the `@code_native` of the lazy and eager cases is quite different.

[Previous page](https://discourse.julialang.org/t/big-overhead-with-the-new-lazy-reshape-reinterpret/7635.md?page=1)
