Skip to content
This repository has been archived by the owner on May 25, 2021. It is now read-only.

Major performance improvment by bypassing the sequence of ports when sending tree data #592

Merged
merged 5 commits into from
Sep 6, 2016

Conversation

clbond
Copy link
Contributor

@clbond clbond commented Sep 2, 2016

This PR represents a major performance improvement over previous builds.

Before this change, we were sending tree data through the normal channel. That meant every time we sent a tree or a tree delta, it had to go through this sequence:

Backend script -> content script -> background channel -> frontend

Each one of these steps required a serialize + deserialize (which happens in the internal Chrome code, not our code). Therefore for large trees, it was an absolute performance killer. This PR fixes that. Now the trees are just serialized and deserialized once on their way from the backend to the frontend.

I encourage anyone who reviews this to do a side-by-side performance comparison using the Kitchen Sink stress tester or any other app.

 * Revert the recursion change I made to the serializer as it performs way worse than the old implementation
 * Do not expand large arrays by default in the State view because it
   takes a long time to render them
(Note: There is a big performance fix coming around message transmission but this is not it)
alternate channel instead of the sequence of ports that require 4
serializations and deserializations for each message
@mention-bot
Copy link

@clbond, thanks for your PR! By analyzing the annotation information on this pull request, we identified @xorgy, @sumitarora and @ericjim to be potential reviewers

/// we simply send the entire tree again instead of trying to patch it
/// since it will be faster than trying to apply hundreds or thousands of
/// changes to an existing tree.
const deltaThreshold = 512;
Copy link
Contributor

@xorgy xorgy Sep 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you profile to find this parameter, or is it very ballpark?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have measurements. But I did do a bit of testing around it and it appeared to improve performance. Logically it also makes sense. There is no sense trying to compare two massive trees that you already know are vastly different. Just send the new one. Other than that does the PR look OK? Did you try running it?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am ok with 512 being a ballpark estimate at this point

@oskarols
Copy link

oskarols commented Sep 6, 2016

Tried testing it on a large RC4 app, component tree is showing up blank unfortunately.
No errors in the background page. Lots of "got msg from backend" messages in the console.

I'm assuming this only works for RC5 or 6?

@clbond
Copy link
Contributor Author

clbond commented Sep 6, 2016

@oskarols Are there any exceptions in the backend or the frontend? For backend, you can just open the Console tab that you would normally use for your app. For the frontend, open Augury inside a popup (not docked) and then hit Cmd-Shift-I (Mac) or Ctrl-Shift-I (Windows).

Is your app publicly available so I can reproduce?

@oskarols
Copy link

oskarols commented Sep 6, 2016

Sadly it's not publicly available. Seeing no exceptions in either.

@clbond
Copy link
Contributor Author

clbond commented Sep 6, 2016

If you can make a plunkr that reproduces the issue I would love to debug and fix it. I have used Augury for RC4 appals and it appeared to work properly. Alternatively if you have a bit of time to do a screen-sharing session with me, we could look into the issue together.

/// circuitous route and will be serialized and deserialized repeatedly. Therefore large
/// messages must be sent using the {@link MessageBuffer} mechanism in order to avoid major
/// performance bottlenecks and UI latency.
case MessageType.CompleteTree:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@clbond Do we need those 2 empty case conditions here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they fall through to the error handler. The alternative would be to do:

if (messageType == MessageType.TreeDiff || messageType == MessageType.CompleteTree || messageType == MessageType.DispatchWrapper) {
  throw ...;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Replaced with if statement

previousTree
? MessageFactory.treeDiff(previousTree.diff(newTree))
: MessageFactory.completeTree(newTree));
previousTree = tree;
Copy link

@igor-ka igor-ka Sep 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future let's extract the variable assignment out of it. One way is to have a redux store on the backend that will manage this. Or simply wrap this in a class. This is completely out of scope though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, I will make a note of this to address in the near future.

@igor-ka
Copy link

igor-ka commented Sep 6, 2016

@clbond LGTM :shipit:

@clbond
Copy link
Contributor Author

clbond commented Sep 6, 2016

Thank you Igor. I appreciate your thorough review :)

@clbond clbond merged commit db9310a into rangle:dev Sep 6, 2016
@clbond
Copy link
Contributor Author

clbond commented Sep 7, 2016

@oskarols Are you trying to debug an app that is running in production mode?

@oskarols
Copy link

oskarols commented Sep 9, 2016

@clbond Nope, not in production mode. Looked into it, and it seems we're getting some exception from Augury.

zone.js:269 Uncaught TypeError: Cannot read property 'name' of undefined

exports.functionName                @   function-name.ts?6954:7
(anonymous function)                @   transformer.ts?d0de:89
dependencies                        @   transformer.ts?d0de:89
(anonymous function)                @   transformer.ts?d0de:137
load                                @   transformer.ts?d0de:53
exports.transform                   @   transformer.ts?d0de:61
(anonymous function)                @   transformer.ts?d0de:153
transformChildren                   @   transformer.ts?d0de:151
(anonymous function)                @   transformer.ts?d0de:172
load                                @   transformer.ts?d0de:53
exports.transform                   @   transformer.ts?d0de:61
(anonymous function)                @   transformer.ts?d0de:153
transformChildren                   @   transformer.ts?d0de:151
(anonymous function)                @   transformer.ts?d0de:172
load                                @   transformer.ts?d0de:53
exports.transform                   @   transformer.ts?d0de:61
(anonymous function)                @   transformer.ts?d0de:153
transformChildren                   @   transformer.ts?d0de:151
(anonymous function)                @   transformer.ts?d0de:172
load                                @   transformer.ts?d0de:53
exports.transform                   @   transformer.ts?d0de:61
(anonymous function)                @   transformer.ts?d0de:153
transformChildren                   @   transformer.ts?d0de:151
(anonymous function)                @   transformer.ts?d0de:172
load                                @   transformer.ts?d0de:53
exports.transform                   @   transformer.ts?d0de:61
(anonymous function)                @   transformer.ts?d0de:153
transformChildren                   @   transformer.ts?d0de:151
(anonymous function)                @   transformer.ts?d0de:172
load                                @   transformer.ts?d0de:53
exports.transform                   @   transformer.ts?d0de:61
(anonymous function)                @   transformer.ts?d0de:153
transformChildren                   @   transformer.ts?d0de:151
(anonymous function)                @   transformer.ts?d0de:172
load                                @   transformer.ts?d0de:53
exports.transform                   @   transformer.ts?d0de:61
(anonymous function)                @   transformer.ts?d0de:153
transformChildren                   @   transformer.ts?d0de:151
(anonymous function)                @   transformer.ts?d0de:172
load                                @   transformer.ts?d0de:53
exports.transform                   @   transformer.ts?d0de:61
(anonymous function)                @   transformer.ts?d0de:153
transformChildren                   @   transformer.ts?d0de:151
(anonymous function)                @   transformer.ts?d0de:172
load                                @   transformer.ts?d0de:53
exports.transform                   @   transformer.ts?d0de:61
(anonymous function)                @   transformer.ts?d0de:153
transformChildren                   @   transformer.ts?d0de:151
(anonymous function)                @   transformer.ts?d0de:172
load                                @   transformer.ts?d0de:53
exports.transform                   @   transformer.ts?d0de:61
(anonymous function)                @   transformer.ts?d0de:153
transformChildren                   @   transformer.ts?d0de:151
(anonymous function)                @   transformer.ts?d0de:172
load                                @   transformer.ts?d0de:53
exports.transform                   @   transformer.ts?d0de:61
exports.transformToTree             @   mutable-tree-factory.ts?f7a1:12
(anonymous function)                @   mutable-tree-factory.ts?f7a1:40
exports.createTreeFromElements      @   mutable-tree-factory.ts?f7a1:40
updateTree                      @   backend.ts:64
update                          @   backend.ts:83
(anonymous function)                @   backend.ts:94

(stack trace continues, but those are all the parts related to Augury as far as I can tell)

Ping me if you want to do some screen-sharing debugging.

@tb
Copy link

tb commented Sep 9, 2016

I have same error on Angular2 2.0.0-rc.5 in development

Uncaught TypeError: Cannot read property 'name' of undefined
exports.functionName    @   function-name.ts?6954:7

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants