variable timer intervals

This patch introduces dynamic timer intervals: we slow down the refresh
rate when there in no much activity but we get back to a fast refresh
rate when the activity resume.

Please note that qemu_timer_expired is not an inline function any more
because I needed to call it from vnc.c however I don't think this change
should have any serious consequence.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Message-Id:
This commit is contained in:
Stefano Stabellini 2009-08-03 10:56:01 +01:00 committed by Anthony Liguori
parent 1fc624122f
commit 2430ffe4c8
4 changed files with 33 additions and 10 deletions

View File

@ -24,6 +24,7 @@ void qemu_free_timer(QEMUTimer *ts);
void qemu_del_timer(QEMUTimer *ts); void qemu_del_timer(QEMUTimer *ts);
void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
int qemu_timer_pending(QEMUTimer *ts); int qemu_timer_pending(QEMUTimer *ts);
int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time);
extern int64_t ticks_per_sec; extern int64_t ticks_per_sec;

2
vl.c
View File

@ -992,7 +992,7 @@ int qemu_timer_pending(QEMUTimer *ts)
return 0; return 0;
} }
static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
{ {
if (!timer_head) if (!timer_head)
return 0; return 0;

39
vnc.c
View File

@ -30,7 +30,9 @@
#include "qemu-timer.h" #include "qemu-timer.h"
#include "acl.h" #include "acl.h"
#define VNC_REFRESH_INTERVAL (1000 / 30) #define VNC_REFRESH_INTERVAL_BASE 30
#define VNC_REFRESH_INTERVAL_INC 50
#define VNC_REFRESH_INTERVAL_MAX 2000
#include "vnc_keysym.h" #include "vnc_keysym.h"
#include "d3des.h" #include "d3des.h"
@ -215,7 +217,7 @@ static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
3) resolutions > 1024 3) resolutions > 1024
*/ */
static void vnc_update_client(VncState *vs, int has_dirty); static int vnc_update_client(VncState *vs, int has_dirty);
static void vnc_disconnect_start(VncState *vs); static void vnc_disconnect_start(VncState *vs);
static void vnc_disconnect_finish(VncState *vs); static void vnc_disconnect_finish(VncState *vs);
static void vnc_init_timer(VncDisplay *vd); static void vnc_init_timer(VncDisplay *vd);
@ -751,7 +753,7 @@ static int find_and_clear_dirty_height(struct VncState *vs,
return h; return h;
} }
static void vnc_update_client(VncState *vs, int has_dirty) static int vnc_update_client(VncState *vs, int has_dirty)
{ {
if (vs->need_update && vs->csock != -1) { if (vs->need_update && vs->csock != -1) {
VncDisplay *vd = vs->vd; VncDisplay *vd = vs->vd;
@ -761,10 +763,10 @@ static void vnc_update_client(VncState *vs, int has_dirty)
if (vs->output.offset && !vs->audio_cap && !vs->force_update) if (vs->output.offset && !vs->audio_cap && !vs->force_update)
/* kernel send buffers are full -> drop frames to throttle */ /* kernel send buffers are full -> drop frames to throttle */
return; return 0;
if (!has_dirty && !vs->audio_cap && !vs->force_update) if (!has_dirty && !vs->audio_cap && !vs->force_update)
return; return 0;
/* /*
* Send screen updates to the vnc client using the server * Send screen updates to the vnc client using the server
@ -806,11 +808,13 @@ static void vnc_update_client(VncState *vs, int has_dirty)
vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF; vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
vnc_flush(vs); vnc_flush(vs);
vs->force_update = 0; vs->force_update = 0;
return n_rectangles;
} }
if (vs->csock == -1) if (vs->csock == -1)
vnc_disconnect_finish(vs); vnc_disconnect_finish(vs);
return 0;
} }
/* audio */ /* audio */
@ -1701,6 +1705,13 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
{ {
int i; int i;
uint16_t limit; uint16_t limit;
VncDisplay *vd = vs->vd;
if (data[0] > 3) {
vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
if (!qemu_timer_expired(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval))
qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
}
switch (data[0]) { switch (data[0]) {
case 0: case 0:
@ -2104,7 +2115,7 @@ static void vnc_refresh(void *opaque)
{ {
VncDisplay *vd = opaque; VncDisplay *vd = opaque;
VncState *vs = NULL; VncState *vs = NULL;
int has_dirty = 0; int has_dirty = 0, rects = 0;
vga_hw_update(); vga_hw_update();
@ -2112,15 +2123,25 @@ static void vnc_refresh(void *opaque)
vs = vd->clients; vs = vd->clients;
while (vs != NULL) { while (vs != NULL) {
vnc_update_client(vs, has_dirty); rects += vnc_update_client(vs, has_dirty);
vs = vs->next; vs = vs->next;
} }
qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL); if (has_dirty && rects) {
vd->timer_interval /= 2;
if (vd->timer_interval < VNC_REFRESH_INTERVAL_BASE)
vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
} else {
vd->timer_interval += VNC_REFRESH_INTERVAL_INC;
if (vd->timer_interval > VNC_REFRESH_INTERVAL_MAX)
vd->timer_interval = VNC_REFRESH_INTERVAL_MAX;
}
qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
} }
static void vnc_init_timer(VncDisplay *vd) static void vnc_init_timer(VncDisplay *vd)
{ {
vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
if (vd->timer == NULL && vd->clients != NULL) { if (vd->timer == NULL && vd->clients != NULL) {
vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd); vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd);
vnc_refresh(vd); vnc_refresh(vd);

1
vnc.h
View File

@ -93,6 +93,7 @@ struct VncSurface
struct VncDisplay struct VncDisplay
{ {
QEMUTimer *timer; QEMUTimer *timer;
int timer_interval;
int lsock; int lsock;
DisplayState *ds; DisplayState *ds;
VncState *clients; VncState *clients;