From: falcovorbis <fal...@us...> - 2024-10-08 13:09:59
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 98018e6f51e2e7bf6ffe3274e6e8d94769860640 (commit) from d0f35280e58557ae330e5b00d013fb4cc77f1195 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 98018e6f51e2e7bf6ffe3274e6e8d94769860640 Author: Paul Cercueil <pa...@cr...> Date: Tue Oct 8 15:09:37 2024 +0200 kernel: Add performance monitor API (#795) Add a new performance monitor API, built on top of the performance counters API. The performance monitor API is started with perf_monitor_init(), which takes two performance events (perf_cntr_event_t) that will be monitored aside from the call count and the total time, and is stopped with perf_monitor_exit(). Then, a performance monitor can be added to any functional block using the perf_monitor() macro. The performance will be monitored from the moment the macro is called until the end of the functional block, and the execution statistics of each call will be summed to total numbers. Finally, perf_monitor_print() will display the collected information about the performance monitors. Signed-off-by: Paul Cercueil <pa...@cr...> ----------------------------------------------------------------------- Summary of changes: doc/CHANGELOG.md | 1 + kernel/arch/dreamcast/include/dc/perf_monitor.h | 96 +++++++++++++++++++++++++ kernel/arch/dreamcast/kernel/Makefile | 2 +- kernel/arch/dreamcast/kernel/perf_monitor.c | 63 ++++++++++++++++ utils/ldscripts/shlelf.xc | 8 +++ 5 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 kernel/arch/dreamcast/include/dc/perf_monitor.h create mode 100644 kernel/arch/dreamcast/kernel/perf_monitor.c diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 83a7aed1..f987f66f 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -8,6 +8,7 @@ Platform-specific changes are prefixed with the platform name, otherwise the cha - Replaced previous implementation of realpath() to remove license from AUTHORS [AB] - Enabled hybrid PVR DR/DMA vertex submission in driver + sped up pvr_prim() [FG] - Add thread priority boosting system [Paul Cercueil = PC] +- Add performance monitor API [PC] ## KallistiOS version 2.1.0 - Cleaned up generated stubs files on a make clean [Lawrence Sebald == LS] diff --git a/kernel/arch/dreamcast/include/dc/perf_monitor.h b/kernel/arch/dreamcast/include/dc/perf_monitor.h new file mode 100644 index 00000000..cdf20cdf --- /dev/null +++ b/kernel/arch/dreamcast/include/dc/perf_monitor.h @@ -0,0 +1,96 @@ +/* KallistiOS ##version## + + arch/dreamcast/include/dc/perf_monitor.h + * Copyright (C) 2024 Paul Cercueil + +*/ + +/** \file dc/perf_monitor.h + \brief Low-level performance monitor + \ingroup perf_monitor + + This file contains an API that can be used to monitor specific + performance events in one or several functional blocks. + + \author Paul Cercueil +*/ + +#ifndef __KOS_PERF_MONITOR_H +#define __KOS_PERF_MONITOR_H + +#include <sys/cdefs.h> +__BEGIN_DECLS + +#include <dc/perfctr.h> +#include <stdint.h> +#include <stdio.h> + +/** \defgroup perf_monitor Performance monitor + \brief Code performance monitor + \ingroup debugging + + The performance monitor API is built on top of the performance counter API, + and as such cannot be used at the same time. + With this API, programs can set probe points in different functional blocks + and later obtain statistics about the execution of said functional blocks. + + @{ +*/ + +/** /cond */ +struct perf_monitor { + const char *fn; + unsigned int line; + uint64_t calls; + uint64_t time_ns, time_start; + uint64_t event0, event0_start; + uint64_t event1, event1_start; +}; + +void __stop_perf_monitor(struct perf_monitor **monitor); + +struct perf_monitor *__start_perf_monitor(struct perf_monitor *monitor); + +#define __perf_monitor(f, l) \ + static struct perf_monitor __perf_monitor_##l \ + __attribute__((section(".monitors"))) = { f, l, }; \ + struct perf_monitor *___perf_monitor_##l \ + __attribute__((cleanup(__stop_perf_monitor))) = \ + __start_perf_monitor(&__perf_monitor_##l) + +#define _perf_monitor(f, l) __perf_monitor(f, l) +/** /endcond */ + +/** \brief Register a performance monitor in the current functional block + + The performance monitor will run from the moment this macro is used, till + the end of the functional block. +*/ +#define perf_monitor() _perf_monitor(__func__, __LINE__) + +/** \brief Initialize the performance monitor system + + Set up the performance monitor system. Note that using the performance + monitor system will conflict with any external usage of the performance + counter API. + + \param event1 The first event mode (pef_cntr_event_t). + \param event2 The second event mode (pef_cntr_event_t). +*/ +void perf_monitor_init(perf_cntr_event_t event1, perf_cntr_event_t event2); + +/** \brief De-initialize the performance monitor system + + After this function is called, the performance counter API can be + used again. +*/ +void perf_monitor_exit(void); + +/** \brief Print statistics about the probe points to the given file descriptor + \param f A valid file descriptor to which the messages will + be printed. Use "stdout" for the standard output. +*/ +void perf_monitor_print(FILE *f); + +__END_DECLS +#endif /* __KOS_PERF_MONITOR_H */ diff --git a/kernel/arch/dreamcast/kernel/Makefile b/kernel/arch/dreamcast/kernel/Makefile index 566efc80..7b202f44 100644 --- a/kernel/arch/dreamcast/kernel/Makefile +++ b/kernel/arch/dreamcast/kernel/Makefile @@ -10,7 +10,7 @@ # that minimum set must be present. COPYOBJS = banner.o cache.o entry.o irq.o init.o mm.o panic.o -COPYOBJS += rtc.o timer.o wdt.o perfctr.o +COPYOBJS += rtc.o timer.o wdt.o perfctr.o perf_monitor.o COPYOBJS += init_flags_default.o COPYOBJS += mmu.o itlb.o COPYOBJS += exec.o execasm.o stack.o gdb_stub.o thdswitch.o arch_exports.o diff --git a/kernel/arch/dreamcast/kernel/perf_monitor.c b/kernel/arch/dreamcast/kernel/perf_monitor.c new file mode 100644 index 00000000..bb596078 --- /dev/null +++ b/kernel/arch/dreamcast/kernel/perf_monitor.c @@ -0,0 +1,63 @@ +/* KallistiOS ##version## + + arch/dreamcast/kernel/perf_monitor.c + Copyright (C) 2024 Paul Cercueil +*/ + +#include <arch/timer.h> +#include <dc/perf_monitor.h> + +extern struct perf_monitor _monitors_start, _monitors_end; + +void __stop_perf_monitor(struct perf_monitor **monitor) { + struct perf_monitor *data = *monitor; + + data->event0 += perf_cntr_count(PRFC0) - data->event0_start; + data->event1 += perf_cntr_count(PRFC1) - data->event1_start; + data->time_ns += timer_ns_gettime64() - data->time_start; +} + +struct perf_monitor *__start_perf_monitor(struct perf_monitor *data) { + data->calls++; + data->time_start = timer_ns_gettime64(); + data->event0_start = perf_cntr_count(PRFC0); + data->event1_start = perf_cntr_count(PRFC1); + + return data; +} + +void perf_monitor_init(perf_cntr_event_t event1, perf_cntr_event_t event2) { + perf_cntr_timer_disable(); + + perf_cntr_clear(PRFC0); + perf_cntr_clear(PRFC1); + + perf_cntr_start(PRFC0, event1, PMCR_COUNT_CPU_CYCLES); + perf_cntr_start(PRFC1, event2, PMCR_COUNT_CPU_CYCLES); +} + +void perf_monitor_exit(void) { + perf_cntr_stop(PRFC0); + perf_cntr_stop(PRFC1); + + perf_cntr_clear(PRFC0); + perf_cntr_clear(PRFC1); + + perf_cntr_timer_enable(); +} + +void perf_monitor_print(FILE *f) { + struct perf_monitor *monitor; + + fprintf(f, "Performance monitors:\n"); + + for (monitor = &_monitors_start; monitor < &_monitors_end; monitor++) { + fprintf(f, "\t%s: %llu calls\n\t\t%llu ns (%f ns/call)\n\t\tevent 0: %llu (%f event/call)\n\t\tevent 1: %llu (%f event/call)\n", + monitor->fn, monitor->calls, monitor->time_ns, + monitor->calls ? (float)monitor->time_ns / (float)monitor->calls : 0.0f, + monitor->event0, + monitor->event0 ? (float)monitor->event0 / (float)monitor->calls : 0.0f, + monitor->event1, + monitor->event1 ? (float)monitor->event1 / (float)monitor->calls : 0.0f); + } +} diff --git a/utils/ldscripts/shlelf.xc b/utils/ldscripts/shlelf.xc index 907a1d9c..10358882 100644 --- a/utils/ldscripts/shlelf.xc +++ b/utils/ldscripts/shlelf.xc @@ -184,6 +184,14 @@ SECTIONS *(.sdata .sdata.* .gnu.linkonce.s.*) } _edata = .; PROVIDE (edata = .); + . = ALIGN(8); + __monitors_start = .; + .monitors : + { + *(.monitors) + } + __monitors_end = .; + . = ALIGN(8); __bss_start = .; .sbss : { hooks/post-receive -- A pseudo Operating System for the Dreamcast. |