ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
sweep_block_report.c
Go to the documentation of this file.
1
21#include <stdio.h>
22#include <string.h>
23
25
27static const double s_cbs_pct_f = 100.0;
29static const double s_cbs_mib_f = 1048576.0;
31static const double s_cbs_ns_per_s_f = 1000000000.0;
33static const double s_cbs_ns_per_us_f = 1000.0;
34
38{
39 if ((r == nullptr) || (r->reads == 0U)) {
40 return 0;
41 }
42 const uint64_t wall = (r->wall_ns == 0U) ? 1U : r->wall_ns;
43 const double mib_s =
44 ((double)r->reads * (double)k_cbs_req_bytes / s_cbs_mib_f) / ((double)wall / s_cbs_ns_per_s_f);
45 return (cb_sink_format(
46 sink,
47 "sweep-block backend=%s leg=%s block=%u frames=%u reads=%llu hits=%llu "
48 "misses=%llu evictions=%llu backend_calls=%llu backend_bytes=%llu "
49 "src_bytes=%llu backing_bytes=%llu wall_us=%llu mib_s=%.1f ns_per_read=%.1f\n",
50 r->backend,
51 r->leg,
52 r->block_bytes,
53 r->frames,
54 (unsigned long long)r->reads,
55 (unsigned long long)r->hits,
56 (unsigned long long)r->misses,
57 (unsigned long long)r->evictions,
58 (unsigned long long)r->be_calls,
59 (unsigned long long)r->be_bytes,
60 (unsigned long long)r->src_bytes,
61 (unsigned long long)r->backing_bytes,
62 (unsigned long long)(wall / (uint64_t)k_cbs_ns_per_us),
63 mib_s,
64 (double)wall / (double)r->reads) == k_cb_io_ok)
65 ? 0
66 : 1;
67}
68
89static void internal_block_label(uint32_t block, char* out, size_t cap)
90{
91 if ((out == nullptr) || (cap == 0U)) {
92 return;
93 }
94 if (block >= (uint32_t)k_cbs_kib) {
95 (void)snprintf(out, cap, "%uK", block / (uint32_t)k_cbs_kib);
96 } else {
97 (void)snprintf(out, cap, "%uB", block);
98 }
99}
100
103static const cbs_row_t* internal_find_row(const cbs_row_t* rows,
104 uint32_t n,
105 const char* be,
106 const char* leg,
107 uint32_t block)
108{
109 if ((rows == nullptr) || (be == nullptr) || (leg == nullptr)) {
110 return nullptr;
111 }
112 for (uint32_t i = 0U; i < n; ++i) {
113 if ((rows[i].block_bytes == block) && (strcmp(rows[i].backend, be) == 0) &&
114 (strcmp(rows[i].leg, leg) == 0)) {
115 return &rows[i];
116 }
117 }
118 return nullptr;
119}
120
143static double internal_row_mibs(const cbs_row_t* r)
144{
145 if ((r == nullptr) || (r->reads == 0U)) {
146 return 0.0;
147 }
148 const uint64_t wall = (r->wall_ns == 0U) ? 1U : r->wall_ns;
149 return ((double)r->reads * (double)k_cbs_req_bytes / s_cbs_mib_f) /
150 ((double)wall / s_cbs_ns_per_s_f);
151}
152
156 const cbs_row_t* rows,
157 uint32_t nrows,
158 const char* be,
159 const uint32_t* blocks,
160 uint32_t nblocks)
161{
162 if ((cb_sink_format(sink, "\n### `%s` -- sequential whole-object scan (leg a)\n\n", be) !=
163 k_cb_io_ok) ||
164 (cb_sink_format(sink,
165 "| block | frames | MiB/s | ns/read | est us/miss | backend calls | "
166 "src MiB | backing MiB |\n") != k_cb_io_ok) ||
167 (cb_sink_format(sink,
168 "|------:|-------:|------:|--------:|------------:|--------------:|"
169 "--------:|------------:|\n") != k_cb_io_ok)) {
170 return 1;
171 }
172 for (uint32_t i = 0U; i < nblocks; ++i) {
173 const cbs_row_t* s = internal_find_row(rows, nrows, be, "seq", blocks[i]);
174 const cbs_row_t* h = internal_find_row(rows, nrows, be, "hot", blocks[i]);
175 if ((s == nullptr) || (h == nullptr) || (s->reads == 0U) || (h->reads == 0U)) {
176 continue;
177 }
178 const double hit_ns = (double)h->wall_ns / (double)h->reads;
179 double miss_ns = (double)s->wall_ns - (hit_ns * (double)s->reads);
180 miss_ns = (s->misses == 0U) ? 0.0 : (miss_ns / (double)s->misses);
181 if (miss_ns < 0.0) {
182 miss_ns = 0.0;
183 }
184 char label[16] = {};
185 internal_block_label(blocks[i], label, sizeof(label));
186 if (cb_sink_format(sink,
187 "| %5s | %6u | %5.0f | %7.1f | %11.1f | %13llu | %7.2f | %11.2f |\n",
188 label,
189 s->frames,
191 (double)s->wall_ns / (double)s->reads,
192 miss_ns / s_cbs_ns_per_us_f,
193 (unsigned long long)s->be_calls,
194 (double)s->src_bytes / s_cbs_mib_f,
195 (double)s->backing_bytes / s_cbs_mib_f) != k_cb_io_ok) {
196 return 1;
197 }
198 }
199 return 0;
200}
201
205 const cbs_row_t* rows,
206 uint32_t nrows,
207 const char* be,
208 const uint32_t* blocks,
209 uint32_t nblocks)
210{
211 if ((cb_sink_format(sink, "\n### `%s` -- same-block re-read (leg b, pure hit path)\n\n", be) !=
212 k_cb_io_ok) ||
213 (cb_sink_format(sink, "| block | ns/read | hits | misses |\n") != k_cb_io_ok) ||
214 (cb_sink_format(sink, "|------:|--------:|-----:|-------:|\n") != k_cb_io_ok)) {
215 return 1;
216 }
217 for (uint32_t i = 0U; i < nblocks; ++i) {
218 const cbs_row_t* h = internal_find_row(rows, nrows, be, "hot", blocks[i]);
219 if ((h == nullptr) || (h->reads == 0U)) {
220 continue;
221 }
222 char label[16] = {};
223 internal_block_label(blocks[i], label, sizeof(label));
224 if (cb_sink_format(sink,
225 "| %5s | %7.1f | %llu | %6llu |\n",
226 label,
227 (double)h->wall_ns / (double)h->reads,
228 (unsigned long long)h->hits,
229 (unsigned long long)h->misses) != k_cb_io_ok) {
230 return 1;
231 }
232 }
233 return 0;
234}
235
244typedef struct {
245 double peak_mibs;
246 uint32_t peak_block;
247 double knee_mibs;
248 uint32_t knee_block;
249} cbs_knee_t;
250
278static bool internal_find_knee(const cbs_row_t* rows,
279 uint32_t nrows,
280 const uint32_t* blocks,
281 uint32_t nblocks,
282 cbs_knee_t* out)
283{
284 if ((out == nullptr) || (blocks == nullptr)) {
285 return false;
286 }
287 *out = (cbs_knee_t){};
288 for (uint32_t i = 0U; i < nblocks; ++i) {
289 const cbs_row_t* s = internal_find_row(rows, nrows, "rbkc-z9", "seq", blocks[i]);
290 const double m = internal_row_mibs(s);
291 if (m > out->peak_mibs) {
292 out->peak_mibs = m;
293 out->peak_block = blocks[i];
294 }
295 }
296 if (out->peak_mibs <= 0.0) {
297 return false;
298 }
299 const double bar = out->peak_mibs * ((double)k_cbs_knee_pct / s_cbs_pct_f);
300 out->knee_block = out->peak_block;
301 out->knee_mibs = out->peak_mibs;
302 for (uint32_t i = 0U; i < nblocks; ++i) {
303 const cbs_row_t* s = internal_find_row(rows, nrows, "rbkc-z9", "seq", blocks[i]);
304 const double m = internal_row_mibs(s);
305 if (m >= bar) {
306 out->knee_block = blocks[i];
307 out->knee_mibs = m;
308 break;
309 }
310 }
311 return true;
312}
313
335 const cbs_knee_t* knee,
336 const char* knee_label,
337 const char* default_label,
338 double knee_pct)
339{
340 if (knee->knee_block == (uint32_t)k_cbs_default_chunk) {
341 return (cb_sink_format(sink,
342 "The measured knee lands on the current %s `.rabook` chunk default "
343 "(#204): keep it.\n",
344 default_label) == k_cb_io_ok)
345 ? 0
346 : 1;
347 }
348 if (knee->knee_block < (uint32_t)k_cbs_default_chunk) {
349 return (cb_sink_format(sink,
350 "The knee sits BELOW the current %s default: %s already reaches "
351 "%.1f%% of peak on this backend, at a smaller per-miss inflate "
352 "latency and less RAM per frame.\n",
353 default_label,
354 knee_label,
355 knee_pct) == k_cb_io_ok)
356 ? 0
357 : 1;
358 }
359 return (cb_sink_format(sink,
360 "The knee sits ABOVE the current %s default: sequential throughput "
361 "is still climbing past it; consider a larger chunk if per-miss "
362 "latency allows.\n",
363 default_label) == k_cb_io_ok)
364 ? 0
365 : 1;
366}
367
371 const cbs_row_t* rows,
372 uint32_t nrows,
373 const uint32_t* blocks,
374 uint32_t nblocks)
375{
376 cbs_knee_t k = {};
377 if (!internal_find_knee(rows, nrows, blocks, nblocks, &k)) {
378 return (cb_sink_format(sink, "\n(no rbkc-z9 sequential rows; crossover not computed)\n") ==
380 ? 0
381 : 1;
382 }
383 const double knee_pct = s_cbs_pct_f * k.knee_mibs / k.peak_mibs;
384 char peak_l[16] = {};
385 char knee_l[16] = {};
386 char def_l[16] = {};
387 internal_block_label(k.peak_block, peak_l, sizeof(peak_l));
388 internal_block_label(k.knee_block, knee_l, sizeof(knee_l));
389 internal_block_label((uint32_t)k_cbs_default_chunk, def_l, sizeof(def_l));
390 if ((cb_sink_format(sink, "\n### Measured crossover (rbkc-z9, sequential)\n\n") != k_cb_io_ok) ||
391 (cb_sink_format(sink,
392 "Peak %.0f MiB/s at %s; knee (first size within %u%% of peak) at %s "
393 "(%.0f MiB/s, %.1f%% of peak).\n",
394 k.peak_mibs,
395 peak_l,
396 (unsigned)k_cbs_knee_pct,
397 knee_l,
398 k.knee_mibs,
399 knee_pct) != k_cb_io_ok)) {
400 return 1;
401 }
402 if (internal_print_verdict(sink, &k, knee_l, def_l, knee_pct) != 0) {
403 return 1;
404 }
405 return (cb_sink_format(sink,
406 "Caveat: these are host numbers -- per-request cost here is only the "
407 "chunk lookup + zlib stream setup. SD-over-SPI adds real per-command "
408 "overhead (CMD17 loops, #202), which pushes the knee toward larger "
409 "blocks; the hardware leg of #208 must re-run this sweep on the bench "
410 "before shrinking the chunk size below the default.\n") == k_cb_io_ok)
411 ? 0
412 : 1;
413}
cb_io_status_t cb_sink_format(cb_sink_t *sink, const char *format,...)
Format one bounded record and publish it atomically to the sink seam.
@ k_cb_io_ok
Operation completed.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
Injected output sink.
The computed crossover of the chunked backend's sequential sweep.
double peak_mibs
Best sequential throughput seen.
uint32_t peak_block
Size achieving the peak.
double knee_mibs
Throughput at the knee.
uint32_t knee_block
Smallest size within the knee bar.
One measured (backend, leg, block size) result row.
uint64_t evictions
ra8_vmem evictions.
const char * leg
Workload leg: "seq" or "hot".
uint64_t reads
Reader requests issued.
uint64_t backing_bytes
On-medium backing size at this block size.
uint32_t frames
Cache frames at this size (budget / block).
uint64_t wall_ns
Wall-clock time of the timed loop, in ns.
uint64_t be_calls
Backend read calls (storage commands).
uint32_t block_bytes
Swept block / frame / chunk size in bytes.
uint64_t be_bytes
Bytes delivered to the cache by the backend.
uint64_t misses
ra8_vmem misses.
const char * backend
Backend name (cbs_backend_t.name).
uint64_t hits
ra8_vmem hits.
uint64_t src_bytes
Raw medium bytes moved (compressed for RBKC).
Module-private seams shared by the #208 sweep translation units.
@ k_cbs_ns_per_us
Nanoseconds per microsecond.
@ k_cbs_kib
Bytes per KiB (block-size labels).
@ k_cbs_knee_pct
%% of peak throughput that names the knee.
@ k_cbs_default_chunk
#204 .rabook chunk-size default.
@ k_cbs_req_bytes
Reader request grain (divides every size).
RA8_PRIV int priv_print_seq_table(cb_sink_t *sink, const cbs_row_t *rows, uint32_t nrows, const char *be, const uint32_t *blocks, uint32_t nblocks)
Implementation of priv_print_seq_table() – Ch 23.2 miss-cost split.
static const double s_cbs_ns_per_s_f
Nanoseconds per second as a double, for throughput maths.
static RA8_INTERNAL void internal_block_label(uint32_t block, char *out, size_t cap)
Format a block size as a short label ("512B", "64K") into out.
static const double s_cbs_mib_f
Bytes per MiB as a double, for throughput maths.
RA8_PRIV int priv_print_crossover(cb_sink_t *sink, const cbs_row_t *rows, uint32_t nrows, const uint32_t *blocks, uint32_t nblocks)
Implementation of priv_print_crossover() – knee verdict prose.
static RA8_INTERNAL double internal_row_mibs(const cbs_row_t *r)
Delivered-payload throughput of a row in MiB/s.
RA8_PRIV int priv_print_hot_table(cb_sink_t *sink, const cbs_row_t *rows, uint32_t nrows, const char *be, const uint32_t *blocks, uint32_t nblocks)
Implementation of priv_print_hot_table() – pure hit-path table.
static RA8_INTERNAL bool internal_find_knee(const cbs_row_t *rows, uint32_t nrows, const uint32_t *blocks, uint32_t nblocks, cbs_knee_t *out)
Locate the rbkc-z9 sequential throughput peak and knee.
RA8_PRIV int priv_print_row(cb_sink_t *sink, const cbs_row_t *r)
Implementation of priv_print_row() – one key=value line.
static RA8_INTERNAL int internal_print_verdict(cb_sink_t *sink, const cbs_knee_t *knee, const char *knee_label, const char *default_label, double knee_pct)
Publish the knee/default relationship as one bounded paragraph.
static const double s_cbs_ns_per_us_f
Nanoseconds per microsecond as a double, for latency maths.
static RA8_INTERNAL const cbs_row_t * internal_find_row(const cbs_row_t *rows, uint32_t n, const char *be, const char *leg, uint32_t block)
Find the row for (backend, leg, block), or NULL.
static const double s_cbs_pct_f
100.0 as a double, for percentage maths.