-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Enforce memory limit for Cesium3DTilesetCache
#11310
Conversation
Thanks for the pull request @jjhembd!
Reviewers, don't forget to make sure that:
|
Instead of |
Remove console.logs
@jjhembd if it's not too much trouble would it be possible to move the cleanup changes into a separate PR? I have some minor comments there but don't want to distract from the main review. |
@lilleyse I moved all the cleanup commits into the |
* @property {number} [maximumMemoryUsage=512] The maximum amount of memory in MB that can be used by the tileset. Deprecated. | ||
* @property {number} [cacheBytes=536870912] The size (in bytes) to which the tile cache will be trimmed, if the cache contains tiles not needed for the current view. | ||
* @property {number} [maximumCacheOverflowBytes=536870912] The maximum additional memory (in bytes) to allow for cache headroom, if more than {@link Cesium3DTileset#cacheBytes} are needed for the current view. Must be at least 10 * 1024 * 1024. |
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.
Make sure to include instructions in CHANGES.md
for replicating the previous behavior.
I think that would be setting maximumCacheOverflowBytes
to Number.MAX_VALUE
?
* @property {number} [maximumMemoryUsage=512] The maximum amount of memory in MB that can be used by the tileset. Deprecated. | ||
* @property {number} [cacheBytes=536870912] The size (in bytes) to which the tile cache will be trimmed, if the cache contains tiles not needed for the current view. | ||
* @property {number} [maximumCacheOverflowBytes=536870912] The maximum additional memory (in bytes) to allow for cache headroom, if more than {@link Cesium3DTileset#cacheBytes} are needed for the current view. Must be at least 10 * 1024 * 1024. |
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.
Must be at least 10 * 1024 * 1024
This seems a bit arbitrary. Why can't it be 0?
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.
We currently allow maximumMemoryUsage == 0
, to force the cache to be trimmed to the minimum size possible. This is used several times in the specs, so I also allowed cacheBytes == 0
for consistency.
If both cacheBytes == 0
and maximumCacheOverflowBytes == 0
, then no tiles will be processed and memoryAdjustedScreenSpaceError
will grow to infinity. This feels buggy, as Matt noticed already, even with a small non-zero value.
I chose 10 MB as a number that should guarantee we render at least one tile.
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.
As discussed with @ggetz, I changed this to allow maximumCacheOverflowBytes == 0
, and simply added a oneTimeWarning
inside increaseScreenSpaceError
, to alert the developer that the values of cacheBytes
and maximumCacheOverflowBytes
might be too small.
* If tiles sized more than <code>cacheBytes</code> are needed to meet the | ||
* desired screen space error, determined by {@link Cesium3DTileset#maximumScreenSpaceError}, | ||
* for the current view, then the memory usage of the tiles loaded will exceed | ||
* <code>cacheBytes</code>. For example, if the maximum is 256 MB, but 300 MB | ||
* of tiles are needed to meet the screen space error, then 300 MB of tiles may | ||
* be loaded. When these tiles go out of view, they will be unloaded. |
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 description is a bit incomplete without also mentioning maximumCacheOverflowBytes
@@ -1545,17 +1571,123 @@ Object.defineProperties(Cesium3DTileset.prototype, { | |||
* | |||
* @exception {DeveloperError} <code>maximumMemoryUsage</code> must be greater than or equal to zero. | |||
* @see Cesium3DTileset#totalMemoryUsageInBytes | |||
* | |||
* @deprecated | |||
*/ | |||
maximumMemoryUsage: { |
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.
Several tests should be updated to use cacheBytes
.
const tiles = tileset._processingQueue.filter( | ||
(tile) => | ||
!tile.isDestroyed() && | ||
tile._contentState === Cesium3DTileContentState.PROCESSING | ||
); |
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.
While more concise, this will allocate an array every frame (which is what filterProcessingQueue
avoids)
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 restored filterProcessingQueue
for now.
We are also potentially re-allocating by using tileset._processingQueue.push()
in requestContent
. If this is really an issue, perhaps a separate PR could convert ._processingQueue
to a ManagedArray
, and move the custom filter function to a method of ManagedArray
.
for (let i = 0; i < tiles.length; ++i) { | ||
tiles[i].updatePriority(); | ||
} | ||
tiles.sort(sortTilesByPriority); |
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 wonder if we should always be updating priority and sorting, not just when the SSE changes. Because it doesn't seem strictly necessary to just do it here.
Also is there a reason it's updated here and not in decreaseScreenSpaceError
?
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.
Increasing screen space error may result in some of the tiles in ._processingQueue
becoming irrelevant for rendering. This is why I thought a sort was essential here, and not in decreaseScreenSpaceError
.
I at first tried sorting every frame (in processTiles
), but couldn't see any performance benefit. So I avoided too many sorts to be safe. Note that ._processingQueue
can be significantly longer than ._requestedTiles
, so this sort is potentially more expensive.
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.
Reminder to add some unit tests
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.
Thanks @jjhembd! This is working well! Just a few comments.
CHANGES.md
Outdated
|
||
##### Additions :tada: | ||
|
||
- Added `Cesium3DTileset.cacheBytes` and `Cesium3DTileset.maximumCacheOverflowBytes` to better control memory usage. To replicate previous behavior, change `maximumMemoryUsage` to `cacheBytes`, and set `maximumCacheOverflowBytes = Number.MAX_VALUE` |
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.
And convert MB to bytes, correct?
@@ -3471,11 +3471,11 @@ describe( | |||
}); | |||
}); | |||
|
|||
it("Unload some cached tiles not required to meet SSE using maximumMemoryUsage", function () { | |||
it("Unload some cached tiles not required to meet SSE using cacheBytes", 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.
Since it was deprecated, can we leave the old tests specifically for maximumMemoryUsage
, and add new ones to cover cacheBytes
?
Thanks @ggetz! I think I addressed all your feedback. Let me know if there's anything else. |
All looks good to me! Thanks @jjhembd! |
Resolves #6226.
This PR deprecates the
Cesium3DTileset
constructor optionmaximumMemoryUsage
, and replaces it with two new options:cacheBytes
: The size (in bytes) to which the tile cache will be trimmed, if the cache contains tiles not needed for the current view.maximumCacheOverflowBytes
: The maximum additional memory (in bytes) to allow for cache overflow, if more thancacheBytes
are needed for the current view.If the tileset's
totalMemoryUsageInBytes
exceedscacheBytes + maximumCacheOverflowBytes
, processing of new tiles will be interrupted, and the target screen-space error used to drive level-of-detail refinement will be adjusted higher. When the camera moves to an area wheretotalMemoryUsageInBytes
drops belowcacheBytes
, the target screen-space error will be adjusted back down toward the user-provided value inmaximumScreenSpaceError
.The adjusted screen-space error is exposed as a new read-only property
memoryAdjustedScreenSpaceError
Here is a hosted Sandcastle demonstrating the interaction between memory usage and adjusted screen-space error.