Browse Source

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 <rghaddab@baylibre.com>
pull/90028/head
Riadh Ghaddab 4 months ago committed by Benjamin Cabé
parent
commit
5c38c58f0c
  1. 9
      subsys/fs/zms/Kconfig
  2. 33
      subsys/fs/zms/zms.c

9
subsys/fs/zms/Kconfig

@ -50,6 +50,15 @@ config ZMS_CUSTOM_BLOCK_SIZE @@ -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

33
subsys/fs/zms/zms.c

@ -12,6 +12,9 @@ @@ -12,6 +12,9 @@
#include <zephyr/fs/zms.h>
#include <zephyr/sys/crc.h>
#include "zms_priv.h"
#ifdef CONFIG_ZMS_LOOKUP_CACHE_FOR_SETTINGS
#include <settings/settings_zms.h>
#endif
#include <zephyr/logging/log.h>
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 @@ -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;
}

Loading…
Cancel
Save