我正在开发一个 monothreaded 进程applet,它创建了一个代理虚拟设备(更确切地说是一个虚拟的 Xbox 360 pad);我设法使用uinput界面创建它,我正确设置它并且它工作得很好。
为了向此虚拟设备提供命令,我从另一个真实界面(在本例中为 PS3 平台)读取事件,然后用这些标志打开真实设备文件:
fd = open("/dev/input/event22", O_RDONLY); // open the PS3 pad
主循环类似于(减去错误检查):
while(run) {
input_event ev = {0};
read(fd, &ev, sizeof(struct input_event));
// convert from PS3 --> Xbox 360
convert(ev);
// write to the new virtual pad
write(fd_virtual, &ev, sizeof(struct input_event));
}
你可以想象read(fd, &ev, sizeof(struct input_event));
是一个阻塞调用,我希望有一种超时循环循环并检查其他事件/执行其他代码。
由于这些原因,我想在epoll循环中封装read(fd...
调用,所以我也可以暂停。
问题是,以这种方式完成它会有效吗? 由于使用了epoll_wait,我是否会对当前循环引入额外的延迟,从而导致虚拟键盘的响应速度延迟?
答案 0 :(得分:0)
由于使用了epoll_wait,我是否会对当前循环引入额外的延迟,从而延迟虚拟键盘的响应速度?
是的,你确定。
以这种方式完成它会有效吗?
我确定是的,但这在很大程度上取决于你对“有效”的定义。
我们在这里谈论的是人类输入设备。在处理HID时我们最关心的是延迟,它不应该滞后,对按键的反应应该是即时的。什么是人类的“即时”?有一个很好的discussion there,但我最喜欢的一个论点是,在高水平的田径比赛中,你将disqualified在信号发出后不到100毫秒内开始。
但是100 ms是一个时间预算,用于对输入信号进行整体处理,从按键到游戏中的某些可感知的变化。 Wikipedia page on input lag有关于此预算通常花费的数字。
无论如何,我认为1 ms是绝对安全的开销,你可以添加你的代理,没有人会注意到,让我们说这是我们的最大延迟目标(如“高效”的定义)。
因此,我们假设您对当前代码的响应时间感到满意。添加epoll()
电话后会发生什么变化?基本上,你正在为另一个系统调用添加一些时间,因为现在而不是一个系统调用来获得你正在制作两个的值。因此,它可能比原始代码慢两倍(让我们忘记目前不同系统调用的处理时间差异)。但它真的那么糟糕吗?
要回答这个问题,我们需要对系统调用开销有一些估计。如果我们自己懒得测量它,我们可以使用一些numbers from 20 years ago,一些numbers from people that care about syscalls,一些IPC numbers from microkernel guys (they always care),一些random numbers from StackOverflow或just ask Rich并安顿下来微秒级作为一种安全的假设。
所以问题归结为是否在毫秒(如1000μs)时间预算内添加一些(甚至可以说是10)微秒是显而易见的。我认为不是。
当您从“只是添加epoll()
”转到
循环循环并检查其他事件/执行其他代码。
您需要小心保持这些循环和检查的时间预算。但是再说1 ms对你来说可能已经足够了。