]>
Commit | Line | Data |
---|---|---|
904a90cc DM |
1 | From: Luiz Capitulino <lcapitulino@redhat.com> |
2 | Subject: [Qemu-devel] [PATCH 2/3] virtio-balloon: re-enable balloon stats | |
3 | ||
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. | |
7 | ||
8 | The following control properties are introduced: | |
9 | ||
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 | |
14 | ||
15 | o stats-last-update: last stats update timestamp, in seconds. | |
16 | ||
17 | The following stats properties are introduced, all values are in bytes: | |
18 | ||
19 | o stat-swap-in | |
20 | o stat-swap-out | |
21 | o stat-major-faults | |
22 | o stat-minor-faults | |
23 | o stat-free-memory | |
24 | o stat-total-memory | |
25 | ||
26 | Please, refer to the documentation introduced by the next commit for | |
27 | more information and examples. | |
28 | ||
29 | Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com> | |
30 | --- | |
31 | hw/virtio-balloon.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++- | |
32 | 1 file changed, 165 insertions(+), 2 deletions(-) | |
33 | ||
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 | |
38 | @@ -22,6 +22,8 @@ | |
39 | #include "virtio-balloon.h" | |
40 | #include "kvm.h" | |
41 | #include "exec-memory.h" | |
42 | +#include "qemu-timer.h" | |
43 | +#include "qapi/qapi-visit-core.h" | |
44 | ||
45 | #if defined(__linux__) | |
46 | #include <sys/mman.h> | |
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; | |
54 | DeviceState *qdev; | |
55 | } VirtIOBalloon; | |
56 | ||
57 | @@ -53,6 +58,16 @@ static void balloon_page(void *addr, int deflate) | |
58 | #endif | |
59 | } | |
60 | ||
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 | |
69 | +}; | |
70 | + | |
71 | /* | |
72 | * reset_stats - Mark all items in the stats array as unset | |
73 | * | |
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); | |
76 | } | |
77 | ||
78 | +static bool balloon_stats_supported(const VirtIOBalloon *s) | |
79 | +{ | |
80 | + return s->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ); | |
81 | +} | |
82 | + | |
83 | +static bool balloon_stats_enabled(const VirtIOBalloon *s) | |
84 | +{ | |
85 | + return s->stats_poll_interval > 0; | |
86 | +} | |
87 | + | |
88 | +static void balloon_stats_destroy_timer(VirtIOBalloon *s) | |
89 | +{ | |
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; | |
95 | + } | |
96 | +} | |
97 | + | |
98 | +static void balloon_stats_change_timer(VirtIOBalloon *s, int secs) | |
99 | +{ | |
100 | + qemu_mod_timer(s->stats_timer, qemu_get_clock_ms(vm_clock) + secs * 1000); | |
101 | +} | |
102 | + | |
103 | +static void balloon_stats_poll_cb(void *opaque) | |
104 | +{ | |
105 | + VirtIOBalloon *s = opaque; | |
106 | + | |
107 | + virtqueue_push(s->svq, &s->stats_vq_elem, s->stats_vq_offset); | |
108 | + virtio_notify(&s->vdev, s->svq); | |
109 | +} | |
110 | + | |
111 | +static void balloon_stats_get_last_update(Object *obj, struct Visitor *v, | |
112 | + void *opaque, const char *name, | |
113 | + Error **errp) | |
114 | +{ | |
115 | + VirtIOBalloon *s = opaque; | |
116 | + visit_type_int(v, &s->stats_last_update, name, errp); | |
117 | +} | |
118 | + | |
119 | +static void balloon_stats_get_stat(Object *obj, struct Visitor *v, | |
120 | + void *opaque, const char *name, Error **errp) | |
121 | +{ | |
122 | + VirtIOBalloon *s = opaque; | |
123 | + int i; | |
124 | + | |
125 | + for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) { | |
126 | + if (!strcmp(balloon_stat_names[i], name)) { | |
127 | + break; | |
128 | + } | |
129 | + } | |
130 | + | |
131 | + if (i == VIRTIO_BALLOON_S_NR) { | |
132 | + error_setg(errp, "invalid stat name '%s'", name); | |
133 | + return; | |
134 | + } | |
135 | + | |
136 | + if (s->stats[i] == -1) { | |
137 | + error_setg(errp, | |
138 | + "timer hasn't been enabled or guest doesn't support '%s'", name); | |
139 | + return; | |
140 | + } | |
141 | + | |
142 | + visit_type_int(v, (int64_t *) &s->stats[i], name, errp); | |
143 | +} | |
144 | + | |
145 | +static void balloon_stats_get_poll_interval(Object *obj, struct Visitor *v, | |
146 | + void *opaque, const char *name, | |
147 | + Error **errp) | |
148 | +{ | |
149 | + VirtIOBalloon *s = opaque; | |
150 | + visit_type_int(v, &s->stats_poll_interval, name, errp); | |
151 | +} | |
152 | + | |
153 | +static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v, | |
154 | + void *opaque, const char *name, | |
155 | + Error **errp) | |
156 | +{ | |
157 | + VirtIOBalloon *s = opaque; | |
158 | + int64_t value; | |
159 | + | |
160 | + if (!balloon_stats_supported(s)) { | |
161 | + error_setg(errp, "guest doesn\'t support balloon stats"); | |
162 | + return; | |
163 | + } | |
164 | + | |
165 | + visit_type_int(v, &value, name, errp); | |
166 | + if (error_is_set(errp)) { | |
167 | + return; | |
168 | + } | |
169 | + | |
170 | + if (value < 0) { | |
171 | + error_setg(errp, "timer value must be positive"); | |
172 | + return; | |
173 | + } | |
174 | + | |
175 | + if (value == s->stats_poll_interval) { | |
176 | + return; | |
177 | + } | |
178 | + | |
179 | + if (value == 0) { | |
180 | + /* timer=0 disables the timer */ | |
181 | + balloon_stats_destroy_timer(s); | |
182 | + return; | |
183 | + } | |
184 | + | |
185 | + if (balloon_stats_enabled(s)) { | |
186 | + /* timer interval change */ | |
187 | + s->stats_poll_interval = value; | |
188 | + balloon_stats_change_timer(s, value); | |
189 | + return; | |
190 | + } | |
191 | + | |
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); | |
197 | +} | |
198 | + | |
199 | static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) | |
200 | { | |
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; | |
205 | size_t offset = 0; | |
206 | + qemu_timeval tv; | |
207 | ||
208 | if (!virtqueue_pop(vq, elem)) { | |
209 | - return; | |
210 | + goto out; | |
211 | } | |
212 | ||
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) | |
215 | s->stats[tag] = val; | |
216 | } | |
217 | s->stats_vq_offset = offset; | |
218 | + | |
219 | + if (qemu_gettimeofday(&tv) < 0) { | |
220 | + fprintf(stderr, "warning: %s: failed to get time of day\n", __func__); | |
221 | + goto out; | |
222 | + } | |
223 | + | |
224 | + s->stats_last_update = tv.tv_sec; | |
225 | + | |
226 | +out: | |
227 | + if (balloon_stats_enabled(s)) { | |
228 | + balloon_stats_change_timer(s, s->stats_poll_interval); | |
229 | + } | |
230 | } | |
231 | ||
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) | |
235 | { | |
236 | VirtIOBalloon *s; | |
237 | - int ret; | |
238 | + int i, ret; | |
239 | ||
240 | s = (VirtIOBalloon *)virtio_common_init("virtio-balloon", | |
241 | VIRTIO_ID_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); | |
245 | ||
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); | |
249 | + } | |
250 | + | |
251 | + object_property_add(OBJECT(dev), "stats-last-update", "int", | |
252 | + balloon_stats_get_last_update, NULL, NULL, s, NULL); | |
253 | + | |
254 | + object_property_add(OBJECT(dev), "stats-polling-interval", "int", | |
255 | + balloon_stats_get_poll_interval, | |
256 | + balloon_stats_set_poll_interval, | |
257 | + NULL, s, NULL); | |
258 | + | |
259 | return &s->vdev; | |
260 | } | |
261 | ||
262 | @@ -246,6 +408,7 @@ void virtio_balloon_exit(VirtIODevice *vdev) | |
263 | { | |
264 | VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev); | |
265 | ||
266 | + balloon_stats_destroy_timer(s); | |
267 | qemu_remove_balloon_handler(s); | |
268 | unregister_savevm(s->qdev, "virtio-balloon", s); | |
269 | virtio_cleanup(vdev); | |
270 | -- | |
271 | 1.8.0 | |
272 | ||
273 | ||
274 | ||
275 |