SPICE鼠标报点率降低问题分析

问题描述

在VDI环境(SPICE/QEMU)下,鼠标的报点率有比较严重的下降: 125 → 32。

当前策略

禁用vdagent的鼠标写入接口,统一采用qemu的虚拟鼠标设备接口来写入鼠标事件,可以把报点率提高到非绘制情况下 90, 绘制情况下60。

未来可能的优化方向

放弃当前UI组件监听鼠标事件的方式,直接通过监听usb鼠标设备的事件。

测试记录

对比测试了usb鼠标设备的事件数和GTK 鼠标事件的回调数目发现,GTK Widget的鼠标事件相比usb原始数据存在21% ~ 36%的丢失。

USBGTK丢点率
画板有绘制78549736.7%
画板无绘制59947021.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鼠标设备事件的测试代码

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char **argv)
{
    int fd, bytes;
    static int cnt = 0;
    unsigned char data[3];

    const char *pDevice = "/dev/input/mice";

    // Open Mouse
    fd = open(pDevice, O_RDWR);
    if (fd == -1)
    {
        printf("ERROR Opening %s\n", pDevice);
        return -1;
    }

    int left, middle, right;
    signed char x, y;
    while (1)
    {
        printf("cnt: %d\n", ++cnt);
        // Read Mouse
        bytes = read(fd, data, sizeof(data));

        if (bytes > 0)
        {
            left = data[0] & 0x1;
            right = data[0] & 0x2;
            middle = data[0] & 0x4;

            x = data[1];
            y = data[2];
            printf("x=%d, y=%d, left=%d, middle=%d, right=%d\n", x, y, left, middle, right);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时光机121906

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值