-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change request queue from a heap to a sorted array #6240
Conversation
@lilleyse, thanks for the pull request! Maintainers, we have a signed CLA from @lilleyse, so you can review this at any time.
I am a bot who helps you make Cesium awesome! Contributions to my configuration are welcome. 🌍 🌎 🌏 |
f6a20de
to
4e76de8
Compare
|
I switched the base branch to |
I don't have enough context to digest those apples-to-apples, but are you sure this is not creating a lot of GC pressure given all the array slicing and splicing? With a tree, small object allocation is efficient AFAIK and could also be replaced with a custom allocator. Are you also sure that this array will always be small even as we tune other things? I would suggest one of two paths forward:
|
The array and heap both have a fixed size capacity so no allocations are occurring during insertion or any of the other operations. The main GC pressure might be the constant creation of
That could be possible. I don't think it makes sense for the array to get too high, but I suppose it could get up to around 50 if testing shows that helps. I'd rather move on to another area for now, so I'll open that task list with ideas. |
OK, will do a quick review now, just all re-considering this to the tasklist. |
* | ||
* @return {Request|undefined} The request that was removed from the queue if the queue is at full capacity. | ||
*/ | ||
RequestQueue.prototype.insert = function(request) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering how and when this is called during a frame - you know better than me - does it make more sense to queue up inserts, sort them, then merge once per frame so there is potentially less overhand that constantly keeping this sorted?
Or maybe there is another variation - just take advantage of this being specific to requests, not a general min-max queue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the rationale for not queuing up all the requests is we can know right away if a request will not be able to be issued, and return undefined
in RequestScheduler.request
. This leads to a faster path in terrain/imagery/3d-tiles than if the request is issued but later cancelled. I'll have to think about tradeoffs between the two approaches.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that can be roadmapped as part of the optimizations.
/** | ||
* Sorts the queue. | ||
*/ | ||
RequestQueue.prototype.sort = function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we stay with this, is it worth extracting this out like we did for mergeSort?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was about to start extracting it out but realized that this is a slightly atypical case. This class contains a fixed-sized array and a separate length variable, the idea being that we would not have to edit .length
constantly. I don't think a generic insertion-sort-on-array would work with this.
|
||
this._array = new Array(maximumLength); | ||
this._length = 0; | ||
this._maximumLength = maximumLength; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this were public, there should be a getter for this. As private, I guess it doesn't matter.
All items added to the task list in #6243.
Same comment as #6247 (comment) |
@ggetz is this worth considering for you to work on? |
This will most likely become obsolete with @kring's changes to request scheduling, so I'm going to close for now, but not delete the branch yet. |
This changes the data structure that
RequestScheduler
uses to prioritize requests. Previously it used a heap-based priority queue. This was fine for getting the highest-priority requests, but probably more often we need to get the lowest-priority requests, such as when a request is inserted and pushes a lower priority request out of the queue.The problem with a max-heap is you don't actually know the min value, so we were approximating the min value to be the last element in the array. While that element is definitely not the highest priority item, it is not guaranteed to be the lowest.
I went with a lower-tech solution instead and am just using a sorted array so we always know the request with the highest and lowest priorities. Yes - insertion can be O(n) instead of O(log(n)) now, but it isn't TOO bad because the 3D Tiles traversal code pushes requests in a semi-sorted order already so the average complexity is probably better than that. Plus our queue is only 20 elements at the moment.
I ran this on a few 3D Tiles datasets and saw some decent improvements with the new method: