-
Notifications
You must be signed in to change notification settings - Fork 14
Optimize the cache size to avoid unnecessary re-rendering #56
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
Changes from all commits
57e5e3b
8fb666d
b7fe988
e4ab3d0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,6 +69,28 @@ def tileset(self, key): | |
| except KeyError: | ||
| return {} | ||
|
|
||
| def prepare(self, tiles): | ||
| """Make room before rendering new tiles. | ||
|
|
||
| This ensures there is space for the new tiles by adjusting | ||
| the cache size and/or purging older images as needed. | ||
|
|
||
| """ | ||
| # approximate size of the new tiles at 32 bits (== 4 bytes) per pixel | ||
| tileBytes = sum(tile.w * tile.h for tile in tiles) * 4 | ||
|
|
||
| # adjust the cache size to fit at least two pages' visible tiles | ||
| # to avoid re-rendering either page when both are displayed | ||
| oldsize = self.maxsize | ||
| self.maxsize = max(type(self).maxsize, 2 * tileBytes) | ||
| if self.maxsize < oldsize: | ||
| # clear everything when shrinking the cache because otherwise | ||
| # larger tiles might prove difficult to purge() | ||
| self.clear() | ||
| else: | ||
| # free memory from unneeded tiles before rendering the new ones | ||
| self.purge(tileBytes) | ||
|
|
||
| def addtile(self, key, tile, image): | ||
| """Add image for the specified key and tile.""" | ||
| d = self._cache.setdefault(key.group, {}).setdefault(key.ident, {}).setdefault(key[2:], {}) | ||
|
|
@@ -77,17 +99,20 @@ def addtile(self, key, tile, image): | |
| except KeyError: | ||
| pass | ||
|
|
||
| purgeneeded = self.currentsize > self.maxsize | ||
|
|
||
| e = d[tile] = ImageEntry(image) | ||
| self.currentsize += e.bcount | ||
|
|
||
| if not purgeneeded: | ||
| def purge(self, reservedsize=0): | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was previously part of |
||
| """Purge old images if needed. | ||
|
|
||
| At least `reservedsize` bytes will remain available. | ||
|
|
||
| """ | ||
| limit = self.maxsize - reservedsize | ||
| if self.currentsize <= limit: | ||
| return | ||
|
|
||
| # purge old images is needed, | ||
| # cache groups may have disappeared so count all images | ||
|
|
||
| entries = iter(sorted( | ||
| ((entry.time, entry.bcount, group, ident, key, tile) | ||
| for group, identd in self._cache.items() | ||
|
|
@@ -96,11 +121,11 @@ def addtile(self, key, tile, image): | |
| for tile, entry in tiled.items()), | ||
| key=(lambda item: item[:2]), reverse=True)) | ||
|
|
||
| # now count the newest images until maxsize ... | ||
| # now count the newest images until our limit ... | ||
| currentsize = 0 | ||
| for time, bcount, group, ident, key, tile in entries: | ||
| currentsize += bcount | ||
| if currentsize > self.maxsize: | ||
| if currentsize >= limit: | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changing to |
||
| break | ||
| self.currentsize = currentsize | ||
| # ... and delete the remaining images, deleting empty dicts as well | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -380,6 +380,7 @@ def schedule(self, page, key, tiles, callback): | |
| pending job. | ||
|
|
||
| """ | ||
| self.cache.prepare(tiles) | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This calls our new code to adjust the maximum cache size and purge old tiles just before creating the jobs to render new ones. Previously, the maximum cache size was fixed, and old tiles were purged after rendering and caching new ones. |
||
| for tile in tiles: | ||
| try: | ||
| job = _jobs[(key, 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.
Previously, the cache size was fixed at 200MB, which was too small for the tile images at higher zoom levels. This code dynamically adjusts the size to the larger of 200MB or two pages' visible tiles. We do two pages because otherwise each would purge the other from cache when scrolling over a page break, forcing frequent re-renders (you can see this now scrolling over a page break at 800% zoom).