Skip to content

Commit bf20b78

Browse files
rghaddabkartben
authored andcommitted
settings: zms: add cache for linked list hash
Increase the load performance by adding an optional cache for the linked list hashes. This is used only when the settings_load is called with NULL parameter and we need to load all Settings that exist in the persistent storage. Cache is enabled using SETTINGS_ZMS_LL_CACHE and the size of the cache is set using SETTINGS_ZMS_LL_CACHE_SIZE. Each cache entry will add 8 bytes of RAM usage. Signed-off-by: Riadh Ghaddab <[email protected]>
1 parent ae46151 commit bf20b78

File tree

3 files changed

+97
-16
lines changed

3 files changed

+97
-16
lines changed

subsys/settings/Kconfig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,25 @@ config SETTINGS_ZMS
4747
help
4848
Use ZMS as settings storage backend.
4949

50+
if SETTINGS_ZMS
51+
52+
config SETTINGS_ZMS_LL_CACHE
53+
bool "ZMS linked list lookup cache"
54+
help
55+
Enable ZMS lookup cache for linked list, used to reduce the
56+
Settings load time by having most linked list elements already
57+
in cache.
58+
59+
config SETTINGS_ZMS_LL_CACHE_SIZE
60+
int "ZMS linked list lookup cache size"
61+
default 128
62+
range 1 $(UINT32_MAX)
63+
depends on SETTINGS_ZMS_LL_CACHE
64+
help
65+
Number of entries in Settings ZMS linked list cache.
66+
67+
endif # SETTINGS_ZMS
68+
5069
config SETTINGS_FCB
5170
bool "FCB"
5271
depends on FCB

subsys/settings/include/settings/settings_zms.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,25 @@ extern "C" {
6868
#define ZMS_COLLISION_NUM(x) ((x & ZMS_COLLISIONS_MASK) >> 1)
6969
#define ZMS_NAME_ID_FROM_HASH(x) ((x & ZMS_HASH_TOTAL_MASK) | BIT(31))
7070

71+
struct settings_hash_linked_list {
72+
uint32_t previous_hash;
73+
uint32_t next_hash;
74+
};
75+
7176
struct settings_zms {
7277
struct settings_store cf_store;
7378
struct zms_fs cf_zms;
7479
const struct device *flash_dev;
80+
#if CONFIG_SETTINGS_ZMS_LL_CACHE
81+
struct settings_hash_linked_list ll_cache[CONFIG_SETTINGS_ZMS_LL_CACHE_SIZE];
82+
uint32_t ll_cache_next;
83+
bool ll_has_changed;
84+
#endif /* CONFIG_SETTINGS_ZMS_LL_CACHE */
7585
uint32_t last_hash_id;
7686
uint32_t second_to_last_hash_id;
7787
uint8_t hash_collision_num;
7888
};
7989

80-
struct settings_hash_linked_list {
81-
uint32_t previous_hash;
82-
uint32_t next_hash;
83-
};
84-
8590
#ifdef __cplusplus
8691
}
8792
#endif

subsys/settings/src/settings_zms.c

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ static int settings_zms_delete(struct settings_zms *cf, uint32_t name_hash)
135135
}
136136

137137
#ifndef CONFIG_SETTINGS_ZMS_NO_LL_DELETE
138+
#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
139+
cf->ll_has_changed = true;
140+
#endif
138141
rc = settings_zms_unlink_ll_node(cf, name_hash);
139142
if (rc < 0) {
140143
return rc;
@@ -220,16 +223,28 @@ static int settings_zms_load(struct settings_store *cs, const struct settings_lo
220223
}
221224
#endif /* CONFIG_SETTINGS_ZMS_LOAD_SUBTREE_PATH */
222225

226+
#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
227+
uint32_t ll_cache_index = 0;
228+
229+
if (cf->ll_has_changed) {
230+
/* reload the linked list in cache */
231+
ret = settings_zms_get_last_hash_ids(cf);
232+
if (ret < 0) {
233+
return ret;
234+
}
235+
}
236+
settings_element = cf->ll_cache[ll_cache_index++];
237+
#else
223238
ret = zms_read(&cf->cf_zms, ZMS_LL_HEAD_HASH_ID, &settings_element,
224239
sizeof(struct settings_hash_linked_list));
225240
if (ret < 0) {
226241
return ret;
227242
}
243+
#endif /* CONFIG_SETTINGS_ZMS_LL_CACHE */
228244
ll_hash_id = settings_element.next_hash;
229245

230246
/* If subtree is NULL then we must load all found Settings */
231247
while (ll_hash_id) {
232-
233248
/* In the ZMS backend, each setting item is stored in two ZMS
234249
* entries one for the setting's name and one with the
235250
* setting's value.
@@ -254,12 +269,24 @@ static int settings_zms_load(struct settings_store *cs, const struct settings_lo
254269
return ret;
255270
}
256271
#endif /* CONFIG_SETTINGS_ZMS_NO_LL_DELETE */
257-
258-
ret = zms_read(&cf->cf_zms, ll_hash_id, &settings_element,
259-
sizeof(struct settings_hash_linked_list));
260-
if (ret < 0) {
261-
return ret;
272+
#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
273+
if (ll_cache_index < cf->ll_cache_next) {
274+
settings_element = cf->ll_cache[ll_cache_index++];
275+
} else if (ll_hash_id == cf->second_to_last_hash_id) {
276+
/* The last ll node is not stored in the cache as it is already
277+
* in the cf->last_hash_id.
278+
*/
279+
settings_element.next_hash = cf->last_hash_id;
280+
} else {
281+
#endif
282+
ret = zms_read(&cf->cf_zms, ll_hash_id, &settings_element,
283+
sizeof(struct settings_hash_linked_list));
284+
if (ret < 0) {
285+
return ret;
286+
}
287+
#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
262288
}
289+
#endif
263290
/* update next ll_hash_id */
264291
ll_hash_id = settings_element.next_hash;
265292
continue;
@@ -276,12 +303,22 @@ static int settings_zms_load(struct settings_store *cs, const struct settings_lo
276303
break;
277304
}
278305

279-
/* update next ll_hash_id */
280-
ret = zms_read(&cf->cf_zms, ll_hash_id, &settings_element,
281-
sizeof(struct settings_hash_linked_list));
282-
if (ret < 0) {
283-
return ret;
306+
#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
307+
if (ll_cache_index < cf->ll_cache_next) {
308+
settings_element = cf->ll_cache[ll_cache_index++];
309+
} else if (ll_hash_id == cf->second_to_last_hash_id) {
310+
settings_element.next_hash = cf->last_hash_id;
311+
} else {
312+
#endif
313+
ret = zms_read(&cf->cf_zms, ll_hash_id, &settings_element,
314+
sizeof(struct settings_hash_linked_list));
315+
if (ret < 0) {
316+
return ret;
317+
}
318+
#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
284319
}
320+
#endif
321+
/* update next ll_hash_id */
285322
ll_hash_id = settings_element.next_hash;
286323
}
287324

@@ -418,6 +455,7 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
418455
if (rc < 0) {
419456
return rc;
420457
}
458+
421459
/* Now update the previous linked list element */
422460
settings_element.next_hash = name_hash | 1;
423461
settings_element.previous_hash = cf->second_to_last_hash_id;
@@ -428,6 +466,12 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
428466
}
429467
cf->second_to_last_hash_id = cf->last_hash_id;
430468
cf->last_hash_id = name_hash | 1;
469+
#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
470+
if (cf->ll_cache_next < CONFIG_SETTINGS_ZMS_LL_CACHE_SIZE) {
471+
cf->ll_cache[cf->ll_cache_next] = settings_element;
472+
cf->ll_cache_next = cf->ll_cache_next + 1;
473+
}
474+
#endif
431475
}
432476
#ifdef CONFIG_SETTINGS_ZMS_NO_LL_DELETE
433477
no_ll_update:
@@ -441,6 +485,9 @@ static int settings_zms_get_last_hash_ids(struct settings_zms *cf)
441485
uint32_t ll_last_hash_id = ZMS_LL_HEAD_HASH_ID;
442486
int rc = 0;
443487

488+
#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
489+
cf->ll_cache_next = 0;
490+
#endif
444491
cf->hash_collision_num = 0;
445492
do {
446493
rc = zms_read(&cf->cf_zms, ll_last_hash_id, &settings_element,
@@ -461,6 +508,13 @@ static int settings_zms_get_last_hash_ids(struct settings_zms *cf)
461508
return rc;
462509
}
463510

511+
#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
512+
if ((cf->ll_cache_next < CONFIG_SETTINGS_ZMS_LL_CACHE_SIZE) &&
513+
(settings_element.next_hash)) {
514+
cf->ll_cache[cf->ll_cache_next] = settings_element;
515+
cf->ll_cache_next = cf->ll_cache_next + 1;
516+
}
517+
#endif
464518
/* increment hash collision number if necessary */
465519
if (ZMS_COLLISION_NUM(ll_last_hash_id) > cf->hash_collision_num) {
466520
cf->hash_collision_num = ZMS_COLLISION_NUM(ll_last_hash_id);
@@ -470,6 +524,9 @@ static int settings_zms_get_last_hash_ids(struct settings_zms *cf)
470524
ll_last_hash_id = settings_element.next_hash;
471525
} while (settings_element.next_hash);
472526

527+
#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
528+
cf->ll_has_changed = false;
529+
#endif
473530
return 0;
474531
}
475532

0 commit comments

Comments
 (0)