Bug 206438 - Frequent sync BackForwardBackListCount/BackForwardForwardListCount IPC on reddit.com
Summary: Frequent sync BackForwardBackListCount/BackForwardForwardListCount IPC on red...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebKit2 (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Chris Dumez
URL:
Keywords: InRadar
Depends on:
Blocks: 206442
  Show dependency treegraph
 
Reported: 2020-01-17 13:18 PST by Chris Dumez
Modified: 2020-01-26 20:39 PST (History)
8 users (show)

See Also:


Attachments
Patch (9.99 KB, patch)
2020-01-17 13:23 PST, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (22.02 KB, patch)
2020-01-22 10:26 PST, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (29.56 KB, patch)
2020-01-22 10:38 PST, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (28.78 KB, patch)
2020-01-22 10:42 PST, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (26.07 KB, patch)
2020-01-26 17:16 PST, Chris Dumez
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Dumez 2020-01-17 13:18:18 PST
Frequent sync BackForwardBackListCount/BackForwardForwardListCount IPC on reddit.com. When scrolling on reddit.com, you frequently see 2 consecutive sync IPCs (WebPageProxy::BackForwardBackListCount then WebPageProxy::BackForwardForwardListCount) from the WebContent process to the UIProcess. Those are bad for performance. This happens every time the script on the back accesses history.length, which is unfortunate, since this history length rarely changes.
Comment 1 Chris Dumez 2020-01-17 13:23:17 PST
Created attachment 388082 [details]
Patch
Comment 2 Sam Weinig 2020-01-18 11:59:26 PST
Comment on attachment 388082 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=388082&action=review

> Source/WebKit/ChangeLog:18
> +        2. Cache those counts in WebBackForwardListProxy and blow away the cached counts whenever the back/forward list changes. In the
> +           common case (where the back/forward list rarely changes), we now see a single sync IPC instead of many (verified on reddit.com).

If we are going to start caching, why do we need even one sync ipc? In what cases does the WebProcess not know about items added or removed from the list?
Comment 3 Darin Adler 2020-01-20 12:07:52 PST
Comment on attachment 388082 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=388082&action=review

>> Source/WebKit/ChangeLog:18
>> +           common case (where the back/forward list rarely changes), we now see a single sync IPC instead of many (verified on reddit.com).
> 
> If we are going to start caching, why do we need even one sync ipc? In what cases does the WebProcess not know about items added or removed from the list?

In other words, once we start caching we introduce a race, and there is no need to use synchronous IPC to avoid the race. We should just include the counts in the messages that is currently the "invalidate caches" message. Right?
Comment 4 Chris Dumez 2020-01-21 08:23:09 PST
Comment on attachment 388082 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=388082&action=review

>>> Source/WebKit/ChangeLog:18
>>> +           common case (where the back/forward list rarely changes), we now see a single sync IPC instead of many (verified on reddit.com).
>> 
>> If we are going to start caching, why do we need even one sync ipc? In what cases does the WebProcess not know about items added or removed from the list?
> 
> In other words, once we start caching we introduce a race, and there is no need to use synchronous IPC to avoid the race. We should just include the counts in the messages that is currently the "invalidate caches" message. Right?

I am not convinced there is a race here since the changes to the list in the UIProcess are made by IPCs from the WebContent process. I invalidate the local cache, and then send the IPC to the UIProcess that will update its list. I guess we could do what Darin suggests and have IPCs that invalidate the cache also send back the counts. I would need to see how much extra complexity this adds though. It is also trickier than it sounds because not all IPCs that update the list in the UIProcess are synchronous. For example, the WebProcess sends a WebPageProxy::BackForwardAddItem async IPC to the UIProcess, which may change those counts. I don't want to make this IPC synchronous so I cannot get updated counts synchronously.

The WebContent process currently does not maintain a BackForward "list", it merely has a map of items and asks the UIProcess whenever it needs to do something with history. I guess we could maintain more state in the WebContent process in order to avoid the sync IPC altogether but this would likely be significant refactoring. Given that the back/forward list does not change very often, especially when running the page's script, I do believe that my patch gets us most of the perf win, with very little complexity.
Comment 5 Chris Dumez 2020-01-22 09:59:19 PST
(In reply to Chris Dumez from comment #4)
> Comment on attachment 388082 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=388082&action=review
> 
> >>> Source/WebKit/ChangeLog:18
> >>> +           common case (where the back/forward list rarely changes), we now see a single sync IPC instead of many (verified on reddit.com).
> >> 
> >> If we are going to start caching, why do we need even one sync ipc? In what cases does the WebProcess not know about items added or removed from the list?
> > 
> > In other words, once we start caching we introduce a race, and there is no need to use synchronous IPC to avoid the race. We should just include the counts in the messages that is currently the "invalidate caches" message. Right?
> 
> I am not convinced there is a race here since the changes to the list in the
> UIProcess are made by IPCs from the WebContent process. I invalidate the
> local cache, and then send the IPC to the UIProcess that will update its
> list. I guess we could do what Darin suggests and have IPCs that invalidate
> the cache also send back the counts. I would need to see how much extra
> complexity this adds though. It is also trickier than it sounds because not
> all IPCs that update the list in the UIProcess are synchronous. For example,
> the WebProcess sends a WebPageProxy::BackForwardAddItem async IPC to the
> UIProcess, which may change those counts. I don't want to make this IPC
> synchronous so I cannot get updated counts synchronously.
> 
> The WebContent process currently does not maintain a BackForward "list", it
> merely has a map of items and asks the UIProcess whenever it needs to do
> something with history. I guess we could maintain more state in the
> WebContent process in order to avoid the sync IPC altogether but this would
> likely be significant refactoring. Given that the back/forward list does not
> change very often, especially when running the page's script, I do believe
> that my patch gets us most of the perf win, with very little complexity.

I looked into this more and I am still think the patch is correct.
1. I do not think there is a race because the WebBackForwardList changes in the UIProcess are made as a result of IPC messages (e.g. WebPageProxy::BackForwardClear) that are sent by the WebContent process and I make sure the clear the cache in the WebContent process *before* sending those IPCs to the UIProcess.
2. There would be a race if we did what Darin suggest and include counts in response to messages that invalidate the cache. For example, if the WebPageProxy::BackForwardClear async IPC included a response with the updated counts, then responses to WebCore while we're waiting for the IPC response would use stale data. This would not be an issue if IPCs such as WebPageProxy::BackForwardClear were synchronous but we do not want to add more sync IPC.

I do not have a better proposal at the moment. I agree it would be good to get rid of the sync IPC entirely but this patch at least gets us a most of the way there in terms of perf since history rarely changes.
Comment 6 Chris Dumez 2020-01-22 10:26:13 PST
Created attachment 388435 [details]
Patch
Comment 7 Alex Christensen 2020-01-22 10:36:51 PST
Comment on attachment 388435 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=388435&action=review

> Source/WebKit/WebProcess/WebPage/WebBackForwardListProxy.cpp:133
> +    return m_page ? cacheListCountsIfNecessary().backCount : 0;

It looks strange to have the m_page check here, where m_page is not used.  Let's move it into cacheListCountsIfNecessary

> WebKit.xcworkspace/xcshareddata/xcschemes/All Source.xcscheme:60
> +               BuildableName = "libANGLE.a"

This change shouldn't be here.
Comment 8 Chris Dumez 2020-01-22 10:38:35 PST
Created attachment 388436 [details]
Patch
Comment 9 Chris Dumez 2020-01-22 10:42:00 PST
Created attachment 388439 [details]
Patch
Comment 10 Chris Dumez 2020-01-22 10:42:18 PST
(In reply to Alex Christensen from comment #7)
> Comment on attachment 388435 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=388435&action=review
> 
> > Source/WebKit/WebProcess/WebPage/WebBackForwardListProxy.cpp:133
> > +    return m_page ? cacheListCountsIfNecessary().backCount : 0;
> 
> It looks strange to have the m_page check here, where m_page is not used. 
> Let's move it into cacheListCountsIfNecessary
> 
> > WebKit.xcworkspace/xcshareddata/xcschemes/All Source.xcscheme:60
> > +               BuildableName = "libANGLE.a"
> 
> This change shouldn't be here.

Done.
Comment 11 Chris Dumez 2020-01-22 10:43:44 PST
Comment on attachment 388439 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=388439&action=review

> Source/WebKit/WebProcess/WebPage/WebBackForwardListProxy.cpp:63
> +    clearCachedListCounts();

Technically, when the UIProcess restores the session, it could send the counts along with the sessionState so we could populate here. Let me know if you think we should do this.

> Source/WebKit/WebProcess/WebPage/WebBackForwardListProxy.cpp:102
>      m_page->send(Messages::WebPageProxy::BackForwardAddItem(toBackForwardListItemState(item.get())));

We could do a sendWithAsyncReply() here and get the updated counts back. Let me know if you think I should do this.
Comment 12 Chris Dumez 2020-01-23 14:13:57 PST
ping review?
Comment 13 Darin Adler 2020-01-23 18:28:10 PST
Comment on attachment 388439 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=388439&action=review

>> Source/WebKit/WebProcess/WebPage/WebBackForwardListProxy.cpp:63
>> +    clearCachedListCounts();
> 
> Technically, when the UIProcess restores the session, it could send the counts along with the sessionState so we could populate here. Let me know if you think we should do this.

Our past experience is that anything we can do to avoid sync calls ends up helping us prevent surprise performance hiccups. So it seems we’d want to do anything we could do to cut down on them. But despite the explanations you gave earlier, still honestly not sure I understand why we can’t get rid of the sync messaging entirely, which seems like the best longer term solution.

>> Source/WebKit/WebProcess/WebPage/WebBackForwardListProxy.cpp:102
>>      m_page->send(Messages::WebPageProxy::BackForwardAddItem(toBackForwardListItemState(item.get())));
> 
> We could do a sendWithAsyncReply() here and get the updated counts back. Let me know if you think I should do this.

Same thought.

> Source/WebKit/WebProcess/WebPage/WebBackForwardListProxy.cpp:113
> +    m_cachedBackForwardListCounts = WTFMove(backForwardListCounts);

No need to use WTFMove for a structure containing two integers.

> Source/WebKit/WebProcess/WebPage/WebBackForwardListProxy.cpp:148
> +        m_cachedBackForwardListCounts = WTFMove(backForwardListCounts);

Ditto.
Comment 14 Chris Dumez 2020-01-26 17:14:46 PST
(In reply to Darin Adler from comment #13)
> Comment on attachment 388439 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=388439&action=review
> 
> >> Source/WebKit/WebProcess/WebPage/WebBackForwardListProxy.cpp:63
> >> +    clearCachedListCounts();
> > 
> > Technically, when the UIProcess restores the session, it could send the counts along with the sessionState so we could populate here. Let me know if you think we should do this.
> 
> Our past experience is that anything we can do to avoid sync calls ends up
> helping us prevent surprise performance hiccups. So it seems we’d want to do
> anything we could do to cut down on them. But despite the explanations you
> gave earlier, still honestly not sure I understand why we can’t get rid of
> the sync messaging entirely, which seems like the best longer term solution.
> 
> >> Source/WebKit/WebProcess/WebPage/WebBackForwardListProxy.cpp:102
> >>      m_page->send(Messages::WebPageProxy::BackForwardAddItem(toBackForwardListItemState(item.get())));
> > 
> > We could do a sendWithAsyncReply() here and get the updated counts back. Let me know if you think I should do this.
> 
> Same thought.

Will follow-up for these optimizations.

> 
> > Source/WebKit/WebProcess/WebPage/WebBackForwardListProxy.cpp:113
> > +    m_cachedBackForwardListCounts = WTFMove(backForwardListCounts);
> 
> No need to use WTFMove for a structure containing two integers.
> 
> > Source/WebKit/WebProcess/WebPage/WebBackForwardListProxy.cpp:148
> > +        m_cachedBackForwardListCounts = WTFMove(backForwardListCounts);
> 
> Ditto.
Comment 15 Chris Dumez 2020-01-26 17:16:38 PST
Created attachment 388818 [details]
Patch
Comment 16 WebKit Commit Bot 2020-01-26 20:38:55 PST
Comment on attachment 388818 [details]
Patch

Clearing flags on attachment: 388818

Committed r255135: <https://trac.webkit.org/changeset/255135>
Comment 17 WebKit Commit Bot 2020-01-26 20:38:57 PST
All reviewed patches have been landed.  Closing bug.
Comment 18 Radar WebKit Bug Importer 2020-01-26 20:39:14 PST
<rdar://problem/58908146>