All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 0/2] Balloon event change notifications
@ 2012-06-14 17:12 Daniel P. Berrange
  2012-06-14 17:12 ` [Qemu-devel] [PATCH v3 1/2] Add event notification for guest balloon changes Daniel P. Berrange
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Daniel P. Berrange @ 2012-06-14 17:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Markus Armbruster, Anthony Liguori, Luiz Capitulino

This is a followup to:

  https://lists.gnu.org/archive/html/qemu-devel/2012-05/msg02833.html


Changes since v2:

  - Drop 'query-events' patch which is already merged
  - Rename balloon_change() function to balloon_changed per
    Amit's request
  - Misc typos fixed
  - Remove monitor_global_init(), folding code into the
    one-time initialization block in monitor_init()

This series is being tested with a corresponding patch to libvirt
for handling balloon events

https://www.redhat.com/archives/libvir-list/2012-May/msg00868.html

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH v3 1/2] Add event notification for guest balloon changes
  2012-06-14 17:12 [Qemu-devel] [PATCH v3 0/2] Balloon event change notifications Daniel P. Berrange
@ 2012-06-14 17:12 ` Daniel P. Berrange
  2012-06-14 17:12 ` [Qemu-devel] [PATCH v3 2/2] Add rate limiting of RTC_CHANGE, BALLOON_CHANGE & WATCHDOG events Daniel P. Berrange
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Daniel P. Berrange @ 2012-06-14 17:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Markus Armbruster, Anthony Liguori, Luiz Capitulino

From: "Daniel P. Berrange" <berrange@redhat.com>

After setting a balloon target value, applications have to
continually poll 'query-balloon' to determine whether the
guest has reacted to this request. The virtio-balloon backend
knows exactly when the guest has reacted though, and thus it
is possible to emit a JSON event to tell the mgmt application
whenever the guest balloon changes.

This introduces a new 'qemu_balloon_changed()' API which is
to be called by balloon driver backends, whenever they have
a change in balloon value. This takes the 'actual' balloon
value, as would be found in the BalloonInfo struct.

The qemu_balloon_change API emits a JSON monitor event which
looks like:

  {"timestamp": {"seconds": 1337162462, "microseconds": 814521},
   "event": "BALLOON_CHANGE", "data": {"actual": 944766976}}

* balloon.c, balloon.h: Introduce qemu_balloon_changed() for
  emitting balloon change events on the monitor
* hw/virtio-balloon.c: Invoke qemu_balloon_changed() whenever
  the guest changes the balloon actual value
* monitor.c, monitor.h: Define QEVENT_BALLOON_CHANGE

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 QMP/qmp-events.txt  |   18 ++++++++++++++++++
 balloon.c           |   14 ++++++++++++++
 balloon.h           |    2 ++
 hw/virtio-balloon.c |    5 +++++
 monitor.c           |    1 +
 monitor.h           |    1 +
 6 files changed, 41 insertions(+), 0 deletions(-)

diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
index 9286af5..9ba7079 100644
--- a/QMP/qmp-events.txt
+++ b/QMP/qmp-events.txt
@@ -335,3 +335,21 @@ Example:
                "len": 10737418240, "offset": 134217728,
                "speed": 0 },
      "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+
+
+BALLOON_CHANGE
+----------
+
+Emitted when the guest changes the actual BALLOON level. This
+value is equivalent to the 'actual' field return by the
+'query-balloon' command
+
+Data:
+
+- "actual": actual level of the guest memory balloon in bytes (json-number)
+
+Example:
+
+{ "event": "BALLOON_CHANGE",
+    "data": { "actual": 944766976 },
+    "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
diff --git a/balloon.c b/balloon.c
index aa354f7..e02ab1c 100644
--- a/balloon.c
+++ b/balloon.c
@@ -30,6 +30,7 @@
 #include "balloon.h"
 #include "trace.h"
 #include "qmp-commands.h"
+#include "qjson.h"
 
 static QEMUBalloonEvent *balloon_event_fn;
 static QEMUBalloonStatus *balloon_stat_fn;
@@ -80,6 +81,19 @@ static int qemu_balloon_status(BalloonInfo *info)
     return 1;
 }
 
+void qemu_balloon_changed(int64_t actual)
+{
+    QObject *data;
+
+    data = qobject_from_jsonf("{ 'actual': %" PRId64 " }",
+                              actual);
+
+    monitor_protocol_event(QEVENT_BALLOON_CHANGE, data);
+
+    qobject_decref(data);
+}
+
+
 BalloonInfo *qmp_query_balloon(Error **errp)
 {
     BalloonInfo *info;
diff --git a/balloon.h b/balloon.h
index b60fd5d..b803a00 100644
--- a/balloon.h
+++ b/balloon.h
@@ -24,4 +24,6 @@ int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
 			     QEMUBalloonStatus *stat_func, void *opaque);
 void qemu_remove_balloon_handler(void *opaque);
 
+void qemu_balloon_changed(int64_t actual);
+
 #endif
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 075ed87..d048cef 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -146,8 +146,13 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
 {
     VirtIOBalloon *dev = to_virtio_balloon(vdev);
     struct virtio_balloon_config config;
+    uint32_t oldactual = dev->actual;
     memcpy(&config, config_data, 8);
     dev->actual = le32_to_cpu(config.actual);
+    if (dev->actual != oldactual) {
+        qemu_balloon_changed(ram_size -
+                             (dev->actual << VIRTIO_BALLOON_PFN_SHIFT));
+    }
 }
 
 static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
diff --git a/monitor.c b/monitor.c
index a3bc2c7..75fd4cf 100644
--- a/monitor.c
+++ b/monitor.c
@@ -443,6 +443,7 @@ static const char *monitor_event_names[] = {
     [QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
     [QEVENT_SUSPEND] = "SUSPEND",
     [QEVENT_WAKEUP] = "WAKEUP",
+    [QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE",
 };
 QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
 
diff --git a/monitor.h b/monitor.h
index cd1d878..5f4de1b 100644
--- a/monitor.h
+++ b/monitor.h
@@ -41,6 +41,7 @@ typedef enum MonitorEvent {
     QEVENT_DEVICE_TRAY_MOVED,
     QEVENT_SUSPEND,
     QEVENT_WAKEUP,
+    QEVENT_BALLOON_CHANGE,
 
     /* Add to 'monitor_event_names' array in monitor.c when
      * defining new events here */
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH v3 2/2] Add rate limiting of RTC_CHANGE, BALLOON_CHANGE & WATCHDOG events
  2012-06-14 17:12 [Qemu-devel] [PATCH v3 0/2] Balloon event change notifications Daniel P. Berrange
  2012-06-14 17:12 ` [Qemu-devel] [PATCH v3 1/2] Add event notification for guest balloon changes Daniel P. Berrange
@ 2012-06-14 17:12 ` Daniel P. Berrange
  2012-06-15  7:29 ` [Qemu-devel] [PATCH v3 0/2] Balloon event change notifications Amit Shah
  2012-06-15 16:39 ` Luiz Capitulino
  3 siblings, 0 replies; 5+ messages in thread
From: Daniel P. Berrange @ 2012-06-14 17:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Markus Armbruster, Anthony Liguori, Luiz Capitulino

From: "Daniel P. Berrange" <berrange@redhat.com>

Allow certain event types to be rate limited to avoid flooding
monitor clients. The monitor_protocol_event() method is changed
such that instead of immediately emitting the event to Monitor
instances, it will call a new monitor_protocol_event_queue()
method.

This will check to see if the rate limit for the event has been
exceeded, and if so schedule a timer to wakeup at the end of the
rate limit period. If further events arrive before the timer fires,
the previously queued event will be discarded in favour of the new
event. The event will eventually be emitted when the timer fires.

This logic is applied to RTC_CHANGE, BALLOON_CHANGE & WATCHDOG
events, since the data associated with these events is stateless

 * monitor.c: Add support for rate limiting
 * monitor.h: Define monitor_global_init for one-time setup tasks
 * vl.c: Invoke monitor_global_init
 * trace-events: Add hooks for monitor event tracing

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 monitor.c    |  158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 trace-events |    5 ++
 2 files changed, 157 insertions(+), 6 deletions(-)

diff --git a/monitor.c b/monitor.c
index 75fd4cf..f6107ba 100644
--- a/monitor.c
+++ b/monitor.c
@@ -66,6 +66,7 @@
 #include "memory.h"
 #include "qmp-commands.h"
 #include "hmp.h"
+#include "qemu-thread.h"
 
 /* for pic/irq_info */
 #if defined(TARGET_SPARC)
@@ -145,6 +146,19 @@ typedef struct MonitorControl {
     int command_mode;
 } MonitorControl;
 
+/*
+ * To prevent flooding clients, events can be throttled. The
+ * throttling is calculated globally, rather than per-Monitor
+ * instance.
+ */
+typedef struct MonitorEventState {
+    MonitorEvent event; /* Event being tracked */
+    int64_t rate;       /* Period over which to throttle. 0 to disable */
+    int64_t last;       /* Time at which event was last emitted */
+    QEMUTimer *timer;   /* Timer for handling delayed events */
+    QObject *data;      /* Event pending delayed dispatch */
+} MonitorEventState;
+
 struct Monitor {
     CharDriverState *chr;
     int mux_out;
@@ -447,6 +461,141 @@ static const char *monitor_event_names[] = {
 };
 QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
 
+MonitorEventState monitor_event_state[QEVENT_MAX];
+QemuMutex monitor_event_state_lock;
+
+/*
+ * Emits the event to every monitor instance
+ */
+static void
+monitor_protocol_event_emit(MonitorEvent event,
+                            QObject *data)
+{
+    Monitor *mon;
+
+    trace_monitor_protocol_event_emit(event, data);
+    QLIST_FOREACH(mon, &mon_list, entry) {
+        if (monitor_ctrl_mode(mon) && qmp_cmd_mode(mon)) {
+            monitor_json_emitter(mon, data);
+        }
+    }
+}
+
+
+/*
+ * Queue a new event for emission to Monitor instances,
+ * applying any rate limiting if required.
+ */
+static void
+monitor_protocol_event_queue(MonitorEvent event,
+                             QObject *data)
+{
+    MonitorEventState *evstate;
+    int64_t now = qemu_get_clock_ns(rt_clock);
+    assert(event < QEVENT_MAX);
+
+    qemu_mutex_lock(&monitor_event_state_lock);
+    evstate = &(monitor_event_state[event]);
+    trace_monitor_protocol_event_queue(event,
+                                       data,
+                                       evstate->rate,
+                                       evstate->last,
+                                       now);
+
+    /* Rate limit of 0 indicates no throttling */
+    if (!evstate->rate) {
+        monitor_protocol_event_emit(event, data);
+        evstate->last = now;
+    } else {
+        int64_t delta = now - evstate->last;
+        if (evstate->data ||
+            delta < evstate->rate) {
+            /* If there's an existing event pending, replace
+             * it with the new event, otherwise schedule a
+             * timer for delayed emission
+             */
+            if (evstate->data) {
+                qobject_decref(evstate->data);
+            } else {
+                int64_t then = evstate->last + evstate->rate;
+                qemu_mod_timer_ns(evstate->timer, then);
+            }
+            evstate->data = data;
+            qobject_incref(evstate->data);
+        } else {
+            monitor_protocol_event_emit(event, data);
+            evstate->last = now;
+        }
+    }
+    qemu_mutex_unlock(&monitor_event_state_lock);
+}
+
+
+/*
+ * The callback invoked by QemuTimer when a delayed
+ * event is ready to be emitted
+ */
+static void monitor_protocol_event_handler(void *opaque)
+{
+    MonitorEventState *evstate = opaque;
+    int64_t now = qemu_get_clock_ns(rt_clock);
+
+    qemu_mutex_lock(&monitor_event_state_lock);
+
+    trace_monitor_protocol_event_handler(evstate->event,
+                                         evstate->data,
+                                         evstate->last,
+                                         now);
+    if (evstate->data) {
+        monitor_protocol_event_emit(evstate->event, evstate->data);
+        qobject_decref(evstate->data);
+        evstate->data = NULL;
+    }
+    evstate->last = now;
+    qemu_mutex_unlock(&monitor_event_state_lock);
+}
+
+
+/*
+ * @event: the event ID to be limited
+ * @rate: the rate limit in milliseconds
+ *
+ * Sets a rate limit on a particular event, so no
+ * more than 1 event will be emitted within @rate
+ * milliseconds
+ */
+static void
+monitor_protocol_event_throttle(MonitorEvent event,
+                                int64_t rate)
+{
+    MonitorEventState *evstate;
+    assert(event < QEVENT_MAX);
+
+    evstate = &(monitor_event_state[event]);
+
+    trace_monitor_protocol_event_throttle(event, rate);
+    evstate->event = event;
+    evstate->rate = rate * SCALE_MS;
+    evstate->timer = qemu_new_timer(rt_clock,
+                                    SCALE_MS,
+                                    monitor_protocol_event_handler,
+                                    evstate);
+    evstate->last = 0;
+    evstate->data = NULL;
+}
+
+
+/* Global, one-time initializer to configure the rate limiting
+ * and initialize state */
+static void monitor_protocol_event_init(void)
+{
+    qemu_mutex_init(&monitor_event_state_lock);
+    /* Limit RTC & BALLOON events to 1 per second */
+    monitor_protocol_event_throttle(QEVENT_RTC_CHANGE, 1000);
+    monitor_protocol_event_throttle(QEVENT_BALLOON_CHANGE, 1000);
+    monitor_protocol_event_throttle(QEVENT_WATCHDOG, 1000);
+}
+
 /**
  * monitor_protocol_event(): Generate a Monitor event
  *
@@ -456,7 +605,6 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
 {
     QDict *qmp;
     const char *event_name;
-    Monitor *mon;
 
     assert(event < QEVENT_MAX);
 
@@ -471,11 +619,8 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
         qdict_put_obj(qmp, "data", data);
     }
 
-    QLIST_FOREACH(mon, &mon_list, entry) {
-        if (monitor_ctrl_mode(mon) && qmp_cmd_mode(mon)) {
-            monitor_json_emitter(mon, QOBJECT(qmp));
-        }
-    }
+    trace_monitor_protocol_event(event, event_name, qmp);
+    monitor_protocol_event_queue(event, QOBJECT(qmp));
     QDECREF(qmp);
 }
 
@@ -4571,6 +4716,7 @@ void monitor_init(CharDriverState *chr, int flags)
 
     if (is_first_init) {
         key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL);
+        monitor_protocol_event_init();
         is_first_init = 0;
     }
 
diff --git a/trace-events b/trace-events
index f70523c..5c82b3a 100644
--- a/trace-events
+++ b/trace-events
@@ -677,6 +677,11 @@ esp_mem_writeb_cmd_ensel(uint32_t val) "Enable selection (%2.2x)"
 # monitor.c
 handle_qmp_command(void *mon, const char *cmd_name) "mon %p cmd_name \"%s\""
 monitor_protocol_emitter(void *mon) "mon %p"
+monitor_protocol_event(uint32_t event, const char *evname, void *data) "event=%d name \"%s\" data %p"
+monitor_protocol_event_handler(uint32_t event, void *data, uint64_t last, uint64_t now) "event=%d data=%p last=%" PRId64 " now=%" PRId64
+monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p"
+monitor_protocol_event_queue(uint32_t event, void *data, uint64_t rate, uint64_t last, uint64_t now) "event=%d data=%p rate=%" PRId64 " last=%" PRId64 " now=%" PRId64
+monitor_protocol_event_throttle(uint32_t event, uint64_t rate) "event=%d rate=%" PRId64
 
 # hw/opencores_eth.c
 open_eth_mii_write(unsigned idx, uint16_t v) "MII[%02x] <- %04x"
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/2] Balloon event change notifications
  2012-06-14 17:12 [Qemu-devel] [PATCH v3 0/2] Balloon event change notifications Daniel P. Berrange
  2012-06-14 17:12 ` [Qemu-devel] [PATCH v3 1/2] Add event notification for guest balloon changes Daniel P. Berrange
  2012-06-14 17:12 ` [Qemu-devel] [PATCH v3 2/2] Add rate limiting of RTC_CHANGE, BALLOON_CHANGE & WATCHDOG events Daniel P. Berrange
@ 2012-06-15  7:29 ` Amit Shah
  2012-06-15 16:39 ` Luiz Capitulino
  3 siblings, 0 replies; 5+ messages in thread
From: Amit Shah @ 2012-06-15  7:29 UTC (permalink / raw)
  To: Daniel P. Berrange
  Cc: Markus Armbruster, qemu-devel, Anthony Liguori, Luiz Capitulino

On (Thu) 14 Jun 2012 [18:12:55], Daniel P. Berrange wrote:
> This is a followup to:
> 
>   https://lists.gnu.org/archive/html/qemu-devel/2012-05/msg02833.html
> 
> 
> Changes since v2:
> 
>   - Drop 'query-events' patch which is already merged
>   - Rename balloon_change() function to balloon_changed per
>     Amit's request
>   - Misc typos fixed
>   - Remove monitor_global_init(), folding code into the
>     one-time initialization block in monitor_init()
> 
> This series is being tested with a corresponding patch to libvirt
> for handling balloon events
> 
> https://www.redhat.com/archives/libvir-list/2012-May/msg00868.html

Acked-by: Amit Shah <amit.shah@redhat.com>

		Amit

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/2] Balloon event change notifications
  2012-06-14 17:12 [Qemu-devel] [PATCH v3 0/2] Balloon event change notifications Daniel P. Berrange
                   ` (2 preceding siblings ...)
  2012-06-15  7:29 ` [Qemu-devel] [PATCH v3 0/2] Balloon event change notifications Amit Shah
@ 2012-06-15 16:39 ` Luiz Capitulino
  3 siblings, 0 replies; 5+ messages in thread
From: Luiz Capitulino @ 2012-06-15 16:39 UTC (permalink / raw)
  To: Daniel P. Berrange
  Cc: Amit Shah, qemu-devel, Anthony Liguori, Markus Armbruster

On Thu, 14 Jun 2012 18:12:55 +0100
"Daniel P. Berrange" <berrange@redhat.com> wrote:

> This is a followup to:
> 
>   https://lists.gnu.org/archive/html/qemu-devel/2012-05/msg02833.html

Applied to the qmp branch, thanks Daniel.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2012-06-15 16:39 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-14 17:12 [Qemu-devel] [PATCH v3 0/2] Balloon event change notifications Daniel P. Berrange
2012-06-14 17:12 ` [Qemu-devel] [PATCH v3 1/2] Add event notification for guest balloon changes Daniel P. Berrange
2012-06-14 17:12 ` [Qemu-devel] [PATCH v3 2/2] Add rate limiting of RTC_CHANGE, BALLOON_CHANGE & WATCHDOG events Daniel P. Berrange
2012-06-15  7:29 ` [Qemu-devel] [PATCH v3 0/2] Balloon event change notifications Amit Shah
2012-06-15 16:39 ` Luiz Capitulino

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.