Re: Simultaneous destructors
Chris Jones <[email protected]>
| Newsgroups | gmane.comp.mozilla.devel.dom |
|---|---|
| Message-ID | <[email protected]> |
Jason Duell wrote:
>> state CANCELLED:
>> discard dataavailable;
>> send datadone goto DEAD;
>
> That's fine. I'd prefer to not lose the "recv", so it would look
> like
>
> recv discard dataavailable;
>
> But I don't care very much.
>
>>>> Explicitly acknowledging channel messages seems like a high burden
>>>> on total throughput.
>>> This is a potential issue. In the case of a small HTTP reply, for
>>> instance, the parent necko will get it all in one socket read(), and
>>> thus would essentially call OnStartRequest, OnDataAvailable, and
>>> onStopRequest in succession. Requiring an IPDL reply for each of
>>> these would introduce two IPC round-trip latencies to the process.
>>> I'm not sure how much that would show up in the overall reponsiveness
>>> of the browser, but the sequence itself would possibly be orders of
>>> magnitude more expensive, time-wise.
>> OnStart/OnStop haven't entered into the discussion so far, so I'd
>> tentatively claim that you're arguing against a strawman. How do they
>> fit into the protocols that have been tossed around so far?
>
> Once an HTTP channel is opened by the child process, the chrome HTTP
> channel that gets created will go through the regular steps of getting
> data from the network, and calling OnStartRequest/OnDataAvailable/
> OnStopRequest. These functions (and the data/headers) need to be made
> available in the child process. Right now my plan is to simply proxy
> each OnStart/OnData/OnStop function to the child via an IPDL message
> (it may be possible to glob them together into one message which is
> sent to the child, but that may not be trivial, given that there may
> be chains of listeners/observers that need to be called in the correct
> order).
>
So OnStopRequest() is what bsmedberg has been referring to as
"datadone()"? (Sorry, no spreche Necko.) That's what I'm assuming below.
> So we're looking at 3 IPC messages in a row, for a small HTTP reply
> that comes in with one socket read(). One possibility is that we can
> send them all in a row:
>
> PARENT CHILD
> -------------------------
> OnStart --->
> OnData --->
> OnStop --->
>
> We still have the overhead of 3 IPC messages, but they can be "in
> flight" at the same time.
>
For all intents and purposes, we can treat the overhead of these 3
messages as the same as sending only 1. (The overhead should be about
the same already, and if it's not, then it's easy to optimize away.)
> But under your proposed rule that one side can't send multiple
> messages in a row in IPDL, we have to add acknowledgements to each
> message:
>
> PARENT CHILD PARENT CHILD PARENT CHILD
> -----------------------------------------------------
> OnStart -->
> moar -->
> OnData -->
> moar -->
> OnStop -->
>
> (I hope the ASCII art is comprehensible). Here we're adding two round-
> trip IPC times, because each message needs to be ACK'd before we can
> send the next one. This certainly adds extra latency, and might
> affect overall bandwidth as well (for larger replies with many
> onDataAvailable calls), depending on the overheads involved.
>
Right, this is an argument against a strawman.
Assuming I understand OnStart/OnStop correctly, then in IPDL as it
exists now your protocol might look something like
protocol NeckoChannel {
child:
OnStart(); OnData(); OnStop();
parent:
Moar(); Cancel();
// start in OPENING after creating channel
state OPENING:
send OnStart goto NORMAL;
state NORMAL:
send OnData goto SENT;
send OnStop goto STOPPED;
recv Cancel goto CANCELLED;
state SENT:
recv Moar goto NORMAL;
recv Cancel goto DEAD;
state STOPPED:
recv Cancel goto DEAD;
state CANCELLED:
send OnData goto DEAD;
send OnStop goto DEAD;
state DEAD:
recv delete;
};
In which case the timing diagram for your small HTTP response scenario
would be
PARENT CHILD PARENT CHILD
-----------------------------------------
OnStart -->
OnData -->
Moar -->
OnStop -->
Cancel-->
delete-->
It appears that we have an "extra" roundtrip with Moar/Stop. But
remember that the import performance measure here is critical path to
user-visible response. Speaking abstractly, the critical path for the
small HTTP response case is
network --> [buf = read(socket)] --> IPC --> parse/layout/draw
In this case, having the Moar/OnStop round-trip *doesn't* affect the
critical path, because the content process is parsing/laying out/drawing
the HTTP response while Moar/OnStop fly back and forth.
But wait, there's more! ;)
We could also *optimize away* the Moar/OnCancel round trip, assuming
that Necko already knows there's no more data available (i.e. response's
done or socket's closed) when it sends the first OnData() message.
Assuming this knowledge is available, then with the new message signature
async OnData(bool isMoreData, ...);
then we can do
PARENT CHILD
-----------------------
OnStart -->
OnData(false) -->
Cancel-->
delete-->
without race conditions and with no "extra" round trips. I should add
that this is somewhat of a moot point performance-wise, because removing
the "extra" Moar/OnStop doesn't alter the critical path affecting
user-visible responsiveness.
>> And you're worried about the IPC/IPDL overhead being "more expensive"
>> than what? The current case where OnStart/OnData/OnStop are processed
>> as Runnable events in a single event loop?
>
> Yes. Obviously we're going be to more expensive (3 IPC calls can't be
> free), but there's a potentially big difference between issuing them
> in a row versus waiting for an ACK between each.
>
Yes, 3 consecutive "overlapping" async messages vs. 3 send/recv pairs
would be a huge difference. Like I wrote above, we can assume that the
former case is "free" compared to sending only 1 message.
>> I don't think there'll be throughput issues with double-buffering, but I
>> agree that we don't need to solve this to get started.
>
> I agree that double-buffering doesn't inherently cause a throughput
> issue here.
>
We could work this out in a timing diagram if you wish. The important
issue again is critical path to user-visible response, and double
buffering ensures that IPC isn't the bottleneck: the chrome process
fills a network buffer while the content process drains another, so
except in exotic cases, either network or parse/layout/draw will be the
bottleneck (common case, probably the latter).
Cheers,
Chris