Discussion:
Cost of constructing a communication path vs. sending a message
Mike Kristoffersen
2010-09-16 11:03:18 UTC
Permalink
Working on Bug 587414 that makes Geolocation work from the content
process, while the geolocators are in the chrome process an interesting
discussion have emerged.

This is about sending of messages vs. using the protocol constructor and
delete function to transmit information across a process boundary.

Now what I understand from the dialog going on in bug 587414, is that
when we always send the same event after the constructor then that event
should be implicit by the constructor and if the last message is always
the same then that should be implicit by the destructor (to reduce the
number of messages send).

So if I from the child process do:

SendP<myProtocol>Constructor(...)
SendStart(...)
<other messages>
SendStop(...)
Send__delete__(...)

Then I should merge the start with the Constructor and the stop with the
__delete__ message, so the communication becomes like:

SendP<myProtocol>Constructor(...)
<other messages>
Send__delete__(...)

I can understand the argumentation here, no need to send messages that
we don't have to.

Now in this specific case message Start and Stop might be repeated a
number of times at unknown intervals, because it depends on the content
of the pages that the user visits.

SendP<myProtocol>Constructor(...)
.
.
.
SendStart(...)
<other messages>
SendStop(...)
.
.
.
SendStart(...)
<other messages>
SendStop>(...)
.
.
.
SendStart(...)
<other messages>
SendStop>(...)
.
.
.
Send__delete__(...)

Now in a review I was asked to merge the "start" with the constructor
and the "stop" with the __delete__ as the first message is always start
and the last one is stop (a bit simplified here to illustrate the key point)

I don't have a problem with implementing that, but it made me think:

As I don't know when the last stop is, I would then have to assume that
every stop is the last one - giving the following:

SendP<myProtocol>Constructor(...)
<other messages>
Send__delete__(...)
.
.
.
SendP<myProtocol>Constructor(...)
<other messages>
Send__delete__(...)
.
.
.
SendP<myProtocol>Constructor(...)
<other messages>
Send__delete__(...)

Looking at the code it seems like constructing a protocol is much more
expensive than just sending a message - so in a case like this where we
have two objects communicating over time, is it then the best choice to
create the connection between them once, and use this connection to
communicate over time - or is it really better to (re-)create the
connection each time it is needed? - Is there a significant cost to
having a connection open all the time?
Chris Jones
2010-09-17 05:41:11 UTC
Permalink
Post by Mike Kristoffersen
Looking at the code it seems like constructing a protocol is much more
expensive than just sending a message - so in a case like this where we
have two objects communicating over time, is it then the best choice to
create the connection between them once, and use this connection to
communicate over time - or is it really better to (re-)create the
connection each time it is needed? - Is there a significant cost to
having a connection open all the time?
There's not a general answer to that question. it depends on the
problem. I don't know exactly what problem you're solving here, but the
"request protocol" pattern with Constructor/__delete__ encapsulating the
request might be what you want. Depending on what start/stop really
mean, tracking nested and overlapping requests can become tricky, and
you'd likely end up duplicating the actor-management logic.

Creating/destroying an actor is cheap, essentially |new
FooActor()/delete actor|| and a hash table insert/delete on both sides.
Sending a message with IPC is much much more expensive than
constructing/registering/unregistering/deleting an actor.

Cheers,
Chris
Mike Kristoffersen
2010-09-17 07:45:57 UTC
Permalink
On Thu, 16 Sep 2010 22:41:11 -0700, Chris Jones wrote:

Thank you for your answer Chris - I'm learning from it :)
Post by Chris Jones
Post by Mike Kristoffersen
Looking at the code it seems like constructing a protocol is much more
expensive than just sending a message - so in a case like this where we
have two objects communicating over time, is it then the best choice to
create the connection between them once, and use this connection to
communicate over time - or is it really better to (re-)create the
connection each time it is needed? - Is there a significant cost to
having a connection open all the time?
There's not a general answer to that question. it depends on the
problem. I don't know exactly what problem you're solving here, but the
"request protocol" pattern with Constructor/__delete__ encapsulating the
request might be what you want. Depending on what start/stop really
mean, tracking nested and overlapping requests can become tricky, and
you'd likely end up duplicating the actor-management logic.
Start means "Start sending me geolocation positions", Stop means "Stop
sending me geolocation positions" - they can't be nested, nor
overlapping.

They are always send between the same objects (the objects are never
deleted after they are initially created (*), they are part of a service
and there is never more than one instance in each process)
Post by Chris Jones
Creating/destroying an actor is cheap, essentially |new
FooActor()/delete actor|| and a hash table insert/delete on both sides.
Sending a message with IPC is much much more expensive than
constructing/registering/unregistering/deleting an actor.
I could be misunderstanding what you are saying, but what I'm hearing is
that you say it is cheaper to transmit information between the child
process and the parent process by doing a "SendPGeolocationConstructor()"
than sending a message like "SendStart()" on an existing connection - if
I didn't misunderstand this, and we strive to use the cheapest solution,
why do we have the messages then, is it only to ensure communication
between specific end points? (only talking about the async case here)

If I may extend the question a bit - as a response to the start request
from the child process, the parent process will start to send geolocation
events to the child process - should I create a separate protocol for
this and then call the constructor in it to transmit the position, or
keep it as the message on the protocol that is setup when the child needs
to get geolocations?

^__^
Mike

(*) The objects are deleted as part of the shutdown of the browser, but
as far as this discussion goes, they can be seen as always being there.
Chris Jones
2010-09-20 19:11:08 UTC
Permalink
Post by Mike Kristoffersen
Post by Chris Jones
Post by Mike Kristoffersen
Looking at the code it seems like constructing a protocol is much more
expensive than just sending a message - so in a case like this where we
have two objects communicating over time, is it then the best choice to
create the connection between them once, and use this connection to
communicate over time - or is it really better to (re-)create the
connection each time it is needed? - Is there a significant cost to
having a connection open all the time?
There's not a general answer to that question. it depends on the
problem. I don't know exactly what problem you're solving here, but the
"request protocol" pattern with Constructor/__delete__ encapsulating the
request might be what you want. Depending on what start/stop really
mean, tracking nested and overlapping requests can become tricky, and
you'd likely end up duplicating the actor-management logic.
Start means "Start sending me geolocation positions", Stop means "Stop
sending me geolocation positions" - they can't be nested, nor
overlapping.
They are always send between the same objects (the objects are never
deleted after they are initially created (*), they are part of a service
and there is never more than one instance in each process)
If you're already tracking enough state in the service to ensure that
start/stop don't overlap or nest, the request-actor pattern probably
doesn't buy you anything here. Start/Stop messages seem OK to me.
Post by Mike Kristoffersen
Post by Chris Jones
Creating/destroying an actor is cheap, essentially |new
FooActor()/delete actor|| and a hash table insert/delete on both sides.
Sending a message with IPC is much much more expensive than
constructing/registering/unregistering/deleting an actor.
I could be misunderstanding what you are saying, but what I'm hearing is
that you say it is cheaper to transmit information between the child
process and the parent process by doing a "SendPGeolocationConstructor()"
than sending a message like "SendStart()" on an existing connection - if
I didn't misunderstand this, and we strive to use the cheapest solution,
why do we have the messages then, is it only to ensure communication
between specific end points? (only talking about the async case here)
No, you're misunderstanding ;). I'm saying that the non-IPC parts of
actor creation and destruction (new FooActor()/delete actor and hash
table operations) are much much cheaper than sending a message with IPC.
The request-actor pattern can reduce extra IPC messages by having the
the SendFooActorConstructor() message also mean "start request" and the
Send__delete__() message also mean "stop request", instead of having
extra (extraneous) StartRequest()/StopRequest() messages between
SendCtor()/Send__delete__().
Post by Mike Kristoffersen
If I may extend the question a bit - as a response to the start request
from the child process, the parent process will start to send geolocation
events to the child process - should I create a separate protocol for
this and then call the constructor in it to transmit the position, or
keep it as the message on the protocol that is setup when the child needs
to get geolocations?
See above; sounds like explicit Start/Stop on the service actor is good
enough, since the content-process part of the service is apparently
tracking a lot of state already.

Cheers,
Chris
Mike Kristoffersen
2010-09-20 20:20:26 UTC
Permalink
Post by Chris Jones
Post by Mike Kristoffersen
Post by Chris Jones
Creating/destroying an actor is cheap, essentially |new
FooActor()/delete actor|| and a hash table insert/delete on both sides.
Sending a message with IPC is much much more expensive than
constructing/registering/unregistering/deleting an actor.
I could be misunderstanding what you are saying, but what I'm hearing
is that you say it is cheaper to transmit information between the child
process and the parent process by doing a
"SendPGeolocationConstructor()" than sending a message like
"SendStart()" on an existing connection - if I didn't misunderstand
this, and we strive to use the cheapest solution, why do we have the
messages then, is it only to ensure communication between specific end
points? (only talking about the async case here)
No, you're misunderstanding ;). I'm saying that the non-IPC parts of
actor creation and destruction (new FooActor()/delete actor and hash
table operations) are much much cheaper than sending a message with IPC.
I'm happy I didn't got it right the first time, I was very puzzled by the
consequences of my initial understanding. I guess the total cost is more
important than the cost of each component.
Post by Chris Jones
The request-actor pattern can reduce extra IPC messages by having the
the SendFooActorConstructor() message also mean "start request" and the
Send__delete__() message also mean "stop request", instead of having
extra (extraneous) StartRequest()/StopRequest() messages between
SendCtor()/Send__delete__().
This time I think I understand what you are saying, at least this last
bit makes sense to me this time (usually a good indicator).

Thank you for the help Chris.

Continue reading on narkive:
Loading...