Why is there memory allocation and time difference in @views and view?

Julia Version 1.5.3

julia> f(a, b, c) = a + b - c;

julia> X = randn(1000, 5);

julia> y = zeros(1000);

# feed the last three columns of `X` into `f` and write the result into `y`

julia> @btime $y .= f((view($X, :, j) for j = 3:5)...);
  1.922 μs (9 allocations: 16.23 KiB)

julia> @btime $y .= @views f(($X[:, j] for j = 3:5)...);
  1.922 μs (9 allocations: 16.23 KiB)

I have three questions:

  1. What causes the large memory allocation in both cases?
  2. Why is there a significant time difference between view and @views? ([updated] Due to the error mentioned by @sudete :sweat_smile: )
  3. What is the recommended way to achieve the above goal, i.e., broadcasting over multiple columns of a matrix?

You forgot to interpolate X in the first case :slight_smile:

1 Like

First thing to note, you’re interpolating the value of X in the second but not the first case.

julia> @btime $y .= f((view($X, :, j) for j = 3:5)...);
  1.234 μs (2 allocations: 15.88 KiB)

julia> @btime $y .= @views f(($X[:, j] for j = 3:5)...);
  1.127 μs (2 allocations: 15.88 KiB)

You might leave away the interpolation altogether and do

julia> @btime y .= f((view(X, :, j) for j = 3:5)...) setup=(X = randn(1000, 5); y = rand(1000););
  1.347 μs (2 allocations: 15.88 KiB)

julia> @btime y .= @views(f((X[:,j] for j = 3:5)...)) setup=(X = randn(1000, 5); y = rand(1000););
  1.186 μs (2 allocations: 15.88 KiB)

(This is on Julia 1.6.)

1 Like

Note that you need 1.6 to get only 2 allocations… On 1.5.3 I get 11.

Thanks. But I cannot understand where the 2 allocations: 15.88 KiB comes.

See @sudete’s comment. I’m running Julia 1.6.

It depends on the specific requirements but this doesn’t allocate at all (either on 1.5 or 1.6):

julia> @btime y .= (@views X[:,3] .+ X[:,4] .- X[:,5]) setup=(X = randn(1000, 5); y = rand(1000));
  182.881 ns (0 allocations: 0 bytes)

You weren’t broadcasting f, so it was allocating a result that you then used a broadcast to copy into y.

3 Likes

Implementing @Elrod’s comment:

Julia 1.6:

julia> @btime y .= f.((view(X, :, j) for j = 3:5)...) setup=(X = randn(1000, 5); y = rand(1000););
  133.359 ns (0 allocations: 0 bytes)

julia> @btime y .= @views(f.((X[:,j] for j = 3:5)...)) setup=(X = randn(1000, 5); y = rand(1000););
  139.092 ns (0 allocations: 0 bytes)

Julia 1.5:

julia> @btime y .= f.((view(X, :, j) for j = 3:5)...) setup=(X = randn(1000, 5); y = rand(1000););
  711.807 ns (9 allocations: 624 bytes)

julia> @btime y .= @views(f.((X[:,j] for j = 3:5)...)) setup=(X = randn(1000, 5); y = rand(1000););
  729.203 ns (9 allocations: 624 bytes)
2 Likes

Thanks. A stupid mistake. :joy: