Re: Web Workers

On Sat, Mar 17, 2012 at 2:16 AM, Dmitry Lomov <dslomov@google.com> wrote:

> (sorry for late reply - I somehow missed this)
>

Heh, I'm glad I'm not alone in my email issues :-)

On Thu, Mar 8, 2012 at 4:10 PM, Robert O'Callahan <robert@ocallahan.org>wrote:
>
>> On Thu, Mar 1, 2012 at 9:49 PM, Dmitry Lomov <dslomov@google.com> wrote:
>>
>>> On Wed, Feb 29, 2012 at 3:23 PM, Robert O'Callahan <robert@ocallahan.org
>>> > wrote:
>>>
>>>> The writeAudio method still does a copy. Maybe that copy can be avoided
>>>> with an alternative design using transfers, but simply preallocating an
>>>> output buffer as Dmitry suggested isn't quite the right solution since an
>>>> onprocessmedia handler can output any amount of audio, including none.
>>>> Instead we probably should have writeAudio take ownership of the buffer and
>>>> neuter it, or alternatively keep the current copy semantics for writeAudio
>>>> and have a separate transferAudio method that uses the transfer semantics.
>>>>
>>>>
>>> So these two proposals handle transfer-out but not transfer-in. As you
>>> say, it will either be a copy in a writeAudio, or, if we have a
>>> transferAudio method, an allocation on every callback (because you cannot
>>> reuse a transferred-out array buffer).
>>> If event has a perallocated output buffer, we will avoid any copies and
>>> allocations.
>>>
>>
>> The allocation overhead can be practically eliminated by recycling
>> buffers internally in the browser.
>>
>
> This assumes a lot about how the array buffers are implemented in the UA.
> Note that unless the GC happens for the  worker the browser wouldn't even
> know that array buffer can be recycled.
>

Actually it doesn't. transferAudio(buffer) passes ownership of the
underlying buffer back to the browser. Once the browser has finished using
that underlying buffer, it is immediately available for recycling in a new
allocation even if the worker hasn't done a GC.

Right - so we should have separate input and output buffers. My
> understanding is that in the typical case the processor outputs the same
> amount of output per each input?
>

Yes.


> In that case, here is what we can do:
>
> self.onprocessmedia = function (event) {
>   var len = event.audioLength;
>   if (!event.outputBuffer || output.outputBuffer.length != len) {
>     output.outputBuffer = new Float32Array(len);
>   }
>   ...
> }
>
> I.e. event has an outputBuffer property that the processor allocates once
> and then it is transferred in and out. If the processor outputs
> variable-length outputs, we can have an adjustable limit:
>
> self.onprocessmedia = function (event) {
>   var len = event.audioLength;
>   if (!event.outputBuffer || output.outputBuffer.length < len) {
>     output.outputBuffer = new Float32Array(len);
>   }
>   event.setOuputSampleLength(len);
>   ...
> }
>

If we go this way, I think I'd rather just say that event.outputBuffer is
what gets written out. If you want to write out 'len' bytes that's
different from event.outputBuffer.length, set outputBuffer to a new array
with the right length. You could create a view of an existing buffer if you
want to avoid allocation.

With this approach, what happens if the script stores away a reference to
event.outputBuffer and writes to the buffer during some other event, say an
onmessage callback? Would you allow racing/undefined behavior?

The dynamic dispatch call dispatchTable[event.params.type](event) might be
> pretty expensive, esp compared with simple array operations that processors
> usually are.
>

It should be approximately a hash lookup and virtual function call per
onprocessmedia callback. That doesn't seem like much to me.


>
>>
>>  My proposal, that lets you specify a callback name, solves all of that.
>>> Moreover, I can see other benefits:
>>> a. no need to add extra methods to WorkerContext.idl
>>> b. ease of code use and re-use. The user can package her library of
>>> audio effects, where all audio effects have different names but conform to
>>> the same signature, and then easily import those into worker and    call
>>> them - no need for any boilerplate in the worker code itself.
>>>
>>
>> On the other hand, it reduces isolation of the worker since it gives page
>> script the ability to call any global function in the worker instead of
>> going through predefined entry points (onmessage, onprocessmedia). I
>> suspect that's not a good idea.
>>
>
> I do not think the isolation here is a big deal: the worker code as well
> as the page code is fully under control of the web page author (there is a
> same-origin restriction for workers etc etc).
>

The modularity is still nice. We should talk to Hixie or other people
involved in Workers. It seems to me that your arguments would also apply to
postMessage, and yet postMessage is restricted to a single entry point. I'd
rather not deviate from that pattern without understanding why it's there
in the first place.


> It's also more work to implement, for a case that maybe doesn't even
>> matter that much.
>>
>
> I feel this is where our friction point is: I think ease of writing
> reusable effect libraries and being able to easily control worker
> allocation is an important use case.
>

I agree writing reusable effect libraries is important. I'm not convinced
that the overhead of dispatching within onprocessmessage is important.

Rob
-- 
“You have heard that it was said, ‘Love your neighbor and hate your enemy.’
But I tell you, love your enemies and pray for those who persecute you,
that you may be children of your Father in heaven. ... If you love those
who love you, what reward will you get? Are not even the tax collectors
doing that? And if you greet only your own people, what are you doing more
than others?" [Matthew 5:43-47]

Received on Monday, 19 March 2012 04:29:59 UTC