From: Markus Armbruster <armbru@redhat.com>
To: Dinah Baum <dinahbaum123@gmail.com>
Cc: qemu-devel@nongnu.org, "Eduardo Habkost" <eduardo@habkost.net>,
"Marcel Apfelbaum" <marcel.apfelbaum@gmail.com>,
"Philippe Mathieu-Daudé" <philmd@linaro.org>,
"Yanan Wang" <wangyanan55@huawei.com>,
"Richard Henderson" <richard.henderson@linaro.org>,
"Paolo Bonzini" <pbonzini@redhat.com>
Subject: Re: [PATCH v2 3/3] cpu, qdict, vl: Enable printing options for CPU type
Date: Fri, 26 May 2023 08:07:58 +0200 [thread overview]
Message-ID: <878rdbfww1.fsf@pond.sub.org> (raw)
In-Reply-To: <20230404011956.90375-4-dinahbaum123@gmail.com> (Dinah Baum's message of "Mon, 3 Apr 2023 21:19:56 -0400")
This is really, really, *really* for maintainers of the code parsing
-cpu to review. Code parsing -cpu:
* parse_cpu_option() in cpu.c
Eduardo Habkost <eduardo@habkost.net> (supporter:Machine core)
Marcel Apfelbaum <marcel.apfelbaum@gmail.com> (supporter:Machine core)
"Philippe Mathieu-Daudé" <philmd@linaro.org> (reviewer:Machine core)
Yanan Wang <wangyanan55@huawei.com> (reviewer:Machine core)
* cpu_common_parse_features() in hw/core/cpu-common.c
No maintainers *boggle*
* x86_cpu_parse_featurestr() in qemu/target/i386/cpu.c
No maintainers *BOGGLE*
* sparc_cpu_parse_features() in target/sparc/cpu.c
Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> (maintainer:SPARC TCG CPUs)
Artyom Tarasenko <atar4qemu@gmail.com> (maintainer:SPARC TCG CPUs)
Paolo, Richard, Eduardo, care to get these covered in MAINTAINERS?
Since the patch has been waiting for review for so long, I'll give it a
try, even though I'm only passingly familiar with -cpu parsing.
Paolo, I have a question for you further down.
Dinah Baum <dinahbaum123@gmail.com> writes:
> Change parsing of -cpu argument to allow -cpu cpu,help
> to print options for the CPU type similar to
> how the '-device' option works.
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1480
>
> Signed-off-by: Dinah Baum <dinahbaum123@gmail.com>
> ---
> cpu.c | 41 +++++++++++++++++++++++++++++++++++++++
> include/exec/cpu-common.h | 2 ++
> include/qapi/qmp/qdict.h | 2 ++
> qemu-options.hx | 7 ++++---
> qobject/qdict.c | 5 +++++
> softmmu/vl.c | 36 ++++++++++++++++++++++++++++++++--
> 6 files changed, 88 insertions(+), 5 deletions(-)
>
> diff --git a/cpu.c b/cpu.c
> index daf4e1ff0d..5f8a72e51f 100644
> --- a/cpu.c
> +++ b/cpu.c
> @@ -23,7 +23,9 @@
> #include "exec/target_page.h"
> #include "hw/qdev-core.h"
> #include "hw/qdev-properties.h"
> +#include "qemu/cutils.h"
> #include "qemu/error-report.h"
> +#include "qemu/qemu-print.h"
> #include "migration/vmstate.h"
> #ifdef CONFIG_USER_ONLY
> #include "qemu.h"
> @@ -43,6 +45,8 @@
> #include "trace/trace-root.h"
> #include "qemu/accel.h"
> #include "qemu/plugin.h"
> +#include "qapi/qmp/qdict.h"
> +#include "qapi/qmp/qobject.h"
>
> uintptr_t qemu_host_page_size;
> intptr_t qemu_host_page_mask;
> @@ -312,6 +316,43 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> return get_cpu_model_expansion_info(type, model, errp);
> }
>
> +void list_cpu_model_expansion(CpuModelExpansionType type,
> + CpuModelInfo *model,
> + Error **errp)
> +{
> + CpuModelExpansionInfo *expansion_info;
> + QDict *qdict;
> + QDictEntry *qdict_entry;
> + const char *key;
> + QObject *obj;
> + QType q_type;
> + GPtrArray *array;
> + int i;
> + const char *type_name;
> +
> + expansion_info = get_cpu_model_expansion_info(type, model, errp);
> + if (expansion_info) {
Avoid nesting:
if (!expansion_info) {
return;
}
... work with expansion_info ...
> + qdict = qobject_to(QDict, expansion_info->model->props);
> + if (qdict) {
Likewise.
> + qemu_printf("%s features:\n", model->name);
> + array = g_ptr_array_new();
Name it @props, please.
> + for (qdict_entry = (QDictEntry *)qdict_first(qdict); qdict_entry;
> + qdict_entry = (QDictEntry *)qdict_next(qdict, qdict_entry)) {
> + g_ptr_array_add(array, qdict_entry);
> + }
@qdict can change while we're using it here (if it could, your code
would be wrong). So, no need for a flexible array. Create a dynamic
one with g_new(QDictEntry, qdict_size(qdict), fill it, then sort with
qsort().
> + g_ptr_array_sort(array, (GCompareFunc)dict_key_compare);
Casting function pointers is iffy. The clean way is to define the
function so it is a GCompareFunc exactly, and have it cast its arguments
if necessary.
> + for (i = 0; i < array->len; i++) {
> + qdict_entry = array->pdata[i];
> + key = qdict_entry_key(qdict_entry);
> + obj = qdict_get(qdict, key);
> + q_type = qobject_type(obj);
> + type_name = QType_str(q_type);
> + qemu_printf(" %s=<%s>\n", key, type_name);
Contract to
qemu_printf(" %s=<%s>\n",
key, QType_str(qobject_type(obj)));
Actually, don't use QType_str(), because the type comes out as "qnum",
"qstring", "qbool" (bad), or as "qdict", "qlist" (worse), or as "qnull"
(still worse, but impossible, I think).
Is CpuModelInfo the appropriate source? Could we get properties
straight from QOM instead, like we do for "-device TYPE,help" and
"-object TYPE,help"? I guess this question is for Paolo.
> + }
> + }
> + }
> +}
> +
> #if defined(CONFIG_USER_ONLY)
> void tb_invalidate_phys_addr(target_ulong addr)
> {
> diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
> index ec6024dfde..8fc05307ad 100644
> --- a/include/exec/cpu-common.h
> +++ b/include/exec/cpu-common.h
> @@ -174,5 +174,7 @@ typedef void (*cpu_model_expansion_func)(CpuModelExpansionType type,
> CpuModelExpansionInfo *get_cpu_model_expansion_info(CpuModelExpansionType type,
> CpuModelInfo *model,
> Error **errp);
> +void list_cpu_model_expansion(CpuModelExpansionType type,
> + CpuModelInfo *model, Error **errp);
>
> #endif /* CPU_COMMON_H */
> diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
> index 82e90fc072..1ff9523a13 100644
> --- a/include/qapi/qmp/qdict.h
> +++ b/include/qapi/qmp/qdict.h
> @@ -68,4 +68,6 @@ const char *qdict_get_try_str(const QDict *qdict, const char *key);
>
> QDict *qdict_clone_shallow(const QDict *src);
>
> +int dict_key_compare(QDictEntry **entry1, QDictEntry **entry2);
> +
> #endif /* QDICT_H */
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 59bdf67a2c..10601626b7 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -169,11 +169,12 @@ SRST
> ERST
>
> DEF("cpu", HAS_ARG, QEMU_OPTION_cpu,
> - "-cpu cpu select CPU ('-cpu help' for list)\n", QEMU_ARCH_ALL)
> + "-cpu cpu select CPU ('-cpu help' for list)\n"
> + " use '-cpu cpu,help' to print possible properties\n", QEMU_ARCH_ALL)
> SRST
> ``-cpu model``
> - Select CPU model (``-cpu help`` for list and additional feature
> - selection)
> + Select CPU model (``-cpu help`` and ``-cpu cpu,help``) for list and additional feature
> + selection
> ERST
>
> DEF("accel", HAS_ARG, QEMU_OPTION_accel,
> diff --git a/qobject/qdict.c b/qobject/qdict.c
> index 8faff230d3..31407e62f6 100644
> --- a/qobject/qdict.c
> +++ b/qobject/qdict.c
> @@ -447,3 +447,8 @@ void qdict_unref(QDict *q)
> {
> qobject_unref(q);
> }
> +
> +int dict_key_compare(QDictEntry **entry1, QDictEntry **entry2)
> +{
> + return g_strcmp0(qdict_entry_key(*entry1), qdict_entry_key(*entry2));
> +}
This file's external functions start with qdict_, not dict_.
There is just one caller. Let's put the function next to it, and make
it static.
> diff --git a/softmmu/vl.c b/softmmu/vl.c
> index ea20b23e4c..af6753a7e3 100644
> --- a/softmmu/vl.c
> +++ b/softmmu/vl.c
> @@ -500,6 +500,15 @@ static QemuOptsList qemu_action_opts = {
> },
> };
>
> +static QemuOptsList qemu_cpu_opts = {
> + .name = "cpu",
> + .implied_opt_name = "cpu",
> + .head = QTAILQ_HEAD_INITIALIZER(qemu_cpu_opts.head),
> + .desc = {
> + { /* end of list */ }
> + },
> +};
> +
> const char *qemu_get_vm_name(void)
> {
> return qemu_name;
> @@ -1147,6 +1156,26 @@ static int device_init_func(void *opaque, QemuOpts *opts, Error **errp)
> return 0;
> }
>
> +static int cpu_help_func(void *opaque, QemuOpts *opts, Error **errp)
> +{
> + CpuModelInfo *model;
> +
> + if (cpu_option && is_help_option(cpu_option)) {
> + list_cpus(cpu_option);
> + return 1;
> + }
> +
> + if (!cpu_option || !qemu_opt_has_help_opt(opts)) {
> + return 0;
> + }
> +
> + model = g_new0(CpuModelInfo, 1);
> + model->name = (char *)qemu_opt_get(opts, "cpu");
> + /* TODO: handle other expansion cases */
> + list_cpu_model_expansion(CPU_MODEL_EXPANSION_TYPE_FULL, model, errp);
> + return 1;
> +}
> +
> static int chardev_init_func(void *opaque, QemuOpts *opts, Error **errp)
> {
> Error *local_err = NULL;
> @@ -2431,8 +2460,9 @@ static void qemu_process_help_options(void)
> * type and the user did not specify one, so that the user doesn't need
> * to say '-cpu help -machine something'.
> */
> - if (cpu_option && is_help_option(cpu_option)) {
> - list_cpus(cpu_option);
> + Error *errp = NULL;
> + if (qemu_opts_foreach(qemu_find_opts("cpu"),
> + cpu_help_func, NULL, &errp)) {
> exit(0);
> }
>
> @@ -2673,6 +2703,7 @@ void qemu_init(int argc, char **argv)
> qemu_add_opts(&qemu_semihosting_config_opts);
> qemu_add_opts(&qemu_fw_cfg_opts);
> qemu_add_opts(&qemu_action_opts);
> + qemu_add_opts(&qemu_cpu_opts);
> module_call_init(MODULE_INIT_OPTS);
>
> error_init(argv[0]);
> @@ -2724,6 +2755,7 @@ void qemu_init(int argc, char **argv)
> switch(popt->index) {
> case QEMU_OPTION_cpu:
> /* hw initialization will check this */
> + qemu_opts_parse_noisily(qemu_find_opts("cpu"), optarg, true);
No :)
We have bespoke parsers for the argument of -cpu: parse_cpu_option()
together with CPUClass methods parse_features(). The syntax they parse
is superficially similar to QemuOpts (parts separated with comma), but
it's not the same. If it was, we'd use QemuOpts and ditch the bespoke
parsers.
If qemu_opts_parse_noisily() rejects @optarg here, it reports an error,
and we continue anyway.
If parse_cpu_option() also rejects @optarg later on, the error is
reported twice. Bad.
If it doesn't, the error qemu_opts_parse_noisily() reported is bogus.
If both succeed, they may well yield different parse results. I can try
to dig up examples if necessary.
As far as I can see, you use the result of qemu_opts_parse_noisily()
only with cpu_help_func(). Can we slot the help feature into the
bespoke parser instead? Let's have a look.
When the argument of -cpu is "help", qemu_process_help_options() shows
help and exits before we call parse_cpu_option().
parse_cpu_option() splits the argument of -cpu at the first comma into
CPU class name and features.
If you factor the splitting out of parse_cpu_option(), you can call it
from qemu_process_help_options(), then check whether the features are
"help".
> cpu_option = optarg;
> break;
> case QEMU_OPTION_hda:
next prev parent reply other threads:[~2023-05-26 6:08 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-04-04 1:19 [RESEND PATCH v2 0/3] Enable -cpu <cpu>,help Dinah Baum
2023-04-04 1:19 ` [PATCH v2 1/3] qapi/machine-target: refactor machine-target Dinah Baum
2023-05-11 14:38 ` Markus Armbruster
2023-04-04 1:19 ` [PATCH v2 2/3] cpu, qapi, target/arm, i386, s390x: Generalize query-cpu-model-expansion Dinah Baum
2023-05-11 17:41 ` Markus Armbruster
2023-04-04 1:19 ` [PATCH v2 3/3] cpu, qdict, vl: Enable printing options for CPU type Dinah Baum
2023-05-26 6:07 ` Markus Armbruster [this message]
2023-05-11 12:16 ` [RESEND PATCH v2 0/3] Enable -cpu <cpu>,help Peter Maydell
2023-05-11 13:51 ` Markus Armbruster
2023-05-26 14:28 ` Igor Mammedov
2023-05-26 19:47 ` Peter Maydell
-- strict thread matches above, loose matches on Subject: below --
2023-03-14 10:00 [PATCH " Dinah Baum
2023-03-14 10:00 ` [PATCH v2 3/3] cpu, qdict, vl: Enable printing options for CPU type Dinah Baum
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=878rdbfww1.fsf@pond.sub.org \
--to=armbru@redhat.com \
--cc=dinahbaum123@gmail.com \
--cc=eduardo@habkost.net \
--cc=marcel.apfelbaum@gmail.com \
--cc=pbonzini@redhat.com \
--cc=philmd@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=richard.henderson@linaro.org \
--cc=wangyanan55@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).