From 53b5eeb2560802cca78940531c674d38d7f772eb Mon Sep 17 00:00:00 2001 From: Toby Jaffey Date: Mon, 15 Dec 2025 14:10:49 +0000 Subject: [PATCH] Add a simple statistical profiler Enabled by -p, will sample program counter and store frequency. Using "-i 1" will make execution pause on every instruction and sample PC. host-sdl -p -i 1 foo.bin | grep times > log.txt cat log.txt | sort -n -k4 Can match addresses with riscv64-elf-objdump -S -d -f foo.bin --- hosts/host-sdl/host-sdl.c | 44 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/hosts/host-sdl/host-sdl.c b/hosts/host-sdl/host-sdl.c index a305863..3752410 100644 --- a/hosts/host-sdl/host-sdl.c +++ b/hosts/host-sdl/host-sdl.c @@ -22,6 +22,8 @@ int HEIGHT = 200; #define WINDOW_WIDTH WIDTH*3 #define WINDOW_HEIGHT HEIGHT*3 +static uint32_t *profiling_data = NULL; + // circular buffer of keypresses, so vm code can read them as it's ready typedef struct { bool down; @@ -39,6 +41,29 @@ static int16_t audioBuffer[AUDIOBUFFER_LEN]; static int audioBufferWr = 0; static int audioBufferRd = 0; +void profiling_init(uvm32_state_t *vmst) { + profiling_data = malloc(sizeof(uint32_t) * UVM32_MEMORY_SIZE); + memset(profiling_data, 0x00, sizeof(uint32_t) * UVM32_MEMORY_SIZE); +} + +void profiling_update(uvm32_state_t *vmst) { + uint32_t pc_rel = uvm32_getProgramCounter(vmst) - 0x80000000; + if (pc_rel > UVM32_MEMORY_SIZE) { + // don't handle PC being in extram + printf("pc > memory size! %08x\n", pc_rel); + } else { + profiling_data[pc_rel] += 1; + } +} + +void profiling_dump(void) { + for (int i=0;i 0) { + printf("Addr %08x hit %d times\n", 0x80000000 + i, profiling_data[i]); + } + } +} + void key_enq(uint16_t scancode, bool down) { keyBuffer[keyBufferWr].scancode = scancode; keyBuffer[keyBufferWr].down = down; @@ -126,6 +151,7 @@ void usage(const char *name) { printf(" -h show help\n"); printf(" -i max instrs before requiring a syscall\n"); printf(" -e numbers of bytes for extram\n"); + printf(" -p enable profiling\n"); exit(1); } @@ -168,6 +194,7 @@ int main(int argc, char *argv[]) { SDL_Window *screen = NULL; SDL_Event event; SDL_Texture *render_target = NULL; + bool use_profiling = false; // memory for vmst is very large, so allocate vmst = (uvm32_state_t *)malloc(sizeof(uvm32_state_t)); @@ -177,7 +204,7 @@ int main(int argc, char *argv[]) { } // parse commandline args - while ((c = getopt(argc, argv, "hi:e:W:H:")) != -1) { + while ((c = getopt(argc, argv, "hi:e:W:H:p")) != -1) { switch(c) { case 'h': usage(argv[0]); @@ -197,6 +224,9 @@ int main(int argc, char *argv[]) { case 'H': HEIGHT = strtoll(optarg, NULL, 10); break; + case 'p': + use_profiling = true; + break; } } if (optind < argc) { @@ -261,6 +291,10 @@ int main(int argc, char *argv[]) { } SDL_ResumeAudioStreamDevice(stream); + if (use_profiling) { + profiling_init(vmst); + } + while (isrunning) { SDL_PollEvent(&event); @@ -280,6 +314,10 @@ int main(int argc, char *argv[]) { break; } + if (use_profiling) { + profiling_update(vmst); + } + total_instrs += uvm32_run(vmst, &evt, max_instrs_per_run); // num instructions before vm considered hung num_syscalls++; @@ -396,6 +434,10 @@ int main(int argc, char *argv[]) { printf("Executed total of %lu instructions and %lu syscalls\n", (unsigned long)total_instrs, (unsigned long)num_syscalls); + if (use_profiling) { + profiling_dump(); + } + free(rom); if (extram_buf != NULL) { free(extram_buf);