问题描述
在VDI环境(SPICE/QEMU)下,鼠标的报点率有比较严重的下降: 125 → 32。
当前策略
禁用vdagent的鼠标写入接口,统一采用qemu的虚拟鼠标设备接口来写入鼠标事件,可以把报点率提高到非绘制情况下 90, 绘制情况下60。
未来可能的优化方向
放弃当前UI组件监听鼠标事件的方式,直接通过监听usb鼠标设备的事件。
测试记录
对比测试了usb鼠标设备的事件数和GTK 鼠标事件的回调数目发现,GTK Widget的鼠标事件相比usb原始数据存在21% ~ 36%的丢失。
USB | GTK | 丢点率 | |
---|---|---|---|
画板有绘制 | 785 | 497 | 36.7% |
画板无绘制 | 599 | 470 | 21.5% |
此外测试了client端和server端发送和接受的鼠标事件信息,几乎一致,且没有命中Client端的丢点逻辑,所以网络传输层面没有影响。
关于多线程:
SPICE-GTK可以通过配置meson参数开启多线程:
-Dcoroutine=gthread
开启多线程后对比测试无明显差别。
关键代码
client 端鼠标事件注册
// spice-widget.c gtkwidget_class->motion_notify_event = motion_event; |
鼠标事件注册的回调中,根据MOUSE_MODE的不同,会进入不同的接口调用, 其中都有一个拥塞窗口的逻辑判断:
// 窗口大小就是SPICE_INPUT_MOTION_ACK_BUNCH * 2,超过这个大小的事件会丢弃 if (c->motion_count < SPICE_INPUT_MOTION_ACK_BUNCH * 2) { send_position(channel); } |
服务端针对鼠标事件的响应逻辑在inputs-channel.cpp:
case SPICE_MSGC_INPUTS_MOUSE_MOTION: { static int mouse_motion_count = 0; printf("SPICE_MSGC_INPUTS_MOUSE_MOTION %d\n", ++mouse_motion_count); SpiceMouseInstance *mouse = inputs_channel->mouse; auto mouse_motion = static_cast<SpiceMsgcMouseMotion *>(message); on_mouse_motion(); // 发给客户端回执 if (mouse && reds_get_mouse_mode(reds) == SPICE_MOUSE_MODE_SERVER) { //SpiceMouseInterface在QEMU中实现 SpiceMouseInterface *sif; sif = SPICE_UPCAST(SpiceMouseInterface, mouse->base.sif); sif->motion(mouse, mouse_motion->dx, mouse_motion->dy, 0, RED_MOUSE_STATE_TO_LOCAL(mouse_motion->buttons_state)); } break; } case SPICE_MSGC_INPUTS_MOUSE_POSITION: { static int mouse_position_cnt = 0; printf("SPICE_MSGC_INPUTS_MOUSE_POSITION %d\n", ++mouse_position_cnt); auto pos = static_cast<SpiceMsgcMousePosition *>(message); // SpiceTabletInstance在QEMU中实现 SpiceTabletInstance *tablet = inputs_channel->tablet; spice_assert(tablet); on_mouse_motion(); // 发给客户端回执 if (reds_get_mouse_mode(reds) != SPICE_MOUSE_MODE_CLIENT) { break; } spice_assert((reds_config_get_agent_mouse(reds) && reds_has_vdagent(reds)) || tablet); if (!reds_config_get_agent_mouse(reds) || !reds_has_vdagent(reds)) { SpiceTabletInterface *sif; sif = SPICE_UPCAST(SpiceTabletInterface, tablet->base.sif); sif->position(tablet, pos->x, pos->y, RED_MOUSE_STATE_TO_LOCAL(pos->buttons_state)); break; } VDAgentMouseState *mouse_state = &inputs_channel->mouse_state; mouse_state->x = pos->x; mouse_state->y = pos->y; mouse_state->buttons = RED_MOUSE_BUTTON_STATE_TO_AGENT(pos->buttons_state); mouse_state->display_id = pos->display_id; // 调用vdagent的接口,报点率暴跌的元凶 reds_handle_agent_mouse_event(reds, mouse_state); break; } |
值得注意的是,SPICE-SERVER的鼠标事件处理是基于QEMU提供的虚拟设备接口来做的,这其实就是USB重定向中的设备重定向。
附录
监听usb鼠标设备事件的测试代码
|