[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [HVM][VNC] Add a backoff feature to the vnc server, so that if it detects
# HG changeset patch # User Steven Smith <ssmith@xxxxxxxxxxxxx> # Node ID 449dcaff25513813da8bcda94ffc85f3f14c5857 # Parent c742b2ae920c45c476a4c8b7fd28870df124071e [HVM][VNC] Add a backoff feature to the vnc server, so that if it detects that the display hasn't changed for a while it starts scanning more slowly. Signed-off-by: Steven Smith <sos22@xxxxxxxxx> --- tools/ioemu/vl.c | 6 + tools/ioemu/vl.h | 1 tools/ioemu/vnc.c | 254 ++++++++++++++++++++++++++++++++---------------------- 3 files changed, 158 insertions(+), 103 deletions(-) diff -r c742b2ae920c -r 449dcaff2551 tools/ioemu/vl.c --- a/tools/ioemu/vl.c Thu Sep 21 17:56:14 2006 +0100 +++ b/tools/ioemu/vl.c Thu Sep 21 18:29:48 2006 +0100 @@ -723,6 +723,12 @@ void qemu_del_timer(QEMUTimer *ts) } pt = &t->next; } +} + +void qemu_advance_timer(QEMUTimer *ts, int64_t expire_time) +{ + if (ts->expire_time > expire_time) + qemu_mod_timer(ts, expire_time); } /* modify the current timer so that it will be fired when current_time diff -r c742b2ae920c -r 449dcaff2551 tools/ioemu/vl.h --- a/tools/ioemu/vl.h Thu Sep 21 17:56:14 2006 +0100 +++ b/tools/ioemu/vl.h Thu Sep 21 18:29:48 2006 +0100 @@ -405,6 +405,7 @@ void qemu_free_timer(QEMUTimer *ts); void qemu_free_timer(QEMUTimer *ts); void qemu_del_timer(QEMUTimer *ts); void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); +void qemu_advance_timer(QEMUTimer *ts, int64_t expire_time); int qemu_timer_pending(QEMUTimer *ts); extern int64_t ticks_per_sec; diff -r c742b2ae920c -r 449dcaff2551 tools/ioemu/vnc.c --- a/tools/ioemu/vnc.c Thu Sep 21 17:56:14 2006 +0100 +++ b/tools/ioemu/vnc.c Thu Sep 21 18:29:48 2006 +0100 @@ -27,7 +27,19 @@ #include "vl.h" #include "qemu_socket.h" -#define VNC_REFRESH_INTERVAL (1000 / 30) +/* The refresh interval starts at BASE. If we scan the buffer and + find no change, we increase by INC, up to MAX. If the mouse moves + or we get a keypress, the interval is set back to BASE. If we find + an update, halve the interval. + + All times in milliseconds. */ +#define VNC_REFRESH_INTERVAL_BASE 30 +#define VNC_REFRESH_INTERVAL_INC 50 +#define VNC_REFRESH_INTERVAL_MAX 2000 + +/* Wait at most one second between updates, so that we can detect a + minimised vncviewer reasonably quickly. */ +#define VNC_MAX_UPDATE_INTERVAL 5000 #include "vnc_keysym.h" #include "keymaps.c" @@ -64,10 +76,11 @@ struct VncState struct VncState { QEMUTimer *timer; + int timer_interval; + int64_t last_update_time; int lsock; int csock; DisplayState *ds; - int need_update; int width; int height; uint64_t *dirty_row; /* screen regions which are possibly dirty */ @@ -97,8 +110,6 @@ struct VncState int visible_y; int visible_w; int visible_h; - - int slow_client; int ctl_keys; /* Ctrl+Alt starts calibration */ }; @@ -380,7 +391,7 @@ static void vnc_copy(DisplayState *ds, i int y = 0; int pitch = ds->linesize; VncState *vs = ds->opaque; - int updating_client = !vs->slow_client; + int updating_client = 1; if (src_x < vs->visible_x || src_y < vs->visible_y || dst_x < vs->visible_x || dst_y < vs->visible_y || @@ -389,11 +400,6 @@ static void vnc_copy(DisplayState *ds, i (dst_x + w) > (vs->visible_x + vs->visible_w) || (dst_y + h) > (vs->visible_y + vs->visible_h)) updating_client = 0; - - if (updating_client) { - vs->need_update = 1; - _vnc_update_client(vs); - } if (dst_y > src_y) { y = h - 1; @@ -445,110 +451,145 @@ static void _vnc_update_client(void *opa static void _vnc_update_client(void *opaque) { VncState *vs = opaque; - int64_t now = qemu_get_clock(rt_clock); - - if (vs->need_update && vs->csock != -1) { - int y; - char *row; - char *old_row; - uint64_t width_mask; - int n_rectangles; - int saved_offset; - int maxx, maxy; - int tile_bytes = vs->depth * DP2X(vs, 1); - - qemu_mod_timer(vs->timer, now + VNC_REFRESH_INTERVAL); - - if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS)) - width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1; - else - width_mask = ~(0ULL); - - /* Walk through the dirty map and eliminate tiles that - really aren't dirty */ - row = vs->ds->data; - old_row = vs->old_data; - - for (y = 0; y < vs->ds->height; y++) { - if (vs->dirty_row[y] & width_mask) { - int x; - char *ptr, *old_ptr; - - ptr = row; - old_ptr = old_row; - - for (x = 0; x < X2DP_UP(vs, vs->ds->width); x++) { - if (vs->dirty_row[y] & (1ULL << x)) { - if (memcmp(old_ptr, ptr, tile_bytes)) { - vs->has_update = 1; - vs->update_row[y] |= (1ULL << x); - memcpy(old_ptr, ptr, tile_bytes); - } - vs->dirty_row[y] &= ~(1ULL << x); + int64_t now; + int y; + char *row; + char *old_row; + uint64_t width_mask; + int n_rectangles; + int saved_offset; + int maxx, maxy; + int tile_bytes = vs->depth * DP2X(vs, 1); + + if (vs->csock == -1) + return; + + now = qemu_get_clock(rt_clock); + + if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS)) + width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1; + else + width_mask = ~(0ULL); + + /* Walk through the dirty map and eliminate tiles that really + aren't dirty */ + row = vs->ds->data; + old_row = vs->old_data; + + for (y = 0; y < vs->ds->height; y++) { + if (vs->dirty_row[y] & width_mask) { + int x; + char *ptr, *old_ptr; + + ptr = row; + old_ptr = old_row; + + for (x = 0; x < X2DP_UP(vs, vs->ds->width); x++) { + if (vs->dirty_row[y] & (1ULL << x)) { + if (memcmp(old_ptr, ptr, tile_bytes)) { + vs->has_update = 1; + vs->update_row[y] |= (1ULL << x); + memcpy(old_ptr, ptr, tile_bytes); } - - ptr += tile_bytes; - old_ptr += tile_bytes; + vs->dirty_row[y] &= ~(1ULL << x); } + + ptr += tile_bytes; + old_ptr += tile_bytes; } - - row += vs->ds->linesize; - old_row += vs->ds->linesize; } - - if (!vs->has_update || vs->visible_y >= vs->ds->height || - vs->visible_x >= vs->ds->width) - return; - - /* Count rectangles */ - n_rectangles = 0; - vnc_write_u8(vs, 0); /* msg id */ - vnc_write_u8(vs, 0); - saved_offset = vs->output.offset; - vnc_write_u16(vs, 0); - - maxy = vs->visible_y + vs->visible_h; - if (maxy > vs->ds->height) - maxy = vs->ds->height; - maxx = vs->visible_x + vs->visible_w; - if (maxx > vs->ds->width) - maxx = vs->ds->width; - - for (y = vs->visible_y; y < maxy; y++) { - int x; - int last_x = -1; - for (x = X2DP_DOWN(vs, vs->visible_x); - x < X2DP_UP(vs, maxx); x++) { - if (vs->update_row[y] & (1ULL << x)) { - if (last_x == -1) - last_x = x; - vs->update_row[y] &= ~(1ULL << x); - } else { - if (last_x != -1) { - int h = find_update_height(vs, y, maxy, last_x, x); + + row += vs->ds->linesize; + old_row += vs->ds->linesize; + } + + if (!vs->has_update || vs->visible_y >= vs->ds->height || + vs->visible_x >= vs->ds->width) + goto backoff; + + /* Count rectangles */ + n_rectangles = 0; + vnc_write_u8(vs, 0); /* msg id */ + vnc_write_u8(vs, 0); + saved_offset = vs->output.offset; + vnc_write_u16(vs, 0); + + maxy = vs->visible_y + vs->visible_h; + if (maxy > vs->ds->height) + maxy = vs->ds->height; + maxx = vs->visible_x + vs->visible_w; + if (maxx > vs->ds->width) + maxx = vs->ds->width; + + for (y = vs->visible_y; y < maxy; y++) { + int x; + int last_x = -1; + for (x = X2DP_DOWN(vs, vs->visible_x); + x < X2DP_UP(vs, maxx); x++) { + if (vs->update_row[y] & (1ULL << x)) { + if (last_x == -1) + last_x = x; + vs->update_row[y] &= ~(1ULL << x); + } else { + if (last_x != -1) { + int h = find_update_height(vs, y, maxy, last_x, x); + if (h != 0) { send_framebuffer_update(vs, DP2X(vs, last_x), y, DP2X(vs, (x - last_x)), h); n_rectangles++; } - last_x = -1; } + last_x = -1; } - if (last_x != -1) { - int h = find_update_height(vs, y, maxy, last_x, x); + } + if (last_x != -1) { + int h = find_update_height(vs, y, maxy, last_x, x); + if (h != 0) { send_framebuffer_update(vs, DP2X(vs, last_x), y, DP2X(vs, (x - last_x)), h); n_rectangles++; } } - vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF; - vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF; - - vs->has_update = 0; - vs->need_update = 0; - vnc_flush(vs); - vs->slow_client = 0; - } else - vs->slow_client = 1; + } + vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF; + vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF; + + if (n_rectangles == 0) + goto backoff; + + vs->has_update = 0; + vnc_flush(vs); + vs->last_update_time = now; + + vs->timer_interval /= 2; + if (vs->timer_interval < VNC_REFRESH_INTERVAL_BASE) + vs->timer_interval = VNC_REFRESH_INTERVAL_BASE; + + return; + + backoff: + /* No update -> back off a bit */ + vs->timer_interval += VNC_REFRESH_INTERVAL_INC; + if (vs->timer_interval > VNC_REFRESH_INTERVAL_MAX) { + vs->timer_interval = VNC_REFRESH_INTERVAL_MAX; + if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL) { + /* Send a null update. If the client is no longer + interested (e.g. minimised) it'll ignore this, and we + can stop scanning the buffer until it sends another + update request. */ + /* Note that there are bugs in xvncviewer which prevent + this from actually working. Leave the code in place + for correct clients. */ + vnc_write_u8(vs, 0); + vnc_write_u8(vs, 0); + vnc_write_u16(vs, 0); + vnc_flush(vs); + vs->last_update_time = now; + return; + } + } + qemu_mod_timer(vs->timer, now + vs->timer_interval); + return; } static void vnc_update_client(void *opaque) @@ -561,8 +602,10 @@ static void vnc_update_client(void *opaq static void vnc_timer_init(VncState *vs) { - if (vs->timer == NULL) + if (vs->timer == NULL) { vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs); + vs->timer_interval = VNC_REFRESH_INTERVAL_BASE; + } } static void vnc_dpy_refresh(DisplayState *ds) @@ -622,7 +665,6 @@ static int vnc_client_io_error(VncState vs->csock = -1; buffer_reset(&vs->input); buffer_reset(&vs->output); - vs->need_update = 0; return 0; } return ret; @@ -892,7 +934,6 @@ static void framebuffer_update_request(V int x_position, int y_position, int w, int h) { - vs->need_update = 1; if (!incremental) framebuffer_set_updated(vs, x_position, y_position, w, h); vs->visible_x = x_position; @@ -1015,6 +1056,7 @@ static int protocol_client_msg(VncState { int i; uint16_t limit; + int64_t now; switch (data[0]) { case 0: @@ -1054,12 +1096,18 @@ static int protocol_client_msg(VncState if (len == 1) return 8; + vs->timer_interval = VNC_REFRESH_INTERVAL_BASE; + qemu_advance_timer(vs->timer, + qemu_get_clock(rt_clock) + vs->timer_interval); key_event(vs, read_u8(data, 1), read_u32(data, 4)); break; case 5: if (len == 1) return 6; + vs->timer_interval = VNC_REFRESH_INTERVAL_BASE; + qemu_advance_timer(vs->timer, + qemu_get_clock(rt_clock) + vs->timer_interval); pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4)); break; case 6: @@ -1268,7 +1316,7 @@ int vnc_start_viewer(int port) exit(1); case 0: /* child */ - execlp("vncviewer", "vncviewer", s, 0); + execlp("vncviewer", "vncviewer", s, NULL); fprintf(stderr, "vncviewer execlp failed\n"); exit(1); _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |