1 From: Luiz Capitulino <lcapitulino@redhat.com>
2 Subject: [Qemu-devel] [PATCH 2/3] virtio-balloon: re-enable balloon stats
4 The statistics are now available through device properties via a
5 polling mechanism. First a client has to enable polling, then it
6 can query each stat individually.
8 The following control properties are introduced:
10 o stats-polling-interval: a value greater than zero enables polling
11 in the specified interval (in seconds). When value equals zero,
12 polling is disabled. If polling is already enabled and a value
13 greater than zero is written, the polling interval time is changed
15 o stats-last-update: last stats update timestamp, in seconds.
17 The following stats properties are introduced, all values are in bytes:
26 Please, refer to the documentation introduced by the next commit for
27 more information and examples.
29 Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
31 hw/virtio-balloon.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++-
32 1 file changed, 165 insertions(+), 2 deletions(-)
34 diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
35 index 4398025..4bab2ae 100644
36 --- a/hw/virtio-balloon.c
37 +++ b/hw/virtio-balloon.c
39 #include "virtio-balloon.h"
41 #include "exec-memory.h"
42 +#include "qemu-timer.h"
43 +#include "qapi/qapi-visit-core.h"
45 #if defined(__linux__)
47 @@ -36,6 +38,9 @@ typedef struct VirtIOBalloon
48 uint64_t stats[VIRTIO_BALLOON_S_NR];
49 VirtQueueElement stats_vq_elem;
50 size_t stats_vq_offset;
51 + QEMUTimer *stats_timer;
52 + int64_t stats_last_update;
53 + int64_t stats_poll_interval;
57 @@ -53,6 +58,16 @@ static void balloon_page(void *addr, int deflate)
61 +static const char *balloon_stat_names[] = {
62 + [VIRTIO_BALLOON_S_SWAP_IN] = "stat-swap-in",
63 + [VIRTIO_BALLOON_S_SWAP_OUT] = "stat-swap-out",
64 + [VIRTIO_BALLOON_S_MAJFLT] = "stat-major-faults",
65 + [VIRTIO_BALLOON_S_MINFLT] = "stat-minor-faults",
66 + [VIRTIO_BALLOON_S_MEMFREE] = "stat-free-memory",
67 + [VIRTIO_BALLOON_S_MEMTOT] = "stat-total-memory",
68 + [VIRTIO_BALLOON_S_NR] = NULL
72 * reset_stats - Mark all items in the stats array as unset
74 @@ -67,6 +82,127 @@ static inline void reset_stats(VirtIOBalloon *dev)
75 for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1);
78 +static bool balloon_stats_supported(const VirtIOBalloon *s)
80 + return s->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ);
83 +static bool balloon_stats_enabled(const VirtIOBalloon *s)
85 + return s->stats_poll_interval > 0;
88 +static void balloon_stats_destroy_timer(VirtIOBalloon *s)
90 + if (balloon_stats_enabled(s)) {
91 + qemu_del_timer(s->stats_timer);
92 + qemu_free_timer(s->stats_timer);
93 + s->stats_timer = NULL;
94 + s->stats_poll_interval = 0;
98 +static void balloon_stats_change_timer(VirtIOBalloon *s, int secs)
100 + qemu_mod_timer(s->stats_timer, qemu_get_clock_ms(vm_clock) + secs * 1000);
103 +static void balloon_stats_poll_cb(void *opaque)
105 + VirtIOBalloon *s = opaque;
107 + virtqueue_push(s->svq, &s->stats_vq_elem, s->stats_vq_offset);
108 + virtio_notify(&s->vdev, s->svq);
111 +static void balloon_stats_get_last_update(Object *obj, struct Visitor *v,
112 + void *opaque, const char *name,
115 + VirtIOBalloon *s = opaque;
116 + visit_type_int(v, &s->stats_last_update, name, errp);
119 +static void balloon_stats_get_stat(Object *obj, struct Visitor *v,
120 + void *opaque, const char *name, Error **errp)
122 + VirtIOBalloon *s = opaque;
125 + for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) {
126 + if (!strcmp(balloon_stat_names[i], name)) {
131 + if (i == VIRTIO_BALLOON_S_NR) {
132 + error_setg(errp, "invalid stat name '%s'", name);
136 + if (s->stats[i] == -1) {
138 + "timer hasn't been enabled or guest doesn't support '%s'", name);
142 + visit_type_int(v, (int64_t *) &s->stats[i], name, errp);
145 +static void balloon_stats_get_poll_interval(Object *obj, struct Visitor *v,
146 + void *opaque, const char *name,
149 + VirtIOBalloon *s = opaque;
150 + visit_type_int(v, &s->stats_poll_interval, name, errp);
153 +static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v,
154 + void *opaque, const char *name,
157 + VirtIOBalloon *s = opaque;
160 + if (!balloon_stats_supported(s)) {
161 + error_setg(errp, "guest doesn\'t support balloon stats");
165 + visit_type_int(v, &value, name, errp);
166 + if (error_is_set(errp)) {
171 + error_setg(errp, "timer value must be positive");
175 + if (value == s->stats_poll_interval) {
180 + /* timer=0 disables the timer */
181 + balloon_stats_destroy_timer(s);
185 + if (balloon_stats_enabled(s)) {
186 + /* timer interval change */
187 + s->stats_poll_interval = value;
188 + balloon_stats_change_timer(s, value);
192 + /* create a new timer */
193 + g_assert(s->stats_timer == NULL);
194 + s->stats_timer = qemu_new_timer_ms(vm_clock, balloon_stats_poll_cb, s);
195 + s->stats_poll_interval = value;
196 + balloon_stats_change_timer(s, 0);
199 static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
201 VirtIOBalloon *s = to_virtio_balloon(vdev);
202 @@ -107,9 +243,10 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
203 VirtQueueElement *elem = &s->stats_vq_elem;
204 VirtIOBalloonStat stat;
208 if (!virtqueue_pop(vq, elem)) {
213 /* Initialize the stats to get rid of any stale values. This is only
214 @@ -128,6 +265,18 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
217 s->stats_vq_offset = offset;
219 + if (qemu_gettimeofday(&tv) < 0) {
220 + fprintf(stderr, "warning: %s: failed to get time of day\n", __func__);
224 + s->stats_last_update = tv.tv_sec;
227 + if (balloon_stats_enabled(s)) {
228 + balloon_stats_change_timer(s, s->stats_poll_interval);
232 static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
233 @@ -212,7 +361,7 @@ static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
234 VirtIODevice *virtio_balloon_init(DeviceState *dev)
240 s = (VirtIOBalloon *)virtio_common_init("virtio-balloon",
242 @@ -239,6 +388,19 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
243 register_savevm(dev, "virtio-balloon", -1, 1,
244 virtio_balloon_save, virtio_balloon_load, s);
246 + for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) {
247 + object_property_add(OBJECT(dev), balloon_stat_names[i], "int",
248 + balloon_stats_get_stat, NULL, NULL, s, NULL);
251 + object_property_add(OBJECT(dev), "stats-last-update", "int",
252 + balloon_stats_get_last_update, NULL, NULL, s, NULL);
254 + object_property_add(OBJECT(dev), "stats-polling-interval", "int",
255 + balloon_stats_get_poll_interval,
256 + balloon_stats_set_poll_interval,
262 @@ -246,6 +408,7 @@ void virtio_balloon_exit(VirtIODevice *vdev)
264 VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
266 + balloon_stats_destroy_timer(s);
267 qemu_remove_balloon_handler(s);
268 unregister_savevm(s->qdev, "virtio-balloon", s);
269 virtio_cleanup(vdev);