Skip to content
This repository has been archived by the owner on Jul 29, 2019. It is now read-only.

Group redraw performance #3409

Merged
merged 8 commits into from
Sep 18, 2017
Merged

Group redraw performance #3409

merged 8 commits into from
Sep 18, 2017

Conversation

yotamberk
Copy link
Contributor

Addressing some of the group performance issues and implementation of discussion from #3248 (using gist https://gist.github.com/grimalschi/df9a44ac12b5420e0cc6f2d42f1febed/revisions#diff-32e31f368549caca635e81cdb8a0a82dR21132)
This is the best implementation in the meantime - I've tried using fasdom and some other methods but concluded that it's not what we need. Fastdom allows prioritization of "read" operations over "write" operations, whilst our problem has to do with paralleling the operations done in a group redraw for all groups.
Further analysis that will be done:

  • The exact operations done in the group redraw - we might be able to use fasdom/combining "reads" and "writes" to fewer operations for every redraw queue.
  • Implementation like this should also be done in items' redraws.

Shout out to @grimalschi for supplying the solution.

@yotamberk
Copy link
Contributor Author

@wimrijnders @macleodbroad-wf can one of you please review and approve this? It is extremely important

@grimalschi
Copy link
Contributor

Actually I did not think you will use my code :)

That was just demo to show the idea.

@yotamberk
Copy link
Contributor Author

yotamberk commented Sep 3, 2017

if the shoe fits, wear it.

The code is good. It might be written in a cleaner manner but for now it's good. I've tried using fasdom and some other techniques but always came back to your code as being clearer than what I did. I'm working on further work on items redraw. I hope to have anther refactor iteration to clean this code

item.redraw();
me.visibleItems.push(item);
Group.prototype.redraw = function(range, margin, forceRestack, returnQueue) {
var queue = [];
Copy link
Contributor

@macleodbroad-wf macleodbroad-wf Sep 3, 2017

Choose a reason for hiding this comment

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

If pure performance is the concern, I think it would be more readable and slightly more performant (maybe a micro optimization?) to have all of these anonymous functions defined at a higher level, and then simply:

var queue = [recalcHeight(this), recalcSubGroupHeights(this), calcSizeAndPosition, etc...];
if (returnQueue) {
    return queue;
} else {
    var result;
    queue.forEach(function (fn) {
        result = fn(this);
    });
    return result;
}
...

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 agree but I was planning doing it in another PR

Copy link
Contributor

Choose a reason for hiding this comment

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

How often does redraw get called?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

every zoom/scroll/drag - alot

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, can you include a reference to the follow-up issue? Just want to make sure it doesn't get lost.

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 can include it here if you think it's really important.
Wait with this PR if so

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's worth doing, given how often this is used.

var redrawResults = {};

for (var i = 0; i < redrawQueueLength; i++) {
util.forEach(redrawQueue, function (fns, key) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Oof this stuff is almost over the top of my head.

But shouldn't this be: util.forEach(redrawQueue[i]...?

redrawQueue is a hash, of which every value is a queue of functions to run. I'm inferring that you want to run all function in the queue for every key of redrawQueue.

If I got it wrong here, please explain.

Copy link
Contributor

Choose a reason for hiding this comment

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

Im sorry for bad naming :(

group.redraw(range, groupMargin, forceRestack, returnQueue) returns array of functions.

So redrawQueue is an queue, and every element in this queue is array of functions.

And when we release this queue, we call all functions from every element of queue.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice to see you react to a question on the code. I was expecting @yotamberk, but I understand the original comes from you.

Will try to wrap my brain around it again. Perhaps some commenting would be in order here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I think I got it. redrawQueue values are all arrays of the same size, containing functions.
In the loop, the first functions in the arrays of all redrawQueue values are called, then the second, etc.

The logic of this escapes me, but there must be a good reason for it. Perhaps I should not be reviewing.


for (var i = 0; i < redrawQueueLength; i++) {
util.forEach(redrawQueue, function (fns, key) {
redrawResults[key] = fns[i]();
Copy link
Contributor

Choose a reason for hiding this comment

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

But then the [i] does not make sense. Why go through all the trouble of creating a Queue instance, when the separate items in it are meant for set individual items?

if (!this.isVisible && this.height) {
return resized = false;
}
if (!this.isVisible && this.height) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Tabs?

Copy link
Contributor

@wimrijnders wimrijnders left a comment

Choose a reason for hiding this comment

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

Just react to the comments for my understanding.

wimrijnders
wimrijnders previously approved these changes Sep 14, 2017
var redrawResults = {};

for (var i = 0; i < redrawQueueLength; i++) {
util.forEach(redrawQueue, function (fns, key) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I think I got it. redrawQueue values are all arrays of the same size, containing functions.
In the loop, the first functions in the arrays of all redrawQueue values are called, then the second, etc.

The logic of this escapes me, but there must be a good reason for it. Perhaps I should not be reviewing.

@yotamberk
Copy link
Contributor Author

I've reacted to the comments. Please address.
@wimrijnders @macleodbroad-wf

}

Group.prototype._updateItemsVerticalPosition = function(resized, margin) {
// update vertical position of items after they are re-stacked and the height of the group is calculated
Copy link
Contributor

Choose a reason for hiding this comment

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

Might be better as function header comment

}

if (!this.isVisible && this.height) {
return resized = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why this construct? I think return false would be enough here

var labelHeight = this.dom.inner.clientHeight;
resized = util.updateProperty(this.props.label, 'width', labelWidth) || resized;
resized = util.updateProperty(this.props.label, 'height', labelHeight) || resized;
return resized
Copy link
Contributor

Choose a reason for hiding this comment

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

;


// update vertical position of items after they are re-stacked and the height of the group is calculated
(function() {
return resized = this._updateItemsVerticalPosition.bind(this)(resized, margin)
Copy link
Contributor

Choose a reason for hiding this comment

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

For my understanding: this is the last function in the queue and it returns something. The return value is collected here. Is this the intention?

Copy link
Contributor

Choose a reason for hiding this comment

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

I suppose the assignment to resize isn't really necessary for the return, but it's kept in for completeness. I guess this is OK (I would probably do the same).

Copy link
Contributor

@wimrijnders wimrijnders left a comment

Choose a reason for hiding this comment

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

Overall a big improvement in readability and therefore understanding. Just some small remarks.

@yotamberk
Copy link
Contributor Author

@wimrijnders done! Thanks!

@yotamberk yotamberk merged commit 9830616 into almende:develop Sep 18, 2017
yotamberk added a commit that referenced this pull request Sep 18, 2017
primozs pushed a commit to primozs/vis that referenced this pull request Jan 3, 2019
* Implement group redraw @grimalschi performance enhancement

* Fix JSDoc for redraw

* Remove commented out in itemset

* Remove fasdom

* Clean up queue functions in group redraw

* Fix mistake in comments

* Remove extra read-write from _didResize

* Resolve review comments
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.

4 participants