Browse Source
We recently introduced new plugin API for registration of discontinuity related callbacks. This change introduces a minimal plugin showcasing the new API. It simply counts the occurances of interrupts, exceptions and host calls per CPU and reports the counts when exitting. Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Julian Ganz <neither@nut.email> Message-ID: <20251027110344.2289945-11-alex.bennee@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>pull/307/head
committed by
Alex Bennée
3 changed files with 92 additions and 1 deletions
@ -0,0 +1,83 @@ |
|||
/*
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later |
|||
* Copyright (C) 2025, Julian Ganz <neither@nut.email> |
|||
* |
|||
* Traps - count traps |
|||
* |
|||
* Count the number of interrupts (asyncronous events), exceptions (synchronous |
|||
* events) and host calls (e.g. semihosting) per cpu and report those counts on |
|||
* exit. |
|||
*/ |
|||
|
|||
#include <stdio.h> |
|||
|
|||
#include <qemu-plugin.h> |
|||
|
|||
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; |
|||
|
|||
typedef struct { |
|||
uint64_t interrupts; |
|||
uint64_t exceptions; |
|||
uint64_t hostcalls; |
|||
} TrapCounters; |
|||
|
|||
static struct qemu_plugin_scoreboard *traps; |
|||
|
|||
static void vcpu_discon(qemu_plugin_id_t id, unsigned int vcpu_index, |
|||
enum qemu_plugin_discon_type type, uint64_t from_pc, |
|||
uint64_t to_pc) |
|||
{ |
|||
TrapCounters *rec = qemu_plugin_scoreboard_find(traps, vcpu_index); |
|||
switch (type) { |
|||
case QEMU_PLUGIN_DISCON_INTERRUPT: |
|||
rec->interrupts++; |
|||
break; |
|||
case QEMU_PLUGIN_DISCON_EXCEPTION: |
|||
rec->exceptions++; |
|||
break; |
|||
case QEMU_PLUGIN_DISCON_HOSTCALL: |
|||
rec->hostcalls++; |
|||
break; |
|||
default: |
|||
g_assert_not_reached(); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
static void plugin_exit(qemu_plugin_id_t id, void *p) |
|||
{ |
|||
g_autoptr(GString) report; |
|||
report = g_string_new("VCPU, interrupts, exceptions, hostcalls\n"); |
|||
int max_vcpus = qemu_plugin_num_vcpus(); |
|||
int vcpu; |
|||
|
|||
for (vcpu = 0; vcpu < max_vcpus; vcpu++) { |
|||
TrapCounters *rec = qemu_plugin_scoreboard_find(traps, vcpu); |
|||
g_string_append_printf(report, |
|||
"% 4d, % 10"PRId64", % 10"PRId64", % 10"PRId64 |
|||
"\n", vcpu, rec->interrupts, rec->exceptions, |
|||
rec->hostcalls); |
|||
} |
|||
|
|||
qemu_plugin_outs(report->str); |
|||
qemu_plugin_scoreboard_free(traps); |
|||
} |
|||
|
|||
QEMU_PLUGIN_EXPORT |
|||
int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, |
|||
int argc, char **argv) |
|||
{ |
|||
if (!info->system_emulation) { |
|||
qemu_plugin_outs("Note: interrupts are only reported in system" |
|||
" emulation mode."); |
|||
} |
|||
|
|||
traps = qemu_plugin_scoreboard_new(sizeof(TrapCounters)); |
|||
|
|||
qemu_plugin_register_vcpu_discon_cb(id, QEMU_PLUGIN_DISCON_ALL, |
|||
vcpu_discon); |
|||
|
|||
qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); |
|||
|
|||
return 0; |
|||
} |
|||
Loading…
Reference in new issue