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 <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski 2021-07-21 12:59:14 +02:00 committed by Carles Cufí
parent 54a64edb0e
commit 1b3a12ce8e
3 changed files with 201 additions and 0 deletions

View file

@ -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(

104
subsys/logging/log_cache.c Normal file
View file

@ -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 <sys/printk.h>
#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);
}

View file

@ -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 <zephyr/sys/slist.h>
#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_ */