bugGNU Octave - Bugs: bug #49927, audioread slow when extracting...

 
 

bug #49927: audioread slow when extracting only part of a file

Submitter:  None
Submitted:  Sun 25 Dec 2016 02:06:44 PM UTC
   
 
Category:  Octave Function Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Performance
Status:  Confirmed Assigned to:  None
Originator Name:  kml Originator Email:  -email is unavailable-
Open/Closed:  * Open Release:  * dev
Operating System:  * Any Fixed Release:  None
Planned Release:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Fri 27 Jan 2017 02:08:56 AM UTC, comment #16: 

Following up on comment #13, yes Kai, Octave is following Matlab's convention for reading and writing audio files, which is that the entire audio sequence is read/written at once. There is nothing preventing anyone from building a different interface using the same sndfile library that would allow files to be written in blocks without knowing the full audio length up front. But that would be outside the scope of what we're doing at this point to be Matlab compatible. Matlab has no functions or classes for dealing with audio files that way.

Mike Miller <mtmiller>
Group Member
Wed 28 Dec 2016 03:55:56 PM UTC, comment #15: 

The OP seems to have 64bit Octave on 64bit Windows w 4 GB RAM. IMO it is remarkable to not have 600 MB contiguous free RAM on such a system.
So there may be other issues going on leading to the OOM errors.

Philip Nienhuis <philipnienhuis>
Group Member
Wed 28 Dec 2016 01:06:19 AM UTC, comment #14: 

The 32-bit version of Octave has arrays which can hold 2^31 elements.  If each element is a float, as it is in this case, then the allowable file size would be


2^31 * 4B = 8 GB


I don't think Octave's internal limits are being hit.  It is the operating system which doesn't have 575MB of contiguous memory.


Rik <rik5>
Group administrator
Wed 28 Dec 2016 12:39:07 AM UTC, comment #13: 

It is at least the most obvious deficiency of audioread.
If the memory limit of 64 Bit Octave under Windows 7 Home Premium 64 Bit is close to 570 MB, it is also the probable explanation for the read failures I encountered initially after having read already 4000 blocks. This could happen, when at the beginning of script execution slightly more memory is available but gets smaller during execution e.g. through memory allocation for graphics queues.
In the present state audioread is a nuisance. It will be more efficient (and more work) to do direct binary reads on wav-files. Binary writing to wav files seems to be necessary anyhow, as there is no support for writing audio data with initially unknown size, as is e.g. the case when you are doing adaptive resampling. You don't know the required file size before you have finished processing, but you have to write the already processed audio blocks to disk like a stream. After that you must update the file header. Apparently this can only be done through direct binary writing (and learning how to handle a wav file header).

Kai-Michael <kaicheck>
Wed 28 Dec 2016 12:32:27 AM UTC, comment #12: 

kbhit is a separate issue.  That was fixed in 4.0.1, another reason why it's important to run a supported version of Octave.

I think you're right that the problem is the straightforward, but memory-intensive, strategy in audioread.cc of reading in the WHOLE file and then extracting just the relevant bit.

This is the ine that does it


  OCTAVE_LOCAL_BUFFER (float, data, info.frames * info.channels);


OCTAVE_LOCAL_BUFFER uses new or malloc underneath to try and get a contiguous block of memory.  Even if you have a fair amount of memory, it could be rare to have a 575MB contiguous chunk.

The API for libsndfile is at http://www.mega-nerd.com/libsndfile/api.html.  In particular, it looks like the input parsing for the second input which determines which samples to extract could be moved up earlier.  Then the OCTAVE_LOCAL_BUFFER call could be sized to a smaller value, the file pointer could be advanced using sf_seek(), and sf_read_float() could be called with only the number of items to read.

Re-titling bug report to reflect the underlying issue.

Rik <rik5>
Group administrator
Tue 27 Dec 2016 09:35:43 PM UTC, comment #11: 

Yes, it does look like audioread reads the entire file into memory, and then copies out a subset of the data if it was called with start and end indices. That is something that could definitely be improved on the original implementation.

The code is here: http://hg.savannah.gnu.org/hgweb/octave/file/023026207910/libinterp/dldfcn/audioread.cc#l74, and the libsndfile API definitely does include functions to seek and read subsets of a file.

It sounds like that is essentially the bug in this report, do you agree? And other devs who have been following this more closely than me?

As to kbhit, that may be a Windows shortcoming, using the keyboard() function to drop to a debug shell (followed by dbcont at the prompt to continue execution) may be more reliable on your operating system.

Mike Miller <mtmiller>
Group Member
Tue 27 Dec 2016 09:23:32 PM UTC, comment #10: 

You could try the single line of code of my previous posting on files of similar size. It failes on large files. That is a bug.
In the meantime I have done some further testing. I have checked the time audioread takes to read 100 blocks of 4096 samples in a read loop on files of different sizes. It turns out that the time is proportional to the file size, not to the block size. audioread obviously does not read the data block requested but instead the whole file. That is the reason, why it failes on large files and why it is a factor of 112 slower than MATLAB on a 270 MB file.
File size : 128. 270   321 504 MB
Read time : 13s  29.6s 33s 52s for 100 4k-sample blocks
A file with 575 MB could not be processed.
If you do not call this a bug, it is at least worst programming practice.
I am including the test script as an attachment.
By the way, in the code I tried to use the function kbhit(1) as a means for early termination of the script by pressing the key "e" on the keyboard. It does not work either. Different from its desription in the documentation, it seems to wait for further input instead of returning immediately.


(file #39321)

Kai-Michael <kaicheck>
Tue 27 Dec 2016 05:02:05 PM UTC, comment #9: 

No problem installing 4.2.0 alongside 4.0.0, esp. not on Windows.  At home I have ~6 Octave versions installed on my Win7 desktop PC.

I still see no code example that we can use to try out ourselves. That said, in this Xmas week there may not be that much activity from at least my side :-)

Philip Nienhuis <philipnienhuis>
Group Member
Mon 26 Dec 2016 09:53:53 PM UTC, comment #8: 

Here is some further information:
The previous test ran successfully up to the end of the file. It took 104.7 minutes versus 93 minutes for just scanning the file without any data processing.
After that I started the script on a 588.298 kB wav file. I got immediately the error message:
out of memory error or dimension too large for Octave's index type.
At that time "whos" reported memory usage of 822177 bytes.
The script line that caused the error was:
[Y,fs,Nbits]=wavread(wavname,1);
which means: read one sample and return it in Y, get the the sample rate fs from the file header and the bits per sample in Nbits.
This worked for the previous file with ~295 MB, but does not work for larger 2nd file with ~574.5 MB. The wav file header is 44 bytes long.
So the task is to read just the first 48 bytes (1 sample = 4 bytes).
Regards Kai

Kai-Michael <kaicheck>
Mon 26 Dec 2016 08:51:23 PM UTC, comment #7: 

Hi Philip and Rik,
I have done some further testing:
1.:
ver: 4.0.0, MINGW32_NT-6.1 WINDOWS 7 ServicePack 1 i686
log2(sizemax)= 31.0
Is this consistent with a 64 Bit version ?
2.: I have prepared a copy of my script, reduced to a minimum, just scanning a wav-file (no further processing), and have tested it on a 295 MB file, i.e. 18881 blocks of 4096 samples.
The test had a positive and a negative result:
2a:The script ran through the whole file without premature termination.
2b: It took 93 minutes ! Every 100 blocks I let the script report the size of the data array (was a constant 4096 rows, 2 columns, i.e 4096 samples Stereo) and the time it took: 29.6 s for 100 blocks.
I let (almost) the same script run on the 2002 LapTop , Pentium 4 at 2 GHz, MATLAB 6.1 (R12.1). This took 26.5 s för 10000 blocks !
So there must be something awfully wrong with audioread in Octave. It is by a factor of 112 slower.
Just now I am running my original script again on the same file. it has already proceeded to block 16700. So it has already gone much further than during my first 2 attempts, when it stopped around block 4000 and 2xxx. I have checked the code for any statements that might call for additional allocation of memory, but I don't see any explicit ones. But I am updating 5 graph-figures every 20 blocks and am using interpft with a variable interpolation ratio.
Right now I am avoiding any mouse action on those figures. I have noticed at other times, that clicking on or moving/resizing of existing figures may cause Octave to terminate script execution with syntax or parsing error messages on code that has already been executed several hundred times.

In fact I already downloaded version 4.2 64 Bit, but I hesitated to install it for 2 reasons: I don't find any hint, whether previous versions have to be de-installed or may be over-installed. Second reason is: as far as I remember, installation takes a long time due to those more than 3xxx (small) files. The execution of build_packages made the impression that some things were going wrong. I tried it a second time, a considerable number of files were reported as not found. The whole procedure seemed to loop around 2 or more times. I was actually not shure, whether the installation was ok.
Regards Kai

Kai-Michael <kaicheck>
Mon 26 Dec 2016 07:44:45 PM UTC, comment #6: 

i686-w64-mingw32 is indeed 64-bit Octave.

So with 32bit ruled out I think Rik's suggestions make sense.

What does your script/function/code look like? so that we can try to reproduce your issues? As you can see without it we can only guess ATM.

Philip Nienhuis <philipnienhuis>
Group Member
Mon 26 Dec 2016 04:31:59 PM UTC, comment #5: 

1.


ver
log2 (sizemax)


2.

Maybe it's not Octave, but your own script that is building up an array 16KB at a time?  I can't tell.  If the there is nothing proprietary, you could upload the script and data to see if anyone else can duplicate your problem.

Rik <rik5>
Group administrator
Mon 26 Dec 2016 03:44:05 PM UTC, comment #4: 

3 remarks:

1. I thought, I had installed the 64-Bit version.
At least there are many references to i686-w64-mingw32 . Or does this mean something else ? Octave does not tell me whether it is 32 or 64 Bits. How can I check this ?

2. I am not trying to read a 700 MB WAV-file.
I am just reading 4k sample blocks (16k bytes) always into the same data array, processing them and writing to a new file.
I don't see any need for allocation of several hundert MByte of memory. I hope, audioread does not do such a nonsense, when I am trying to read 16 kByte at file position 16.xxx.xxx.
On the other hand it was possible to read that block after a restart.

3. (Almost) the same code runs without any problems on an old Windows XP (32 Bit) Laptop with MATLAB 6.1 from 2001. 
( and by the way much faster although it is just a 2GHz Pentium, while the PC running Octave is a Quadcore i5-3570 at almost 4 GHz.)

So to repeat once more, the data size read is a mere
size = 4096 * 4 = 16 kByte !

Kai-Michael <kaicheck>
Mon 26 Dec 2016 03:19:47 PM UTC, comment #3: 

This bug is reported against version 4.0.0 which is deprecated.  Could the original reporter try again with the recent stable release of Octave (4.2.0)?  A lot has improved since 4.0.0, and you can try the 32-bit or 64-bit version of Octave-4.2.0 as Philip suggests.

If neither the 32-bit or 64-bit version solve the problem then there might be an issue worth debugging here.  The size of the data read is not all that large:


size = 4000*4096*4 = 65 MiB


If there are clues in the file about the eventual size of the output then Octave could do one single allocation at the start of the read, rather than re-sizing an array each time through the loop.  This would help prevent memory fragmentation in the heap.


Rik <rik5>
Group administrator
Sun 25 Dec 2016 07:42:29 PM UTC, comment #2: 

Right, you have Win64, sorry for overlooking that.

The rest of your report indicates the usual symptoms of memory fragmentation. That is, after several attempts to declare large arrays there isn't enough contiguous free RAM available, although total free RAM may look to be sufficient, and after a restart it works again for few moments.

There's no cure for this other than 64-bit Octave.

Philip Nienhuis <philipnienhuis>
Group Member
Sun 25 Dec 2016 07:37:12 PM UTC, comment #1: 

Do you have 32-bit Octave installed?
I'm asking because this looks very much like you've hit the memory limits for 32-bit programs.  32-bit Octave usually cannot allocate larger arrays than in the order of 600-800 MB. Whether you have a 64-bit OS is irrelevant (provided you have enough RAM installed).

If you have a 64-bit OS, try the 64-bit Octave-4.2.0 version that is now the current release.

Philip Nienhuis <philipnienhuis>
Group Member
Sun 25 Dec 2016 02:06:44 PM UTC, original submission:  

Wavread / audioread refuses to continue reading a WAV-File after having read a few thousand 4096-sample blocks of 16-Bit Stereo (4 Bytes). The error message is "out of memory or dimension too large...". The number of blocks successfully read was once 4000, in a second try 2280. In the command interface I could still declare e.g. a new variable of 100x100 double values. The "whos" command reported memmory use of just somewhat above 1 MByte. It is a PC running Windows 7 Premium Home 64 Bits with 4 GByte memory installed. After that it was not even possible to read the first block of the wav-file. After a restart the block with sample numbers in the 16-million range could be read. The same code runs under MATLAB without this problem.

Anonymous

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

Attached Files
file #39321:  audioread_BugCheck.m added by kaicheck (2KiB - application/octet-stream)

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by mtmiller (Posted a comment)
  • -email is unavailable- added by kaicheck (Posted a comment)
  • -email is unavailable- added by rik5 (Posted a comment)
  • -email is unavailable- added by None (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only group members can vote.

     

    Follow 6 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2016-12-28 rik5 StatusNeed Info Confirmed
        Release4.0.0 dev
        Operating SystemMicrosoft Windows Any
        Summarywavread/audioread refuses to continue reading wav-file audioread slow when extracting only part of a file
    2016-12-27 kaicheck Attached File- Added audioread_BugCheck.m, #39321
    2016-12-25 philipnienhuis StatusNone Need Info

    Back to the top

    Powered by Savane 3.13-02a9.
    Corresponding source code