ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
trace.c
Go to the documentation of this file.
1
13#include "trace.h"
14
15#include <errno.h>
16#include <limits.h>
17#include <stdlib.h>
18#include <string.h>
19
20#include "ra8_attributes.h"
21
41
42typedef enum : uint8_t {
49
50typedef enum : uint64_t {
51 k_rng_seed_random = 0x9E3779B97F4A7C15ULL,
52 k_rng_seed_reread = 0xD1B54A32D192ED03ULL,
53 k_rng_seed_toc = 0x2545F4914F6CDD1DULL,
54 k_rng_seed_mixed_a = 0x9E3779B97F4A7C15ULL,
55 k_rng_seed_mixed_b = 0xABCDEF1234567890ULL,
56 k_cb_hash_offset = 0xCBF29CE484222325ULL,
57 k_cb_hash_prime = 0x100000001B3ULL,
59
74static uint64_t internal_rng(uint64_t* state)
75{
76 uint64_t value = *state;
77 value ^= value << (uint8_t)k_rng_shift_a;
78 value ^= value >> (uint8_t)k_rng_shift_b;
79 value ^= value << (uint8_t)k_rng_shift_c;
80 *state = value;
81 return value;
82}
83
101static uint32_t internal_rand_below(uint64_t* state, uint32_t span)
102{
103 return (span == 0U) ? 0U : (uint32_t)(internal_rng(state) % (uint64_t)span);
104}
105
122static uint64_t internal_trace_hash(uint64_t hash, cb_key_t key)
123{
124 const uint8_t bytes[sizeof(key)] = {
125 (uint8_t)key.object_id,
126 (uint8_t)(key.object_id >> 8U),
127 (uint8_t)(key.object_id >> 16U),
128 (uint8_t)(key.object_id >> (uint8_t)k_cb_key_high_shift),
129 (uint8_t)key.page,
130 (uint8_t)(key.page >> 8U),
131 (uint8_t)(key.page >> 16U),
132 (uint8_t)(key.page >> (uint8_t)k_cb_key_high_shift),
133 };
134 for (size_t i = 0U; i < sizeof(bytes); ++i) {
135 hash ^= bytes[i];
136 hash *= (uint64_t)k_cb_hash_prime;
137 }
138 return hash;
139}
140
142{
143 static const char* const names[k_cb_synthetic_trace_count] = {
144 "seq-pageturn",
145 "random",
146 "reread-locality",
147 "linear+jumps",
148 "cbz-scroll",
149 "hotset+scan",
150 "hugebook-7GiB",
151 "mixed-session",
152 };
153 static const uint32_t footprints[k_cb_synthetic_trace_count] = {
162 };
163 for (uint8_t i = 0U; i < (uint8_t)k_cb_synthetic_trace_count; ++i) {
164 out[i] = (cb_trace_t){.name = names[i],
165 .n = (uint64_t)k_cb_accesses,
166 .footprint = footprints[i],
167 .kind = (cb_trace_kind_t)i};
168 }
169}
170
190static cb_io_status_t internal_trace_read_byte(cb_trace_cursor_t* cursor, uint8_t* out, bool* eof)
191{
192 if (cursor->read_at == cursor->read_count) {
193 if (cursor->source_offset >= cursor->trace->source.size) {
194 *eof = true;
195 return k_cb_io_ok;
196 }
197 size_t count = 0U;
198 const uint64_t remaining = cursor->trace->source.size - cursor->source_offset;
199 const size_t request =
200 (remaining < sizeof(cursor->read_buffer)) ? (size_t)remaining : sizeof(cursor->read_buffer);
201 const cb_io_status_t status = cursor->trace->source.read(cursor->trace->source.ctx,
202 cursor->source_offset,
203 cursor->read_buffer,
204 request,
205 &count);
206 if ((status != k_cb_io_ok) || (count == 0U) || (count > request)) {
207 return (status == k_cb_io_ok) ? k_cb_io_fault : status;
208 }
209 cursor->source_offset += count;
210 cursor->read_at = 0U;
211 cursor->read_count = count;
212 }
213 *out = cursor->read_buffer[cursor->read_at];
214 cursor->read_at++;
215 *eof = false;
216 return k_cb_io_ok;
217}
218
237static bool internal_parse_trace_line(const char* line, uint32_t* object_id, uint32_t* page)
238{
239 char* end = nullptr;
240 errno = 0;
241 const unsigned long object = strtoul(line, &end, (int)k_cb_base_dec);
242 if ((end == line) || (errno != 0)) {
243 return false;
244 }
245#if ULONG_MAX > UINT32_MAX
246 if (object > (unsigned long)UINT32_MAX) {
247 return false;
248 }
249#endif
250 const char* second = end;
251 errno = 0;
252 const unsigned long page_value = strtoul(second, &end, (int)k_cb_base_dec);
253 if ((end == second) || (errno != 0)) {
254 return false;
255 }
256#if ULONG_MAX > UINT32_MAX
257 if (page_value > (unsigned long)UINT32_MAX) {
258 return false;
259 }
260#endif
261 *object_id = (uint32_t)object;
262 *page = (uint32_t)page_value;
263 return true;
264}
265
285static cb_io_status_t
287{
288 size_t length = 0U;
289 bool eof = false;
290 while ((length + 1U) < sizeof(cursor->line)) {
291 uint8_t value = 0U;
292 const cb_io_status_t status = internal_trace_read_byte(cursor, &value, &eof);
293 if (status != k_cb_io_ok) {
294 return status;
295 }
296 if (eof) {
297 break;
298 }
299 cursor->line[length] = (char)value;
300 length++;
301 if (value == (uint8_t)'\n') {
302 break;
303 }
304 }
305 if ((length == 0U) && eof) {
306 *done = true;
307 return k_cb_io_ok;
308 }
309 cursor->line[length] = '\0';
310 if (!internal_parse_trace_line(cursor->line, &key->object_id, &key->page)) {
311 *done = true;
312 return k_cb_io_ok;
313 }
314 *done = false;
315 return k_cb_io_ok;
316}
317
334static cb_key_t internal_trace_scan_key(uint64_t index, bool huge)
335{
336 const uint32_t hot = huge ? (uint32_t)k_cb_huge_hot : (uint32_t)k_cb_sr_hot;
337 const uint32_t passes = huge ? (uint32_t)k_cb_huge_hot_pass : (uint32_t)k_cb_sr_hot_pass;
338 const uint32_t scan = huge ? (uint32_t)k_cb_huge_scan : (uint32_t)k_cb_sr_scan;
339 const uint32_t footprint = huge ? (uint32_t)k_cb_huge_footprint : (uint32_t)k_cb_footprint;
340 const uint64_t hot_span = (uint64_t)hot * (uint64_t)passes;
341 const uint64_t cycle = hot_span + (uint64_t)scan;
342 const uint64_t round = index / cycle;
343 const uint64_t pos = index % cycle;
344 const uint32_t page = (pos < hot_span)
345 ? (uint32_t)(pos % hot)
346 : hot + (uint32_t)(((uint64_t)hot + (round * scan) + (pos - hot_span)) %
347 (uint64_t)(footprint - hot));
348 return (cb_key_t){.object_id = k_cb_obj_book, .page = page};
349}
350
367{
368 const uint64_t index = cursor->index;
369 switch (cursor->trace->kind) {
370 case k_cb_trace_seq:
371 return (cb_key_t){.object_id = k_cb_obj_book,
372 .page = (uint32_t)(index % (uint64_t)k_cb_footprint)};
374 return (cb_key_t){.object_id = k_cb_obj_book,
375 .page = internal_rand_below(&cursor->rng, k_cb_footprint)};
376 case k_cb_trace_reread: {
377 uint32_t page = 0U;
379 page = cursor->hot + internal_rand_below(&cursor->rng, k_cb_hot_pages);
380 } else {
381 page = internal_rand_below(&cursor->rng, k_cb_footprint);
382 cursor->hot = (page < k_cb_hot_pages) ? 0U : (page - k_cb_hot_pages);
383 }
384 return (cb_key_t){.object_id = k_cb_obj_book, .page = page % k_cb_footprint};
385 }
386 case k_cb_trace_jumps:
389 : (cursor->page + 1U) % k_cb_footprint;
390 return (cb_key_t){.object_id = k_cb_obj_book, .page = cursor->page};
392 return (cb_key_t){.object_id = k_cb_obj_comic,
393 .page = (uint32_t)(index % (uint64_t)k_cb_tile_span)};
394 case k_cb_trace_scan:
395 return internal_trace_scan_key(index, false);
396 case k_cb_trace_huge:
397 return internal_trace_scan_key(index, true);
398 case k_cb_trace_mixed: {
399 const uint32_t phase = (uint32_t)((index / k_cb_mixed_phase) % 4U);
400 if (phase == 0U) {
401 cursor->page = (cursor->page + 1U) % k_cb_footprint;
402 } else if (phase == 1U) {
403 cursor->page = cursor->hot + internal_rand_below(&cursor->rng, k_cb_hot_pages);
404 } else if (phase == 2U) {
405 cursor->page = internal_rand_below(&cursor->rng, k_cb_footprint);
406 cursor->hot = (cursor->page < k_cb_hot_pages) ? 0U : cursor->page - k_cb_hot_pages;
407 } else {
408 return (cb_key_t){.object_id = k_cb_obj_comic, .page = cursor->page % k_cb_tile_span};
409 }
410 return (cb_key_t){.object_id = k_cb_obj_book, .page = cursor->page % k_cb_footprint};
411 }
413 break;
414 }
415 return (cb_key_t){};
416}
417
419{
420 if ((trace == nullptr) || (cursor == nullptr)) {
421 return k_cb_io_fault;
422 }
423 *cursor = (cb_trace_cursor_t){.trace = trace, .fingerprint = (uint64_t)k_cb_hash_offset};
424 if (trace->kind == k_cb_trace_random) {
425 cursor->rng = (uint64_t)k_rng_seed_random;
426 } else if (trace->kind == k_cb_trace_reread) {
427 cursor->rng = (uint64_t)k_rng_seed_reread;
428 } else if (trace->kind == k_cb_trace_jumps) {
429 cursor->rng = (uint64_t)k_rng_seed_toc;
430 } else if (trace->kind == k_cb_trace_mixed) {
431 cursor->rng = (uint64_t)k_rng_seed_mixed_a ^ (uint64_t)k_rng_seed_mixed_b;
432 } else if ((trace->kind == k_cb_trace_captured) && (trace->source.read == nullptr)) {
433 return k_cb_io_fault;
434 }
435 return k_cb_io_ok;
436}
437
439{
440 if ((cursor == nullptr) || (cursor->trace == nullptr) || (key == nullptr) || (done == nullptr)) {
441 return k_cb_io_fault;
442 }
443 cb_io_status_t status = k_cb_io_ok;
444 if (cursor->trace->kind == k_cb_trace_captured) {
445 status = internal_trace_captured_next(cursor, key, done);
446 } else {
447 *done = cursor->index >= cursor->trace->n;
448 if (!*done) {
449 *key = internal_trace_synthetic_next(cursor);
450 }
451 }
452 if ((status == k_cb_io_ok) && !*done) {
453 cursor->fingerprint = internal_trace_hash(cursor->fingerprint, *key);
454 cursor->index++;
455 }
456 return status;
457}
458
460{
461 if ((cursor == nullptr) || (cursor->trace == nullptr)) {
462 return k_cb_io_fault;
463 }
464 if ((cursor->index != cursor->trace->n) ||
465 ((cursor->trace->kind == k_cb_trace_captured) &&
466 (cursor->fingerprint != cursor->trace->fingerprint))) {
467 return k_cb_io_mutated;
468 }
469 return k_cb_io_ok;
470}
471
473cb_trace_bind(const cb_source_t* source, const char* name, size_t name_length, cb_trace_t* out)
474{
475 if ((source == nullptr) || (source->read == nullptr) || (name == nullptr) || (out == nullptr) ||
476 (name_length == 0U) || (name_length >= (size_t)k_cb_trace_name_capacity)) {
477 return k_cb_io_capacity;
478 }
479 *out = (cb_trace_t){.kind = k_cb_trace_captured, .source = *source};
480 memcpy(out->name_storage, name, name_length);
481 out->name_storage[name_length] = '\0';
482 out->name = out->name_storage;
483 cb_trace_cursor_t cursor = {};
484 cb_io_status_t status = cb_trace_cursor_open(out, &cursor);
485 bool done = false;
486 while ((status == k_cb_io_ok) && !done) {
487 cb_key_t key = {};
488 status = cb_trace_cursor_next(&cursor, &key, &done);
489 }
490 if ((status != k_cb_io_ok) || (cursor.index == 0U)) {
491 *out = (cb_trace_t){};
492 return (status == k_cb_io_ok) ? k_cb_io_fault : status;
493 }
494 out->n = cursor.index;
495 out->fingerprint = cursor.fingerprint;
496 return k_cb_io_ok;
497}
struct cb_trace cb_trace_t
Definition cache_bench.h:28
cb_io_status_t
Status returned by tool-local injected I/O callbacks.
@ k_cb_io_ok
Operation completed.
@ k_cb_io_fault
Backing device or sink failed.
@ k_cb_io_mutated
A replay source changed between passes.
@ k_cb_io_capacity
Caller-owned storage was too small.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
A cache key: one (object, page) the reader's vm_get touches.
Definition cache_bench.h:31
uint32_t object_id
Opaque object handle (book / archive / font).
Definition cache_bench.h:32
uint32_t page
Page index within the object (offset / page-size).
Definition cache_bench.h:33
Immutable injected byte source with a snapshotted length.
void * ctx
Caller-owned binding.
uint64_t size
Size observed when bound.
cb_source_read_fn read
Read-at implementation.
Caller-owned state for one independent trace pass.
Definition trace.h:54
uint32_t page
Stateful generator page.
Definition trace.h:60
uint64_t source_offset
Next source byte offset.
Definition trace.h:59
size_t read_count
Valid read-ahead bytes.
Definition trace.h:63
uint64_t fingerprint
Captured pass fingerprint.
Definition trace.h:58
char line[k_cb_trace_line_capacity]
Bounded line assembly.
Definition trace.h:65
const cb_trace_t * trace
Bound immutable descriptor.
Definition trace.h:55
uint64_t rng
Generator state.
Definition trace.h:57
size_t read_at
Read-ahead cursor.
Definition trace.h:62
uint32_t hot
Stateful hot-window base.
Definition trace.h:61
uint8_t read_buffer[k_cb_trace_read_capacity]
Bounded read-ahead.
Definition trace.h:64
uint64_t index
Accesses emitted.
Definition trace.h:56
const char * name
Stable display name.
Definition trace.h:43
cb_trace_kind_t kind
Generator/parser selection.
Definition trace.h:46
cb_source_t source
Captured source binding, when selected.
Definition trace.h:47
uint64_t fingerprint
Bound captured-content fingerprint.
Definition trace.h:48
char name_storage[k_cb_trace_name_capacity]
Captured-name copy.
Definition trace.h:50
uint64_t n
Valid access count.
Definition trace.h:44
static bool internal_parse_trace_line(const char *line, uint32_t *object_id, uint32_t *page)
Parse one captured decimal object/page record.
Definition trace.c:237
static uint64_t internal_rng(uint64_t *state)
Advance a deterministic trace pseudo-random generator.
Definition trace.c:74
cb_io_status_t cb_trace_cursor_next(cb_trace_cursor_t *cursor, cb_key_t *key, bool *done)
Emit the next key.
Definition trace.c:438
cb_trace_seed_t
Definition trace.c:50
@ k_rng_seed_mixed_a
Mixed hot-phase seed.
Definition trace.c:54
@ k_rng_seed_mixed_b
Mixed scan-phase seed.
Definition trace.c:55
@ k_rng_seed_toc
Jump workload seed.
Definition trace.c:53
@ k_rng_seed_reread
Reread workload seed.
Definition trace.c:52
@ k_rng_seed_random
Random workload seed.
Definition trace.c:51
@ k_cb_hash_prime
FNV-1a multiplication.
Definition trace.c:57
@ k_cb_hash_offset
FNV-1a offset basis.
Definition trace.c:56
static uint32_t internal_rand_below(uint64_t *state, uint32_t span)
Select a deterministic pseudo-random value below a bound.
Definition trace.c:101
cb_io_status_t cb_trace_cursor_finish(const cb_trace_cursor_t *cursor)
Validate a captured pass against its bound count and fingerprint.
Definition trace.c:459
static cb_io_status_t internal_trace_captured_next(cb_trace_cursor_t *cursor, cb_key_t *key, bool *done)
Emit the next key from a captured decimal trace.
Definition trace.c:286
static cb_io_status_t internal_trace_read_byte(cb_trace_cursor_t *cursor, uint8_t *out, bool *eof)
Pull one byte through the captured-source read-ahead buffer.
Definition trace.c:190
cb_io_status_t cb_trace_cursor_open(const cb_trace_t *trace, cb_trace_cursor_t *cursor)
Reset a cursor for an independent pass over a trace.
Definition trace.c:418
static cb_key_t internal_trace_synthetic_next(cb_trace_cursor_t *cursor)
Emit one key from the selected synthetic workload generator.
Definition trace.c:366
static cb_key_t internal_trace_scan_key(uint64_t index, bool huge)
Generate one scan-resistant hot-set-plus-scan workload key.
Definition trace.c:334
cb_workload_dim_t
Definition trace.c:22
@ k_cb_mixed_phase
Accesses per mixed phase.
Definition trace.c:35
@ k_cb_obj_book
Synthetic book object key.
Definition trace.c:23
@ k_cb_tile_span
Scroll workload page span.
Definition trace.c:30
@ k_cb_pct_full
Complete percentage denominator.
Definition trace.c:34
@ k_cb_sr_hot_pass
Hot passes per scan-resistant run.
Definition trace.c:32
@ k_cb_footprint
Ordinary working-set pages.
Definition trace.c:25
@ k_cb_huge_hot_pass
Huge workload hot passes.
Definition trace.c:38
@ k_cb_huge_scan
Huge workload scan pages.
Definition trace.c:39
@ k_cb_huge_footprint
Huge workload working-set pages.
Definition trace.c:36
@ k_cb_accesses
Ordinary workload access count.
Definition trace.c:26
@ k_cb_obj_comic
Synthetic comic object key.
Definition trace.c:24
@ k_cb_reread_pct
Reread hot-set percentage.
Definition trace.c:28
@ k_cb_sr_scan
Scan pages per resistant run.
Definition trace.c:33
@ k_cb_hot_pages
Ordinary reread hot-set pages.
Definition trace.c:27
@ k_cb_jump_pct
Random-jump percentage.
Definition trace.c:29
@ k_cb_sr_hot
Scan-resistant hot-set pages.
Definition trace.c:31
@ k_cb_huge_hot
Huge workload hot-set pages.
Definition trace.c:37
cb_trace_math_t
Definition trace.c:42
@ k_rng_shift_a
First xorshift distance.
Definition trace.c:43
@ k_cb_key_high_shift
Object-key high-word shift.
Definition trace.c:47
@ k_cb_base_dec
Captured decimal parser radix.
Definition trace.c:46
@ k_rng_shift_b
Middle xorshift distance.
Definition trace.c:44
@ k_rng_shift_c
Final xorshift distance.
Definition trace.c:45
static uint64_t internal_trace_hash(uint64_t hash, cb_key_t key)
Fold one cache key into the captured-trace fingerprint.
Definition trace.c:122
cb_io_status_t cb_trace_bind(const cb_source_t *source, const char *name, size_t name_length, cb_trace_t *out)
Validate and bind one captured decimal <object> <page> source.
Definition trace.c:473
void cb_traces_synthetic(cb_trace_t out[k_cb_synthetic_trace_count])
Populate the fixed built-in corpus without acquiring storage.
Definition trace.c:141
Resettable, allocation-free access streams for cache_bench.
@ k_cb_trace_name_capacity
Captured trace display-name bound.
Definition trace.h:23
@ k_cb_synthetic_trace_count
Fixed corpus size.
Definition trace.h:22
cb_trace_kind_t
Workload implementation selected by a trace descriptor.
Definition trace.h:29
@ k_cb_trace_seq
Sequential page walk.
Definition trace.h:30
@ k_cb_trace_mixed
Alternating access phases.
Definition trace.h:37
@ k_cb_trace_reread
Hot-set reread workload.
Definition trace.h:32
@ k_cb_trace_scroll
Repeated scrolling window.
Definition trace.h:34
@ k_cb_trace_huge
Oversized hot-set and scan.
Definition trace.h:36
@ k_cb_trace_captured
Caller-injected captured accesses.
Definition trace.h:38
@ k_cb_trace_scan
Hot-set plus streaming scan.
Definition trace.h:35
@ k_cb_trace_jumps
Mostly sequential with jumps.
Definition trace.h:33
@ k_cb_trace_random
Uniform pseudo-random accesses.
Definition trace.h:31