From 3198e67220f777ff893ee29eb067929a482c92ca Mon Sep 17 00:00:00 2001 From: Symmetricity <184246+Symmetricity@users.noreply.github.com> Date: Thu, 4 Jun 2026 11:08:10 +0200 Subject: [PATCH 1/2] Increase AttributeStore lookup caches Attribute pair and set lookups are very frequent during profile processing. The existing 64-entry thread-local caches leave many repeated lookups to fall back to the shared stores on larger fixtures. Use a still-small 256-entry cache so more hot lookups are served locally without changing generated tile semantics. On the Austria fixture this was neutral to slightly faster and reduced native RSS in warmed alternating runs. Co-authored-by: Codex --- src/attribute_store.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/attribute_store.cpp b/src/attribute_store.cpp index 73ed4775..93b813e8 100644 --- a/src/attribute_store.cpp +++ b/src/attribute_store.cpp @@ -101,8 +101,8 @@ const AttributePair& AttributePairStore::getPairUnsafe(uint32_t i) const { thread_local uint64_t tlsPairLookups = 0; thread_local uint64_t tlsPairLookupsUncached = 0; -thread_local std::vector cachedAttributePairPointers(64); -thread_local std::vector cachedAttributePairIndexes(64); +thread_local std::vector cachedAttributePairPointers(256); +thread_local std::vector cachedAttributePairIndexes(256); uint32_t AttributePairStore::addPair(AttributePair& pair, bool isHot) { if (isHot) { { @@ -300,8 +300,8 @@ void AttributeSet::finalize() { // Remember recently queried/added sets so that we can return them in the // future without taking a lock. -thread_local std::vector cachedAttributeSetPointers(64); -thread_local std::vector cachedAttributeSetIndexes(64); +thread_local std::vector cachedAttributeSetPointers(256); +thread_local std::vector cachedAttributeSetIndexes(256); thread_local uint64_t tlsSetLookups = 0; thread_local uint64_t tlsSetLookupsUncached = 0; From 0f58d99aee529c7fe5675e35356430b3ef0f5bb6 Mon Sep 17 00:00:00 2001 From: Symmetricity <184246+Symmetricity@users.noreply.github.com> Date: Thu, 4 Jun 2026 11:33:02 +0200 Subject: [PATCH 2/2] Cache vector layer metadata updates Layer metadata is shared across Lua processing threads and still needs the mutex added by the thread-safety fix in PR #761. On larger fixtures, repeated Attribute() calls now make that coarse lock a major futex source. Remember metadata types already recorded by the current thread for the active LayerDefinition, and skip the lock only for exact same-type repeats. This preserves the protected shared map update for first sightings and type changes while avoiding redundant lock traffic. On the Austria fixture this reduced futex syscalls by about 96%, voluntary context switches by about 89%, and wall time by about 4% without changing decoded Liechtenstein output. Co-authored-by: Codex --- src/osm_lua_processing.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/osm_lua_processing.cpp b/src/osm_lua_processing.cpp index 076505b2..5ac56184 100644 --- a/src/osm_lua_processing.cpp +++ b/src/osm_lua_processing.cpp @@ -10,6 +10,7 @@ #include "node_store.h" #include "polylabel.h" #include +#include using namespace std; @@ -18,6 +19,8 @@ thread_local kaguya::State *g_luaState = nullptr; thread_local OsmLuaProcessing* osmLuaProcessing = nullptr; std::mutex vectorLayerMetadataMutex; +thread_local const LayerDefinition* vectorLayerMetadataCacheLayers = nullptr; +thread_local std::vector> vectorLayerMetadataCache; std::unordered_map OsmLuaProcessing::dataStore; std::mutex OsmLuaProcessing::dataStoreMutex; @@ -1058,8 +1061,23 @@ std::string OsmLuaProcessing::FindInRelation(const std::string &key) { // Record attribute name/type for vector_layers table void OsmLuaProcessing::setVectorLayerMetadata(const uint_least8_t layer, const string &key, const uint type) { - std::lock_guard lock(vectorLayerMetadataMutex); - layers.layers[layer].attributeMap[key] = type; + if (vectorLayerMetadataCacheLayers != &layers) { + vectorLayerMetadataCache.clear(); + vectorLayerMetadataCacheLayers = &layers; + } + if (vectorLayerMetadataCache.size() <= layer) + vectorLayerMetadataCache.resize(layer + 1); + + auto &metadataCache = vectorLayerMetadataCache[layer]; + const auto it = metadataCache.find(key); + if (it != metadataCache.end() && it->second == type) + return; + + { + std::lock_guard lock(vectorLayerMetadataMutex); + layers.layers[layer].attributeMap[key] = type; + } + metadataCache[key] = type; } // Scan relation (but don't write geometry)