From 5c38c58f0c25249580ad48084a9e587bb3de807a Mon Sep 17 00:00:00 2001 From: Riadh Ghaddab Date: Fri, 7 Mar 2025 16:42:27 +0100 Subject: [PATCH] zms: optimize cache for settings subsystem Settings subsystem is storing the name ID and the linked list node ID with only one bit difference at BIT(0). Settings subsystem is also storing the name ID and the data ID in two different ZMS entries at an exact offset of ZMS_DATA_ID_OFFSET. Using the regular lookup function could result in many cache misses. Therefore, to assure the least number of collisions in the lookup cache, the BIT(0) of the hash indicates whether the given ZMS ID represents a linked list entry or not, the BIT(1) indicates whether the ZMS ID is a name or data and the remaining bits of the hash are set to a truncated part of the original hash generated by Settings. Signed-off-by: Riadh Ghaddab --- subsys/fs/zms/Kconfig | 9 +++++++++ subsys/fs/zms/zms.c | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/subsys/fs/zms/Kconfig b/subsys/fs/zms/Kconfig index aed3a398f2d..f371d75647f 100644 --- a/subsys/fs/zms/Kconfig +++ b/subsys/fs/zms/Kconfig @@ -50,6 +50,15 @@ config ZMS_CUSTOM_BLOCK_SIZE help Changes the internal buffer size of ZMS +config ZMS_LOOKUP_CACHE_FOR_SETTINGS + bool "ZMS Storage lookup cache optimized for settings" + depends on ZMS_LOOKUP_CACHE && SETTINGS_ZMS + help + Enable usage of lookup cache based on hashes to get, the best ZMS performance, + provided that the ZMS is used only for the purpose of providing the settings + backend. This option should NOT be enabled if the ZMS is also written to + directly, outside the settings layer. + config ZMS_NO_DOUBLE_WRITE bool "Avoid writing the same data again in the storage" help diff --git a/subsys/fs/zms/zms.c b/subsys/fs/zms/zms.c index 43d8a273f11..80b86a41cdc 100644 --- a/subsys/fs/zms/zms.c +++ b/subsys/fs/zms/zms.c @@ -12,6 +12,9 @@ #include #include #include "zms_priv.h" +#ifdef CONFIG_ZMS_LOOKUP_CACHE_FOR_SETTINGS +#include +#endif #include LOG_MODULE_REGISTER(fs_zms, CONFIG_ZMS_LOG_LEVEL); @@ -28,15 +31,41 @@ static int zms_ate_valid_different_sector(struct zms_fs *fs, const struct zms_at static inline size_t zms_lookup_cache_pos(uint32_t id) { - uint32_t hash; + uint32_t hash = id; + +#ifdef CONFIG_ZMS_LOOKUP_CACHE_FOR_SETTINGS + /* + * 1. Settings subsystem is storing the name ID and the linked list node ID + * with only one bit difference at BIT(0). + * 2. Settings subsystem is also storing the name ID and the data ID in two + * different ZMS entries at an exact offset of ZMS_DATA_ID_OFFSET. + * + * Therefore, to assure the least number of collisions in the lookup cache, + * the BIT(0) of the hash indicates whether the given ZMS ID represents a + * linked list entry or not, the BIT(1) indicates whether the ZMS ID is a name + * or data and the remaining bits of the hash are set to a truncated part of the + * original hash generated by Settings. + */ + BUILD_ASSERT(IS_POWER_OF_TWO(ZMS_DATA_ID_OFFSET), "ZMS_DATA_ID_OFFSET is not power of 2"); + + uint32_t key_value_bit; + uint32_t key_value_hash; + uint32_t key_value_ll; + + key_value_bit = (id >> LOG2(ZMS_DATA_ID_OFFSET)) & 1; + key_value_hash = (id & ZMS_HASH_MASK) >> (CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS + 1); + key_value_ll = id & BIT(0); + + hash = (key_value_hash << 2) | (key_value_bit << 1) | key_value_ll; +#else /* 32-bit integer hash function found by https://github.com/skeeto/hash-prospector. */ - hash = id; hash ^= hash >> 16; hash *= 0x7feb352dU; hash ^= hash >> 15; hash *= 0x846ca68bU; hash ^= hash >> 16; +#endif /* CONFIG_ZMS_LOOKUP_CACHE_FOR_SETTINGS */ return hash % CONFIG_ZMS_LOOKUP_CACHE_SIZE; }