|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Byte-range page cache with SLRU eviction (Layer 2, #147). More...
Go to the source code of this file.
Data Structures | |
| struct | ra8_vmem_key_t |
| The (object_id, frame-aligned offset) key the page cache hashes on. More... | |
| struct | ra8_vmem_cfg_t |
| Caller-supplied storage + loader for ra8_vmem_init. More... | |
| struct | ra8_vmem_t |
| Page-cache state (caller-owned; treat as private). More... | |
Typedefs | |
| typedef ra8_err_t(* | ra8_vmem_loader_fn) (void *ctx, uint32_t object_id, uint64_t offset, uint8_t *frame, uint32_t frame_bytes) |
| Fill a frame with one page of an object (the storage DIP seam). | |
| typedef ra8_keycache_cell_t | ra8_vmem_frame_t |
| Per-frame cache metadata (one caller-owned array entry per frame). | |
Functions | |
| 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. | |
Byte-range page cache with SLRU eviction (Layer 2, #147).
The heart of the #147 memory hierarchy: a software page cache that lets the reader touch objects far larger than RAM (GB-class EPUB/CBZ) while the resident set stays bounded by a fixed frame budget, independent of file size. There is no MMU, so access is handle-based – ra8_vmem_get(object_id, offset) returns a pointer to a pinned frame holding that page; a miss evicts an unpinned victim, loads the page through a caller-supplied loader, and inserts it. The caller ra8_vmem_puts the frame when done.
ra8_vmem no longer carries its own hash/pin/evict machinery. It is a thin typed facade over ::ra8_keycache, the single reader cache engine, configured for the SLRU policy with an (object_id, frame-aligned offset) key: the byte page is the cell payload, the ra8_vmem_loader_fn adapts to the engine's render-on-miss seam, and the page-number hash is injected. The image-tile and glyph caches are the LRU facades over the same engine. What ra8_vmem adds on top is this pointer-handle API, the frame-boundary alignment, and the ra8_vmem_prefetch read-ahead helper – the representation its byte-range consumers want and the tile/glyph consumers do not.
Eviction is SLRU (Segmented LRU / 2Q) – the policy chosen in #147 because it is the only scan-resistant policy with deterministic O(1) (WCET = 1) victim selection: a probationary segment absorbs one-shot linear scans while a protected segment holds the re-referenced working set, so a page-turn flood does not evict the hot set. The victim is always the probationary LRU (then the protected LRU); pinned frames are skipped.
The one policy knob is the share of frames the protected segment may hold; the rest is the probationary scan buffer. It is a per-cache tuning axis (#232) because the sweet spot depends on the workload's hot-set size versus its scan volume:
The split changes which frame is evicted, never how many are resident: the bounded-RAM guarantee (residency <= frame_count) is independent of the knob.
Zero allocation (NASA P10 Rule 3): the caller provides the frame storage, the per-frame metadata array, the key-storage array, and the hash-bucket array – all carved once from a tier arena (::ra8_arena) at init. The frames themselves come from a tier's ::ra8_slab in production, but ra8_vmem only needs a contiguous frame region.
Definition in file ra8_vmem.h.
| typedef ra8_keycache_cell_t ra8_vmem_frame_t |
Per-frame cache metadata (one caller-owned array entry per frame).
Treat as private; the cache owns the contents. Since #345 folded the cache machinery into ::ra8_keycache, this is exactly an ra8_keycache_cell_t – allocate an array of frame_count of them alongside the frame storage, the key array, and the hash buckets.
Definition at line 122 of file ra8_vmem.h.
| typedef ra8_err_t(* ra8_vmem_loader_fn) (void *ctx, uint32_t object_id, uint64_t offset, uint8_t *frame, uint32_t frame_bytes) |
Fill a frame with one page of an object (the storage DIP seam).
Called on a cache miss to populate frame with frame_bytes of object object_id starting at byte offset (a frame-aligned offset). Layer 1 (SD-paged / OSPI-XIP backends) implements this; tests use a synthetic generator.
| [in] | ctx | Opaque loader context (loader_ctx from the config). |
| [in] | object_id | Object being paged in. |
| [in] | offset | Frame-aligned byte offset within the object. |
| [out] | frame | Destination frame (frame_bytes writable). |
| [in] | frame_bytes | Frame size in bytes. |
Definition at line 105 of file ra8_vmem.h.
|
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.
| [in] | vm | Initialised cache. |
| [in] | object_id | Object to page in. |
| [in] | offset | Byte offset; rounded down to a frame boundary internally. |
| [out] | out_page | Receives the pinned frame pointer (frame_bytes wide). |
| k_ra8_ok | Page resident and pinned; *out_page set. |
| k_ra8_err_null_ptr | vm or out_page was NULL. |
| k_ra8_err_no_mem | Every frame is pinned (cannot evict for the miss). |
| k_ra8_err_* | The loader failed (returned verbatim). |
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().
|
nodiscard |
Initialise a page cache over caller-supplied storage.
| [out] | vm | Cache state to populate (zero-initialised by the caller). |
| [in] | cfg | Storage + loader configuration (see ra8_vmem_cfg_t). |
| k_ra8_ok | Cache ready; all frames cold/free. |
| k_ra8_err_null_ptr | vm, cfg, or a required cfg pointer is NULL. |
| k_ra8_err_invalid_size | frame_count, frame_bytes, or bucket_count was zero. |
| k_ra8_err_invalid_arg | cfg->protected_pct exceeds 100. |
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().
|
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.
| [in] | vm | Initialised cache. |
| [in] | object_id | Object to warm. |
| [in] | offset | Byte offset; rounded down to a frame boundary internally. |
| k_ra8_ok | The page is resident and left unpinned. |
| k_ra8_err_null_ptr | vm was NULL. |
| k_ra8_err_no_mem | Every frame is pinned (cannot evict to warm). |
| k_ra8_err_* | The loader failed (returned verbatim; nothing warmed). |
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().
|
nodiscard |
Release one pin on a frame previously returned by ra8_vmem_get.
| [in] | vm | Initialised cache. |
| [in] | page | A frame pointer returned by ra8_vmem_get. |
| k_ra8_ok | Pin released. |
| k_ra8_err_null_ptr | vm or page was NULL. |
| k_ra8_err_invalid_arg | page is not a frame of this cache, or the frame was not pinned. |
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().
|
nodiscard |
Report the cache hit / miss / eviction counters.
| [in] | vm | Initialised cache. |
| [out] | out_hits | Get hits so far (may be NULL). |
| [out] | out_misses | Get misses so far (may be NULL). |
| [out] | out_evictions | Pages evicted so far (may be NULL). |
| k_ra8_ok | Counters reported. |
| k_ra8_err_null_ptr | vm was NULL. |
| k_ra8_err_invalid_state | The cache was not initialised. |
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().