# Should view(array, 1:length(array)) return a SubArray?

**URL:** <https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449>\
**Category:** Data\
**Tags:** array\
**Created:** [August 18, 2017, 3:04pm UTC](https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449 "2017-08-18T15:04:48Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![sambitdash](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sambitdash/32/1377_2.png) [@sambitdash](https://discourse.julialang.org/u/sambitdash)\
**Post date:** [August 18, 2017, 3:04pm UTC](https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449/1 "2017-08-18T15:04:49Z")

</div>

Hi All,

```julia
julia> arr = zeros(Int, 3)
3-element Array{Int64,1}:
 0
 0
 0

julia> b = view(arr, 1:length(arr))
3-element SubArray{Int64,1,Array{Int64,1},Tuple{UnitRange{Int64}},true}:
 0
 0
 0

```

Now that `b` will be treated like a SubArray() there may be additional overheads in computations. Are SubArray methods in general identify these cases internally and provide the same level of performance?

regards,

Sambit

---

<div class="post-metadata">

**Author:** ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)\
**Post date:** [August 18, 2017, 3:12pm UTC](https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449/2 "2017-08-18T15:12:24Z")

</div>

It is important for performance that a function has return types only dependent on the input types and not values (search for “type stable”, also look at `@code_warntype`). Thus this is correct.

---

<div class="post-metadata">

**Author:** ![Evizero](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evizero/32/10118_2.png) [@Evizero](https://discourse.julialang.org/u/Evizero)\
**Post date:** [August 18, 2017, 3:34pm UTC](https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449/3 "2017-08-18T15:34:50Z")

</div>

> [@sambitdash](#):
>
> Are SubArray methods in generally identify these cases internally and provide the same level of performance

I’d guess the answer to the performance question should be at least interesting. Notice the last type parameter is the value `true`.

> <https://github.com/JuliaLang/julia/blob/master/base/subarray.jl#L7-L8>

Without checking this myself I am guessing that this information is used somewhere to provide a speed bonus

---

<div class="post-metadata">

**Author:** ![sambitdash](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sambitdash/32/1377_2.png) [@sambitdash](https://discourse.julialang.org/u/sambitdash)\
**Post date:** [August 18, 2017, 3:37pm UTC](https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449/4 "2017-08-18T15:37:34Z")

</div>

Just did a benchmark will share the result. I see a 20% performance drop.

---

<div class="post-metadata">

**Author:** ![sambitdash](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sambitdash/32/1377_2.png) [@sambitdash](https://discourse.julialang.org/u/sambitdash)\
**Post date:** [August 18, 2017, 3:40pm UTC](https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449/5 "2017-08-18T15:40:39Z")

</div>

```julia
julia> @benchmark f_hsB_SubArray_view()
BenchmarkTools.Trial: 
  memory estimate: 1.06 KiB
  allocs estimate: 36
  --------------
  minimum time: 58.720 ms (0.00% GC)
  median time: 59.373 ms (0.00% GC)
  mean time: 59.477 ms (0.00% GC)
  maximum time: 63.780 ms (0.00% GC)
  --------------
  samples: 85
  evals/sample: 1

julia> @benchmark f_hsB_SubArray_noview()
BenchmarkTools.Trial: 
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 43.614 ms (0.00% GC)
  median time: 44.429 ms (0.00% GC)
  mean time: 44.783 ms (0.00% GC)
  maximum time: 54.849 ms (0.00% GC)
  --------------
  samples: 112
  evals/sample: 1

```

---

<div class="post-metadata">

**Author:** ![sambitdash](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sambitdash/32/1377_2.png) [@sambitdash](https://discourse.julialang.org/u/sambitdash)\
**Post date:** [August 18, 2017, 3:42pm UTC](https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449/6 "2017-08-18T15:42:56Z")

</div>

Data input:

```julia
arr=UInt8[rand(['0','1','2','3','4','5','6','7','8','9','0','a','b','c','d','e','f'])
 for x = 1:mb_10]
arr1=zeros(UInt8, (10<<19))

f_hsB_SubArray_view() = hex2bytes!(view(arr1, 1:length(arr1)),view(arr, 1:length(arr)))
f_hsB_SubArray_noview() = hex2bytes!(arr1,arr)

```

---

<div class="post-metadata">

**Author:** ![sambitdash](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sambitdash/32/1377_2.png) [@sambitdash](https://discourse.julialang.org/u/sambitdash)\
**Post date:** [August 18, 2017, 3:46pm UTC](https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449/7 "2017-08-18T15:46:12Z")

</div>

The `hex2bytes!` is a new method we are introducing as part of PR:

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

Essentially, the same code executed with view and without view has different performance outcomes. It may be desired but good to know or document.

---

<div class="post-metadata">

**Author:** ![traktofon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/traktofon/32/591_2.png) [@traktofon](https://discourse.julialang.org/u/traktofon)\
**Post date:** [August 18, 2017, 11:47pm UTC](https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449/8 "2017-08-18T23:47:35Z")

</div>

Aren’t you using global variables here? That might negatively affect the benchmark results.

---

<div class="post-metadata">

**Author:** ![sambitdash](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sambitdash/32/1377_2.png) [@sambitdash](https://discourse.julialang.org/u/sambitdash)\
**Post date:** [August 19, 2017, 3:22am UTC](https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449/9 "2017-08-19T03:22:15Z")

</div>

@traktofon the comparison is relative here so ideally the effect should be equally seen in both cases. In any case, here is the result with local variables:

```julia
julia> f_hsB_SubArray_view()
BenchmarkTools.Trial: 
  memory estimate: 1.06 KiB
  allocs estimate: 36
  --------------
  minimum time: 58.579 ms (0.00% GC)
  median time: 59.293 ms (0.00% GC)
  mean time: 59.487 ms (0.00% GC)
  maximum time: 65.059 ms (0.00% GC)
  --------------
  samples: 85
  evals/sample: 1

julia> f_hsB_SubArray_noview()
BenchmarkTools.Trial: 
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 43.517 ms (0.00% GC)
  median time: 44.126 ms (0.00% GC)
  mean time: 44.310 ms (0.00% GC)
  maximum time: 49.490 ms (0.00% GC)
  --------------
  samples: 113
  evals/sample: 1

```

The concern I had with local variables was optimization may optimize away computations and replace with the final result as it does not take any inputs or process it.

for example:

`int factorial_5()` may be short circuited to a fixed value of 120 after first JIT compilation.

Since, the arrays I use are random number sequences it’ll be dependent on the system state. Also note the `@benchmark` is applied on the computation only and not allocations.

---

<div class="post-metadata">

**Author:** ![sambitdash](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sambitdash/32/1377_2.png) [@sambitdash](https://discourse.julialang.org/u/sambitdash)\
**Post date:** [August 19, 2017, 3:27am UTC](https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449/10 "2017-08-19T03:27:43Z")

</div>

I understand the concern raised on datatype instability of global variables. Just theoretically that to my understanding should be concern for assignment of previously declared or unassigned variables. Not the case here where the initialization of the variable is happening with pre-specified concrete datatype. But I am sure there may be practical constraints where such rules may not hold good.

---

<div class="post-metadata">

**Author:** ![sambitdash](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sambitdash/32/1377_2.png) [@sambitdash](https://discourse.julialang.org/u/sambitdash)\
**Post date:** [August 19, 2017, 3:29am UTC](https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449/11 "2017-08-19T03:29:47Z")

</div>

Code snippet used.

```julia
f_hsB_SubArray_view() = begin
    const mb_10 = (10 << 20)

    arr=UInt8[rand(['0','1','2','3','4','5','6','7','8','9','0','a','b','c','d','e','f'])
                for x = 1:mb_10]
    str = String(arr)
    b_str = from_hexstringS(str)
    arr1=zeros(UInt8, (10<<19))

    @benchmark hex2bytes!(view(arr1, 1:length(arr1)),view(arr, 1:length(arr)))
end

f_hsB_SubArray_noview() = begin
    const mb_10 = (10 << 20)

    arr=UInt8[rand(['0','1','2','3','4','5','6','7','8','9','0','a','b','c','d','e','f'])
                for x = 1:mb_10]
    str = String(arr)
    b_str = from_hexstringS(str)
    arr1=zeros(UInt8, (10<<19))

    @benchmark hex2bytes!(arr1,arr)
end

```

---

<div class="post-metadata">

**Author:** ![sambitdash](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sambitdash/32/1377_2.png) [@sambitdash](https://discourse.julialang.org/u/sambitdash)\
**Post date:** [August 19, 2017, 3:33am UTC](https://discourse.julialang.org/t/should-view-array-1-length-array-return-a-subarray/5449/12 "2017-08-19T03:33:35Z")

</div>

The methods that are being reviewed.

```julia
@inline number_from_hex(c::UInt) = begin
    DIGIT_ZERO = UInt('0')
    DIGIT_NINE = UInt('9')
    LATIN_UPPER_A = UInt('A')
    LATIN_UPPER_F = UInt('F')
    LATIN_A = UInt('a')
    LATIN_F = UInt('f')

    return (DIGIT_ZERO <= c <= DIGIT_NINE) ? c - DIGIT_ZERO :
        (LATIN_UPPER_A <= c <= LATIN_UPPER_F) ? c - LATIN_UPPER_A + 10 :
        (LATIN_A <= c <= LATIN_F) ? c - LATIN_A + 10 :
        throw(ArgumentError("Not a hexadecimal number"))
end

function hex2bytes!(d::AbstractVector{UInt8}, s::AbstractVector{UInt8})
    i, j = start(s), 0
    # This line is important as this ensures computation happens in word boundary and not
    # byte boundary. Boundary computation can be almost 10 times slower
    n::UInt = 0
    c1::UInt = 0
    c2::UInt = 0
    while !done(s, i)
        n = 0
        c1, i = next(s, i)
        done(s, i) && throw(ArgumentError("source vector length must be even"))
        c2, i = next(s, i)
        n = number_from_hex(c1)
        n <<= 4
        n += number_from_hex(c2)
        d[j+=1] = (n & 0xFF)
    end
    return d
end

```
