Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reading wav files is extremely slow. #52

Closed
Ashymad opened this issue Jan 7, 2018 · 7 comments
Closed

Reading wav files is extremely slow. #52

Ashymad opened this issue Jan 7, 2018 · 7 comments

Comments

@Ashymad
Copy link

Ashymad commented Jan 7, 2018

Suppose I create a test file. about 3 minutes of 440Hz sine at 48kHz sampling rate

using WAV;
y = sin.((0:9999999)/48000*2pi*440);
wavwrite(y, "test.wav", Fs=48000)

Let's load it.

julia> @time y2, fs = wavread("test.wav")
 4.120818 seconds (30.00 M allocations: 572.200 MiB, 5.97% gc time)

Now let's load this file into GNU Octave.

octave:1> tic(); [y, fs] = audioread('test.wav'); toc()
Elapsed time is 0.173757 seconds.

Let's try SciPy.

In [1]: from scipy.io.wavfile import read
In [2]: from time import time
In [3]: a = time(); y, fs = read("test.wav"); time() - a
Out[3]: 0.12526440620422363

WAV.jl is around 40 times slower than both.
I have Julia 0.6.2 and WAV.jl 0.9.0.

@baggepinnen
Copy link
Contributor

In julia v1.3, io is thread safe. When reading WAV files, a lot of time is taken to lock and unlock the stream lock in the function.

function read(s::IOStream, T::Union{Type{Int16},Type{UInt16},Type{Int32},Type{UInt32},Type{Int64},Type{UInt64}})
    n = sizeof(T)
    lock(s.lock)
    if ccall(:jl_ios_buffer_n, Cint, (Ptr{Cvoid}, Csize_t), s.ios, n) != 0
        unlock(s.lock)
        throw(EOFError())
    end
    x = ccall(:jl_ios_get_nbyte_int, UInt64, (Ptr{Cvoid}, Csize_t), s.ios, n) % T
    unlock(s.lock)
    return x
end

I suspect it comes from the fact that very small amounts of data is read in every call to read, i.e.:

read_le(stream::IO, x::Type{T}) where {T} = ltoh(read(stream, T))

reads a single value at a time

@baggepinnen
Copy link
Contributor

baggepinnen commented Sep 4, 2019

Defining these function mitigates the issue somewhat and reduces readtime by more than 3x, at the expense of not being thread safe

read_le(stream::IO, x::Type{T}) where {T} = ltoh(fastread(stream, T))

fastread(s::IOStream, T) = read(s,T)
function fastread(s::IOStream, T::Union{Type{Int16},Type{UInt16},Type{Int32},Type{UInt32},Type{Int64},Type{UInt64}})
    n = sizeof(T)
    # lock(s.lock)
    if ccall(:jl_ios_buffer_n, Cint, (Ptr{Cvoid}, Csize_t), s.ios, n) != 0
        # unlock(s.lock)
        throw(EOFError())
    end
    x = ccall(:jl_ios_get_nbyte_int, UInt64, (Ptr{Cvoid}, Csize_t), s.ios, n) % T
    # unlock(s.lock)
    return x
end

fastread(s::IOStream, ::Type{Float16}) = reinterpret(Float16, fastread(s, Int16))
fastread(s::IOStream, ::Type{Float32}) = reinterpret(Float32, fastread(s, Int32))
fastread(s::IOStream, ::Type{Float64}) = reinterpret(Float64, fastread(s, Int64))

@JeffBezanson
Copy link

Is it possible to read in larger chunks? Surely it is?

@baggepinnen
Copy link
Contributor

#79 improves the situation by reading larger chunks

@dancasimiro
Copy link
Owner

@baggepinnen Do you anticipate making any additional changes?

@Ashymad How does the performance (of master) compare now?

@baggepinnen
Copy link
Contributor

I think the performance should be on par with other readers now, no more changes planned from me

@dancasimiro
Copy link
Owner

Thanks for all of your help. I will close this issue as fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants