[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 14/29] plugins: scoreboard API
From: |
Alex Bennée |
Subject: |
[PULL 14/29] plugins: scoreboard API |
Date: |
Wed, 6 Mar 2024 14:40:26 +0000 |
From: Pierrick Bouvier <pierrick.bouvier@linaro.org>
We introduce a cpu local storage, automatically managed (and extended)
by QEMU itself. Plugin allocate a scoreboard, and don't have to deal
with how many cpus are launched.
This API will be used by new inline functions but callbacks can benefit
from this as well. This way, they can operate without a global lock for
simple operations.
At any point during execution, any scoreboard will be dimensioned with
at least qemu_plugin_num_vcpus entries.
New functions:
- qemu_plugin_scoreboard_find
- qemu_plugin_scoreboard_free
- qemu_plugin_scoreboard_new
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Message-Id: <20240304130036.124418-2-pierrick.bouvier@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20240305121005.3528075-15-alex.bennee@linaro.org>
diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index b3c94a34aa4..bf96d2c2aa3 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -112,6 +112,12 @@ struct qemu_plugin_insn {
bool mem_only;
};
+/* A scoreboard is an array of values, indexed by vcpu_index */
+struct qemu_plugin_scoreboard {
+ GArray *data;
+ QLIST_ENTRY(qemu_plugin_scoreboard) entry;
+};
+
/*
* qemu_plugin_insn allocate and cleanup functions. We don't expect to
* cleanup many of these structures. They are reused for each fresh
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index 45e2ebc8f8f..31c468ddb2c 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -222,6 +222,8 @@ void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t
id,
struct qemu_plugin_tb;
/** struct qemu_plugin_insn - Opaque handle for a translated instruction */
struct qemu_plugin_insn;
+/** struct qemu_plugin_scoreboard - Opaque handle for a scoreboard */
+struct qemu_plugin_scoreboard;
/**
* enum qemu_plugin_cb_flags - type of callback
@@ -752,5 +754,34 @@ QEMU_PLUGIN_API
int qemu_plugin_read_register(struct qemu_plugin_register *handle,
GByteArray *buf);
+/**
+ * qemu_plugin_scoreboard_new() - alloc a new scoreboard
+ *
+ * @element_size: size (in bytes) for one entry
+ *
+ * Returns a pointer to a new scoreboard. It must be freed using
+ * qemu_plugin_scoreboard_free.
+ */
+QEMU_PLUGIN_API
+struct qemu_plugin_scoreboard *qemu_plugin_scoreboard_new(size_t element_size);
+
+/**
+ * qemu_plugin_scoreboard_free() - free a scoreboard
+ * @score: scoreboard to free
+ */
+QEMU_PLUGIN_API
+void qemu_plugin_scoreboard_free(struct qemu_plugin_scoreboard *score);
+
+/**
+ * qemu_plugin_scoreboard_find() - get pointer to an entry of a scoreboard
+ * @score: scoreboard to query
+ * @vcpu_index: entry index
+ *
+ * Returns address of entry of a scoreboard matching a given vcpu_index. This
+ * address can be modified later if scoreboard is resized.
+ */
+QEMU_PLUGIN_API
+void *qemu_plugin_scoreboard_find(struct qemu_plugin_scoreboard *score,
+ unsigned int vcpu_index);
#endif /* QEMU_QEMU_PLUGIN_H */
diff --git a/plugins/plugin.h b/plugins/plugin.h
index 00b3509f708..043c740067d 100644
--- a/plugins/plugin.h
+++ b/plugins/plugin.h
@@ -31,6 +31,8 @@ struct qemu_plugin_state {
* but with the HT we avoid adding a field to CPUState.
*/
GHashTable *cpu_ht;
+ QLIST_HEAD(, qemu_plugin_scoreboard) scoreboards;
+ size_t scoreboard_alloc_size;
DECLARE_BITMAP(mask, QEMU_PLUGIN_EV_MAX);
/*
* @lock protects the struct as well as ctx->uninstalling.
@@ -101,4 +103,8 @@ void exec_inline_op(struct qemu_plugin_dyn_cb *cb);
int plugin_num_vcpus(void);
+struct qemu_plugin_scoreboard *plugin_scoreboard_new(size_t element_size);
+
+void plugin_scoreboard_free(struct qemu_plugin_scoreboard *score);
+
#endif /* PLUGIN_H */
diff --git a/plugins/api.c b/plugins/api.c
index e905e995bd6..76b2e652b9c 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -465,3 +465,22 @@ int qemu_plugin_read_register(struct qemu_plugin_register
*reg, GByteArray *buf)
return gdb_read_register(current_cpu, buf, GPOINTER_TO_INT(reg));
}
+
+struct qemu_plugin_scoreboard *qemu_plugin_scoreboard_new(size_t element_size)
+{
+ return plugin_scoreboard_new(element_size);
+}
+
+void qemu_plugin_scoreboard_free(struct qemu_plugin_scoreboard *score)
+{
+ plugin_scoreboard_free(score);
+}
+
+void *qemu_plugin_scoreboard_find(struct qemu_plugin_scoreboard *score,
+ unsigned int vcpu_index)
+{
+ g_assert(vcpu_index < qemu_plugin_num_vcpus());
+ /* we can't use g_array_index since entry size is not statically known */
+ char *base_ptr = score->data->data;
+ return base_ptr + vcpu_index * g_array_get_element_size(score->data);
+}
diff --git a/plugins/core.c b/plugins/core.c
index 2db4d31354b..63f4c6c6ce3 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -18,6 +18,7 @@
#include "qemu/lockable.h"
#include "qemu/option.h"
#include "qemu/plugin.h"
+#include "qemu/queue.h"
#include "qemu/rcu_queue.h"
#include "qemu/xxhash.h"
#include "qemu/rcu.h"
@@ -215,6 +216,35 @@ CPUPluginState *qemu_plugin_create_vcpu_state(void)
return g_new0(CPUPluginState, 1);
}
+static void plugin_grow_scoreboards__locked(CPUState *cpu)
+{
+ if (cpu->cpu_index < plugin.scoreboard_alloc_size) {
+ return;
+ }
+
+ bool need_realloc = FALSE;
+ while (cpu->cpu_index >= plugin.scoreboard_alloc_size) {
+ plugin.scoreboard_alloc_size *= 2;
+ need_realloc = TRUE;
+ }
+
+
+ if (!need_realloc || QLIST_EMPTY(&plugin.scoreboards)) {
+ /* nothing to do, we just updated sizes for future scoreboards */
+ return;
+ }
+
+ /* cpus must be stopped, as tb might still use an existing scoreboard. */
+ start_exclusive();
+ struct qemu_plugin_scoreboard *score;
+ QLIST_FOREACH(score, &plugin.scoreboards, entry) {
+ g_array_set_size(score->data, plugin.scoreboard_alloc_size);
+ }
+ /* force all tb to be flushed, as scoreboard pointers were changed. */
+ tb_flush(cpu);
+ end_exclusive();
+}
+
void qemu_plugin_vcpu_init_hook(CPUState *cpu)
{
bool success;
@@ -225,6 +255,7 @@ void qemu_plugin_vcpu_init_hook(CPUState *cpu)
success = g_hash_table_insert(plugin.cpu_ht, &cpu->cpu_index,
&cpu->cpu_index);
g_assert(success);
+ plugin_grow_scoreboards__locked(cpu);
qemu_rec_mutex_unlock(&plugin.lock);
plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_INIT);
@@ -578,6 +609,8 @@ static void __attribute__((__constructor__))
plugin_init(void)
qemu_rec_mutex_init(&plugin.lock);
plugin.id_ht = g_hash_table_new(g_int64_hash, g_int64_equal);
plugin.cpu_ht = g_hash_table_new(g_int_hash, g_int_equal);
+ QLIST_INIT(&plugin.scoreboards);
+ plugin.scoreboard_alloc_size = 16; /* avoid frequent reallocation */
QTAILQ_INIT(&plugin.ctxs);
qht_init(&plugin.dyn_cb_arr_ht, plugin_dyn_cb_arr_cmp, 16,
QHT_MODE_AUTO_RESIZE);
@@ -588,3 +621,27 @@ int plugin_num_vcpus(void)
{
return plugin.num_vcpus;
}
+
+struct qemu_plugin_scoreboard *plugin_scoreboard_new(size_t element_size)
+{
+ struct qemu_plugin_scoreboard *score =
+ g_malloc0(sizeof(struct qemu_plugin_scoreboard));
+ score->data = g_array_new(FALSE, TRUE, element_size);
+ g_array_set_size(score->data, plugin.scoreboard_alloc_size);
+
+ qemu_rec_mutex_lock(&plugin.lock);
+ QLIST_INSERT_HEAD(&plugin.scoreboards, score, entry);
+ qemu_rec_mutex_unlock(&plugin.lock);
+
+ return score;
+}
+
+void plugin_scoreboard_free(struct qemu_plugin_scoreboard *score)
+{
+ qemu_rec_mutex_lock(&plugin.lock);
+ QLIST_REMOVE(score, entry);
+ qemu_rec_mutex_unlock(&plugin.lock);
+
+ g_array_free(score->data, TRUE);
+ g_free(score);
+}
diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols
index 27fe97239be..3f93e7d6b13 100644
--- a/plugins/qemu-plugins.symbols
+++ b/plugins/qemu-plugins.symbols
@@ -37,6 +37,9 @@
qemu_plugin_register_vcpu_tb_exec_inline;
qemu_plugin_register_vcpu_tb_trans_cb;
qemu_plugin_reset;
+ qemu_plugin_scoreboard_free;
+ qemu_plugin_scoreboard_find;
+ qemu_plugin_scoreboard_new;
qemu_plugin_start_code;
qemu_plugin_tb_get_insn;
qemu_plugin_tb_n_insns;
--
2.39.2
- [PULL 08/29] gdbstub: Call gdbserver_fork() both in parent and in child, (continued)
- [PULL 08/29] gdbstub: Call gdbserver_fork() both in parent and in child, Alex Bennée, 2024/03/06
- [PULL 12/29] gdbstub: Implement follow-fork-mode child, Alex Bennée, 2024/03/06
- [PULL 11/29] gdbstub: Introduce gdb_handle_detach_user(), Alex Bennée, 2024/03/06
- [PULL 07/29] {linux,bsd}-user: Pass pid to gdbserver_fork(), Alex Bennée, 2024/03/06
- [PULL 16/29] plugins: implement inline operation relative to cpu_index, Alex Bennée, 2024/03/06
- [PULL 03/29] {linux,bsd}-user: Introduce get_task_state(), Alex Bennée, 2024/03/06
- [PULL 01/29] tests: bump QOS_PATH_MAX_ELEMENT_SIZE again, Alex Bennée, 2024/03/06
- [PULL 18/29] tests/plugin: add test plugin for inline operations, Alex Bennée, 2024/03/06
- [PULL 19/29] tests/plugin/mem: migrate to new per_vcpu API, Alex Bennée, 2024/03/06
- [PULL 14/29] plugins: scoreboard API,
Alex Bennée <=
- [PULL 15/29] plugins: define qemu_plugin_u64, Alex Bennée, 2024/03/06
- [PULL 13/29] tests/tcg: Add two follow-fork-mode tests, Alex Bennée, 2024/03/06
- [PULL 17/29] plugins: add inline operation per vcpu, Alex Bennée, 2024/03/06
- [PULL 25/29] plugins: cleanup codepath for previous inline operation, Alex Bennée, 2024/03/06
- [PULL 24/29] plugins: remove non per_vcpu inline operation from API, Alex Bennée, 2024/03/06
- [PULL 23/29] contrib/plugins/howvec: migrate to new per_vcpu API, Alex Bennée, 2024/03/06
- [PULL 29/29] target/riscv: honour show_opcodes when disassembling, Alex Bennée, 2024/03/06
- [PULL 21/29] tests/plugin/bb: migrate to new per_vcpu API, Alex Bennée, 2024/03/06
- [PULL 20/29] tests/plugin/insn: migrate to new per_vcpu API, Alex Bennée, 2024/03/06
- [PULL 28/29] target/loongarch: honour show_opcodes when disassembling, Alex Bennée, 2024/03/06