Bug 171904

Summary: Web Inspector: Web Sockets: Unable to inspect a WebSocket that receives >50 messages per second
Product: WebKit Reporter: Nikita Vasilyev <nvasilyev>
Component: Web InspectorAssignee: Nikita Vasilyev <nvasilyev>
Status: RESOLVED FIXED    
Severity: Normal CC: bburg, commit-queue, inspector-bugzilla-changes, joepeck, mattbaker, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: All   
OS: All   
Attachments:
Description Flags
Patch
none
Patch
nvasilyev: review-
Patch
none
Patch
mattbaker: review+
Patch
mattbaker: commit-queue-
Patch none

Nikita Vasilyev
Reported 2017-05-09 18:55:44 PDT
Steps: 1. In Web Inspector, open Network tab. 2. Navigate to http://demo2.kaazing.com/demo/forex/ 3. Filter Web Sockets. 4. Click on the go to arrow right next to the WebSocket connection ("jms"). Expected: WebSocket content view is shown. Actual: Nothing happens. Notes: This page sends a lot of WebSocket messages. You may not be able to reproduce the bug on a slow network connection.
Attachments
Patch (3.89 KB, patch)
2017-05-18 17:54 PDT, Nikita Vasilyev
no flags
Patch (3.72 KB, patch)
2017-05-22 16:11 PDT, Nikita Vasilyev
nvasilyev: review-
Patch (5.62 KB, patch)
2017-05-23 16:56 PDT, Nikita Vasilyev
no flags
Patch (6.53 KB, patch)
2017-05-31 16:33 PDT, Nikita Vasilyev
mattbaker: review+
Patch (6.65 KB, patch)
2017-06-01 14:51 PDT, Nikita Vasilyev
mattbaker: commit-queue-
Patch (6.67 KB, patch)
2017-06-01 15:11 PDT, Nikita Vasilyev
no flags
Radar WebKit Bug Importer
Comment 1 2017-05-09 18:56:18 PDT
Nikita Vasilyev
Comment 2 2017-05-12 19:13:58 PDT
This issue is similar to Bug 170036 - Web Inspector: Adding a WebSocket message may change the currently selected resource. Resource#increaseSize causes a chain reaction that results in ContentBrowser#showContentViewForRepresentedObject being called. showContentViewForRepresentedObject - ContentBrowser.js:146 showRepresentedObject - ContentBrowserTabContentView.js:191 showRepresentedObject - Main.js:1175 _treeSelectionDidChange - NetworkGridContentView.js:397 event: WebInspector.TreeOutline.Event.SelectionDidChange select - TreeElement.js:511 _refreshDirtyDataGridNodes - TimelineDataGrid.js:279 --- requestAnimationFrame --- dataGridNodeNeedsRefresh - TimelineDataGrid.js:198 _needsRefresh - ResourceTimelineDataGridNode.js:277 event: WebInspector.Resource.Event.SizeDidChange increaseSize - Resource.js:755 addFrame - WebSocketResource.js:79
Nikita Vasilyev
Comment 3 2017-05-14 20:49:24 PDT
TimelineDataGrid#_refreshDirtyDataGridNodes is called every time a resource size changes. This is unnecessary expensive. I think the right strategy would be to avoid calling TimelineDataGrid#_refreshDirtyDataGridNodes when TimelineDataGrid isn't visible. We should, however, call this method when a TimelineDataGrid becomes visible.
Blaze Burg
Comment 4 2017-05-15 09:25:58 PDT
(In reply to Nikita Vasilyev from comment #3) > TimelineDataGrid#_refreshDirtyDataGridNodes is called every time a resource > size changes. This is unnecessary expensive. > > I think the right strategy would be to avoid calling > TimelineDataGrid#_refreshDirtyDataGridNodes when TimelineDataGrid isn't > visible. We should, however, call this method when a TimelineDataGrid > becomes visible. We shouldn't be doing layout work / accessing DOM elements unless underneath an override of View.prototype.{initialLayout,layout}. Does DataGrid normally violate this, or is this code doing something special to cause this to happen?
Nikita Vasilyev
Comment 5 2017-05-15 12:17:16 PDT
(In reply to Brian Burg from comment #4) > (In reply to Nikita Vasilyev from comment #3) > > TimelineDataGrid#_refreshDirtyDataGridNodes is called every time a resource > > size changes. This is unnecessary expensive. > > > > I think the right strategy would be to avoid calling > > TimelineDataGrid#_refreshDirtyDataGridNodes when TimelineDataGrid isn't > > visible. We should, however, call this method when a TimelineDataGrid > > becomes visible. > > We shouldn't be doing layout work / accessing DOM elements unless underneath > an override of View.prototype.{initialLayout,layout}. Does DataGrid normally > violate this, or is this code doing something special to cause this to > happen? DataGrid is fairly old and has a lot of layout work / DOM access outside of {initialLayout,layout}. Only TimelineDataGrid has _refreshDirtyDataGridNodes method. I'm not entirely sure what are you asking.
Nikita Vasilyev
Comment 6 2017-05-16 20:14:14 PDT
(In reply to Nikita Vasilyev from comment #3) > TimelineDataGrid#_refreshDirtyDataGridNodes is called every time a resource > size changes. This is unnecessary expensive. > > I think the right strategy would be to avoid calling > TimelineDataGrid#_refreshDirtyDataGridNodes when TimelineDataGrid isn't > visible. We should, however, call this method when a TimelineDataGrid > becomes visible. This alone didn't fix the problem :( Another issue is that Resource#increaseSize causes NetworkSidebarPanel#treeElementAddedOrChanged to be called. Every increase of size in a resource causes a sidebar item to be removed and attached to the DOM. On http://demo2.kaazing.com/demo/forex/ you can see that by hovering over the WebSocket resource in the sidebar — the go-to arrow flickers! Every resource, not just a WebSocket resource, that frequently increases its size must be unclickable.
Nikita Vasilyev
Comment 7 2017-05-18 17:54:51 PDT
Matt Baker
Comment 8 2017-05-19 11:17:05 PDT
Comment on attachment 310583 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=310583&action=review > Source/WebInspectorUI/UserInterface/Views/TreeOutline.js:349 > + reattachIfIndexChanged(treeElement, insertionIndex) If I understand correctly, this function reinserts the tree element if the index is changing OR the status element hasn't been initialized. Maybe the function should be called `reattachIfNeeded`, since the check involves more than just the index? > Source/WebInspectorUI/UserInterface/Views/TreeOutline.js:354 > + // insertionIndex.status and it can be triggered by re-attaching treeElement. `insertionIndex.status` seems wrong. This comment could also be more clear: I don't understand why having a falsey status means the element has to be re-inserted.
Nikita Vasilyev
Comment 9 2017-05-22 13:18:41 PDT
(In reply to Matt Baker from comment #8) > Comment on attachment 310583 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=310583&action=review > > > Source/WebInspectorUI/UserInterface/Views/TreeOutline.js:349 > > + reattachIfIndexChanged(treeElement, insertionIndex) > > If I understand correctly, this function reinserts the tree element if the > index is changing OR the status element hasn't been initialized. Maybe the > function should be called `reattachIfNeeded`, since the check involves more > than just the index? > > > Source/WebInspectorUI/UserInterface/Views/TreeOutline.js:354 > > + // insertionIndex.status and it can be triggered by re-attaching treeElement. > > `insertionIndex.status` seems wrong. This comment could also be more clear: > I don't understand why having a falsey status means the element has to be > re-inserted. treeElement.status has the go-to button and close button elements. Re-inserting treeElement calls NetworkSidebarPanel#treeElementAddedOrChanged, which adds these go-to button and close button elements. treeElementAddedOrChanged(treeElement) { if (treeElement.status || !treeElement.treeOutline) return; var fragment = document.createDocumentFragment(); var closeButton = new WebInspector.TreeElementStatusButton(useSVGSymbol("Images/Close.svg", null, WebInspector.UIString("Close resource view"))); closeButton.element.classList.add("close"); closeButton.addEventListener(WebInspector.TreeElementStatusButton.Event.Clicked, this._treeElementCloseButtonClicked, this); fragment.appendChild(closeButton.element); let goToButton = new WebInspector.TreeElementStatusButton(WebInspector.createGoToArrowButton()); goToButton[WebInspector.NetworkSidebarPanel.TreeElementSymbol] = treeElement; goToButton.addEventListener(WebInspector.TreeElementStatusButton.Event.Clicked, this._treeElementGoToArrowWasClicked, this); fragment.appendChild(goToButton.element); treeElement.status = fragment; } https://github.com/WebKit/webkit/blob/f59f78f7e62bae5cd899a7e6943f5696b764e4cd/Source/WebInspectorUI/UserInterface/Views/NetworkSidebarPanel.js#L154 Now that I'm thinking about it, there should be no need to re-insert treeElements, they should have the go-to & close buttons already. I'll try to implement that instead.
Nikita Vasilyev
Comment 10 2017-05-22 16:11:05 PDT
Created attachment 310948 [details] Patch (In reply to Nikita Vasilyev from comment #9) > Now that I'm thinking about it, there should be no need to re-insert > treeElements, they should have the go-to & close buttons already. > I'll try to implement that instead. This isn't necessarily a good idea because both Network and Resources sidebar use the same TreeElement classes, but tree elements in Network sidebar have the go-to arrows. I think in the future we should re-consider the go-to arrow and close button UI in Network tab. I've seen at least 3 people confused not knowing how to close a content view in the Network tab.
Joseph Pecoraro
Comment 11 2017-05-23 14:46:19 PDT
Comment on attachment 310948 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=310948&action=review > Source/WebInspectorUI/ChangeLog:16 > + This patch makes sure treeElement gets re-attached if: > + - Its position (index) changes. > + - treeElement.status, which contains the go-to arrow and the close resource icon, is not yet added to the DOM. I understand re-attaching if the position changes. I do not understand why status has any affect on reattaching. Why do we do the extra work if there is not a status icon? > Source/WebInspectorUI/UserInterface/Views/TreeOutline.js:354 > + if (treeElement.status && this.children.indexOf(treeElement) === insertionIndex) This appears to be O(n) for what should be a single O(1) check. Instead of: this.children.indexOf(treeElement) === insertionIndex Can you just check: this.children[insertionIndex] === treeElement
Nikita Vasilyev
Comment 12 2017-05-23 16:22:57 PDT
Comment on attachment 310948 [details] Patch (In reply to Joseph Pecoraro from comment #11) > Comment on attachment 310948 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=310948&action=review > > > Source/WebInspectorUI/ChangeLog:16 > > + This patch makes sure treeElement gets re-attached if: > > + - Its position (index) changes. > > + - treeElement.status, which contains the go-to arrow and the close resource icon, is not yet added to the DOM. > > I understand re-attaching if the position changes. I do not understand why > status has any affect on reattaching. > > Why do we do the extra work if there is not a status icon? Without this treeElement.status check, there was no go-to/close icon. I think I finally figured it why. Were these icons removed or never added? ResourceTreeElement#_updateStatus: treeElement.status = <div class="indeterminate-progress-spinner"> ResourceTreeElement#_updateStatus: treeElement.status = "" Turns out they were removed by ResourceTreeElement#_updateStatus. WebSocketResourceTreeElement#_updateConnectionStatus is used in Resources tab, but not Network tab.
Nikita Vasilyev
Comment 13 2017-05-23 16:56:29 PDT
Nikita Vasilyev
Comment 14 2017-05-31 16:33:22 PDT
Created attachment 311653 [details] Patch The previous patch sometimes didn't show the go-to buttons.
Matt Baker
Comment 15 2017-06-01 14:13:03 PDT
Comment on attachment 311653 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=311653&action=review r=me, with a comment. > Source/WebInspectorUI/UserInterface/Views/NetworkSidebarPanel.js:156 > + if (treeElement.status instanceof DocumentFragment || !treeElement.treeOutline) The check for status instanceOf DocumentFragment is a little fragile, since status could be technically be a DocumentFragment other than the goto/close fragment that gets added below. This could be more future-proof by adding a property to the status element: treeElementAddedOrChanged(treeElement) { if (!treeElement.treeOutline) return; if (treeElement.status && treeElement.status[WebInspector.NetworkSidebarPanel.TreeElementStatusButtonSymbol]) return; treeElement.status[WebInspector.NetworkSidebarPanel.TreeElementStatusButtonSymbol] = true; ... } Putting the property on status instead of treeElement also ensures that the property can't get out of sync by someone setting the status elsewhere.
Nikita Vasilyev
Comment 16 2017-06-01 14:17:57 PDT
Comment on attachment 311653 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=311653&action=review >> Source/WebInspectorUI/UserInterface/Views/NetworkSidebarPanel.js:156 >> + if (treeElement.status instanceof DocumentFragment || !treeElement.treeOutline) > > The check for status instanceOf DocumentFragment is a little fragile, since status could be technically be a DocumentFragment other than the goto/close fragment that gets added below. This could be more future-proof by adding a property to the status element: > > treeElementAddedOrChanged(treeElement) > { > if (!treeElement.treeOutline) > return; > > if (treeElement.status && treeElement.status[WebInspector.NetworkSidebarPanel.TreeElementStatusButtonSymbol]) > return; > > treeElement.status[WebInspector.NetworkSidebarPanel.TreeElementStatusButtonSymbol] = true; > ... > } > > Putting the property on status instead of treeElement also ensures that the property can't get out of sync by someone setting the status elsewhere. Agreed. I like the use a symbol.
Nikita Vasilyev
Comment 17 2017-06-01 14:51:02 PDT
Matt Baker
Comment 18 2017-06-01 15:05:35 PDT
Comment on attachment 311762 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=311762&action=review > Source/WebInspectorUI/UserInterface/Views/NetworkSidebarPanel.js:160 > + if (treeElement.status[WebInspector.NetworkSidebarPanel.TreeElementStatusButtonSymbol] || !treeElement.treeOutline) You also need to check that status is defined before accessing the property.
Nikita Vasilyev
Comment 19 2017-06-01 15:11:06 PDT
WebKit Commit Bot
Comment 20 2017-06-01 17:50:20 PDT
Comment on attachment 311764 [details] Patch Clearing flags on attachment: 311764 Committed r217690: <http://trac.webkit.org/changeset/217690>
WebKit Commit Bot
Comment 21 2017-06-01 17:50:22 PDT
All reviewed patches have been landed. Closing bug.
Note You need to log in before you can comment on or make changes to this bug.