From 62b8cc1ecb376f39df67590f8c82914b923a6f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 4 Apr 2025 16:40:31 +0200 Subject: [PATCH 01/17] hw/xen/arch_hvm: Unify x86 and ARM variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As each target declares the same prototypes, we can use a single header, removing the TARGET_XXX uses. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Stefano Stabellini Message-Id: <20250513171737.74386-1-philmd@linaro.org> --- include/hw/arm/xen_arch_hvm.h | 9 --------- include/hw/i386/xen_arch_hvm.h | 11 ----------- include/hw/xen/arch_hvm.h | 14 ++++++++++---- 3 files changed, 10 insertions(+), 24 deletions(-) delete mode 100644 include/hw/arm/xen_arch_hvm.h delete mode 100644 include/hw/i386/xen_arch_hvm.h diff --git a/include/hw/arm/xen_arch_hvm.h b/include/hw/arm/xen_arch_hvm.h deleted file mode 100644 index 8fd645e723..0000000000 --- a/include/hw/arm/xen_arch_hvm.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef HW_XEN_ARCH_ARM_HVM_H -#define HW_XEN_ARCH_ARM_HVM_H - -#include -void arch_handle_ioreq(XenIOState *state, ioreq_t *req); -void arch_xen_set_memory(XenIOState *state, - MemoryRegionSection *section, - bool add); -#endif diff --git a/include/hw/i386/xen_arch_hvm.h b/include/hw/i386/xen_arch_hvm.h deleted file mode 100644 index 1000f8f543..0000000000 --- a/include/hw/i386/xen_arch_hvm.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef HW_XEN_ARCH_I386_HVM_H -#define HW_XEN_ARCH_I386_HVM_H - -#include -#include "hw/xen/xen-hvm-common.h" - -void arch_handle_ioreq(XenIOState *state, ioreq_t *req); -void arch_xen_set_memory(XenIOState *state, - MemoryRegionSection *section, - bool add); -#endif diff --git a/include/hw/xen/arch_hvm.h b/include/hw/xen/arch_hvm.h index df39c819c8..8bacaa4ec4 100644 --- a/include/hw/xen/arch_hvm.h +++ b/include/hw/xen/arch_hvm.h @@ -1,5 +1,11 @@ -#if defined(TARGET_I386) || defined(TARGET_X86_64) -#include "hw/i386/xen_arch_hvm.h" -#elif defined(TARGET_ARM) || defined(TARGET_AARCH64) -#include "hw/arm/xen_arch_hvm.h" +#ifndef HW_XEN_ARCH_HVM_H +#define HW_XEN_ARCH_HVM_H + +#include +#include "hw/xen/xen-hvm-common.h" + +void arch_handle_ioreq(XenIOState *state, ioreq_t *req); +void arch_xen_set_memory(XenIOState *state, + MemoryRegionSection *section, + bool add); #endif From 187aad2896a3775941a9a02ce8d8a4a15970c1e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 4 Apr 2025 16:40:31 +0200 Subject: [PATCH 02/17] hw/arm/xen-pvh: Remove unnecessary 'hw/xen/arch_hvm.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "hw/xen/arch_hvm.h" only declares the arch_handle_ioreq() and arch_xen_set_memory() prototypes, which are not used by xen-pvh.c. Remove the unnecessary header inclusion. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Xiaoyao Li Reviewed-by: Manos Pitsidianakis Message-Id: <20250715071528.46196-1-philmd@linaro.org> --- hw/arm/xen-pvh.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/arm/xen-pvh.c b/hw/arm/xen-pvh.c index 4b26bcff7a..1a9eeb01c8 100644 --- a/hw/arm/xen-pvh.c +++ b/hw/arm/xen-pvh.c @@ -10,7 +10,6 @@ #include "hw/boards.h" #include "system/system.h" #include "hw/xen/xen-pvh-common.h" -#include "hw/xen/arch_hvm.h" #define TYPE_XEN_ARM MACHINE_TYPE_NAME("xenpvh") From 18da42ee4273a66f240bcca7aa4d8ce3b97b1a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 2 Jul 2025 14:44:11 +0200 Subject: [PATCH 03/17] qapi/accel: Move definitions related to accelerators in their own file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract KVM definitions from machine.json to accelerator.json. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Zhao Liu Message-Id: <20250703105540.67664-29-philmd@linaro.org> --- MAINTAINERS | 1 + hw/core/machine-hmp-cmds.c | 1 + hw/core/machine-qmp-cmds.c | 1 + qapi/accelerator.json | 39 ++++++++++++++++++++++++++++++++++++++ qapi/machine.json | 29 ---------------------------- qapi/meson.build | 1 + qapi/qapi-schema.json | 1 + 7 files changed, 44 insertions(+), 29 deletions(-) create mode 100644 qapi/accelerator.json diff --git a/MAINTAINERS b/MAINTAINERS index e88ed2c0a9..0e945f3bd2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -509,6 +509,7 @@ F: accel/Makefile.objs F: accel/stubs/Makefile.objs F: cpu-common.c F: cpu-target.c +F: qapi/accelerator.json F: system/cpus.c Apple Silicon HVF CPUs diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c index c6325cdcaa..5ca0da77b1 100644 --- a/hw/core/machine-hmp-cmds.c +++ b/hw/core/machine-hmp-cmds.c @@ -18,6 +18,7 @@ #include "monitor/monitor.h" #include "qapi/error.h" #include "qapi/qapi-builtin-visit.h" +#include "qapi/qapi-commands-accelerator.h" #include "qapi/qapi-commands-machine.h" #include "qobject/qdict.h" #include "qapi/string-output-visitor.h" diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index d82043e1c6..1af0f29f7d 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -14,6 +14,7 @@ #include "hw/mem/memory-device.h" #include "qapi/error.h" #include "qapi/qapi-builtin-visit.h" +#include "qapi/qapi-commands-accelerator.h" #include "qapi/qapi-commands-machine.h" #include "qobject/qobject.h" #include "qapi/qobject-input-visitor.h" diff --git a/qapi/accelerator.json b/qapi/accelerator.json new file mode 100644 index 0000000000..d55fe1aa0a --- /dev/null +++ b/qapi/accelerator.json @@ -0,0 +1,39 @@ +# -*- Mode: Python -*- +# vim: filetype=python +# +# SPDX-License-Identifier: GPL-2.0-or-later + +## +# = Accelerators +## + +{ 'include': 'common.json' } + +## +# @KvmInfo: +# +# Information about support for KVM acceleration +# +# @enabled: true if KVM acceleration is active +# +# @present: true if KVM acceleration is built into this executable +# +# Since: 0.14 +## +{ 'struct': 'KvmInfo', 'data': {'enabled': 'bool', 'present': 'bool'} } + +## +# @query-kvm: +# +# Return information about KVM acceleration +# +# Returns: @KvmInfo +# +# Since: 0.14 +# +# .. qmp-example:: +# +# -> { "execute": "query-kvm" } +# <- { "return": { "enabled": true, "present": true } } +## +{ 'command': 'query-kvm', 'returns': 'KvmInfo' } diff --git a/qapi/machine.json b/qapi/machine.json index f712e7da6d..f80ba264b5 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -451,35 +451,6 @@ ## { 'command': 'inject-nmi' } -## -# @KvmInfo: -# -# Information about support for KVM acceleration -# -# @enabled: true if KVM acceleration is active -# -# @present: true if KVM acceleration is built into this executable -# -# Since: 0.14 -## -{ 'struct': 'KvmInfo', 'data': {'enabled': 'bool', 'present': 'bool'} } - -## -# @query-kvm: -# -# Return information about KVM acceleration -# -# Returns: @KvmInfo -# -# Since: 0.14 -# -# .. qmp-example:: -# -# -> { "execute": "query-kvm" } -# <- { "return": { "enabled": true, "present": true } } -## -{ 'command': 'query-kvm', 'returns': 'KvmInfo' } - ## # @NumaOptionsType: # diff --git a/qapi/meson.build b/qapi/meson.build index 3b035aea33..ca6b61a608 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -57,6 +57,7 @@ qapi_all_modules = [ ] if have_system qapi_all_modules += [ + 'accelerator', 'acpi', 'audio', 'cryptodev', diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index a8f66163cb..0477696ff0 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -37,6 +37,7 @@ { 'include': 'run-state.json' } { 'include': 'crypto.json' } { 'include': 'job.json' } +{ 'include': 'accelerator.json' } { 'include': 'block.json' } { 'include': 'block-export.json' } { 'include': 'char.json' } From 6ca2eba6d3decff61a725c379876e18869521a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 15 Jul 2025 10:53:49 +0200 Subject: [PATCH 04/17] qapi/machine: Add @qom-type field to CpuInfoFast structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Knowing the QOM type name of a CPU can be useful, in particular to infer its model name. Reviewed-by: Richard Henderson Reviewed-by: Zhao Liu Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Xiaoyao Li Message-Id: <20250715090624.52377-2-philmd@linaro.org> --- hw/core/machine-qmp-cmds.c | 1 + qapi/machine.json | 3 +++ 2 files changed, 4 insertions(+) diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index 1af0f29f7d..b9e7eb64e0 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -48,6 +48,7 @@ CpuInfoFastList *qmp_query_cpus_fast(Error **errp) value->cpu_index = cpu->cpu_index; value->qom_path = object_get_canonical_path(OBJECT(cpu)); value->thread_id = cpu->thread_id; + value->qom_type = g_strdup(object_get_typename(OBJECT(cpu))); if (mc->cpu_index_to_instance_props) { CpuInstanceProperties *props; diff --git a/qapi/machine.json b/qapi/machine.json index f80ba264b5..6d3a480bea 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -76,6 +76,8 @@ # # @cpu-index: index of the virtual CPU # +# @qom-type: QOM type name of the CPU (since 10.1) +# # @qom-path: path to the CPU object in the QOM tree # # @thread-id: ID of the underlying host thread @@ -89,6 +91,7 @@ ## { 'union' : 'CpuInfoFast', 'base' : { 'cpu-index' : 'int', + 'qom-type' : 'str', 'qom-path' : 'str', 'thread-id' : 'int', '*props' : 'CpuInstanceProperties', From d6c73ac306a8fca6d98f91e447904c5149d56ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 19 Jun 2025 18:05:43 +0200 Subject: [PATCH 05/17] hw/core/machine: Display CPU model name in 'info cpus' command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display the CPU model in 'info cpus'. Example before: $ qemu-system-aarch64 -M xlnx-versal-virt -S -monitor stdio QEMU 10.0.0 monitor - type 'help' for more information (qemu) info cpus * CPU #0: thread_id=42924 CPU #1: thread_id=42924 CPU #2: thread_id=42924 CPU #3: thread_id=42924 (qemu) q and after: $ qemu-system-aarch64 -M xlnx-versal-virt -S -monitor stdio QEMU 10.0.50 monitor - type 'help' for more information (qemu) info cpus * CPU #0: thread_id=42916 model=cortex-a72 CPU #1: thread_id=42916 model=cortex-a72 CPU #2: thread_id=42916 model=cortex-r5f CPU #3: thread_id=42916 model=cortex-r5f (qemu) Reviewed-by: Richard Henderson Reviewed-by: Zhao Liu Tested-by: Zhao Liu Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Xiaoyao Li Message-Id: <20250715090624.52377-3-philmd@linaro.org> --- hw/core/machine-hmp-cmds.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c index 5ca0da77b1..3a612e2232 100644 --- a/hw/core/machine-hmp-cmds.c +++ b/hw/core/machine-hmp-cmds.c @@ -33,6 +33,7 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict) cpu_list = qmp_query_cpus_fast(NULL); for (cpu = cpu_list; cpu; cpu = cpu->next) { + g_autofree char *cpu_model = cpu_model_from_type(cpu->value->qom_type); int active = ' '; if (cpu->value->cpu_index == monitor_get_cpu_index(mon)) { @@ -41,7 +42,8 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%c CPU #%" PRId64 ":", active, cpu->value->cpu_index); - monitor_printf(mon, " thread_id=%" PRId64 "\n", cpu->value->thread_id); + monitor_printf(mon, " thread_id=%" PRId64 " model=%s\n", + cpu->value->thread_id, cpu_model); } qapi_free_CpuInfoFastList(cpu_list); From b2ed4df79e82a6c95feadbe6efefced7bbeb4db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 9 Jul 2025 16:14:59 +0200 Subject: [PATCH 06/17] accel/tcg: Do not dump NaN statistics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Manos Pitsidianakis Message-Id: <20250710111303.8917-1-philmd@linaro.org> --- accel/tcg/monitor.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c index e7ed7281a4..778b12613f 100644 --- a/accel/tcg/monitor.c +++ b/accel/tcg/monitor.c @@ -19,7 +19,7 @@ #include "tcg/tcg.h" #include "internal-common.h" #include "tb-context.h" - +#include static void dump_drift_info(GString *buf) { @@ -57,6 +57,7 @@ static void print_qht_statistics(struct qht_stats hst, GString *buf) uint32_t hgram_opts; size_t hgram_bins; char *hgram; + double avg; if (!hst.head_buckets) { return; @@ -73,9 +74,13 @@ static void print_qht_statistics(struct qht_stats hst, GString *buf) hgram_opts |= QDIST_PR_NODECIMAL; } hgram = qdist_pr(&hst.occupancy, 10, hgram_opts); - g_string_append_printf(buf, "TB hash occupancy %0.2f%% avg chain occ. " - "Histogram: %s\n", - qdist_avg(&hst.occupancy) * 100, hgram); + avg = qdist_avg(&hst.occupancy); + if (!isnan(avg)) { + g_string_append_printf(buf, "TB hash occupancy " + "%0.2f%% avg chain occ. " + "Histogram: %s\n", + avg * 100, hgram); + } g_free(hgram); hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS; @@ -87,9 +92,12 @@ static void print_qht_statistics(struct qht_stats hst, GString *buf) hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE; } hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts); - g_string_append_printf(buf, "TB hash avg chain %0.3f buckets. " - "Histogram: %s\n", - qdist_avg(&hst.chain), hgram); + avg = qdist_avg(&hst.chain); + if (!isnan(avg)) { + g_string_append_printf(buf, "TB hash avg chain %0.3f buckets. " + "Histogram: %s\n", + avg, hgram); + } g_free(hgram); } From 05927e9dc9371766d20c97ac609ec8698e95bb45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 3 Jul 2025 16:18:32 +0200 Subject: [PATCH 07/17] accel: Rename 'system/accel-ops.h' -> 'accel/accel-cpu-ops.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unfortunately "system/accel-ops.h" handlers are not only system-specific. For example, the cpu_reset_hold() hook is part of the vCPU creation, after it is realized. Mechanical rename to drop 'system' using: $ sed -i -e s_system/accel-ops.h_accel/accel-cpu-ops.h_g \ $(git grep -l system/accel-ops.h) Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Zhao Liu Reviewed-by: Richard Henderson Message-Id: <20250703173248.44995-38-philmd@linaro.org> --- accel/accel-system.c | 2 +- accel/hvf/hvf-accel-ops.c | 2 +- accel/kvm/kvm-accel-ops.c | 2 +- accel/qtest/qtest.c | 2 +- accel/tcg/tcg-accel-ops.c | 2 +- accel/xen/xen-all.c | 2 +- cpu-target.c | 2 +- gdbstub/system.c | 2 +- include/{system/accel-ops.h => accel/accel-cpu-ops.h} | 8 ++++---- system/cpus.c | 2 +- target/i386/nvmm/nvmm-accel-ops.c | 2 +- target/i386/whpx/whpx-accel-ops.c | 2 +- 12 files changed, 15 insertions(+), 15 deletions(-) rename include/{system/accel-ops.h => accel/accel-cpu-ops.h} (95%) diff --git a/accel/accel-system.c b/accel/accel-system.c index c54c30f18b..c2a955a6da 100644 --- a/accel/accel-system.c +++ b/accel/accel-system.c @@ -26,7 +26,7 @@ #include "qemu/osdep.h" #include "qemu/accel.h" #include "hw/boards.h" -#include "system/accel-ops.h" +#include "accel/accel-cpu-ops.h" #include "system/cpus.h" #include "qemu/error-report.h" #include "accel-internal.h" diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c index be8724ac89..214454bd0b 100644 --- a/accel/hvf/hvf-accel-ops.c +++ b/accel/hvf/hvf-accel-ops.c @@ -54,7 +54,7 @@ #include "gdbstub/enums.h" #include "exec/cpu-common.h" #include "hw/core/cpu.h" -#include "system/accel-ops.h" +#include "accel/accel-cpu-ops.h" #include "system/cpus.h" #include "system/hvf.h" #include "system/hvf_int.h" diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c index 0eafc902c3..b709187c7d 100644 --- a/accel/kvm/kvm-accel-ops.c +++ b/accel/kvm/kvm-accel-ops.c @@ -16,7 +16,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" -#include "system/accel-ops.h" +#include "accel/accel-cpu-ops.h" #include "system/kvm.h" #include "system/kvm_int.h" #include "system/runstate.h" diff --git a/accel/qtest/qtest.c b/accel/qtest/qtest.c index 2b83126020..a7fc8bee6d 100644 --- a/accel/qtest/qtest.c +++ b/accel/qtest/qtest.c @@ -18,7 +18,7 @@ #include "qemu/option.h" #include "qemu/config-file.h" #include "qemu/accel.h" -#include "system/accel-ops.h" +#include "accel/accel-cpu-ops.h" #include "system/qtest.h" #include "system/cpus.h" #include "qemu/guest-random.h" diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index 279dbfa1cf..58ded9d6f0 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -26,7 +26,7 @@ */ #include "qemu/osdep.h" -#include "system/accel-ops.h" +#include "accel/accel-cpu-ops.h" #include "system/tcg.h" #include "system/replay.h" #include "exec/icount.h" diff --git a/accel/xen/xen-all.c b/accel/xen/xen-all.c index bd0ff64bef..55a60bb42c 100644 --- a/accel/xen/xen-all.c +++ b/accel/xen/xen-all.c @@ -19,7 +19,7 @@ #include "chardev/char.h" #include "qemu/accel.h" #include "accel/dummy-cpus.h" -#include "system/accel-ops.h" +#include "accel/accel-cpu-ops.h" #include "system/cpus.h" #include "system/xen.h" #include "system/runstate.h" diff --git a/cpu-target.c b/cpu-target.c index 1c90a30759..2049eb1d0f 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "system/accel-ops.h" +#include "accel/accel-cpu-ops.h" #include "system/cpus.h" #include "exec/cpu-common.h" #include "exec/tswap.h" diff --git a/gdbstub/system.c b/gdbstub/system.c index 8a32d8e1a1..5b6f8d0733 100644 --- a/gdbstub/system.c +++ b/gdbstub/system.c @@ -19,7 +19,7 @@ #include "gdbstub/commands.h" #include "exec/hwaddr.h" #include "exec/tb-flush.h" -#include "system/accel-ops.h" +#include "accel/accel-cpu-ops.h" #include "system/cpus.h" #include "system/runstate.h" #include "system/replay.h" diff --git a/include/system/accel-ops.h b/include/accel/accel-cpu-ops.h similarity index 95% rename from include/system/accel-ops.h rename to include/accel/accel-cpu-ops.h index bf7383511d..a9191dded7 100644 --- a/include/system/accel-ops.h +++ b/include/accel/accel-cpu-ops.h @@ -1,5 +1,5 @@ /* - * Accelerator OPS, used for cpus.c module + * Accelerator per-vCPU handlers * * Copyright 2021 SUSE LLC * @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef ACCEL_OPS_H -#define ACCEL_OPS_H +#ifndef QEMU_ACCEL_CPU_OPS_H +#define QEMU_ACCEL_CPU_OPS_H #include "qemu/accel.h" #include "exec/vaddr.h" @@ -89,4 +89,4 @@ struct AccelOpsClass { void generic_handle_interrupt(CPUState *cpu, int mask); -#endif /* ACCEL_OPS_H */ +#endif /* QEMU_ACCEL_CPU_OPS_H */ diff --git a/system/cpus.c b/system/cpus.c index 8e6da2e060..256723558d 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -31,7 +31,7 @@ #include "qapi/qapi-events-run-state.h" #include "qapi/qmp/qerror.h" #include "exec/gdbstub.h" -#include "system/accel-ops.h" +#include "accel/accel-cpu-ops.h" #include "system/hw_accel.h" #include "exec/cpu-common.h" #include "qemu/thread.h" diff --git a/target/i386/nvmm/nvmm-accel-ops.c b/target/i386/nvmm/nvmm-accel-ops.c index a5517b0abf..3799260bbd 100644 --- a/target/i386/nvmm/nvmm-accel-ops.c +++ b/target/i386/nvmm/nvmm-accel-ops.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" #include "system/kvm_int.h" #include "qemu/main-loop.h" -#include "system/accel-ops.h" +#include "accel/accel-cpu-ops.h" #include "system/cpus.h" #include "qemu/guest-random.h" diff --git a/target/i386/whpx/whpx-accel-ops.c b/target/i386/whpx/whpx-accel-ops.c index 5f4841c9fa..da58805b1a 100644 --- a/target/i386/whpx/whpx-accel-ops.c +++ b/target/i386/whpx/whpx-accel-ops.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" #include "system/kvm_int.h" #include "qemu/main-loop.h" -#include "system/accel-ops.h" +#include "accel/accel-cpu-ops.h" #include "system/cpus.h" #include "qemu/guest-random.h" From f7a7e7dd2179e7189064e0b7b637e6906617221f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 3 Jul 2025 16:44:39 +0200 Subject: [PATCH 08/17] accel: Extract AccelClass definition to 'accel/accel-ops.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only accelerator implementations (and the common accelator code) need to know about AccelClass internals. Move the definition out but forward declare AccelState and AccelClass. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Zhao Liu Reviewed-by: Richard Henderson Message-Id: <20250703173248.44995-39-philmd@linaro.org> --- MAINTAINERS | 2 +- accel/accel-common.c | 2 ++ accel/accel-system.c | 1 + accel/hvf/hvf-all.c | 1 + accel/kvm/kvm-all.c | 1 + accel/qtest/qtest.c | 1 + accel/tcg/tcg-accel-ops.c | 1 + accel/tcg/tcg-all.c | 2 ++ accel/xen/xen-all.c | 1 + bsd-user/main.c | 1 + gdbstub/system.c | 1 + include/accel/accel-ops.h | 49 +++++++++++++++++++++++++++++++++++++ include/qemu/accel.h | 39 ++--------------------------- include/system/hvf_int.h | 3 ++- include/system/kvm_int.h | 1 + linux-user/main.c | 1 + system/memory.c | 1 + target/i386/nvmm/nvmm-all.c | 1 + target/i386/whpx/whpx-all.c | 1 + 19 files changed, 71 insertions(+), 39 deletions(-) create mode 100644 include/accel/accel-ops.h diff --git a/MAINTAINERS b/MAINTAINERS index 0e945f3bd2..9d88c17433 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -502,7 +502,7 @@ F: include/exec/target_long.h F: include/qemu/accel.h F: include/system/accel-*.h F: include/system/cpus.h -F: include/accel/accel-cpu*.h +F: include/accel/accel-*.h F: accel/accel-*.? F: accel/dummy-cpus.? F: accel/Makefile.objs diff --git a/accel/accel-common.c b/accel/accel-common.c index 591ff4cbb6..850c5ab4b8 100644 --- a/accel/accel-common.c +++ b/accel/accel-common.c @@ -10,7 +10,9 @@ #include "qemu/osdep.h" #include "qemu/accel.h" #include "qemu/target-info.h" +#include "accel/accel-ops.h" #include "accel/accel-cpu.h" +#include "accel/accel-cpu-ops.h" #include "accel-internal.h" /* Lookup AccelClass from opt_name. Returns NULL if not found */ diff --git a/accel/accel-system.c b/accel/accel-system.c index c2a955a6da..8df561b953 100644 --- a/accel/accel-system.c +++ b/accel/accel-system.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "qemu/accel.h" #include "hw/boards.h" +#include "accel/accel-ops.h" #include "accel/accel-cpu-ops.h" #include "system/cpus.h" #include "qemu/error-report.h" diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c index 1fa07c8b69..e67a8105a6 100644 --- a/accel/hvf/hvf-all.c +++ b/accel/hvf/hvf-all.c @@ -10,6 +10,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "accel/accel-ops.h" #include "system/address-spaces.h" #include "system/memory.h" #include "system/hvf.h" diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index a106d1ba0f..659ff88156 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -32,6 +32,7 @@ #include "system/runstate.h" #include "system/cpus.h" #include "system/accel-blocker.h" +#include "accel/accel-ops.h" #include "qemu/bswap.h" #include "exec/tswap.h" #include "system/memory.h" diff --git a/accel/qtest/qtest.c b/accel/qtest/qtest.c index a7fc8bee6d..1d4337d698 100644 --- a/accel/qtest/qtest.c +++ b/accel/qtest/qtest.c @@ -18,6 +18,7 @@ #include "qemu/option.h" #include "qemu/config-file.h" #include "qemu/accel.h" +#include "accel/accel-ops.h" #include "accel/accel-cpu-ops.h" #include "system/qtest.h" #include "system/cpus.h" diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index 58ded9d6f0..3b0d7d298e 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -26,6 +26,7 @@ */ #include "qemu/osdep.h" +#include "accel/accel-ops.h" #include "accel/accel-cpu-ops.h" #include "system/tcg.h" #include "system/replay.h" diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 5904582a68..eaeb465dfd 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -39,6 +39,8 @@ #ifndef CONFIG_USER_ONLY #include "hw/boards.h" #endif +#include "accel/accel-ops.h" +#include "accel/accel-cpu-ops.h" #include "accel/tcg/cpu-ops.h" #include "internal-common.h" diff --git a/accel/xen/xen-all.c b/accel/xen/xen-all.c index 55a60bb42c..97377d67d1 100644 --- a/accel/xen/xen-all.c +++ b/accel/xen/xen-all.c @@ -19,6 +19,7 @@ #include "chardev/char.h" #include "qemu/accel.h" #include "accel/dummy-cpus.h" +#include "accel/accel-ops.h" #include "accel/accel-cpu-ops.h" #include "system/cpus.h" #include "system/xen.h" diff --git a/bsd-user/main.c b/bsd-user/main.c index d0cc8e0088..7e5d4bbce0 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -38,6 +38,7 @@ #include "qemu/plugin.h" #include "user/guest-base.h" #include "user/page-protection.h" +#include "accel/accel-ops.h" #include "tcg/startup.h" #include "qemu/timer.h" #include "qemu/envlist.h" diff --git a/gdbstub/system.c b/gdbstub/system.c index 5b6f8d0733..5be0d3c58c 100644 --- a/gdbstub/system.c +++ b/gdbstub/system.c @@ -19,6 +19,7 @@ #include "gdbstub/commands.h" #include "exec/hwaddr.h" #include "exec/tb-flush.h" +#include "accel/accel-ops.h" #include "accel/accel-cpu-ops.h" #include "system/cpus.h" #include "system/runstate.h" diff --git a/include/accel/accel-ops.h b/include/accel/accel-ops.h new file mode 100644 index 0000000000..86a27c30fa --- /dev/null +++ b/include/accel/accel-ops.h @@ -0,0 +1,49 @@ +/* + * Accelerator handlers + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef ACCEL_OPS_H +#define ACCEL_OPS_H + +#include "exec/hwaddr.h" +#include "qemu/accel.h" +#include "qom/object.h" + +struct AccelState { + Object parent_obj; +}; + +struct AccelClass { + ObjectClass parent_class; + + const char *name; + /* Cached by accel_init_ops_interfaces() when created */ + AccelOpsClass *ops; + + int (*init_machine)(AccelState *as, MachineState *ms); + bool (*cpu_common_realize)(CPUState *cpu, Error **errp); + void (*cpu_common_unrealize)(CPUState *cpu); + + /* system related hooks */ + void (*setup_post)(AccelState *as); + void (*pre_resume_vm)(AccelState *as, bool step_pending); + bool (*has_memory)(AccelState *accel, AddressSpace *as, + hwaddr start_addr, hwaddr size); + + /* gdbstub related hooks */ + int (*gdbstub_supported_sstep_flags)(AccelState *as); + + bool *allowed; + /* + * Array of global properties that would be applied when specific + * accelerator is chosen. It works like MachineClass.compat_props + * but it's for accelerators not machines. Accelerator-provided + * global properties may be overridden by machine-type + * compat_props or user-provided global properties. + */ + GPtrArray *compat_props; +}; + +#endif /* ACCEL_OPS_H */ diff --git a/include/qemu/accel.h b/include/qemu/accel.h index 9e821d0fae..d3638c7bfd 100644 --- a/include/qemu/accel.h +++ b/include/qemu/accel.h @@ -26,43 +26,8 @@ #include "qom/object.h" #include "exec/hwaddr.h" -struct AccelState { - /*< private >*/ - Object parent_obj; -}; - -typedef struct AccelClass { - /*< private >*/ - ObjectClass parent_class; - /*< public >*/ - - const char *name; - /* Cached by accel_init_ops_interfaces() when created */ - AccelOpsClass *ops; - - int (*init_machine)(AccelState *as, MachineState *ms); - bool (*cpu_common_realize)(CPUState *cpu, Error **errp); - void (*cpu_common_unrealize)(CPUState *cpu); - - /* system related hooks */ - void (*setup_post)(AccelState *as); - void (*pre_resume_vm)(AccelState *as, bool step_pending); - bool (*has_memory)(AccelState *accel, AddressSpace *as, - hwaddr start_addr, hwaddr size); - - /* gdbstub related hooks */ - int (*gdbstub_supported_sstep_flags)(AccelState *as); - - bool *allowed; - /* - * Array of global properties that would be applied when specific - * accelerator is chosen. It works like MachineClass.compat_props - * but it's for accelerators not machines. Accelerator-provided - * global properties may be overridden by machine-type - * compat_props or user-provided global properties. - */ - GPtrArray *compat_props; -} AccelClass; +typedef struct AccelState AccelState; +typedef struct AccelClass AccelClass; #define TYPE_ACCEL "accel" diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h index 5150c7dd9c..a3b06a3e75 100644 --- a/include/system/hvf_int.h +++ b/include/system/hvf_int.h @@ -14,6 +14,7 @@ #include "qemu/queue.h" #include "exec/vaddr.h" #include "qom/object.h" +#include "accel/accel-ops.h" #ifdef __aarch64__ #include @@ -45,7 +46,7 @@ typedef struct hvf_vcpu_caps { } hvf_vcpu_caps; struct HVFState { - AccelState parent; + AccelState parent_obj; hvf_slot slots[32]; int num_slots; diff --git a/include/system/kvm_int.h b/include/system/kvm_int.h index 756a3c0a25..9247493b02 100644 --- a/include/system/kvm_int.h +++ b/include/system/kvm_int.h @@ -14,6 +14,7 @@ #include "qemu/accel.h" #include "qemu/queue.h" #include "system/kvm.h" +#include "accel/accel-ops.h" #include "hw/boards.h" #include "hw/i386/topology.h" #include "io/channel-socket.h" diff --git a/linux-user/main.c b/linux-user/main.c index f4f2007439..68972f00a1 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -42,6 +42,7 @@ #include "user/page-protection.h" #include "exec/gdbstub.h" #include "gdbstub/user.h" +#include "accel/accel-ops.h" #include "tcg/startup.h" #include "qemu/timer.h" #include "qemu/envlist.h" diff --git a/system/memory.c b/system/memory.c index e8d9b15b28..0983ff8962 100644 --- a/system/memory.c +++ b/system/memory.c @@ -29,6 +29,7 @@ #include "system/runstate.h" #include "system/tcg.h" #include "qemu/accel.h" +#include "accel/accel-ops.h" #include "hw/boards.h" #include "migration/vmstate.h" #include "system/address-spaces.h" diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c index b4a4d50e86..aab12d7732 100644 --- a/target/i386/nvmm/nvmm-all.c +++ b/target/i386/nvmm/nvmm-all.c @@ -12,6 +12,7 @@ #include "system/address-spaces.h" #include "system/ioport.h" #include "qemu/accel.h" +#include "accel/accel-ops.h" #include "system/nvmm.h" #include "system/cpus.h" #include "system/runstate.h" diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index faf56e1972..10df2d398f 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -14,6 +14,7 @@ #include "system/ioport.h" #include "gdbstub/helpers.h" #include "qemu/accel.h" +#include "accel/accel-ops.h" #include "system/whpx.h" #include "system/cpus.h" #include "system/runstate.h" From 2d7dc398ab48d09386c718708b43bd431758f1a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 15 Jul 2025 11:28:10 +0200 Subject: [PATCH 09/17] Revert "accel/tcg: Unregister the RCU before exiting RR thread" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit bc93332fe460211c2d2f4ff50e1a0e030c7b5159, which was merged prematurely, re-introducing Coverity CID 1547782 (unreachable code). Reported-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Manos Pitsidianakis Reviewed-by: Richard Henderson Message-Id: <20250715104015.72663-2-philmd@linaro.org> --- accel/tcg/tcg-accel-ops-rr.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c index a578698d07..6eec5c9eee 100644 --- a/accel/tcg/tcg-accel-ops-rr.c +++ b/accel/tcg/tcg-accel-ops-rr.c @@ -302,8 +302,6 @@ static void *rr_cpu_thread_fn(void *arg) rr_deal_with_unplugged_cpus(); } - rcu_unregister_thread(); - g_assert_not_reached(); } From 8cc04fd9df3b9775eaf0fb1b17d82a1a075aa3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 3 Jul 2025 11:33:46 +0200 Subject: [PATCH 10/17] accel/tcg: Extract statistic related code to tcg-stats.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Statistic code is not specific to system emulation (except cross-page checks) and can be used to analyze user-mode binaries. Extract statistic related code to its own file: tcg-stats.c, keeping the original LGPL-2.1-or-later license tag. Note, this code is not yet reachable by user-mode. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Zhao Liu Reviewed-by: Richard Henderson Message-Id: <20250715140048.84942-3-philmd@linaro.org> --- accel/tcg/meson.build | 1 + accel/tcg/monitor.c | 201 --------------------------------------- accel/tcg/tcg-stats.c | 215 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+), 201 deletions(-) create mode 100644 accel/tcg/tcg-stats.c diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 575e92bb9e..002aa8f458 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -11,6 +11,7 @@ tcg_ss.add(files( 'tcg-runtime-gvec.c', 'tb-maint.c', 'tcg-all.c', + 'tcg-stats.c', 'translate-all.c', 'translator.c', )) diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c index 778b12613f..adb9de5a1c 100644 --- a/accel/tcg/monitor.c +++ b/accel/tcg/monitor.c @@ -7,213 +7,12 @@ */ #include "qemu/osdep.h" -#include "qemu/accel.h" -#include "qemu/qht.h" #include "qapi/error.h" #include "qapi/type-helpers.h" #include "qapi/qapi-commands-machine.h" #include "monitor/monitor.h" -#include "system/cpu-timers.h" -#include "exec/icount.h" #include "system/tcg.h" -#include "tcg/tcg.h" #include "internal-common.h" -#include "tb-context.h" -#include - -static void dump_drift_info(GString *buf) -{ - if (!icount_enabled()) { - return; - } - - g_string_append_printf(buf, "Host - Guest clock %"PRIi64" ms\n", - (cpu_get_clock() - icount_get()) / SCALE_MS); - if (icount_align_option) { - g_string_append_printf(buf, "Max guest delay %"PRIi64" ms\n", - -max_delay / SCALE_MS); - g_string_append_printf(buf, "Max guest advance %"PRIi64" ms\n", - max_advance / SCALE_MS); - } else { - g_string_append_printf(buf, "Max guest delay NA\n"); - g_string_append_printf(buf, "Max guest advance NA\n"); - } -} - -static void dump_accel_info(GString *buf) -{ - AccelState *accel = current_accel(); - bool one_insn_per_tb = object_property_get_bool(OBJECT(accel), - "one-insn-per-tb", - &error_fatal); - - g_string_append_printf(buf, "Accelerator settings:\n"); - g_string_append_printf(buf, "one-insn-per-tb: %s\n\n", - one_insn_per_tb ? "on" : "off"); -} - -static void print_qht_statistics(struct qht_stats hst, GString *buf) -{ - uint32_t hgram_opts; - size_t hgram_bins; - char *hgram; - double avg; - - if (!hst.head_buckets) { - return; - } - g_string_append_printf(buf, "TB hash buckets %zu/%zu " - "(%0.2f%% head buckets used)\n", - hst.used_head_buckets, hst.head_buckets, - (double)hst.used_head_buckets / - hst.head_buckets * 100); - - hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS; - hgram_opts |= QDIST_PR_100X | QDIST_PR_PERCENT; - if (qdist_xmax(&hst.occupancy) - qdist_xmin(&hst.occupancy) == 1) { - hgram_opts |= QDIST_PR_NODECIMAL; - } - hgram = qdist_pr(&hst.occupancy, 10, hgram_opts); - avg = qdist_avg(&hst.occupancy); - if (!isnan(avg)) { - g_string_append_printf(buf, "TB hash occupancy " - "%0.2f%% avg chain occ. " - "Histogram: %s\n", - avg * 100, hgram); - } - g_free(hgram); - - hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS; - hgram_bins = qdist_xmax(&hst.chain) - qdist_xmin(&hst.chain); - if (hgram_bins > 10) { - hgram_bins = 10; - } else { - hgram_bins = 0; - hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE; - } - hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts); - avg = qdist_avg(&hst.chain); - if (!isnan(avg)) { - g_string_append_printf(buf, "TB hash avg chain %0.3f buckets. " - "Histogram: %s\n", - avg, hgram); - } - g_free(hgram); -} - -struct tb_tree_stats { - size_t nb_tbs; - size_t host_size; - size_t target_size; - size_t max_target_size; - size_t direct_jmp_count; - size_t direct_jmp2_count; - size_t cross_page; -}; - -static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data) -{ - const TranslationBlock *tb = value; - struct tb_tree_stats *tst = data; - - tst->nb_tbs++; - tst->host_size += tb->tc.size; - tst->target_size += tb->size; - if (tb->size > tst->max_target_size) { - tst->max_target_size = tb->size; - } - if (tb->page_addr[1] != -1) { - tst->cross_page++; - } - if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) { - tst->direct_jmp_count++; - if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) { - tst->direct_jmp2_count++; - } - } - return false; -} - -static void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide) -{ - CPUState *cpu; - size_t full = 0, part = 0, elide = 0; - - CPU_FOREACH(cpu) { - full += qatomic_read(&cpu->neg.tlb.c.full_flush_count); - part += qatomic_read(&cpu->neg.tlb.c.part_flush_count); - elide += qatomic_read(&cpu->neg.tlb.c.elide_flush_count); - } - *pfull = full; - *ppart = part; - *pelide = elide; -} - -static void tcg_dump_flush_info(GString *buf) -{ - size_t flush_full, flush_part, flush_elide; - - g_string_append_printf(buf, "TB flush count %u\n", - qatomic_read(&tb_ctx.tb_flush_count)); - g_string_append_printf(buf, "TB invalidate count %u\n", - qatomic_read(&tb_ctx.tb_phys_invalidate_count)); - - tlb_flush_counts(&flush_full, &flush_part, &flush_elide); - g_string_append_printf(buf, "TLB full flushes %zu\n", flush_full); - g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part); - g_string_append_printf(buf, "TLB elided flushes %zu\n", flush_elide); -} - -static void dump_exec_info(GString *buf) -{ - struct tb_tree_stats tst = {}; - struct qht_stats hst; - size_t nb_tbs; - - tcg_tb_foreach(tb_tree_stats_iter, &tst); - nb_tbs = tst.nb_tbs; - /* XXX: avoid using doubles ? */ - g_string_append_printf(buf, "Translation buffer state:\n"); - /* - * Report total code size including the padding and TB structs; - * otherwise users might think "-accel tcg,tb-size" is not honoured. - * For avg host size we use the precise numbers from tb_tree_stats though. - */ - g_string_append_printf(buf, "gen code size %zu/%zu\n", - tcg_code_size(), tcg_code_capacity()); - g_string_append_printf(buf, "TB count %zu\n", nb_tbs); - g_string_append_printf(buf, "TB avg target size %zu max=%zu bytes\n", - nb_tbs ? tst.target_size / nb_tbs : 0, - tst.max_target_size); - g_string_append_printf(buf, "TB avg host size %zu bytes " - "(expansion ratio: %0.1f)\n", - nb_tbs ? tst.host_size / nb_tbs : 0, - tst.target_size ? - (double)tst.host_size / tst.target_size : 0); - g_string_append_printf(buf, "cross page TB count %zu (%zu%%)\n", - tst.cross_page, - nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0); - g_string_append_printf(buf, "direct jump count %zu (%zu%%) " - "(2 jumps=%zu %zu%%)\n", - tst.direct_jmp_count, - nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0, - tst.direct_jmp2_count, - nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0); - - qht_statistics_init(&tb_ctx.htable, &hst); - print_qht_statistics(hst, buf); - qht_statistics_destroy(&hst); - - g_string_append_printf(buf, "\nStatistics:\n"); - tcg_dump_flush_info(buf); -} - -void tcg_dump_stats(GString *buf) -{ - dump_accel_info(buf); - dump_exec_info(buf); - dump_drift_info(buf); -} HumanReadableText *qmp_x_query_jit(Error **errp) { diff --git a/accel/tcg/tcg-stats.c b/accel/tcg/tcg-stats.c new file mode 100644 index 0000000000..eb6e20ae98 --- /dev/null +++ b/accel/tcg/tcg-stats.c @@ -0,0 +1,215 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * QEMU TCG statistics + * + * Copyright (c) 2003-2005 Fabrice Bellard + */ + +#include "qemu/osdep.h" +#include "qemu/accel.h" +#include "qemu/qht.h" +#include "qapi/error.h" +#include "system/cpu-timers.h" +#include "exec/icount.h" +#include "hw/core/cpu.h" +#include "tcg/tcg.h" +#include "internal-common.h" +#include "tb-context.h" +#include + +static void dump_drift_info(GString *buf) +{ + if (!icount_enabled()) { + return; + } + + g_string_append_printf(buf, "Host - Guest clock %"PRIi64" ms\n", + (cpu_get_clock() - icount_get()) / SCALE_MS); + if (icount_align_option) { + g_string_append_printf(buf, "Max guest delay %"PRIi64" ms\n", + -max_delay / SCALE_MS); + g_string_append_printf(buf, "Max guest advance %"PRIi64" ms\n", + max_advance / SCALE_MS); + } else { + g_string_append_printf(buf, "Max guest delay NA\n"); + g_string_append_printf(buf, "Max guest advance NA\n"); + } +} + +static void dump_accel_info(GString *buf) +{ + AccelState *accel = current_accel(); + bool one_insn_per_tb = object_property_get_bool(OBJECT(accel), + "one-insn-per-tb", + &error_fatal); + + g_string_append_printf(buf, "Accelerator settings:\n"); + g_string_append_printf(buf, "one-insn-per-tb: %s\n\n", + one_insn_per_tb ? "on" : "off"); +} + +static void print_qht_statistics(struct qht_stats hst, GString *buf) +{ + uint32_t hgram_opts; + size_t hgram_bins; + char *hgram; + double avg; + + if (!hst.head_buckets) { + return; + } + g_string_append_printf(buf, "TB hash buckets %zu/%zu " + "(%0.2f%% head buckets used)\n", + hst.used_head_buckets, hst.head_buckets, + (double)hst.used_head_buckets / + hst.head_buckets * 100); + + hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS; + hgram_opts |= QDIST_PR_100X | QDIST_PR_PERCENT; + if (qdist_xmax(&hst.occupancy) - qdist_xmin(&hst.occupancy) == 1) { + hgram_opts |= QDIST_PR_NODECIMAL; + } + hgram = qdist_pr(&hst.occupancy, 10, hgram_opts); + avg = qdist_avg(&hst.occupancy); + if (!isnan(avg)) { + g_string_append_printf(buf, "TB hash occupancy " + "%0.2f%% avg chain occ. " + "Histogram: %s\n", + avg * 100, hgram); + } + g_free(hgram); + + hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS; + hgram_bins = qdist_xmax(&hst.chain) - qdist_xmin(&hst.chain); + if (hgram_bins > 10) { + hgram_bins = 10; + } else { + hgram_bins = 0; + hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE; + } + hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts); + avg = qdist_avg(&hst.chain); + if (!isnan(avg)) { + g_string_append_printf(buf, "TB hash avg chain %0.3f buckets. " + "Histogram: %s\n", + avg, hgram); + } + g_free(hgram); +} + +struct tb_tree_stats { + size_t nb_tbs; + size_t host_size; + size_t target_size; + size_t max_target_size; + size_t direct_jmp_count; + size_t direct_jmp2_count; + size_t cross_page; +}; + +static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data) +{ + const TranslationBlock *tb = value; + struct tb_tree_stats *tst = data; + + tst->nb_tbs++; + tst->host_size += tb->tc.size; + tst->target_size += tb->size; + if (tb->size > tst->max_target_size) { + tst->max_target_size = tb->size; + } +#ifndef CONFIG_USER_ONLY + if (tb->page_addr[1] != -1) { + tst->cross_page++; + } +#endif + if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) { + tst->direct_jmp_count++; + if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) { + tst->direct_jmp2_count++; + } + } + return false; +} + +static void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide) +{ + CPUState *cpu; + size_t full = 0, part = 0, elide = 0; + + CPU_FOREACH(cpu) { + full += qatomic_read(&cpu->neg.tlb.c.full_flush_count); + part += qatomic_read(&cpu->neg.tlb.c.part_flush_count); + elide += qatomic_read(&cpu->neg.tlb.c.elide_flush_count); + } + *pfull = full; + *ppart = part; + *pelide = elide; +} + +static void tcg_dump_flush_info(GString *buf) +{ + size_t flush_full, flush_part, flush_elide; + + g_string_append_printf(buf, "TB flush count %u\n", + qatomic_read(&tb_ctx.tb_flush_count)); + g_string_append_printf(buf, "TB invalidate count %u\n", + qatomic_read(&tb_ctx.tb_phys_invalidate_count)); + + tlb_flush_counts(&flush_full, &flush_part, &flush_elide); + g_string_append_printf(buf, "TLB full flushes %zu\n", flush_full); + g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part); + g_string_append_printf(buf, "TLB elided flushes %zu\n", flush_elide); +} + +static void dump_exec_info(GString *buf) +{ + struct tb_tree_stats tst = {}; + struct qht_stats hst; + size_t nb_tbs; + + tcg_tb_foreach(tb_tree_stats_iter, &tst); + nb_tbs = tst.nb_tbs; + /* XXX: avoid using doubles ? */ + g_string_append_printf(buf, "Translation buffer state:\n"); + /* + * Report total code size including the padding and TB structs; + * otherwise users might think "-accel tcg,tb-size" is not honoured. + * For avg host size we use the precise numbers from tb_tree_stats though. + */ + g_string_append_printf(buf, "gen code size %zu/%zu\n", + tcg_code_size(), tcg_code_capacity()); + g_string_append_printf(buf, "TB count %zu\n", nb_tbs); + g_string_append_printf(buf, "TB avg target size %zu max=%zu bytes\n", + nb_tbs ? tst.target_size / nb_tbs : 0, + tst.max_target_size); + g_string_append_printf(buf, "TB avg host size %zu bytes " + "(expansion ratio: %0.1f)\n", + nb_tbs ? tst.host_size / nb_tbs : 0, + tst.target_size ? + (double)tst.host_size / tst.target_size : 0); + g_string_append_printf(buf, "cross page TB count %zu (%zu%%)\n", + tst.cross_page, + nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0); + g_string_append_printf(buf, "direct jump count %zu (%zu%%) " + "(2 jumps=%zu %zu%%)\n", + tst.direct_jmp_count, + nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0, + tst.direct_jmp2_count, + nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0); + + qht_statistics_init(&tb_ctx.htable, &hst); + print_qht_statistics(hst, buf); + qht_statistics_destroy(&hst); + + g_string_append_printf(buf, "\nStatistics:\n"); + tcg_dump_flush_info(buf); +} + +void tcg_dump_stats(GString *buf) +{ + dump_accel_info(buf); + dump_exec_info(buf); + dump_drift_info(buf); +} From 1861993f1fc13e42afed6a618c45a5a95a1457ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 2 Jul 2025 15:03:12 +0200 Subject: [PATCH 11/17] accel/system: Introduce @x-accel-stats QMP command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unstable QMP 'x-accel-stats' dispatches to the AccelOpsClass::get_stats() and get_vcpu_stats() handlers. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Markus Armbruster Reviewed-by: Zhao Liu Message-Id: <20250715140048.84942-4-philmd@linaro.org> --- accel/accel-qmp.c | 35 +++++++++++++++++++++++++++++++++++ accel/accel-system.c | 1 + accel/meson.build | 2 +- include/accel/accel-cpu-ops.h | 3 +++ include/accel/accel-ops.h | 2 ++ qapi/accelerator.json | 17 +++++++++++++++++ 6 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 accel/accel-qmp.c diff --git a/accel/accel-qmp.c b/accel/accel-qmp.c new file mode 100644 index 0000000000..5fb70c6631 --- /dev/null +++ b/accel/accel-qmp.c @@ -0,0 +1,35 @@ +/* + * QMP commands related to accelerators + * + * Copyright (c) Linaro + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/accel.h" +#include "qapi/type-helpers.h" +#include "qapi/qapi-commands-accelerator.h" +#include "accel/accel-ops.h" +#include "accel/accel-cpu-ops.h" +#include "hw/core/cpu.h" + +HumanReadableText *qmp_x_accel_stats(Error **errp) +{ + AccelState *accel = current_accel(); + AccelClass *acc = ACCEL_GET_CLASS(accel); + g_autoptr(GString) buf = g_string_new(""); + + if (acc->get_stats) { + acc->get_stats(accel, buf); + } + if (acc->ops->get_vcpu_stats) { + CPUState *cpu; + + CPU_FOREACH(cpu) { + acc->ops->get_vcpu_stats(cpu, buf); + } + } + + return human_readable_text_from_str(buf); +} diff --git a/accel/accel-system.c b/accel/accel-system.c index 8df561b953..76cf4e7ef7 100644 --- a/accel/accel-system.c +++ b/accel/accel-system.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "qemu/accel.h" #include "hw/boards.h" +#include "hw/core/cpu.h" #include "accel/accel-ops.h" #include "accel/accel-cpu-ops.h" #include "system/cpus.h" diff --git a/accel/meson.build b/accel/meson.build index 52909314bf..25b0f100b5 100644 --- a/accel/meson.build +++ b/accel/meson.build @@ -1,6 +1,6 @@ common_ss.add(files('accel-common.c')) specific_ss.add(files('accel-target.c')) -system_ss.add(files('accel-system.c', 'accel-blocker.c')) +system_ss.add(files('accel-system.c', 'accel-blocker.c', 'accel-qmp.c')) user_ss.add(files('accel-user.c')) subdir('tcg') diff --git a/include/accel/accel-cpu-ops.h b/include/accel/accel-cpu-ops.h index a9191dded7..0674764914 100644 --- a/include/accel/accel-cpu-ops.h +++ b/include/accel/accel-cpu-ops.h @@ -65,6 +65,9 @@ struct AccelOpsClass { /* handle_interrupt is mandatory. */ void (*handle_interrupt)(CPUState *cpu, int mask); + /* get_vcpu_stats: Append statistics of this @cpu to @buf */ + void (*get_vcpu_stats)(CPUState *cpu, GString *buf); + /** * @get_virtual_clock: fetch virtual clock * @set_virtual_clock: set virtual clock diff --git a/include/accel/accel-ops.h b/include/accel/accel-ops.h index 86a27c30fa..23a8c246e1 100644 --- a/include/accel/accel-ops.h +++ b/include/accel/accel-ops.h @@ -25,6 +25,8 @@ struct AccelClass { int (*init_machine)(AccelState *as, MachineState *ms); bool (*cpu_common_realize)(CPUState *cpu, Error **errp); void (*cpu_common_unrealize)(CPUState *cpu); + /* get_stats: Append statistics to @buf */ + void (*get_stats)(AccelState *as, GString *buf); /* system related hooks */ void (*setup_post)(AccelState *as); diff --git a/qapi/accelerator.json b/qapi/accelerator.json index d55fe1aa0a..6029e7307a 100644 --- a/qapi/accelerator.json +++ b/qapi/accelerator.json @@ -37,3 +37,20 @@ # <- { "return": { "enabled": true, "present": true } } ## { 'command': 'query-kvm', 'returns': 'KvmInfo' } + +## +# @x-accel-stats: +# +# Query accelerator statistics +# +# Features: +# +# @unstable: This command is meant for debugging. +# +# Returns: accelerator statistics +# +# Since: 10.1 +## +{ 'command': 'x-accel-stats', + 'returns': 'HumanReadableText', + 'features': [ 'unstable' ] } From c10eb740108c24c65f049e5ae85ed10b2779e75d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Jun 2025 14:44:14 +0200 Subject: [PATCH 12/17] accel/system: Add 'info accel' on human monitor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'info accel' dispatches to the AccelOpsClass::get_stats() and get_vcpu_stats() handlers. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Richard Henderson Reviewed-by: Pierrick Bouvier Message-Id: <20250715140048.84942-5-philmd@linaro.org> --- accel/accel-system.c | 8 ++++++++ hmp-commands-info.hx | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/accel/accel-system.c b/accel/accel-system.c index 76cf4e7ef7..1e97c64fdc 100644 --- a/accel/accel-system.c +++ b/accel/accel-system.c @@ -25,6 +25,8 @@ #include "qemu/osdep.h" #include "qemu/accel.h" +#include "qapi/qapi-commands-accelerator.h" +#include "monitor/monitor.h" #include "hw/boards.h" #include "hw/core/cpu.h" #include "accel/accel-ops.h" @@ -103,11 +105,17 @@ void accel_init_ops_interfaces(AccelClass *ac) cpus_register_accel(ops); } +static void accel_ops_class_init(ObjectClass *oc, const void *data) +{ + monitor_register_hmp_info_hrt("accel", qmp_x_accel_stats); +} + static const TypeInfo accel_ops_type_info = { .name = TYPE_ACCEL_OPS, .parent = TYPE_OBJECT, .abstract = true, .class_size = sizeof(AccelOpsClass), + .class_init = accel_ops_class_init, }; static void accel_system_register_types(void) diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index d797922275..6142f60e7b 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -267,6 +267,18 @@ ERST .cmd = hmp_info_sync_profile, }, + { + .name = "accel", + .args_type = "", + .params = "", + .help = "show accelerator info", + }, + +SRST + ``info accel`` + Show accelerator info. +ERST + SRST ``info sync-profile [-m|-n]`` [*max*] Show synchronization profiling info, up to *max* entries (default: 10), From 2320453031f87e4245a5625f3714d444e987ea0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Jul 2025 14:09:29 +0200 Subject: [PATCH 13/17] accel/tcg: Propagate AccelState to dump_accel_info() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declare tcg_dump_stats() in "tcg/tcg.h" so it can be used out of accel/tcg/, like by {bsd,linux}-user. Next commit will register the TCG AccelClass::get_stats handler, which expects a AccelState, so propagate it to dump_accel_info(). Reviewed-by: Manos Pitsidianakis Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20250715140048.84942-6-philmd@linaro.org> --- accel/tcg/internal-common.h | 2 -- accel/tcg/monitor.c | 1 + accel/tcg/tcg-stats.c | 5 ++--- include/tcg/tcg.h | 2 ++ 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/accel/tcg/internal-common.h b/accel/tcg/internal-common.h index 77a3a0684a..1dbc45dd95 100644 --- a/accel/tcg/internal-common.h +++ b/accel/tcg/internal-common.h @@ -139,6 +139,4 @@ G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr); void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr); -void tcg_dump_stats(GString *buf); - #endif diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c index adb9de5a1c..be5c195017 100644 --- a/accel/tcg/monitor.c +++ b/accel/tcg/monitor.c @@ -12,6 +12,7 @@ #include "qapi/qapi-commands-machine.h" #include "monitor/monitor.h" #include "system/tcg.h" +#include "tcg/tcg.h" #include "internal-common.h" HumanReadableText *qmp_x_query_jit(Error **errp) diff --git a/accel/tcg/tcg-stats.c b/accel/tcg/tcg-stats.c index eb6e20ae98..e1a1c4cf4a 100644 --- a/accel/tcg/tcg-stats.c +++ b/accel/tcg/tcg-stats.c @@ -37,9 +37,8 @@ static void dump_drift_info(GString *buf) } } -static void dump_accel_info(GString *buf) +static void dump_accel_info(AccelState *accel, GString *buf) { - AccelState *accel = current_accel(); bool one_insn_per_tb = object_property_get_bool(OBJECT(accel), "one-insn-per-tb", &error_fatal); @@ -209,7 +208,7 @@ static void dump_exec_info(GString *buf) void tcg_dump_stats(GString *buf) { - dump_accel_info(buf); + dump_accel_info(current_accel(), buf); dump_exec_info(buf); dump_drift_info(buf); } diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 0c2a319c11..a6d9aa50d4 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -1005,5 +1005,7 @@ static inline const TCGOpcode *tcg_swap_vecop_list(const TCGOpcode *n) bool tcg_can_emit_vecop_list(const TCGOpcode *, TCGType, unsigned); void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs); +/* tcg_dump_stats: Append TCG statistics to @buf */ +void tcg_dump_stats(GString *buf); #endif /* TCG_H */ From cf4305ed7a24f25cef0bd35609d03ea688fa24fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Jun 2025 14:45:29 +0200 Subject: [PATCH 14/17] accel/tcg: Implement AccelClass::get_stats() handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Factor tcg_get_stats() out of tcg_dump_stats(), passing the current accelerator argument to match the AccelClass::get_stats() prototype. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20250715140048.84942-7-philmd@linaro.org> --- accel/tcg/internal-common.h | 2 ++ accel/tcg/tcg-all.c | 1 + accel/tcg/tcg-stats.c | 9 +++++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/accel/tcg/internal-common.h b/accel/tcg/internal-common.h index 1dbc45dd95..6adfeefe13 100644 --- a/accel/tcg/internal-common.h +++ b/accel/tcg/internal-common.h @@ -139,4 +139,6 @@ G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr); void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr); +void tcg_get_stats(AccelState *accel, GString *buf); + #endif diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index eaeb465dfd..5125e1a4e2 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -243,6 +243,7 @@ static void tcg_accel_class_init(ObjectClass *oc, const void *data) ac->init_machine = tcg_init_machine; ac->cpu_common_realize = tcg_exec_realizefn; ac->cpu_common_unrealize = tcg_exec_unrealizefn; + ac->get_stats = tcg_get_stats; ac->allowed = &tcg_allowed; ac->gdbstub_supported_sstep_flags = tcg_gdbstub_supported_sstep_flags; diff --git a/accel/tcg/tcg-stats.c b/accel/tcg/tcg-stats.c index e1a1c4cf4a..ced5dec0c4 100644 --- a/accel/tcg/tcg-stats.c +++ b/accel/tcg/tcg-stats.c @@ -206,9 +206,14 @@ static void dump_exec_info(GString *buf) tcg_dump_flush_info(buf); } -void tcg_dump_stats(GString *buf) +void tcg_get_stats(AccelState *accel, GString *buf) { - dump_accel_info(current_accel(), buf); + dump_accel_info(accel, buf); dump_exec_info(buf); dump_drift_info(buf); } + +void tcg_dump_stats(GString *buf) +{ + tcg_get_stats(current_accel(), buf); +} From ec5c2e7f38ee05c3edc81f2d0873141e4d8d074e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 4 Jul 2025 00:25:04 +0200 Subject: [PATCH 15/17] accel/hvf: Implement AccelClass::get_vcpu_stats() handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-developed-by: Mads Ynddal Signed-off-by: Mads Ynddal Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20250715104015.72663-8-philmd@linaro.org> --- accel/hvf/hvf-accel-ops.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c index 214454bd0b..d488d6afba 100644 --- a/accel/hvf/hvf-accel-ops.c +++ b/accel/hvf/hvf-accel-ops.c @@ -58,6 +58,7 @@ #include "system/cpus.h" #include "system/hvf.h" #include "system/hvf_int.h" +#include HVFState *hvf_state; @@ -118,6 +119,12 @@ static void dummy_signal(int sig) { } +static void do_hvf_get_vcpu_exec_time(CPUState *cpu, run_on_cpu_data arg) +{ + int r = hv_vcpu_get_exec_time(cpu->accel->fd, arg.host_ptr); + assert_hvf_ok(r); +} + static void hvf_vcpu_destroy(CPUState *cpu) { hv_return_t ret = hv_vcpu_destroy(cpu->accel->fd); @@ -347,6 +354,21 @@ static void hvf_remove_all_breakpoints(CPUState *cpu) } } +static void hvf_get_vcpu_stats(CPUState *cpu, GString *buf) +{ + uint64_t time_mach; /* units of mach_absolute_time() */ + + run_on_cpu(cpu, do_hvf_get_vcpu_exec_time, RUN_ON_CPU_HOST_PTR(&time_mach)); + + mach_timebase_info_data_t timebase; + mach_timebase_info(&timebase); + uint64_t time_ns = time_mach * timebase.numer / timebase.denom; + + g_string_append_printf(buf, "HVF cumulative execution time: %llu.%.3llus\n", + time_ns / 1000000000, + (time_ns % 1000000000) / 1000000); +} + static void hvf_accel_ops_class_init(ObjectClass *oc, const void *data) { AccelOpsClass *ops = ACCEL_OPS_CLASS(oc); @@ -365,7 +387,10 @@ static void hvf_accel_ops_class_init(ObjectClass *oc, const void *data) ops->remove_all_breakpoints = hvf_remove_all_breakpoints; ops->update_guest_debug = hvf_update_guest_debug; ops->supports_guest_debug = hvf_arch_supports_guest_debug; + + ops->get_vcpu_stats = hvf_get_vcpu_stats; }; + static const TypeInfo hvf_accel_ops_type = { .name = ACCEL_OPS_NAME("hvf"), From 5a67e43096484ba11470b5b9aea5d78e32fded63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Jun 2025 06:44:18 +0200 Subject: [PATCH 16/17] system/runstate: Document qemu_add_vm_change_state_handler() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Reviewed-by: Zhao Liu Message-Id: <20250703173248.44995-4-philmd@linaro.org> --- include/system/runstate.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/system/runstate.h b/include/system/runstate.h index fdd5c4a517..b6e8d6beab 100644 --- a/include/system/runstate.h +++ b/include/system/runstate.h @@ -14,6 +14,16 @@ void runstate_replay_enable(void); typedef void VMChangeStateHandler(void *opaque, bool running, RunState state); typedef int VMChangeStateHandlerWithRet(void *opaque, bool running, RunState state); +/** + * qemu_add_vm_change_state_handler: + * @cb: the callback to invoke + * @opaque: user data passed to the callback + * + * Register a callback function that is invoked when the vm starts or stops + * running. + * + * Returns: an entry to be freed using qemu_del_vm_change_state_handler() + */ VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, void *opaque); VMChangeStateEntry *qemu_add_vm_change_state_handler_prio( From 0a94a7b8802b7f6dc2521e48d837d1b5173f9db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 15 Jul 2025 19:14:34 +0200 Subject: [PATCH 17/17] system/runstate: Document qemu_add_vm_change_state_handler_prio* in hdr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generally APIs to the rest of QEMU should be documented in the headers. Comments on individual functions or internal details are fine to live in the C files. Make qemu_add_vm_change_state_handler_prio[_full]() docstrings consistent by moving them from source to header. Suggested-by: Xiaoyao Li Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Message-Id: <20250715171920.89670-1-philmd@linaro.org> --- include/system/runstate.h | 30 ++++++++++++++++++++++++++++++ system/runstate.c | 30 ------------------------------ 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/include/system/runstate.h b/include/system/runstate.h index b6e8d6beab..b8d1bc3d27 100644 --- a/include/system/runstate.h +++ b/include/system/runstate.h @@ -26,9 +26,39 @@ typedef int VMChangeStateHandlerWithRet(void *opaque, bool running, RunState sta */ VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, void *opaque); +/** + * qemu_add_vm_change_state_handler_prio: + * @cb: the callback to invoke + * @opaque: user data passed to the callback + * @priority: low priorities execute first when the vm runs and the reverse is + * true when the vm stops + * + * Register a callback function that is invoked when the vm starts or stops + * running. + * + * Returns: an entry to be freed using qemu_del_vm_change_state_handler() + */ VMChangeStateEntry *qemu_add_vm_change_state_handler_prio( VMChangeStateHandler *cb, void *opaque, int priority); VMChangeStateEntry * +/** + * qemu_add_vm_change_state_handler_prio_full: + * @cb: the main callback to invoke + * @prepare_cb: a callback to invoke before the main callback + * @cb_ret: the main callback to invoke with return value + * @opaque: user data passed to the callbacks + * @priority: low priorities execute first when the vm runs and the reverse is + * true when the vm stops + * + * Register a main callback function and an optional prepare callback function + * that are invoked when the vm starts or stops running. The main callback and + * the prepare callback are called in two separate phases: First all prepare + * callbacks are called and only then all main callbacks are called. As its + * name suggests, the prepare callback can be used to do some preparatory work + * before invoking the main callback. + * + * Returns: an entry to be freed using qemu_del_vm_change_state_handler() + */ qemu_add_vm_change_state_handler_prio_full(VMChangeStateHandler *cb, VMChangeStateHandler *prepare_cb, VMChangeStateHandlerWithRet *cb_ret, diff --git a/system/runstate.c b/system/runstate.c index 38900c935a..fa32aa4795 100644 --- a/system/runstate.c +++ b/system/runstate.c @@ -306,18 +306,6 @@ struct VMChangeStateEntry { static QTAILQ_HEAD(, VMChangeStateEntry) vm_change_state_head = QTAILQ_HEAD_INITIALIZER(vm_change_state_head); -/** - * qemu_add_vm_change_state_handler_prio: - * @cb: the callback to invoke - * @opaque: user data passed to the callback - * @priority: low priorities execute first when the vm runs and the reverse is - * true when the vm stops - * - * Register a callback function that is invoked when the vm starts or stops - * running. - * - * Returns: an entry to be freed using qemu_del_vm_change_state_handler() - */ VMChangeStateEntry *qemu_add_vm_change_state_handler_prio( VMChangeStateHandler *cb, void *opaque, int priority) { @@ -325,24 +313,6 @@ VMChangeStateEntry *qemu_add_vm_change_state_handler_prio( opaque, priority); } -/** - * qemu_add_vm_change_state_handler_prio_full: - * @cb: the main callback to invoke - * @prepare_cb: a callback to invoke before the main callback - * @cb_ret: the main callback to invoke with return value - * @opaque: user data passed to the callbacks - * @priority: low priorities execute first when the vm runs and the reverse is - * true when the vm stops - * - * Register a main callback function and an optional prepare callback function - * that are invoked when the vm starts or stops running. The main callback and - * the prepare callback are called in two separate phases: First all prepare - * callbacks are called and only then all main callbacks are called. As its - * name suggests, the prepare callback can be used to do some preparatory work - * before invoking the main callback. - * - * Returns: an entry to be freed using qemu_del_vm_change_state_handler() - */ VMChangeStateEntry * qemu_add_vm_change_state_handler_prio_full(VMChangeStateHandler *cb, VMChangeStateHandler *prepare_cb,