# Binary reading and matrix allocations: most performant way?

**URL:** https://discourse.julialang.org/t/binary-reading-and-matrix-allocations-most-performant-way/103929
**Category:** Performance
**Tags:** binaryio, matrix
**Created:** [September 16, 2023, 4:31pm UTC](https://discourse.julialang.org/t/binary-reading-and-matrix-allocations-most-performant-way/103929 "2023-09-16T16:31:19Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![myersm0](https://avatars.discourse-cdn.com/v4/letter/m/c5a1d2/32.png) [@myersm0](https://discourse.julialang.org/u/myersm0)
#### Post date: [September 16, 2023, 4:31pm UTC](https://discourse.julialang.org/t/binary-reading-and-matrix-allocations-most-performant-way/103929/1 "2023-09-16T16:31:19Z")

</div>

Would anyone be able to offer some insight towards getting faster performance for the below sort of use case?

Say I have a struct that holds a Matrix and my primary goal is to fill it with values, possibly transposed, and it could be a very large matrix:

```julia
struct mytest
	mat::Matrix
end

```

Now to define dimensions and create some binary data for the sake of a MWE for testing performance:

```julia
m = 5000
n = 50000
dtype = Float32
nbytes = sizeof(dtype) * m * n
bytes = rand(UInt8, nbytes)
tempfile = "tmp"
open(tempfile, "w") do fid
	write(fid, bytes)
end

```

Defining a few different functions for reading the sample data:

```julia
function testread1(fid::IOStream, dtype::Type, m::Int, n::Int)
	seek(fid, 0)
	nbytes = sizeof(dtype) * m * n
	temp = zeros(UInt8, nbytes)
	readbytes!(fid, temp, nbytes)
	temp2 = reinterpret(dtype, temp)
	return reshape(temp2, (m, n))'
end

function testread2(fid::IOStream, dtype::Type, m::Int, n::Int)
	seek(fid, 0)
	read!(fid, Array{dtype}(undef, m, n))'
end

function testread3(fid::IOStream, dtype::Type, m::Int, n::Int)::Matrix
	seek(fid, 0)
	read!(fid, Array{dtype}(undef, m, n))'
end

```

And finally testing performance of both reading the data and then allocating a `mytest` struct:

```julia
using BenchmarkTools

fid = open(tempfile, "r")
@benchmark test1 = testread1(fid, dtype, m, n) # median 0.159 s
@benchmark test2 = testread2(fid, dtype, m, n) # median 0.129 s
@benchmark test3 = testread3(fid, dtype, m, n) # median 1.182 s

@benchmark a = mytest(test1) # median 1.239 s
@benchmark b = mytest(test2) # median 1.241 s
@benchmark c = mytest(test3) # median 0.00074 s

```

As you can see, testread1() and testread2() were fast but they return an `adjoint(::Matrix{Float32})` or similar, which is then costly to finally convert into a plain Matrix when I allocate a `mytest` struct from it.

Any advice?

Update: I realize it’s basically the transpose operation that’s hurting performance, and I guess that’s the heart of my question. I find that it often comes up in my work that I need to transpose a matrix, or reshape it, etc, and then use it in a context that strictly requires a `Matrix`, not an `adjoint` for example.

---

<div class="post-metadata">

### Author: ![jbytecode](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jbytecode/32/17719_2.png) [@jbytecode](https://discourse.julialang.org/u/jbytecode)
#### Post date: [September 16, 2023, 5:52pm UTC](https://discourse.julialang.org/t/binary-reading-and-matrix-allocations-most-performant-way/103929/3 "2023-09-16T17:52:30Z")

</div>

How about using Memory-mapped IO?

[https://docs.julialang.org/en/v1/stdlib/Mmap/](https://docs.julialang.org/en/v1/stdlib/Mmap/)

---

<div class="post-metadata">

### Author: ![Salmon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/salmon/32/22968_2.png) [@Salmon](https://discourse.julialang.org/u/Salmon)
#### Post date: [October 1, 2023, 7:10pm UTC](https://discourse.julialang.org/t/binary-reading-and-matrix-allocations-most-performant-way/103929/4 "2023-10-01T19:10:19Z")

</div>

The biggest performance problem are probably type instabilities `Matrix` is not a concrete type and neither is `Array{dtype}`. (The dimension needs to be specified)  
Unless it is not possible for some reason, that should be fixed first.

---

<div class="post-metadata">

### Author: ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)
#### Post date: [October 1, 2023, 8:54pm UTC](https://discourse.julialang.org/t/binary-reading-and-matrix-allocations-most-performant-way/103929/5 "2023-10-01T20:54:04Z")

</div>

I’m not sure of my measurements (because I get different results on different attempts), but this should be slightly faster

```julia
function testread4(fid::IOStream, dtype::Type, m::Int, n::Int)
	seek(fid, 0)
    rowbytes= sizeof(dtype) * m
    row = Vector{UInt8}(undef, rowbytes)
	mat = Matrix{dtype}(undef, n, m)
    @inbounds for r in 1:n
        readbytes!(fid, row, rowbytes)
	    mat[r,:] .= reinterpret(dtype,row)
    end
	mat
end

# or using this form: It seems as if, by using a function as a for argument, the compiler automatically avoids bounds checks. Does anyone know if this is really the case?

function testread4(fid::IOStream, dtype::Type, m::Int, n::Int)
	seek(fid, 0)
    rowbytes= sizeof(dtype) * m
    row = Vector{UInt8}(undef, rowbytes)
	mat = Matrix{dtype}(undef, n, m)
    for r in axes(mat,1)
        readbytes!(fid, row, rowbytes)
	    mat[r,:] .= reinterpret(dtype,row)
    end
	mat
end

```
