Improve zoom/pan performance by avoiding redundant tag class and label width recomputation#11834
Improve zoom/pan performance by avoiding redundant tag class and label width recomputation#118341-navneet wants to merge 6 commits intoopenstreetmap:developfrom
Conversation
|
Thanks for taking a closer look — glad to hear this is an improvement. I’ll take a closer look at whether we can avoid repeatedly indexing into the entity tags during redraws, or restructure the cache to operate at the entity or tag-set level instead. I’ll report back once I have a clearer picture. |
|
Thanks for the detailed profiling — that was very helpful. I’ve pushed a follow-up commit that adds a WeakMap cache keyed by the entity’s tag object, so getClassesString() can return early without repeatedly indexing t[k] during redraws. Let me know if you’d like me to try a different cache key or gather additional traces. |
|
Could you add some guidance on how to test this properly? And also add some test results here. Is this a case that will be visible in flame charts? |
|
@tordans, How to test: What to look for: Observed results: Let me know if you’d like screenshots attached or traces collected for a specific scenario. |
This comment was marked as resolved.
This comment was marked as resolved.
modules/svg/tag_classes.js
Outdated
| var byBase = _classCache.get(t); | ||
| if (!byBase) { | ||
| byBase = new Map(); | ||
| _classCache.set(t, byBase); |
There was a problem hiding this comment.
currently your cache (WeakMap<Tags, Map<string, string>>) represents this hierarchy: tags → oldClassName → newClassName.
This leads to a few issues:
- the cache hit rate will be very low, because whenever the user hovers or selects a feature, the class name is updated (
.selectedor.hoveris added/removed) - your cache will grow in size quickly, and store many no-op transformations:
To solve these issues, I think you could only cache a weak-mapping of tags → className (i.e. WeakMap<Tags, string>)
This will require some refactoring, so that we have a pure function which is simply f(tags) → className.
for example, something like this:
let cache = new WeakMap();
tagClasses.getClassesString = function(t, oldClassName) {
const oldClassNamestoKeep = oldClassName.split(' ').filter(…).join(' ');
let newClassNames = cache.get(t);
if (newClassNames === undefined) {
newClassNames = getClassesStringPure(t); // refactor everything else into this new function
cache.set(t, newClassNames);
}
return oldClassNamestoKeep + ' ' + newClassNames;
}|
Thanks for the detailed feedback — that makes sense.
|
|
if it helps, 556fbb2 is one way to implement the suggestions above |
|
Thanks for the pointer to 556fbb2 — that helped. I’ve updated the implementation to: • move the cache to module scope Let me know if this matches what you were suggesting, or if you'd prefer it structured differently. |
k-yle
left a comment
There was a problem hiding this comment.
thanks, this works really well now !
@gralp-1: I see you did your own profiling, do you want to take a look at the latest version of this PR?
@1-navneet: last suggestion from me, can you please update the CHANGELOG.md file?
6df8847 to
b8267d1
Compare
|
Updated the CHANGELOG as suggested and rebased onto latest develop. |
|
I still seem to be getting some redraw calls up to 2.5s |
|
although these redraws seem to be spending ~50% of their time doing layout and style calculations |
|
I've been testing this with CPU Throttling set to 'Mid Tier Mobile', and there's noticably less1 time spent in iD's own code ( for future reference, this is the trace from my laptop Footnotes
|
|
Thanks for testing with CPU throttling — that’s helpful. |
b8267d1 to
326cada
Compare
git rebase --continue
|
Hi @k-yle — just a quick follow-up on this when you have time. |
326cada to
dc77c82
Compare

This PR addresses the zoom and pan performance issue described in #11832.
Problem
Profiling during zoom/pan interactions showed significant time spent repeatedly:
These operations were executed on every redraw, even when the underlying data did not change.
Solution
This change reduces redundant work during redraws by:
Result
tagClasses.getClassesStringno longer dominate redraw timeTesting
(zoom level 18 near 53.382847, -1.470167)