From 1b3a12ce8e34feccd47e668eef281c2a4433a3a3 Mon Sep 17 00:00:00 2001 From: Krzysztof Chruscinski Date: Wed, 21 Jul 2021 12:59:14 +0200 Subject: [PATCH] logging: Add log_cache module for caching remote names log_cache is capable of storing fixed length byte arrays identified by a generic ID. If entry identified by given ID is not found in cache, the least recently used entry is evicted from cache. Signed-off-by: Krzysztof Chruscinski --- subsys/logging/CMakeLists.txt | 1 + subsys/logging/log_cache.c | 104 ++++++++++++++++++++++++++++++++++ subsys/logging/log_cache.h | 96 +++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 subsys/logging/log_cache.c create mode 100644 subsys/logging/log_cache.h diff --git a/subsys/logging/CMakeLists.txt b/subsys/logging/CMakeLists.txt index 07a591d5adb..c9463f51f5a 100644 --- a/subsys/logging/CMakeLists.txt +++ b/subsys/logging/CMakeLists.txt @@ -6,6 +6,7 @@ if(NOT CONFIG_LOG_MODE_MINIMAL) log_core.c log_mgmt.c log_msg.c + log_cache.c ) zephyr_sources_ifdef( diff --git a/subsys/logging/log_cache.c b/subsys/logging/log_cache.c new file mode 100644 index 00000000000..e6dd775b50e --- /dev/null +++ b/subsys/logging/log_cache.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "log_cache.h" + +#define LOG_CACHE_DBG 0 + +#if LOG_CACHE_DBG +#include +#define LOG_CACHE_PRINT(...) printk(__VA_ARGS__) +#define LOG_CACHE_DBG_ENTRY(str, entry) \ + printk(str " entry(%p) id %p\n", entry, (void *)entry->id) +#else +#define LOG_CACHE_PRINT(...) +#define LOG_CACHE_DBG_ENTRY(...) +#endif + + +int log_cache_init(struct log_cache *cache, const struct log_cache_config *config) +{ + sys_slist_init(&cache->active); + sys_slist_init(&cache->idle); + + size_t entry_size = ROUND_UP(sizeof(struct log_cache_entry) + config->item_size, + sizeof(uintptr_t)); + uint32_t entry_cnt = config->buf_len / entry_size; + struct log_cache_entry *entry = config->buf; + + /* Add all entries to idle list */ + for (uint32_t i = 0; i < entry_cnt; i++) { + sys_slist_append(&cache->idle, &entry->node); + entry = (struct log_cache_entry *)((uintptr_t)entry + entry_size); + } + + cache->cmp = config->cmp; + cache->item_size = config->item_size; + cache->hit = 0; + cache->miss = 0; + + return 0; +} + +bool log_cache_get(struct log_cache *cache, uintptr_t id, uint8_t **data) +{ + sys_snode_t *prev_node = NULL; + struct log_cache_entry *entry; + bool hit = false; + + LOG_CACHE_PRINT("cache_get for id %lx\n", id); + SYS_SLIST_FOR_EACH_CONTAINER(&cache->active, entry, node) { + LOG_CACHE_DBG_ENTRY("checking", entry); + if (cache->cmp(entry->id, id)) { + cache->hit++; + hit = true; + break; + } + + if (&entry->node == sys_slist_peek_tail(&cache->active)) { + break; + } + prev_node = &entry->node; + } + + if (hit) { + LOG_CACHE_DBG_ENTRY("moving up", entry); + sys_slist_remove(&cache->active, prev_node, &entry->node); + sys_slist_prepend(&cache->active, &entry->node); + } else { + cache->miss++; + + sys_snode_t *from_idle = sys_slist_get(&cache->idle); + + if (from_idle) { + entry = CONTAINER_OF(from_idle, struct log_cache_entry, node); + } else { + LOG_CACHE_DBG_ENTRY("removing", entry); + sys_slist_remove(&cache->active, prev_node, &entry->node); + } + } + + *data = entry->data; + entry->id = id; + + return hit; +} + +void log_cache_put(struct log_cache *cache, uint8_t *data) +{ + struct log_cache_entry *entry = CONTAINER_OF(data, struct log_cache_entry, data); + + LOG_CACHE_DBG_ENTRY("cache_put", entry); + sys_slist_prepend(&cache->active, &entry->node); +} + +void log_cache_release(struct log_cache *cache, uint8_t *data) +{ + struct log_cache_entry *entry = CONTAINER_OF(data, struct log_cache_entry, data); + + LOG_CACHE_DBG_ENTRY("cache_release", entry); + sys_slist_prepend(&cache->idle, &entry->node); +} diff --git a/subsys/logging/log_cache.h b/subsys/logging/log_cache.h new file mode 100644 index 00000000000..01616325840 --- /dev/null +++ b/subsys/logging/log_cache.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_SUBSYS_LOGGING_LOG_CACHE_H_ +#define ZEPHYR_SUBSYS_LOGGING_LOG_CACHE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct log_cache_entry { + sys_snode_t node; + uintptr_t id; + uint8_t data[]; +}; + +typedef bool (*log_cache_cmp_func_t)(uintptr_t id0, uintptr_t id1); + +struct log_cache_config { + void *buf; + size_t buf_len; + size_t item_size; + log_cache_cmp_func_t cmp; +}; + +struct log_cache { + sys_slist_t active; + sys_slist_t idle; + log_cache_cmp_func_t cmp; + uint32_t hit; + uint32_t miss; + size_t item_size; +}; + +int log_cache_init(struct log_cache *cache, const struct log_cache_config *config); + +/** @brief Get cached entry or buffer to fill new data for caching. + * + * @param[in] cache Cache object. + * @param[in] id Identication. + * @param[out] data Location. + * + * @retval true if entry with given @p id was found and @p data contains pointer to it. + * @retval false if entry was not found and @p data points to the empty location. + */ +bool log_cache_get(struct log_cache *cache, uintptr_t id, uint8_t **data); + +/** @brief Put new entry into cache. + * + * @param cache Cache object. + * @param data Buffer filled with new data. It must point to the location returned by + * @ref log_cache_get. + */ +void log_cache_put(struct log_cache *cache, uint8_t *data); + +/** @brief Release entry. + * + * Release entry that was allocated by @ref log_cache_get when requested id was + * not found in the cache. Releasing puts entry in idle list. + * + * @param cache Cache object. + * @param data It must point to the location returned by @ref log_cache_get. + */ +void log_cache_release(struct log_cache *cache, uint8_t *data); + +/** @brief Get hit count. + * + * @param cache Cache object. + * + * @return Number of hits. + */ +static inline uint32_t log_cache_get_hit(struct log_cache *cache) +{ + return cache->hit; +} + +/** @brief Get miss count. + * + * @param cache Cache object. + * + * @return Number of misses. + */ +static inline uint32_t log_cache_get_miss(struct log_cache *cache) +{ + return cache->miss; +} + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_SUBSYS_LOGGING_LOG_CACHE_H_ */