-
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
Request Scheduler Prioritization #3397
Conversation
@@ -58,6 +58,8 @@ | |||
|
|||
/*global jasmineRequire,jasmine,exports,specs*/ | |||
|
|||
Cesium.RequestScheduler.prioritize = false; |
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.
A lot of the specs fail if prioritization is enabled because it lags behind a frame. So I added this here for simplicity sake, but it's probably a bad place...
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.
Looks like an OK place to me, I don't think there is a beforeAll
that applies to all suites.
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.
Also, add a comment about why this line is here.
This won't be general enough because, for example, we want to prioritize all requests like glTF assets and their external resources. |
@@ -200,11 +202,15 @@ define([ | |||
* @param {Number} x The X coordinate of the tile for which to request geometry. | |||
* @param {Number} y The Y coordinate of the tile for which to request geometry. | |||
* @param {Number} level The level of the tile for which to request geometry. | |||
* @param {Boolean} [throttleRequests=true] True if the number of simultaneous requests should be limited, |
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.
When this goes into master - or sooner - include all changes to the public API in CHANGES.md.
It would be good to test this with something like the DC buildings and Bing imagery, and see how it compares to before 3D Tiles requests were prioritized. http://cesiumjs.org/WashingtonDC/ |
return; | ||
} | ||
|
||
printStats(); |
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.
Remove this. Instead, for example, the Sandcastle example could call this each frame (or it could be commented out in the Sandcastle example).
That's all my comments. |
2e2cc25
to
71f6c50
Compare
Updated. I created a I added the ability to defer a request, so if there aren't any open slots on the current frame it will still return a promise that will be resolved once an opening appears. This is useful for all the requests that aren't imagery/terrain/3d-tiles related. I went through the codebase looking for loading functions like I haven't tested with the Washington DC buildings yet because I'm having some problems converting the tileset, but I hope to see it working soon. Also |
@lilleyse can you merge |
This was my gut too, but I'm open to other approaches. Will have a look now. |
*/ | ||
this.distance = defaultValue(options.distance, 0.0); | ||
|
||
// Helper members for RequestScheduler |
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.
Mark these as @private
since they are being used like C#'s internal
.
I know this was already merged into |
* @returns {Promise.<Object>} A Promise for the requested data. | ||
*/ | ||
RequestScheduler.request = function(url, requestFunction, parameters) { | ||
return RequestScheduler.throttleRequest(new 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.
Perhaps this should have a type
of "OTHER", "USER", "CUSTOM", or something like that, which could be useful for setting priorities and avoiding starvation.
@@ -1010,7 +1014,7 @@ define([ | |||
setCachedGltf(model, cachedGltf); | |||
gltfCache[cacheKey] = cachedGltf; | |||
|
|||
loadArrayBuffer(url, options.headers).then(function(arrayBuffer) { | |||
RequestScheduler.request(url, loadArrayBuffer, options.headers).then(function(arrayBuffer) { |
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 I mentioned this in a past review, but Model
may be making requests on behalf of 3D Tiles so I think we should allow an override for the request type via a @private
options parameter on the constructor.
Perhaps each tile would store a reference to a small object that is a new The idea is that if we know a request won't go through this frame, we want to learn that as quickly as possible and bail on tree traversal. Likewise, we want requests that may go through to be queued up as quickly as possible with minimal scheduler overhead. |
var removeFunction = removeFromProcessingQueue(tiles3D, tile); | ||
when(tile.processingPromise).then(addToProcessingQueue(tiles3D, tile)).otherwise(removeFunction); | ||
when(tile.readyPromise).then(removeFunction).otherwise(removeFunction); | ||
} | ||
} | ||
|
||
function hasAvailableRequests(tiles3D) { |
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 believe this line is wrong:
return RequestScheduler.hasAvailableRequests(tiles3D._url)
This assumes that the tile's content has the same base path as tileset.json, right? They could be on two separate servers.
Updated. |
@@ -231,7 +237,19 @@ define([ | |||
url = proxy.getURL(url); | |||
} | |||
|
|||
var promise = RequestScheduler.throttleRequest(url, loadImage); | |||
// TODO : request used to be a boolean called throttleRequest. Continue to handle that case until it is deprecated. |
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.
Remove this TODO
and friends, and submit an issue for the deprecation.
Just those comments. Are you happy with how this worked for the DC dataset? |
if (!tile.isContentUnloaded()) { | ||
var stats = tiles3D._statistics; | ||
++stats.numberOfPendingRequests; | ||
addLoadProgressEvent(tiles3D); |
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.
This call keeps track of the number of requests so it is possible that it could increase the number of pending requests here even though the scheduler doesn't make the request.
At one point we talked about adding an event (or promise or whatever) that fires when the request is actually made (or not). Perhaps we should use that to call addLoadProgressEvent
.
Note that this should all happen before events are raised at the end of the frame with frameState.afterRender
.
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 would also be fine (perhaps even prefer) raising this event once per frame instead of per tile. The former is probably better for a UI, and the later for debugging.
I cleaned up the code and have been testing with the DC dataset. When testing with prioritization enabled vs. disabled, there are some small differences but its hard to say that one method is actually better than another. It's easier to notice the benefits in contrived cases where the maximum requests is set to some low number. Usually both 3D Tiles and Imagery/Terrain servers have enough open slots to do their work with or without budgeting. I also tested the difference for when |
This is ready from my end. |
Looks good. Please cherry pick the commits for a PR into master and update the roadmap as we discussed offline. |
Is this ready to be merged here? |
Yes. |
Request Scheduler Prioritization
Continuation of #3371 for #3241
I added support for prioritizing requests based on distance. While we want something more generic in the future, I would like some feedback on the approach I'm taking.
The request scheduler uses information about the previous frame to determine the number of requests allowed for each server during the given frame.
resetBudgets
will sort by distance any requests that couldn't be made last frame and estimate new budgets. When a request is made, it can give a yes/no answer by either returning a promise or undefined, as it did before. The request can be sent immediately and not defer until the end of the frame. There may be cases where the view changes drastically between frames and the estimates from the previous frame are off, but this may not be a problem. If it is, I can introduce the concept of stealing from budgets like inJobScheduler
.I had to modify a lot of functions in order to send the distance with each request. I considered generating the distance using the x, y, level, and tiling scheme instead, which would make the code cleaner but has its own limitations.