ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_vmem.c File Reference

Byte-range page cache with SLRU eviction – implementation (Layer 2). More...

#include "ra8_vmem.h"
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_keycache.h"
Include dependency graph for ra8_vmem.c:

Go to the source code of this file.

Enumerations

enum  ra8_vmem_hash_const_t : uint32_t {
  k_vmem_hash_mul_obj = 2654435761U ,
  k_vmem_hash_mul_page = 40503U
}
 Multiplicative constants mixing the two halves of the page key. More...
enum  ra8_vmem_shift_const_t : uint8_t { k_vmem_off_shift = 32U }
 Bit shift splitting a 64-bit offset into two 32-bit halves. More...

Functions

static uint32_t internal_vmem_hash (const void *key, uint32_t key_bytes, void *ctx)
 Injected key hash: fold the (object_id, offset) page key (division-free).
static ra8_err_t internal_vmem_fill (void *ctx, const void *key, uint8_t *cell, uint32_t cell_bytes, void *user)
 Fill trampoline: adapt ra8_vmem_loader_fn to the keycache seam.
ra8_err_t ra8_vmem_init (ra8_vmem_t *vm, const ra8_vmem_cfg_t *cfg)
 Initialise a page cache over caller-supplied storage.
ra8_err_t ra8_vmem_get (ra8_vmem_t *vm, uint32_t object_id, uint64_t offset, void **out_page)
 Get (and pin) the frame holding object object_id at offset.
ra8_err_t ra8_vmem_put (ra8_vmem_t *vm, void *page)
 Release one pin on a frame previously returned by ra8_vmem_get.
ra8_err_t ra8_vmem_prefetch (ra8_vmem_t *vm, uint32_t object_id, uint64_t offset)
 Warm the frame holding object object_id at offset into the cache without holding a pin (single-threaded read-ahead / prefetch).
ra8_err_t ra8_vmem_stats (const ra8_vmem_t *vm, uint32_t *out_hits, uint32_t *out_misses, uint32_t *out_evictions)
 Report the cache hit / miss / eviction counters.

Variables

static const char *const s_tag = "ra8_vmem"
 Module log tag.

Detailed Description

Byte-range page cache with SLRU eviction – implementation (Layer 2).

Tag
[Ring 2 / Core] {World: NS}

A thin typed facade over ::ra8_keycache, the one reader cache engine (#345 folded this module's once-duplicate hash/pin/SLRU machinery into that engine). The cache key is an (object_id, frame-aligned offset) pair; the byte page is the cell payload; the ra8_vmem_loader_fn adapts to the engine's render-on-miss seam through internal_vmem_fill; and internal_vmem_hash injects a page-oriented hash of the key. All eviction mechanics – the probationary / protected SLRU lists, the pinned-frame skip, hash chaining – live in ::ra8_keycache. What this file adds is the pointer-handle API, frame-boundary alignment, and the ra8_vmem_prefetch read-ahead helper.

Definition in file ra8_vmem.c.

Enumeration Type Documentation

◆ ra8_vmem_hash_const_t

enum ra8_vmem_hash_const_t : uint32_t

Multiplicative constants mixing the two halves of the page key.

Since
0.1.0
Enumerator
k_vmem_hash_mul_obj 

Knuth multiplicative hash (object id).

k_vmem_hash_mul_page 

Odd multiplier mixing the offset.

Definition at line 43 of file ra8_vmem.c.

◆ ra8_vmem_shift_const_t

enum ra8_vmem_shift_const_t : uint8_t

Bit shift splitting a 64-bit offset into two 32-bit halves.

Since
0.1.0
Enumerator
k_vmem_off_shift 

Shift for the high 32 bits of the offset.

Definition at line 54 of file ra8_vmem.c.

Function Documentation

◆ internal_vmem_fill()

ra8_err_t internal_vmem_fill ( void * ctx,
const void * key,
uint8_t * cell,
uint32_t cell_bytes,
void * user )
static

Fill trampoline: adapt ra8_vmem_loader_fn to the keycache seam.

Casts the keycache render context back to the owning cache and calls the caller's page loader for the cell, forwarding the key's object id and frame-aligned offset. The page cache carries no per-cell user descriptor, so user is ignored.

Parameters
[in]ctxThe owning ra8_vmem_t (keycache render_ctx).
[in]keyThe ra8_vmem_key_t to load.
[out]cellDestination frame buffer (cell_bytes writable).
[in]cell_bytesFrame capacity in bytes.
[out]userUnused (the page cache has no user descriptor).
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe page was loaded into the frame.
k_ra8_err_*The caller's loader error (returned verbatim).
Precondition
ctx and key are non-NULL (the keycache guarantees both here).
cell addresses cell_bytes of writable frame storage.
Postcondition
On success the frame holds the requested page.
On failure the frame contents are unspecified (the victim is dropped).
Note
Not thread-safe.
Since
0.1.0

Definition at line 123 of file ra8_vmem.c.

References ra8_vmem_t::cfg, ra8_vmem_cfg_t::loader, ra8_vmem_cfg_t::loader_ctx, ra8_vmem_key_t::object_id, and ra8_vmem_key_t::offset.

Referenced by ra8_vmem_init().

◆ internal_vmem_hash()

uint32_t internal_vmem_hash ( const void * key,
uint32_t key_bytes,
void * ctx )
static

Injected key hash: fold the (object_id, offset) page key (division-free).

Adapts ra8_keycache_hash_fn for the byte-range key. Mixes the object id and both 32-bit halves of the frame-aligned offset through two odd multipliers, returning a raw 32-bit hash the engine folds to a bucket. Because the offset is always frame-aligned, its sub-frame low bits are zero, so hashing the offset is equivalent to hashing the page number without a run-time division.

Parameters
[in]keyThe ra8_vmem_key_t being hashed.
[in]key_bytesKey width in bytes (unused; the layout is fixed).
[in]ctxUnused (the key carries everything the hash needs).
Returns
A raw 32-bit hash of the page key.
Return values
0The key folded to zero (one possible result).
Precondition
key points at a valid ra8_vmem_key_t.
The key was zero-filled before its fields were set (no stray padding).
Postcondition
No state is modified.
The result depends only on the key's object id and offset.
Note
Pure; thread-safe.
Since
0.1.0

Definition at line 84 of file ra8_vmem.c.

References k_vmem_hash_mul_obj, k_vmem_hash_mul_page, k_vmem_off_shift, ra8_vmem_key_t::object_id, ra8_vmem_key_t::offset, and RA8_INTERNAL.

Referenced by ra8_vmem_init().

◆ ra8_vmem_get()

ra8_err_t ra8_vmem_get ( ra8_vmem_t * vm,
uint32_t object_id,
uint64_t offset,
void ** out_page )
nodiscard

Get (and pin) the frame holding object object_id at offset.

On a hit the frame is re-referenced (SLRU promote) and pinned. On a miss an unpinned victim is evicted (SLRU: probationary LRU first), the page is loaded through the configured loader, inserted, and pinned. The returned pointer stays valid until the matching ra8_vmem_put.

Parameters
[in]vmInitialised cache.
[in]object_idObject to page in.
[in]offsetByte offset; rounded down to a frame boundary internally.
[out]out_pageReceives the pinned frame pointer (frame_bytes wide).
Returns
ra8_err_t Error code.
Return values
k_ra8_okPage resident and pinned; *out_page set.
k_ra8_err_null_ptrvm or out_page was NULL.
k_ra8_err_no_memEvery frame is pinned (cannot evict for the miss).
k_ra8_err_*The loader failed (returned verbatim).
Precondition
vm was populated by ra8_vmem_init.
The caller will ra8_vmem_put the returned frame.
Postcondition
On success the frame's pin_count increased by one.
On any non-ok return no new pin is held.
Note
Not thread-safe.
Since
0.1.0

Definition at line 162 of file ra8_vmem.c.

References ra8_vmem_t::cfg, ra8_vmem_cfg_t::frame_bytes, k_ra8_ok, ra8_vmem_t::kc, ra8_vmem_key_t::object_id, ra8_vmem_key_t::offset, RA8_CHECK_NULL_PTR, ra8_keycache_get(), and s_tag.

Referenced by internal_book_src_read_paged(), internal_drive(), internal_touch(), ra8_vmem_prefetch(), and ra8_vmem_stream_read().

◆ ra8_vmem_init()

ra8_err_t ra8_vmem_init ( ra8_vmem_t * vm,
const ra8_vmem_cfg_t * cfg )
nodiscard

Initialise a page cache over caller-supplied storage.

Parameters
[out]vmCache state to populate (zero-initialised by the caller).
[in]cfgStorage + loader configuration (see ra8_vmem_cfg_t).
Returns
ra8_err_t Error code.
Return values
k_ra8_okCache ready; all frames cold/free.
k_ra8_err_null_ptrvm, cfg, or a required cfg pointer is NULL.
k_ra8_err_invalid_sizeframe_count, frame_bytes, or bucket_count was zero.
k_ra8_err_invalid_argcfg->protected_pct exceeds 100.
Precondition
cfg's arrays cover their declared sizes and out-live the cache.
cfg->loader is non-NULL and cfg->protected_pct <= 100.
Postcondition
On success vm is empty (0 valid frames) and the buckets are cleared.
On any non-ok return vm is left unbound.
Note
Not thread-safe.
Since
0.1.0

Definition at line 131 of file ra8_vmem.c.

References ra8_keycache_cfg_t::bucket_count, ra8_vmem_cfg_t::bucket_count, ra8_keycache_cfg_t::buckets, ra8_vmem_cfg_t::buckets, ra8_keycache_cfg_t::cell_bytes, ra8_keycache_cfg_t::cell_count, ra8_keycache_cfg_t::cell_mem, ra8_vmem_t::cfg, ra8_keycache_cfg_t::evict, ra8_vmem_cfg_t::frame_bytes, ra8_vmem_cfg_t::frame_count, ra8_vmem_cfg_t::frame_mem, ra8_keycache_cfg_t::hash, ra8_keycache_cfg_t::hash_ctx, internal_vmem_fill(), internal_vmem_hash(), k_ra8_keycache_evict_slru, k_ra8_ok, ra8_vmem_t::kc, ra8_keycache_cfg_t::key_bytes, ra8_keycache_cfg_t::key_mem, ra8_vmem_cfg_t::keys, memset(), ra8_keycache_cfg_t::meta, ra8_vmem_cfg_t::meta, ra8_keycache_t::protected_cap, ra8_vmem_t::protected_cap, ra8_keycache_cfg_t::protected_pct, ra8_vmem_cfg_t::protected_pct, RA8_CHECK_NULL_PTR, ra8_keycache_init(), ra8_keycache_cfg_t::render, ra8_keycache_cfg_t::render_ctx, s_tag, ra8_keycache_cfg_t::user_bytes, and ra8_keycache_cfg_t::user_mem.

Referenced by internal_cache_bind(), internal_cache_open(), internal_vmem_setup(), mem_run_vmem(), and sh_paged_bind().

◆ ra8_vmem_prefetch()

ra8_err_t ra8_vmem_prefetch ( ra8_vmem_t * vm,
uint32_t object_id,
uint64_t offset )
nodiscard

Warm the frame holding object object_id at offset into the cache without holding a pin (single-threaded read-ahead / prefetch).

Performs a bounded ra8_vmem_get immediately followed by ra8_vmem_put, so on return the page is resident but unpinned – it enters the SLRU/2Q probationary segment and ages out cheaply if the read-ahead guess was wrong (no prefetch backfire on a fast skim). Intended for the display-flush idle window: after rendering page N, warm page N+1 (and N-1 for back-flips) so the next page-turn tap is already resident. Best-effort – a loader failure is returned, but callers on the idle path typically discard it.

Parameters
[in]vmInitialised cache.
[in]object_idObject to warm.
[in]offsetByte offset; rounded down to a frame boundary internally.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe page is resident and left unpinned.
k_ra8_err_null_ptrvm was NULL.
k_ra8_err_no_memEvery frame is pinned (cannot evict to warm).
k_ra8_err_*The loader failed (returned verbatim; nothing warmed).
Precondition
vm was populated by ra8_vmem_init.
Called from the single owning context (e.g. the reader idle window).
Postcondition
On k_ra8_ok the page is resident with a net-zero change to pin_count.
On any non-ok return this call leaves no frame pinned.
Note
Not thread-safe. Single-threaded read-ahead only.
A warmed-but-unused frame is probationary and evicted before hot data.
See also
ra8_vmem_get() The pinning demand-page primitive this wraps.
Since
0.1.0

Definition at line 186 of file ra8_vmem.c.

References k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_vmem_get(), ra8_vmem_put(), and s_tag.

Referenced by book_src_prefetch_chapter().

◆ ra8_vmem_put()

ra8_err_t ra8_vmem_put ( ra8_vmem_t * vm,
void * page )
nodiscard

Release one pin on a frame previously returned by ra8_vmem_get.

Parameters
[in]vmInitialised cache.
[in]pageA frame pointer returned by ra8_vmem_get.
Returns
ra8_err_t Error code.
Return values
k_ra8_okPin released.
k_ra8_err_null_ptrvm or page was NULL.
k_ra8_err_invalid_argpage is not a frame of this cache, or the frame was not pinned.
Precondition
page came from ra8_vmem_get on this cache and is still pinned.
vm was populated by ra8_vmem_init.
Postcondition
On success the frame's pin_count decreased by one (evictable at zero).
On any non-ok return no state changed.
Note
Not thread-safe.
Since
0.1.0

Definition at line 179 of file ra8_vmem.c.

References ra8_vmem_t::kc, RA8_CHECK_NULL_PTR, ra8_keycache_put(), and s_tag.

Referenced by internal_book_src_read_paged(), internal_drive(), internal_touch(), ra8_vmem_prefetch(), and ra8_vmem_stream_read().

◆ ra8_vmem_stats()

ra8_err_t ra8_vmem_stats ( const ra8_vmem_t * vm,
uint32_t * out_hits,
uint32_t * out_misses,
uint32_t * out_evictions )
nodiscard

Report the cache hit / miss / eviction counters.

Parameters
[in]vmInitialised cache.
[out]out_hitsGet hits so far (may be NULL).
[out]out_missesGet misses so far (may be NULL).
[out]out_evictionsPages evicted so far (may be NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okCounters reported.
k_ra8_err_null_ptrvm was NULL.
k_ra8_err_invalid_stateThe cache was not initialised.
Precondition
vm was populated by ra8_vmem_init.
At least one output pointer is non-NULL to be useful.
Postcondition
On success the requested counters are written.
No cache state is mutated.
Note
Thread-safe with respect to a quiescent cache (pure read).
Since
0.1.0

Definition at line 199 of file ra8_vmem.c.

References ra8_vmem_t::cfg, ra8_vmem_cfg_t::frame_mem, k_ra8_err_invalid_state, ra8_vmem_t::kc, RA8_CHECK_NULL_PTR, ra8_keycache_stats(), and s_tag.

Referenced by internal_drive(), internal_execute(), and mem_run_vmem().

Variable Documentation

◆ s_tag

const char* const s_tag = "ra8_vmem"
static

Module log tag.

Definition at line 35 of file ra8_vmem.c.