New issue
Advanced search Search tips

Issue 881424 link

Starred by 2 users

Issue metadata

Status: Available
Owner: ----
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Android , Windows , Chrome , Mac , Fuchsia
Pri: 3
Type: Bug



Sign in to add a comment

postMessage is 3-4x slower on OOPIFs

Project Member Reported by lfg@chromium.org, Sep 6

Issue description

postMessage on OOPIFs is 3-4x slower than postMessage on local frames.

Notice that if we pass a MessagePort to the OOPIF and start using that to communicate with the OOPIF then the performance is pretty close to a local frame. We should optimize postMessage so that it is faster on OOPIFs.

Here's a run on my computer from the attached benchmark:

> await testCrossOriginFrame('http://127.0.0.1/~lfg/messageports')
testing window postMessage
10000 round trips in  6136.500000022352
testing MessagePort
10000 round trips in  1767.3000004142523

> await testLocalFrame()
testing window postMessage
10000 round trips in  1985.700000077486
testing MessagePort
10000 round trips in  1611.500000115484

 
testPostMessage.html
2.5 KB View Download
Interesting.  How do MessagePorts differ in implementation from postMessage?  I would expect some overhead in the cross-process case regardless of MessagePort / postMessage, but maybe it only gets paid the first time for MessagePorts, vs each time for postMessage?
MessagePort is just a mojo message pipe, where we just send raw serialized messages across (i.e. no mojom interface or anything on top, and messages are send directly from one renderer to another).

Not sure how frame-to-frame postMessage works. Is that still using FrameMsg_PostMessageEvent/FrameHostMsg_RouteMessageEvent, i.e. at least two IPCs + extra browser process overhead for each message?
Yes, postMessage is still routed using legacy IPC through the browser process, so definitely some extra copying of data and process hop.
Yes, frame-to-frame postMessage still uses the old IPC channel. I haven't profiled, but I think we need to wake up 6 threads for OOPIF frame-to-frame postMessage (renderer A main, renderer A IO, browser IO, browser main, renderer B IO and renderer B main).

It's import to know that it's also not a directly apples-to-apples comparison, since frame-to-frame postMessage validates the target origin, but I think that many of the common use cases could be optimized to use a lazily created channel similar to the MessagePort (or reuse it).

It's important to maintain the security checks in postMessage.  If it's possible to do that and establish a direct Mojo connection for future postMessages with the same endpoints, that's great.  We need to be careful not to break cases where the receiver changed documents/origins after the message was sent and before it was received, though.
We also need to be careful if the origin is serialized into the message sent over the pipe, since a compromised renderer can use its real origin to establish the pipe, but then lie about the origin serialized over it.
Status: Available (was: Untriaged)
I think we can lazily create the pipes (mediated by the browser) and bind them to their respective Documents, so if one of the documents goes away (for example, by navigating), it would be destroyed. That also ensure that the origins never changed on the pipe, and they can be validated by both renderers.

The main concern would be the ordering of the messages with respect to other IPCs from the browser (such as layout/resizes). We already have hacks in place to mitigate some of those, but the ordering ir already broken if we utilize MessagePorts. I think we should just get the web developers to stop relying on unspecced quirks of the platform and just treat postMessage as the asynchronous API that it is, without ordering guarantees.

I'll mark this bug as available.

Re: #7, not guaranteeing the ordering wrt layout/resizes is essentially what we've settled on instead of trying to fix the remaining issues in Chrome, and chrishtr@ filed a spec bug for that at https://github.com/whatwg/html/issues/3727.
How would creating pipes bound to their respective documents work when one of them is navigated? I.e. I send a bunch of messages to a particular iframe, at some point the iframe navigates, the messages should now get delivered to the new document but I don't believe that (without building explicit ack-ing) mojo gives you a way to know exactly which messages were or weren't delivered and thus need to be resend over the new pipe?
If frame A sends a message to frame B, and frame B navigates to another same-origin document before the message arrives, wouldn't we still want to deliver the message to the new document?  How would that work with a Document-bound pipe?

I'm also curious about the case where postMessage is sent from an unload handler, in which case it will post a task that runs after the source document has already been detached, yet the message should still go out.
Do we care if the messages get dropped in this situation? What happens today when an iframe navigates? Do we wait until the iframe finishes navigating and queue the postMessages sent? Do we wait until the frame completes loading and installs their message listeners before delivering the messages?

I suspect that even today we already drop messages during frame navigation.

I think if the navigation commits after the message is sent from the source renderer but before reaching RenderFrameProxyHost::OnRouteMessageEvent(), we will just forward the message to the new RFH and it will just work.  If the browser process sends the postMessage IPC to the target RFH, and then a navigation DidCommit from that same RFH races with it, then it probably depends on whether the navigation is same-process or cross-process.  For same-process, I'd expect the WebLocalFrameImpl::DispatchMessageEventWithOriginCheck to fire the event on whatever the new doc is, and for cross-process it will be delivered to the now pending delete RFH and probably won't get to be processed.  So it seems this latter case is already problematic, though I haven't actually tried out any of this.

Sign in to add a comment