-
Notifications
You must be signed in to change notification settings - Fork 228
Use map instead of unordered_map for dictionary properties in CesiumGltf and Cesium3DTiles #372
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
Conversation
… is preserved during the read/write roundtrip and unit tests pass consistently on Linux and Windows
But also std::map is a red-black tree and std::unordered_map is a hash table. So std::unordered_map has constant time lookup and insertion (versus logarithmic time for std::map) and is likely to be much more cache-friendly as well. Are we sure maintaining sort order for dictionary keys justifies the cost? I think it might for some properties (e.g. |
Rename generated extension classes
About the performance:
About the order: One relevant question is whether the order is part of the
If this is not specified, then a unit tests should not make assumptions about the order of the elements. If the unit test has a pesudocode like this
Then it assumes If it does
Then it assumes the insertion order (most likely - depending on the internal parser mechanisms 😬 ) If it does
Then it does not make any assumptions. An aside: When talking about "preserving the order", I'm always wondering about what "preserving" means. But maybe that's a nitpick, rooted in |
Generally since we're dealing with such small dictionaries I wouldn't expect the map implementation to make a tangible difference, also I wouldn't expect the dictionary elements to be accessed too frequently. I like how std::map preserves the order during the roundtrip from reader to writer. For what it's worth, tinygltf also uses std::map |
Never mind, this is not true at all, my test code happened to be ordered alphabetically already. Should have looked closer at what @javagl said above. |
I heard long time ago from CppCon (I can't remember where), std::map performs better than std::unordered_map when input is small (roughly less than 40 elements). I naively never confirmed it, so it maybe a good chance to see if that's true. |
Interesting, I can't really think of why that would be. Maybe std::map does something clever (rather than a heap allocation per tree node) or std::unordered_map does something surprising (like use a large hash table on the first insertion). Considering our dictionaries usually have less than 10 elements, the fastest thing is probably in fact a vector (or, better: two vectors, one with keys, one with values) linearly searched. Anyway I don't mean to bike shed performance here when it's almost certainly not an area we should spend time optimizing. But maintaining order seemed like a fairly dubious benefit in most cases (and if it's not maintaining order but rather imposing alphabetical order, that benefit is even smaller IMO), so even paying a small cost in terms of extra heap allocations (which can involve locking and therefore have an unintuitive effect on performance under multithreaded load) and pointer chasing for tree traversal (which can have an outsized impact on overall performance outside microbenchmarks due to cache thrashing) might not be worth it. If we do want to preserve order, though, there's https://github.com/Tessil/ordered-map and probably other options as well.
I suspect this is more because of its C++03 legacy rather than a considered choice, but I could be wrong. |
The main benefit for preserving order would be to have cross-platform consistent output when writing glTF and 3D Tiles in the tilers, it feels like a weird idiosyncrasy otherwise. https://github.com/Tessil/ordered-map seems promising and I might give that a try. That would also make us consistent with object property order in JavaScript (ES2015 and pre-ES2015 by convention for strings https://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order/23202095#23202095) |
I'll probably repeat the hint for Regarding the option to pull in a dependency like
There may be two forms of consistency.
An aside regarding the performance: I think that there are too many variables for the performance of
Some other variables are hidden. The main one is the type of the key. There might be significant differences between a Eventually, the performance will depend on the |
Add 3DTILES_content_gltf to Cesium3DTiles and Cesium3DTilesReader
Thanks again for your contribution @lilleyse! No one has commented on this pull request in 30 days. Maintainers, can you review, merge or close to keep things tidy? I'm going to re-bump this in 30 days. If you'd like me to stop, just comment with |
3 similar comments
Thanks again for your contribution @lilleyse! No one has commented on this pull request in 30 days. Maintainers, can you review, merge or close to keep things tidy? I'm going to re-bump this in 30 days. If you'd like me to stop, just comment with |
Thanks again for your contribution @lilleyse! No one has commented on this pull request in 30 days. Maintainers, can you review, merge or close to keep things tidy? I'm going to re-bump this in 30 days. If you'd like me to stop, just comment with |
Thanks again for your contribution @lilleyse! No one has commented on this pull request in 30 days. Maintainers, can you review, merge or close to keep things tidy? I'm going to re-bump this in 30 days. If you'd like me to stop, just comment with |
This PR is now well out of date so I'll close it. But it may come up again in the future. |
std::map
will preserve the order of elements in the dictionary so that we don't get different glTF / 3D Tiles serialization results on different compilers.I first noticed this when working on the 3D Tiles writer where one of the unit tests was failing on windows because the order of "property1" and "property2" happened to be swapped.