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:
parent
54a64edb0e
commit
1b3a12ce8e
|
@ -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
104
subsys/logging/log_cache.c
Normal 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);
|
||||
}
|
96
subsys/logging/log_cache.h
Normal file
96
subsys/logging/log_cache.h
Normal 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_ */
|
Loading…
Reference in a new issue