diff mbox series

[RFC,45/48] plugin: lockstep execution support

Message ID 20181025172057.20414-46-cota@braap.org
State New
Headers show
Series Plugin support | expand

Commit Message

Emilio Cota Oct. 25, 2018, 5:20 p.m. UTC
Signed-off-by: Emilio G. Cota <cota@braap.org>
---
 include/qemu/plugin-api.h |  7 +++++++
 include/qemu/plugin.h     |  5 +++++
 cpus.c                    |  1 +
 plugin.c                  | 35 +++++++++++++++++++++++++++++++++++
 qemu-plugins.symbols      |  3 +++
 5 files changed, 51 insertions(+)

Comments

Alex Bennée Nov. 27, 2018, 6:20 p.m. UTC | #1
Emilio G. Cota <cota@braap.org> writes:

> Signed-off-by: Emilio G. Cota <cota@braap.org>

There are no users of this for now so I don't think this qualifies for a
first cut of the plugin API. Is the lockstep support only their for
plugins? Is there any practical use that isn't handled by non-MTTCG
round-robin and icount type scenarios?

> ---
>  include/qemu/plugin-api.h |  7 +++++++
>  include/qemu/plugin.h     |  5 +++++
>  cpus.c                    |  1 +
>  plugin.c                  | 35 +++++++++++++++++++++++++++++++++++
>  qemu-plugins.symbols      |  3 +++
>  5 files changed, 51 insertions(+)
>
> diff --git a/include/qemu/plugin-api.h b/include/qemu/plugin-api.h
> index 076353a2d2..5062e20e08 100644
> --- a/include/qemu/plugin-api.h
> +++ b/include/qemu/plugin-api.h
> @@ -227,6 +227,13 @@ typedef int64_t (*qemu_plugin_clock_func_t)(void);
>  bool qemu_plugin_register_virtual_clock(qemu_plugin_id_t id,
>                                          qemu_plugin_clock_func_t clock);
>
> +void qemu_plugin_enable_lockstep_execution(void);
> +
> +void qemu_plugin_register_lockstep_cb(qemu_plugin_id_t id,
> +                                      qemu_plugin_simple_cb_t cb);
> +
> +void qemu_plugin_end_time_slice(void);
> +
>  /* returns -1 in user-mode */
>  int qemu_plugin_n_vcpus(void);
>
> diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
> index 617161329f..c19071bdbe 100644
> --- a/include/qemu/plugin.h
> +++ b/include/qemu/plugin.h
> @@ -58,6 +58,7 @@ enum qemu_plugin_event {
>      QEMU_PLUGIN_EV_VCPU_RESUME,
>      QEMU_PLUGIN_EV_VCPU_SYSCALL,
>      QEMU_PLUGIN_EV_VCPU_SYSCALL_RET,
> +    QEMU_PLUGIN_EV_LOCKSTEP,
>      QEMU_PLUGIN_EV_FLUSH,
>      QEMU_PLUGIN_EV_ATEXIT,
>      QEMU_PLUGIN_EV_MAX,
> @@ -194,6 +195,7 @@ void qemu_plugin_atexit_cb(void);
>
>  void qemu_plugin_add_dyn_cb_arr(struct qemu_plugin_dyn_cb_arr *arr);
>  int64_t plugin_get_clock(void);
> +void plugin_lockstep_cb(void);
>
>  #else /* !CONFIG_PLUGINS */
>
> @@ -237,6 +239,9 @@ static inline
>  void qemu_plugin_add_dyn_cb_arr(struct qemu_plugin_dyn_cb_arr *arr)
>  { }
>
> +static inline void plugin_lockstep_cb(void)
> +{ }
> +
>  int64_t plugin_get_clock(void);
>
>  #endif /* !CONFIG_PLUGINS */
> diff --git a/cpus.c b/cpus.c
> index a446632a5c..8f490d1b11 100644
> --- a/cpus.c
> +++ b/cpus.c
> @@ -1359,6 +1359,7 @@ static void lockstep_check_stop(CPUState *cpu)
>              /* wake up all waiting cpus */
>              lockstep_ongoing_wakeup = true;
>              n_lockstep_running_cpus = n_lockstep_cpus;
> +            plugin_lockstep_cb();
>              qemu_mutex_unlock(&lockstep_lock);
>              cpu_mutex_unlock(cpu);
>              for (i = 0; i < n_lockstep_cpus; i++) {
> diff --git a/plugin.c b/plugin.c
> index 291767f2bb..117f303249 100644
> --- a/plugin.c
> +++ b/plugin.c
> @@ -472,6 +472,7 @@ static void plugin_cb__simple(enum qemu_plugin_event ev)
>
>      switch (ev) {
>      case QEMU_PLUGIN_EV_FLUSH:
> +    case QEMU_PLUGIN_EV_LOCKSTEP:
>          QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
>              qemu_plugin_simple_cb_t func = cb->f.simple;
>
> @@ -1043,6 +1044,40 @@ int64_t plugin_get_clock(void)
>  }
>  #endif
>
> +/*
> + * We manage the CPU state changes; the plugin will control the length of the
> + * execution windows.
> + */
> +void qemu_plugin_enable_lockstep_execution(void)
> +{
> +#ifdef CONFIG_USER_ONLY
> +    abort();
> +#else
> +    cpu_lockstep_enable();
> +#endif
> +}
> +
> +void qemu_plugin_end_time_slice(void)
> +{
> +#ifdef CONFIG_USER_ONLY
> +    abort();
> +#else
> +    g_assert(current_cpu);
> +    cpu_lockstep_request_stop(current_cpu);
> +#endif
> +}
> +
> +void qemu_plugin_register_lockstep_cb(qemu_plugin_id_t id,
> +                                      qemu_plugin_simple_cb_t cb)
> +{
> +    plugin_register_cb(id, QEMU_PLUGIN_EV_LOCKSTEP, cb);
> +}
> +
> +void plugin_lockstep_cb(void)
> +{
> +    plugin_cb__simple(QEMU_PLUGIN_EV_LOCKSTEP);
> +}
> +
>  static void __attribute__((__constructor__)) plugin_init(void)
>  {
>      int i;
> diff --git a/qemu-plugins.symbols b/qemu-plugins.symbols
> index 93587b07e1..a3268a40c7 100644
> --- a/qemu-plugins.symbols
> +++ b/qemu-plugins.symbols
> @@ -1,5 +1,8 @@
>  {
>    qemu_plugin_uninstall;
> +  qemu_plugin_enable_lockstep_execution;
> +  qemu_plugin_end_time_slice;
> +  qemu_plugin_register_lockstep_cb;
>    qemu_plugin_register_vcpu_init_cb;
>    qemu_plugin_register_vcpu_exit_cb;
>    qemu_plugin_register_vcpu_idle_cb;


--
Alex Bennée
Emilio Cota Nov. 27, 2018, 7:19 p.m. UTC | #2
On Tue, Nov 27, 2018 at 18:20:25 +0000, Alex Bennée wrote:
> 
> Emilio G. Cota <cota@braap.org> writes:
> 
> > Signed-off-by: Emilio G. Cota <cota@braap.org>
> 
> There are no users of this for now so I don't think this qualifies for a
> first cut of the plugin API.

Fair enough. It was more as an example that plugins are not just
for instrumentation purposes. Another example of this is the use of
plugins to control the guest's clock -- for instance, there was
this series
  https://lists.gnu.org/archive/html/qemu-devel/2017-02/msg03028.html
that implemented a module to control the guest's clock over sockets.
Instead, a plugin can just be loaded to take control, and the plugin
is free to interact with the outer world in whatever way it
wants (sockets, pipes, etc.). So having a plugin infrastructure
can make adding those features much easier to implement (FWIW,
that patch never landed on master).

> Is the lockstep support only their for
> plugins? Is there any practical use that isn't handled by non-MTTCG
> round-robin and icount type scenarios?

This is a compromise between icount and MTTCG by limiting the latter's
skew among vCPUs. So you don't get full determinism, but get closer to
it without giving up parallelism.

I think this feature could be added without plugins, by for instance
defaulting to an "MTTCG icount-like" behaviour. That is, the
time window of each CPU would expire after N instructions executed.

But I didn't have a use case for that; my use case is to control
the time windows from the plugins, since in my simulator the
plugin controls the guest clock, and instructions have different
latencies.

So yes, feel free to skip this patch!

Thanks,

		Emilio
diff mbox series

Patch

diff --git a/include/qemu/plugin-api.h b/include/qemu/plugin-api.h
index 076353a2d2..5062e20e08 100644
--- a/include/qemu/plugin-api.h
+++ b/include/qemu/plugin-api.h
@@ -227,6 +227,13 @@  typedef int64_t (*qemu_plugin_clock_func_t)(void);
 bool qemu_plugin_register_virtual_clock(qemu_plugin_id_t id,
                                         qemu_plugin_clock_func_t clock);
 
+void qemu_plugin_enable_lockstep_execution(void);
+
+void qemu_plugin_register_lockstep_cb(qemu_plugin_id_t id,
+                                      qemu_plugin_simple_cb_t cb);
+
+void qemu_plugin_end_time_slice(void);
+
 /* returns -1 in user-mode */
 int qemu_plugin_n_vcpus(void);
 
diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index 617161329f..c19071bdbe 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -58,6 +58,7 @@  enum qemu_plugin_event {
     QEMU_PLUGIN_EV_VCPU_RESUME,
     QEMU_PLUGIN_EV_VCPU_SYSCALL,
     QEMU_PLUGIN_EV_VCPU_SYSCALL_RET,
+    QEMU_PLUGIN_EV_LOCKSTEP,
     QEMU_PLUGIN_EV_FLUSH,
     QEMU_PLUGIN_EV_ATEXIT,
     QEMU_PLUGIN_EV_MAX,
@@ -194,6 +195,7 @@  void qemu_plugin_atexit_cb(void);
 
 void qemu_plugin_add_dyn_cb_arr(struct qemu_plugin_dyn_cb_arr *arr);
 int64_t plugin_get_clock(void);
+void plugin_lockstep_cb(void);
 
 #else /* !CONFIG_PLUGINS */
 
@@ -237,6 +239,9 @@  static inline
 void qemu_plugin_add_dyn_cb_arr(struct qemu_plugin_dyn_cb_arr *arr)
 { }
 
+static inline void plugin_lockstep_cb(void)
+{ }
+
 int64_t plugin_get_clock(void);
 
 #endif /* !CONFIG_PLUGINS */
diff --git a/cpus.c b/cpus.c
index a446632a5c..8f490d1b11 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1359,6 +1359,7 @@  static void lockstep_check_stop(CPUState *cpu)
             /* wake up all waiting cpus */
             lockstep_ongoing_wakeup = true;
             n_lockstep_running_cpus = n_lockstep_cpus;
+            plugin_lockstep_cb();
             qemu_mutex_unlock(&lockstep_lock);
             cpu_mutex_unlock(cpu);
             for (i = 0; i < n_lockstep_cpus; i++) {
diff --git a/plugin.c b/plugin.c
index 291767f2bb..117f303249 100644
--- a/plugin.c
+++ b/plugin.c
@@ -472,6 +472,7 @@  static void plugin_cb__simple(enum qemu_plugin_event ev)
 
     switch (ev) {
     case QEMU_PLUGIN_EV_FLUSH:
+    case QEMU_PLUGIN_EV_LOCKSTEP:
         QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
             qemu_plugin_simple_cb_t func = cb->f.simple;
 
@@ -1043,6 +1044,40 @@  int64_t plugin_get_clock(void)
 }
 #endif
 
+/*
+ * We manage the CPU state changes; the plugin will control the length of the
+ * execution windows.
+ */
+void qemu_plugin_enable_lockstep_execution(void)
+{
+#ifdef CONFIG_USER_ONLY
+    abort();
+#else
+    cpu_lockstep_enable();
+#endif
+}
+
+void qemu_plugin_end_time_slice(void)
+{
+#ifdef CONFIG_USER_ONLY
+    abort();
+#else
+    g_assert(current_cpu);
+    cpu_lockstep_request_stop(current_cpu);
+#endif
+}
+
+void qemu_plugin_register_lockstep_cb(qemu_plugin_id_t id,
+                                      qemu_plugin_simple_cb_t cb)
+{
+    plugin_register_cb(id, QEMU_PLUGIN_EV_LOCKSTEP, cb);
+}
+
+void plugin_lockstep_cb(void)
+{
+    plugin_cb__simple(QEMU_PLUGIN_EV_LOCKSTEP);
+}
+
 static void __attribute__((__constructor__)) plugin_init(void)
 {
     int i;
diff --git a/qemu-plugins.symbols b/qemu-plugins.symbols
index 93587b07e1..a3268a40c7 100644
--- a/qemu-plugins.symbols
+++ b/qemu-plugins.symbols
@@ -1,5 +1,8 @@ 
 {
   qemu_plugin_uninstall;
+  qemu_plugin_enable_lockstep_execution;
+  qemu_plugin_end_time_slice;
+  qemu_plugin_register_lockstep_cb;
   qemu_plugin_register_vcpu_init_cb;
   qemu_plugin_register_vcpu_exit_cb;
   qemu_plugin_register_vcpu_idle_cb;