Message ID | 20181025172057.20414-46-cota@braap.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Plugin support | expand |
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
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 --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;
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(+)