Skip to content

Commit 83f3672

Browse files
Damian-Nordicanangl
authored andcommitted
[nrf noup] settings: nvs: use dedicated lookup cache hash function
Introduce NVS_LOOKUP_CACHE_FOR_SETTINGS Kconfig option that enables a dedicated hash function for the NVS lookup cache that takes advantage of the NVS ID allocation scheme used by the NVS settings backend. As such, this option should only be used if an application uses NVS via the settings layer. Signed-off-by: Damian Krolik <[email protected]> (cherry picked from commit 3198700)
1 parent e8a7c17 commit 83f3672

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

subsys/fs/nvs/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ config NVS_LOOKUP_CACHE_SIZE
2929
Number of entries in Non-volatile Storage lookup cache.
3030
It is recommended that it be a power of 2.
3131

32+
config NVS_LOOKUP_CACHE_FOR_SETTINGS
33+
bool "Non-volatile Storage lookup cache optimized for settings"
34+
depends on NVS_LOOKUP_CACHE
35+
help
36+
Use the lookup cache hash function that results in the least number of
37+
collissions and, in turn, the best NVS performance provided that the NVS
38+
is used as the settings backend only. This option should NOT be enabled
39+
if the NVS is also written to directly, outside the settings layer.
40+
3241
config NVS_DATA_CRC
3342
bool "Non-volatile Storage CRC protection on the data"
3443
help

subsys/fs/nvs/nvs.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
#include <zephyr/sys/crc.h>
1414
#include "nvs_priv.h"
1515

16+
#ifdef CONFIG_NVS_LOOKUP_CACHE_FOR_SETTINGS
17+
#include <zephyr/sys/util.h>
18+
#include <settings/settings_nvs.h>
19+
#endif
20+
1621
#include <zephyr/logging/log.h>
1722
LOG_MODULE_REGISTER(fs_nvs, CONFIG_NVS_LOG_LEVEL);
1823

@@ -21,6 +26,45 @@ static int nvs_ate_valid(struct nvs_fs *fs, const struct nvs_ate *entry);
2126

2227
#ifdef CONFIG_NVS_LOOKUP_CACHE
2328

29+
#ifdef CONFIG_NVS_LOOKUP_CACHE_FOR_SETTINGS
30+
31+
static inline size_t nvs_lookup_cache_pos(uint16_t id)
32+
{
33+
/*
34+
* 1. The NVS settings backend uses up to (NVS_NAME_ID_OFFSET - 1) NVS IDs to
35+
store keys and equal number of NVS IDs to store values.
36+
* 2. For each key-value pair, the value is stored at NVS ID greater by exactly
37+
* NVS_NAME_ID_OFFSET than NVS ID that holds the key.
38+
* 3. The backend tries to minimize the range of NVS IDs used to store keys.
39+
* That is, NVS IDs are allocated sequentially, and freed NVS IDs are reused
40+
* before allocating new ones.
41+
*
42+
* Therefore, to assure the least number of collisions in the lookup cache,
43+
* the least significant bit of the hash indicates whether the given NVS ID
44+
* represents a key or a value, and remaining bits of the hash are set to
45+
* the ordinal number of the key-value pair. Consequently, the hash function
46+
* provides the following mapping:
47+
*
48+
* 1st settings key => hash 0
49+
* 1st settings value => hash 1
50+
* 2nd settings key => hash 2
51+
* 2nd settings value => hash 3
52+
* ...
53+
*/
54+
BUILD_ASSERT(IS_POWER_OF_TWO(NVS_NAMECNT_ID), "NVS_NAMECNT_ID is not power of 2");
55+
BUILD_ASSERT(IS_POWER_OF_TWO(NVS_NAME_ID_OFFSET), "NVS_NAME_ID_OFFSET is not power of 2");
56+
57+
uint16_t key_value_bit;
58+
uint16_t key_value_ord;
59+
60+
key_value_bit = (id >> LOG2(NVS_NAME_ID_OFFSET)) & 1;
61+
key_value_ord = id & (NVS_NAME_ID_OFFSET - 1);
62+
63+
return ((key_value_ord << 1) | key_value_bit) % CONFIG_NVS_LOOKUP_CACHE_SIZE;
64+
}
65+
66+
#else /* CONFIG_NVS_LOOKUP_CACHE_FOR_SETTINGS */
67+
2468
static inline size_t nvs_lookup_cache_pos(uint16_t id)
2569
{
2670
uint16_t hash;
@@ -36,6 +80,8 @@ static inline size_t nvs_lookup_cache_pos(uint16_t id)
3680
return hash % CONFIG_NVS_LOOKUP_CACHE_SIZE;
3781
}
3882

83+
#endif /* CONFIG_NVS_LOOKUP_CACHE_FOR_SETTINGS */
84+
3985
static int nvs_lookup_cache_rebuild(struct nvs_fs *fs)
4086
{
4187
int rc;

0 commit comments

Comments
 (0)