Debugger: Add cache statistics command

Add `info cache` command that reports cache usage and cumulative hit
rates for glyph, CG, and archive data.
This commit is contained in:
kichikuou
2026-09-06 14:02:03 +09:00
parent b7854aaec1
commit 98e9d8bcfb
10 changed files with 99 additions and 2 deletions
+4
View File
@@ -148,3 +148,7 @@ int ald_get_maxno(DRIFILETYPE type) {
return 0;
return dri[type]->maxno;
}
CacheStats ald_get_cache_stats(void) {
return cache_get_stats(dri_cache);
}
+2 -1
View File
@@ -25,6 +25,7 @@
#define __ALD_MANAGER__
#include "portab.h"
#include "cache.h"
#include "dri.h"
#define DRIFILETYPEMAX 7
@@ -44,6 +45,6 @@ bool ald_exists(DRIFILETYPE type, int no);
dridata *ald_getdata(DRIFILETYPE type, int no);
void ald_freedata(dridata *data);
int ald_get_maxno(DRIFILETYPE type);
CacheStats ald_get_cache_stats(void);
#endif /* !__ALD_MANAGER__ */
+18 -1
View File
@@ -41,6 +41,8 @@ struct Cache {
size_t capacity;
size_t size;
size_t count;
size_t hits;
size_t misses;
};
static bool is_pinned(const Cache *cache, const CacheEntry *entry) {
@@ -112,8 +114,11 @@ void *cache_get(Cache *cache, const void *key) {
if (!cache || !key)
return NULL;
CacheEntry *entry = find_entry(cache, key, cache->ops.hash(key));
if (!entry)
if (!entry) {
cache->misses++;
return NULL;
}
cache->hits++;
lru_remove(cache, entry);
lru_prepend(cache, entry);
return entry->data;
@@ -176,3 +181,15 @@ size_t cache_clear(Cache *cache) {
}
return cache->count;
}
CacheStats cache_get_stats(const Cache *cache) {
if (!cache)
return (CacheStats){0};
return (CacheStats){
.count = cache->count,
.size = cache->size,
.capacity = cache->capacity,
.hits = cache->hits,
.misses = cache->misses,
};
}
+11
View File
@@ -40,6 +40,14 @@ typedef enum {
CACHE_INSERT_NOMEM,
} CacheInsertResult;
typedef struct {
size_t count;
size_t size;
size_t capacity;
size_t hits;
size_t misses;
} CacheStats;
Cache *cache_new(size_t capacity, const CacheOps *ops);
void cache_destroy(Cache *cache);
@@ -55,4 +63,7 @@ bool cache_remove(Cache *cache, const void *key);
/* Removes all unpinned entries and returns the number of entries left. */
size_t cache_clear(Cache *cache);
/* Returns zero-filled statistics when cache is NULL. */
CacheStats cache_get_stats(const Cache *cache);
#endif /* XSYSTEM35_CACHE_H */
+20
View File
@@ -64,14 +64,27 @@ void cache_test(void) {
Cache *cache = cache_new(2, &ops);
ASSERT_TRUE(cache);
destroyed = 0;
CacheStats stats = cache_get_stats(cache);
ASSERT_EQUAL(stats.count, 0);
ASSERT_EQUAL(stats.size, 0);
ASSERT_EQUAL(stats.capacity, 2);
ASSERT_EQUAL(stats.hits, 0);
ASSERT_EQUAL(stats.misses, 0);
// A lookup makes k1 most-recently used, so inserting k3 evicts k2.
int k1 = 1, k2 = 2, k3 = 3, k4 = 4, k5 = 5;
ASSERT_EQUAL(cache_insert(cache, &k1, new_value(1), 1), CACHE_INSERT_OK);
ASSERT_EQUAL(cache_insert(cache, &k2, new_value(2), 1), CACHE_INSERT_OK);
stats = cache_get_stats(cache);
ASSERT_EQUAL(stats.count, 2);
ASSERT_EQUAL(stats.size, 2);
ASSERT_EQUAL(stats.capacity, 2);
ASSERT_EQUAL(((TestValue *)cache_get(cache, &k1))->value, 1);
ASSERT_EQUAL(cache_insert(cache, &k3, new_value(3), 1), CACHE_INSERT_OK);
ASSERT_NULL(cache_get(cache, &k2));
stats = cache_get_stats(cache);
ASSERT_EQUAL(stats.hits, 1);
ASSERT_EQUAL(stats.misses, 1);
// Pinned entries survive both capacity eviction and cache_clear().
((TestValue *)cache_get(cache, &k1))->pinned = true;
@@ -94,4 +107,11 @@ void cache_test(void) {
ASSERT_EQUAL(cache_clear(cache), 0);
ASSERT_EQUAL(destroyed, 4);
cache_destroy(cache);
stats = cache_get_stats(NULL);
ASSERT_EQUAL(stats.count, 0);
ASSERT_EQUAL(stats.size, 0);
ASSERT_EQUAL(stats.capacity, 0);
ASSERT_EQUAL(stats.hits, 0);
ASSERT_EQUAL(stats.misses, 0);
}
+4
View File
@@ -354,6 +354,10 @@ void cg_reset(void) {
memset(&loc_where0, 0, sizeof(loc_where0));
}
CacheStats cg_get_cache_stats(void) {
return cache_get_stats(cg_cache);
}
/*
* Set cg display location
* x : display location x
+2
View File
@@ -25,6 +25,7 @@
#define __CG__
#include <SDL_rect.h>
#include "cache.h"
#include "portab.h"
struct SDL_Surface;
@@ -88,6 +89,7 @@ extern void cgdata_free(cgdata *cg);
extern struct SDL_Surface *cg_load_as_sdlsurface(int no);
struct SDL_Surface *cg_load_as_sdlsurface_from_data(uint8_t *data, size_t size, bool mosaic, bool as_alpha);
extern void load_censor_list(const char *path);
extern CacheStats cg_get_cache_stats(void);
extern int cg_vspPB;
extern int cg_fflg;
+32
View File
@@ -23,6 +23,9 @@
#include "debugger.h"
#include "debugger_private.h"
#include "debug_symbol.h"
#include "ald_manager.h"
#include "cg.h"
#include "font.h"
#include "nact.h"
#include "variable.h"
#ifdef HAVE_SIGACTION
@@ -207,6 +210,34 @@ static const char * const help_help = NULL;
static CommandResult cmd_help(void);
static const char desc_info[] = "Print information about the program.";
static const char help_info[] =
"Syntax: info cache\n"
"\n"
"Displays usage and lookup statistics for each cache.";
static void print_cache_stats(const char *name, CacheStats stats) {
size_t lookups = stats.hits + stats.misses;
double hit_rate = lookups ? 100.0 * stats.hits / lookups : 0.0;
printf("%-8s %8zu %12zu %12zu %8zu %8zu %8.1f%%\n",
name, stats.count, stats.size, stats.capacity,
stats.hits, stats.misses, hit_rate);
}
static CommandResult cmd_info(void) {
char *arg = strtok(NULL, whitespaces);
if (!arg || strcmp(arg, "cache") || strtok(NULL, whitespaces)) {
puts(help_info);
return CONTINUE_REPL;
}
puts("Cache Entries Size Capacity Hits Misses Hit rate");
print_cache_stats("Glyph", font_get_cache_stats());
print_cache_stats("CG", cg_get_cache_stats());
print_cache_stats("Archive", ald_get_cache_stats());
return CONTINUE_REPL;
}
static const char desc_list[] = "List specified function or line.";
static const char help_list[] =
"Syntax: list\n"
@@ -361,6 +392,7 @@ const Command dbg_cui_commands[] = {
{"continue", "c", desc_continue, help_continue, cmd_continue},
{"delete", "d", desc_delete, help_delete, cmd_delete},
{"help", "h", desc_help, help_help, cmd_help},
{"info", "i", desc_info, help_info, cmd_info},
{"list", "l", desc_list, help_list, cmd_list},
{"step", "s", desc_step, help_step, cmd_step},
{"finish", NULL, desc_finish, help_finish, cmd_finish},
+4
View File
@@ -416,6 +416,10 @@ bool font_get_antialias(void) {
return this.antialiase_on;
}
CacheStats font_get_cache_stats(void) {
return cache_get_stats(glyph_cache);
}
#ifdef __EMSCRIPTEN__
EM_ASYNC_JS(bool, load_mincho_font, (void), {
return await xsystem35.load_mincho_font();
+2
View File
@@ -25,6 +25,7 @@
#define __FONT_H__
#include <SDL_surface.h>
#include "cache.h"
#include "config.h"
#include "portab.h"
@@ -55,6 +56,7 @@ extern void font_measure_text(FontSpec spec, const char *str_utf8, int len, bool
// Rows by which a rendered surface extends above the character cell. Subtract
// it from a Y coordinate that denotes the cell top before blitting.
extern int font_cell_overhang(FontSpec spec);
extern CacheStats font_get_cache_stats(void);
#ifdef __EMSCRIPTEN__
extern bool load_mincho_font(void);