# ReinterpretedArray Performance (even worse on 1.8)

**URL:** https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102
**Category:** Performance
**Tags:** performance
**Created:** [April 27, 2022, 3:31am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102 "2022-04-27T03:31:02Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![cortner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cortner/32/204_2.png) [@cortner](https://discourse.julialang.org/u/cortner)
#### Post date: [April 27, 2022, 3:31am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/1 "2022-04-27T03:31:02Z")

</div>

I’d like to use reinterpreted arrays to write into and read from an array. Here is a little script that is a bit oversimplified but not too far from my real use-case.

```julia
using BenchmarkTools

function cheb!(A, x)
   A[1] = 1 
   A[2] = x 
   for n = 3:length(A) 
      A[n] = 2 * x * A[n-1] - A[n-2]
   end
end

# Standard Array 
A = zeros(100)
# Reinterpreted Array 
B = reinterpret(Float64, zeros(UInt8, 100 * sizeof(Float64)))

# simple benchmark
x = rand()
print(" Array: "); @btime cheb!($A, $x)
print("ReinterpretArray: "); @btime cheb!($B, $x)

```

I always assumed that the abstraction here would be free, but apparently not. It is ok, not great on Julia 1.7 but terrible on Julia 1.8:

Output:

```julia
> j17 chebtest.jl
           Array: 454.965 ns (0 allocations: 0 bytes)
ReinterpretArray: 690.476 ns (0 allocations: 0 bytes)
> j18 chebtest.jl
           Array: 198.605 ns (0 allocations: 0 bytes)
ReinterpretArray: 965.647 ns (0 allocations: 0 bytes)

```

Julia Versions:

```julia
julia> versioninfo()
Julia Version 1.7.2
Commit bf53498635* (2022-02-06 15:21 UTC)
Platform Info:
  OS: macOS (arm64-apple-darwin21.2.0)
  CPU: Apple M1 Max
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-12.0.1 (ORCJIT, cyclone)

julia> versioninfo()
Julia Version 1.8.0-beta3
Commit 3e092a2521 (2022-03-29 15:42 UTC)
Platform Info:
  OS: macOS (arm64-apple-darwin21.2.0)
  CPU: 10 × Apple M1 Max
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, apple-m1)
  Threads: 1 on 8 virtual cores

```

---

<div class="post-metadata">

### Author: ![cortner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cortner/32/204_2.png) [@cortner](https://discourse.julialang.org/u/cortner)
#### Post date: [April 27, 2022, 3:41am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/2 "2022-04-27T03:41:45Z")

</div>

Updated script, adding `@inbounds`, and two more tests. `unsafe_wrap` and `UnsafeArrays` into the mix. This largely seems to resolve the problem?

```julia
using BenchmarkTools, UnsafeArrays

function cheb!(A, x)
   A[1] = 1 
   A[2] = x 
   for n = 3:length(A) 
      @inbounds A[n] = 2 * x * A[n-1] - A[n-2]
   end
end

# Standard Array 
A = zeros(100)
# Reinterpreted Array 
B = reinterpret(Float64, zeros(UInt8, 100 * sizeof(Float64)))
# unsafe_wrap 
_C = zeros(UInt8, 100 * sizeof(Float64))
ptr = Base.unsafe_convert(Ptr{Float64}, _C)
C = Base.unsafe_wrap(Array, ptr, 100)
# UnsafeArrays
D = UnsafeArray(ptr, (100,))

# simple benchmark
x = rand()
print(" Array: "); @btime cheb!($A, $x)
print("ReinterpretArray: "); @btime cheb!($B, $x)
print(" unsafe: "); @btime cheb!($C, $x)
print(" UnsafeArray: "); @btime cheb!($D, $x)

```

Results:

```julia
> j17 chebtest.jl 7s
           Array: 169.928 ns (0 allocations: 0 bytes)
ReinterpretArray: 426.822 ns (0 allocations: 0 bytes)
          unsafe: 170.455 ns (0 allocations: 0 bytes)
     UnsafeArray: 187.381 ns (0 allocations: 0 bytes)

> j18 chebtest.jl 8s
           Array: 185.108 ns (0 allocations: 0 bytes)
ReinterpretArray: 230.561 ns (0 allocations: 0 bytes)
          unsafe: 183.610 ns (0 allocations: 0 bytes)
     UnsafeArray: 189.774 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

### Author: ![cortner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cortner/32/204_2.png) [@cortner](https://discourse.julialang.org/u/cortner)
#### Post date: [April 27, 2022, 3:50am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/3 "2022-04-27T03:50:26Z")

</div>

I thought maybe something weird about the M1, but same on an AMD EPYC-ROME:

```julia
j17 test_cheb.jl 
           Array: 373.473 ns (0 allocations: 0 bytes)
ReinterpretArray: 962.550 ns (0 allocations: 0 bytes)
          unsafe: 373.473 ns (0 allocations: 0 bytes)
     UnsafeArray: 161.749 ns (0 allocations: 0 bytes)

```

EDIT: adding this is without @inbounds, so it seems that `UnsafeArray` doesn’t do bound checks which explains this behaviour…

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [April 27, 2022, 3:51am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/4 "2022-04-27T03:51:38Z")

</div>

I once again ask for Base to have this:

```julia
function unsafe_arraycast(::Type{D}, ary::Vector{S}) where {S, D}
    l = sizeof(S)*length(ary)÷sizeof(D)
    res = ccall(:jl_reshape_array, Vector{D}, (Any, Any, Any), Vector{D}, ary, (l,))
    return res
end

```

---

<div class="post-metadata">

### Author: ![cortner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cortner/32/204_2.png) [@cortner](https://discourse.julialang.org/u/cortner)
#### Post date: [April 27, 2022, 3:55am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/5 "2022-04-27T03:55:52Z")

</div>

how is this related to `Base.unsafe_wrap` and to `UnsafeArrays`?

---

<div class="post-metadata">

### Author: ![suavesito](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/suavesito/32/34386_2.png) [@suavesito](https://discourse.julialang.org/u/suavesito)
#### Post date: [April 27, 2022, 3:58am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/6 "2022-04-27T03:58:22Z")

</div>

I think is basically what you did with `unsafe_wrap` + `unsafe_convert`.

---

<div class="post-metadata">

### Author: ![cortner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cortner/32/204_2.png) [@cortner](https://discourse.julialang.org/u/cortner)
#### Post date: [April 27, 2022, 3:58am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/7 "2022-04-27T03:58:37Z")

</div>

And maybe my most important Question - is there a reason for me to not use `unsafe_wrap` or `UnsafeArrays` as long as I always keep around the original reference? E.g. like this:

```julia
struct MyVector{T} <: Vector{T}
   _A::Vector{UInt8} 
   A::Vector{T}
end

```

---

<div class="post-metadata">

### Author: ![cortner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cortner/32/204_2.png) [@cortner](https://discourse.julialang.org/u/cortner)
#### Post date: [April 27, 2022, 4:00am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/8 "2022-04-27T04:00:02Z")

</div>

And then still in the end: isn’t the incredibly poor performance of reinterpreted arrays on J1.8 strange when bounds-checking is enabled?

---

<div class="post-metadata">

### Author: ![suavesito](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/suavesito/32/34386_2.png) [@suavesito](https://discourse.julialang.org/u/suavesito)
#### Post date: [April 27, 2022, 4:02am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/9 "2022-04-27T04:02:09Z")

</div>

I think as long you keep the reference to the original `Vector` you are safe to use both, the GC will not free the memory exactly because you keep the original reference.

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [April 27, 2022, 4:02am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/10 "2022-04-27T04:02:14Z")

</div>

this is truly unsafe and best performance because it gives you a native array

```julia
julia> unsafe_arraycast(Float64, rand(UInt8, 64))
8-element Vector{Float64}:
 -6.079564859434036e242
  2.8652427427119243e252
 -7.940145865008032e-108
  8.320185091615792e-8
  5.427223515701773e188
  9.184586067914578e-204
  2.342950753478369e-31
  2.653381005394009e266

```

---

<div class="post-metadata">

### Author: ![cortner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cortner/32/204_2.png) [@cortner](https://discourse.julialang.org/u/cortner)
#### Post date: [April 27, 2022, 5:12am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/11 "2022-04-27T05:12:57Z")

</div>

@jling - thank you. And same principle - I need to keep the reference to the original array?

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [April 27, 2022, 5:20am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/12 "2022-04-27T05:20:31Z")

</div>

nope,

```julia
jl_reshape_array

```

handles that

---

<div class="post-metadata">

### Author: ![suavesito](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/suavesito/32/34386_2.png) [@suavesito](https://discourse.julialang.org/u/suavesito)
#### Post date: [April 27, 2022, 5:21am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/13 "2022-04-27T05:21:51Z")

</div>

I think no, as the reference to the memory is the same. You can check it with

```julia
julia> function unsafe_arraycast(::Type{D}, ary::Vector{S}) where {S, D}
           l = sizeof(S)*length(ary)÷sizeof(D)
           res = ccall(:jl_reshape_array, Vector{D}, (Any, Any, Any), Vector{D}, ary, (l,))
           return res
       end
unsafe_arraycast (generic function with 1 method)

julia> A = zeros(UInt8, 10 * sizeof(Float64));

julia> B = unsafe_arraycast(Float64, A);

julia> pointer(A)
Ptr{UInt8} @0x00007f744d5eba28

julia> pointer(B)
Ptr{Float64} @0x00007f744d5eba28

```

---

<div class="post-metadata">

### Author: ![cortner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cortner/32/204_2.png) [@cortner](https://discourse.julialang.org/u/cortner)
#### Post date: [April 27, 2022, 5:53am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/14 "2022-04-27T05:53:04Z")

</div>

That’s really nice - thanks for the suggestion

---

<div class="post-metadata">

### Author: ![cortner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cortner/32/204_2.png) [@cortner](https://discourse.julialang.org/u/cortner)
#### Post date: [April 27, 2022, 5:54am UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/15 "2022-04-27T05:54:35Z")

</div>

Why do you label it unsafe then?

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [April 27, 2022, 3:15pm UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/16 "2022-04-27T15:15:41Z")

</div>

because it is super unsafe and Julia devs strongly against even having this as `unsafe_*` function in the base.

Notice this doesn’t work before 1.7 and is likely to break again in the future when `jl_reshape_array` changes

---

<div class="post-metadata">

### Author: ![suavesito](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/suavesito/32/34386_2.png) [@suavesito](https://discourse.julialang.org/u/suavesito)
#### Post date: [April 27, 2022, 3:34pm UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/17 "2022-04-27T15:34:52Z")

</div>

> [@jling](#):
>
> it is super unsafe

In what sense is it “super unsafe”? Is if because something internals of Julia? Memory aliasing with different types? 🤔 😕

> [@jling](#):
>
> Notice this doesn’t work before 1.7

Weird, I’m testing on `v1.7` and it looks to work just fine. 😅

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [April 27, 2022, 4:23pm UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/18 "2022-04-27T16:23:33Z")

</div>

before 1.7 means 1.6 doesn’t work

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [April 27, 2022, 4:25pm UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/19 "2022-04-27T16:25:08Z")

</div>

![image](https://global.discourse-cdn.com/julialang/original/3X/4/d/4dfba659804864902834c454c5bfa6c2ef2d2dee.png)

we should ask @jameson I guess

---

<div class="post-metadata">

### Author: ![suavesito](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/suavesito/32/34386_2.png) [@suavesito](https://discourse.julialang.org/u/suavesito)
#### Post date: [April 27, 2022, 4:34pm UTC](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102/20 "2022-04-27T16:34:19Z")

</div>

> [@jling](#):
>
> before 1.7

Sorry, misread. 😅

> [@jling](#):
>
> we should ask @jameson I guess

Oky, doky. 👀

[Next page](https://discourse.julialang.org/t/reinterpretedarray-performance-even-worse-on-1-8/80102.md?page=2)
