W3C home > Mailing lists > Public > public-audio@w3.org > July to September 2013

Re: Data racing proposals

From: Chris Wilson <cwilso@google.com>
Date: Wed, 31 Jul 2013 09:09:15 -0700
Message-ID: <CAJK2wqUDFXmP0v2jzVDawzD4HQWb9aoi-0n_avBx3PpguRkDgA@mail.gmail.com>
To: "Robert O'Callahan" <robert@ocallahan.org>
Cc: "public-audio@w3.org" <public-audio@w3.org>
On Tue, Jul 30, 2013 at 6:53 PM, Robert O'Callahan <robert@ocallahan.org>wrote:

> On Wed, Jul 31, 2013 at 12:46 PM, Chris Wilson <cwilso@google.com> wrote:
>
>> If the developer community shows that this is a problem in practice,
>> particularly as another implementation adds to the corpus of experience, we
>> would of course be open to reopening this question at a later date.
>>
>
> Keep in mind that the more Web Audio is used, the more difficult this
> would be to fix at a later date. Potentially it could become prohibitively
> difficult to fix.
>

Indeed.  I still think we're discussing solving a problem that doesn't need
to be solved here, though, and I can't think of a better way to prove or
disprove that it needs solving.


> and they need to do something different with the ArrayBuffer returned from
>> getChannelData (i.e. re-assign it to another AudioBuffer);
>>
>
> That's not correct. With my proposal, when getChannelData is called while
> or after an AudioBuffer is in use, the app can modify the Float32Array and
> then reuse the same AudioBuffer with those modifications taken into account.
>

I think I now finally understand at least part of the subtlety in your
proposal.  It was not clear to me that when the lazy copy was created,
you're essentially orphaning the audio thread's copy of the buffer from the
AudioBuffer, not the AudioBuffer's [lazily-created] copy.  That does make
more sense.  The concept of "acquiring" implied an ownership that was
confusing.

 This is a reasonable option IMHO. Its main advantage over my proposal is
>> that it simplifies the performance model by making the implicit copies of
>> my proposal explicit. OTOH it gives up some compatibility and makes the API
>> a little harder to use.
>>
>
I agree it gives up some compatibility.  I think it also helps minimize
memory usage (if you're just trying to peek at a section of the buffer
contents, you don't need to copy the entire thing).  I think the explicit
nature probably makes "harder to use" a wash.  The pattern of "grab and
hold a reference via getChannelData, then assign the AudioBuffer to a
.buffer" is likely common enough to cause problems, and this would result
in an (implicit) neutering in your proposal.

In shorter words: I think I understand better now how you've attempted to
hide the memory management from the developer.  I think the neutering side
effects are still going to be a bit problematic.


> I think we could improve this approach a bit. We don't really need a
> Promise here since AudioBuffer contents are expected to be in memory. It
> would also be good to be able to reuse an existing Float32Array instead of
> having to allocate a new one. So I'd suggest something like "void
> copyTo(Float32Array dest, long offset, long length)" instead.
>

See below on async.  On reusing Float32Array: then you need to handle
channel selection too (buffer may be multi-channel, you will need to copyTo
for each channel's Float32Buffer), which is why I didn't do this.  I can
see the value, though.


>  Additionally: in the case when the AudioBuffer's contents are
>> transferred to another thread, the AudioBuffer is again neutered and no
>> longer available for direct access.  In this case, once neutered in this
>> way, the AudioBuffer cannot be played (but, of course, you could request a
>> clone to be made).
>>
>
> I'm not sure what you're getting at here. What exactly do you mean by
> "when the AudioBuffer's contents are transferred to another thread"?
>

Should have said: if the ArrayBuffer is posted to another thread, it is
neutered, and will not play.  In short, the case where I have an
AudioBuffer, I start it playing and then post the arraybuffer contents to
another thread.

You should confirm or elaborate: I think in your proposal, if I post to
another thread prior to assigning the .buffer, the AudioBuffer's contents
are simply neutered; if I post to another thread after assigning, the audio
thread can still play (the lazy copy created another copy when asked for
getChannelData to transfer, then transferred that copy), but the
AudioBuffer's contents will still be neutered (since its shared copy was
neutered).  That is, in all cases transferring an AudioBuffer's
getChannelData to another thread will neu

I think we can assume memory copies between threads can be performed
> synchronously.
>

If this is the case, then yes, I retract this async pattern.


> [a] Optional modifier - once playback has ended, you could un-neuter the
>> ArrayBuffer contents.  I'll resist the temptation to come up with a
>> creative term for this.  This seems challenging to define (as poorly as
>> neutering appears to be defined, there's no precedent I could find for
>> un-neutering), however, so not part of the main proposal
>>
>
> In your proposal, that would be an observable behavior change. In my
> proposal, a UA can do the same thing, but it's not observable --- the
> getChannelData() just becomes nearly-free instead of having to copy, by
> creating a new ArrayBuffer with the data contents stolen back from the
> audio thread. I think this is a slight advantage for my proposal.
>

"Magic memory usage improvement happens sometimes" is the bit that concerns
me.  It may not be observable in the sense of "I can write code that sees
it directly", but it is going to change the memory footprint pattern
dramatically.  Personally, I think this kind of magic makes the web
platform harder to use than some sharing of memory.

Agreed, though, I don't think I could add un-neutering.

-Chris
Received on Wednesday, 31 July 2013 16:09:47 UTC

This archive was generated by hypermail 2.3.1 : Tuesday, 6 January 2015 21:50:10 UTC