From: "Alex Bennée" <alex.bennee@linaro.org>
To: Akihiko Odaki <akihiko.odaki@daynix.com>
Cc: qemu-devel@nongnu.org,
"Yoshinori Sato" <ysato@users.sourceforge.jp>,
"David Hildenbrand" <david@redhat.com>,
"Weiwei Li" <liwei1518@gmail.com>,
"Richard Henderson" <richard.henderson@linaro.org>,
"Michael Rolnik" <mrolnik@gmail.com>,
"Ilya Leoshkevich" <iii@linux.ibm.com>,
"Peter Maydell" <peter.maydell@linaro.org>,
qemu-ppc@nongnu.org, "Paolo Bonzini" <pbonzini@redhat.com>,
qemu-riscv@nongnu.org, "Cleber Rosa" <crosa@redhat.com>,
"Thomas Huth" <thuth@redhat.com>,
"Song Gao" <gaosong@loongson.cn>,
qemu-arm@nongnu.org,
"Pierrick Bouvier" <pierrick.bouvier@linaro.org>,
"John Snow" <jsnow@redhat.com>, "Cédric Le Goater" <clg@kaod.org>,
"Nicholas Piggin" <npiggin@gmail.com>,
qemu-s390x@nongnu.org, "Laurent Vivier" <laurent@vivier.eu>,
"Edgar E. Iglesias" <edgar.iglesias@gmail.com>,
"Daniel Henrique Barboza" <dbarboza@ventanamicro.com>,
"Yanan Wang" <wangyanan55@huawei.com>,
"Palmer Dabbelt" <palmer@dabbelt.com>,
"Marcel Apfelbaum" <marcel.apfelbaum@gmail.com>,
"Brian Cain" <bcain@quicinc.com>,
"Mahmoud Mandour" <ma.mandourr@gmail.com>,
"Alexandre Iooss" <erdnaxe@crans.org>,
"Bin Meng" <bin.meng@windriver.com>,
"Philippe Mathieu-Daudé" <philmd@linaro.org>,
"Daniel Henrique Barboza" <danielhb413@gmail.com>,
"Eduardo Habkost" <eduardo@habkost.net>,
"Alistair Francis" <alistair.francis@wdc.com>,
"Liu Zhiwei" <zhiwei_liu@linux.alibaba.com>
Subject: Re: [PATCH 18/23] plugins: add an API to read registers
Date: Wed, 21 Feb 2024 14:14:21 +0000 [thread overview]
Message-ID: <87zfvtaoqq.fsf@draig.linaro.org> (raw)
In-Reply-To: <bf5e9471-c09f-47f2-a5a3-83713255c47a@daynix.com> (Akihiko Odaki's message of "Wed, 21 Feb 2024 19:11:05 +0900")
Akihiko Odaki <akihiko.odaki@daynix.com> writes:
> On 2024/02/21 19:02, Alex Bennée wrote:
>> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
>>
>>> On 2024/02/20 23:14, Alex Bennée wrote:
>>>> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
>>>>
>>>>> On 2024/02/17 1:30, Alex Bennée wrote:
>>>>>> We can only request a list of registers once the vCPU has been
>>>>>> initialised so the user needs to use either call the get function on
>>>>>> vCPU initialisation or during the translation phase.
>>>>>> We don't expose the reg number to the plugin instead hiding it
>>>>>> behind
>>>>>> an opaque handle. This allows for a bit of future proofing should the
>>>>>> internals need to be changed while also being hashed against the
>>>>>> CPUClass so we can handle different register sets per-vCPU in
>>>>>> hetrogenous situations.
>>>>>> Having an internal state within the plugins also allows us to expand
>>>>>> the interface in future (for example providing callbacks on register
>>>>>> change if the translator can track changes).
>>>>>> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1706
>>>>>> Cc: Akihiko Odaki <akihiko.odaki@daynix.com>
>>>>>> Message-Id: <20240103173349.398526-39-alex.bennee@linaro.org>
>>>>>> Based-on: <20231025093128.33116-18-akihiko.odaki@daynix.com>
>>>>>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>>>>>> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
>>>> <snip>
>>>>>> +/*
>>>>>> + * Register handles
>>>>>> + *
>>>>>> + * The plugin infrastructure keeps hold of these internal data
>>>>>> + * structures which are presented to plugins as opaque handles. They
>>>>>> + * are global to the system and therefor additions to the hash table
>>>>>> + * must be protected by the @reg_handle_lock.
>>>>>> + *
>>>>>> + * In order to future proof for up-coming heterogeneous work we want
>>>>>> + * different entries for each CPU type while sharing them in the
>>>>>> + * common case of multiple cores of the same type.
>>>>>> + */
>>>>>> +
>>>>>> +static QemuMutex reg_handle_lock;
>>>>>> +
>>>>>> +struct qemu_plugin_register {
>>>>>> + const char *name;
>>>>>> + int gdb_reg_num;
>>>>>> +};
>>>>>> +
>>>>>> +static GHashTable *reg_handles; /* hash table of PluginReg */
>>>>>> +
>>>>>> +/* Generate a stable key - would xxhash be overkill? */
>>>>>> +static gpointer cpu_plus_reg_to_key(CPUState *cs, int gdb_regnum)
>>>>>> +{
>>>>>> + uintptr_t key = (uintptr_t) cs->cc;
>>>>>> + key ^= gdb_regnum;
>>>>>> + return GUINT_TO_POINTER(key);
>>>>>> +}
>>>>>
>>>>> I have pointed out this is theoretically prone to collisions and
>>>>> unsafe.
>>>> How is it unsafe? The aim is to share handles for the same CPUClass
>>>> rather than having a unique handle per register/cpu combo.
>>>
>>> THe intention is legitimate, but the implementation is not safe. It
>>> assumes (uintptr)cs->cc ^ gdb_regnum is unique, but there is no such
>>> guarantee. The key of GHashTable must be unique; generating hashes of
>>> keys should be done with hash_func given to g_hash_table_new().
>> This isn't a hash its a non-unique key. It is however unique for
>> the same register on the same class of CPU so for each vCPU in a system
>> can share the same opaque handles.
>> The hashing is done internally by glib. We would assert if there was
>> a
>> duplicate key referring to a different register.
>> I'm unsure what you want here? Do you have a suggestion for the key
>> generation algorithm? As the comment notes I did consider a more complex
>> mixing algorithm using xxhash but that wouldn't guarantee no clash
>> either.
>
> I suggest using a struct that holds both of cs->cc and gdb_regnum, and
> pass g_direct_equal() and g_direct_hash() to g_hash_table_new().
We already do:
if (!reg_handles) {
reg_handles = g_hash_table_new(g_direct_hash, g_direct_equal);
}
But we can't use g_direct_equal with something that exceeds the width of
gpointer as it is a straight equality test of the key. What you are
suggesting requires allocating memory for each key and de-referencing
with a custom GEqualFunc.
This seems overkill for something that as I have said doesn't happen.
The reason it doesn't happen is you will never see two CPUClass
instances so close to each other they share all bits apart from where
gdb_regnum is being xor'd. We could assert that is the case with
something like:
#define MAX_GDBREGS 300
/* Generate a stable key - would xxhash be overkill? */
static gpointer cpu_plus_reg_to_key(CPUState *cs, int gdb_regnum)
{
uintptr_t key = (uintptr_t) cs->cc;
qemu_build_assert(sizeof(*cs->cc) >= MAX_GDBREGS);
g_assert(gdb_regnum < MAX_GDBREGS);
key ^= gdb_regnum;
return GUINT_TO_POINTER(key);
}
although MAX_GDBREGS is currently a guess based on aarch64. In practice
though there are so many allocations thing are much farther apart. As we
can see in the one heterogeneous model we support at the moment (the
last 2 CPUs are cortex-r5f's):
./qemu-system-aarch64 -M xlnx-zcu102 -audio none -smp 6 -serial mon:stdio -s -S -smp 6
cpu_common_class_init: k = 0x5565bebf10f0
arm_cpu_initfn: 0x7f32ee0a8360 -> klass = 0x5565bee50e00
aarch64_cpu_instance_init: 0x7f32ee0a8360 -> klass = 0x5565bee50e00
arm_cpu_initfn: 0x7f32ee0be1f0 -> klass = 0x5565bee50e00
aarch64_cpu_instance_init: 0x7f32ee0be1f0 -> klass = 0x5565bee50e00
arm_cpu_initfn: 0x7f32ee0d4080 -> klass = 0x5565bee50e00
aarch64_cpu_instance_init: 0x7f32ee0d4080 -> klass = 0x5565bee50e00
arm_cpu_initfn: 0x7f32ee0e9f10 -> klass = 0x5565bee50e00
aarch64_cpu_instance_init: 0x7f32ee0e9f10 -> klass = 0x5565bee50e00
arm_cpu_initfn: 0x7f32ee0ffda0 -> klass = 0x5565bed0fad0
arm_cpu_initfn: 0x7f32ee115c30 -> klass = 0x5565bed0fad0
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
next prev parent reply other threads:[~2024-02-21 15:53 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-16 16:30 [PATCH 00/23] maintainer updates for 9.0 pre-PR (tests, plugin register support) Alex Bennée
2024-02-16 16:30 ` [PATCH 01/23] tests/tcg: update licenses to GPLv2 as intended Alex Bennée
2024-02-16 16:30 ` [PATCH 02/23] target/arm: Use GDBFeature for dynamic XML Alex Bennée
2024-02-16 16:30 ` [PATCH 03/23] target/ppc: " Alex Bennée
2024-02-16 16:30 ` [PATCH 04/23] target/riscv: " Alex Bennée
2024-02-16 16:30 ` [PATCH 05/23] gdbstub: Use GDBFeature for gdb_register_coprocessor Alex Bennée
2024-02-16 16:30 ` [PATCH 06/23] gdbstub: Use GDBFeature for GDBRegisterState Alex Bennée
2024-02-16 16:30 ` [PATCH 07/23] gdbstub: Change gdb_get_reg_cb and gdb_set_reg_cb Alex Bennée
2024-02-16 16:30 ` [PATCH 08/23] gdbstub: Simplify XML lookup Alex Bennée
2024-02-16 16:30 ` [PATCH 09/23] gdbstub: Infer number of core registers from XML Alex Bennée
2024-02-16 16:30 ` [PATCH 10/23] hw/core/cpu: Remove gdb_get_dynamic_xml member Alex Bennée
2024-02-16 16:30 ` [PATCH 11/23] gdbstub: Add members to identify registers to GDBFeature Alex Bennée
2024-02-16 16:30 ` [PATCH 12/23] plugins: remove previous n_vcpus functions from API Alex Bennée
2024-02-16 16:30 ` [PATCH 13/23] plugins: add qemu_plugin_num_vcpus function Alex Bennée
2024-02-16 16:30 ` [PATCH 14/23] plugins: fix order of init/idle/resume callback Alex Bennée
2024-02-16 16:30 ` [PATCH 15/23] cpu: call plugin init hook asynchronously Alex Bennée
2024-02-16 16:30 ` [PATCH 16/23] plugins: Use different helpers when reading registers Alex Bennée
2024-02-16 16:30 ` [PATCH 17/23] gdbstub: expose api to find registers Alex Bennée
2024-02-16 16:30 ` [PATCH 18/23] plugins: add an API to read registers Alex Bennée
2024-02-17 8:01 ` Akihiko Odaki
2024-02-20 14:14 ` Alex Bennée
2024-02-21 4:45 ` Akihiko Odaki
2024-02-21 10:02 ` Alex Bennée
2024-02-21 10:11 ` Akihiko Odaki
2024-02-21 14:14 ` Alex Bennée [this message]
2024-02-22 6:37 ` Akihiko Odaki
2024-02-22 10:20 ` Alex Bennée
2024-02-22 13:22 ` Akihiko Odaki
2024-02-22 17:27 ` Alex Bennée
2024-02-23 10:58 ` Akihiko Odaki
2024-02-23 11:44 ` Alex Bennée
2024-02-23 16:24 ` Alex Bennée
2024-02-16 16:30 ` [PATCH 19/23] contrib/plugins: fix imatch Alex Bennée
2024-02-16 16:30 ` [PATCH 20/23] contrib/plugins: extend execlog to track register changes Alex Bennée
2024-02-17 11:36 ` Pierrick Bouvier
2024-02-16 16:30 ` [PATCH 21/23] docs/devel: lift example and plugin API sections up Alex Bennée
2024-02-16 16:30 ` [PATCH 22/23] docs/devel: document some plugin assumptions Alex Bennée
2024-02-16 16:30 ` [PATCH 23/23] docs/devel: plugins can trigger a tb flush Alex Bennée
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=87zfvtaoqq.fsf@draig.linaro.org \
--to=alex.bennee@linaro.org \
--cc=akihiko.odaki@daynix.com \
--cc=alistair.francis@wdc.com \
--cc=bcain@quicinc.com \
--cc=bin.meng@windriver.com \
--cc=clg@kaod.org \
--cc=crosa@redhat.com \
--cc=danielhb413@gmail.com \
--cc=david@redhat.com \
--cc=dbarboza@ventanamicro.com \
--cc=edgar.iglesias@gmail.com \
--cc=eduardo@habkost.net \
--cc=erdnaxe@crans.org \
--cc=gaosong@loongson.cn \
--cc=iii@linux.ibm.com \
--cc=jsnow@redhat.com \
--cc=laurent@vivier.eu \
--cc=liwei1518@gmail.com \
--cc=ma.mandourr@gmail.com \
--cc=marcel.apfelbaum@gmail.com \
--cc=mrolnik@gmail.com \
--cc=npiggin@gmail.com \
--cc=palmer@dabbelt.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=philmd@linaro.org \
--cc=pierrick.bouvier@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=qemu-ppc@nongnu.org \
--cc=qemu-riscv@nongnu.org \
--cc=qemu-s390x@nongnu.org \
--cc=richard.henderson@linaro.org \
--cc=thuth@redhat.com \
--cc=wangyanan55@huawei.com \
--cc=ysato@users.sourceforge.jp \
--cc=zhiwei_liu@linux.alibaba.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).