From 0940954e28422c0aabc40d242711dd2ae3cd4c42 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 05f5e43ff0a414822c5d54d3d9ccd1ac0c8afda8 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 make that coarse lock a contention point. 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. Measured with these cache changes stacked on PR #902, the combined Austria fixture result reduced wall time by about 4.9%, system CPU by about 43%, and voluntary context switches by about 44% without changing decoded Liechtenstein output in the candidate semantic checks. 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 bc5271a4..541a8a81 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; @@ -1032,8 +1035,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)