Hi.
There was a problem found recently in a fan-made mod of Forsaken (game), that
certain input combinations were slowing wine very seriously. Holding down a
keyboard button and moving mouse was found to be especially devastating to
performance (200 fps to 10fps in a matter of 10-20 seconds).
With help from people who develop this mod, I was able to isolate it in a very
small and simplistic testcase, which shows this same problem. It will be
included as attachment. Holding a key and moving mouse over the window steadily
increases main loop latency from 10 to 50 (and even 100) in a short time,
especially so if quickly clicking both mouse buttons as well. In a game this
means going from 100 fps to 20 or 10 just because of input messages. Has to be
noted that in the actual game the rate of slowdown seemed at least 2-3 times
faster for reasons I don't know, but the testcase still should enough to show
the problem.
Now, I do realize that what the testcase is doing is bad practice, it's
basically refusing to process certain types of messages, and PeekMessage just
once during a loop is probably bad as well, but that's what the game was
originally doing in its main game loop. They do plan to fix it in the game.
Still, there are several concerns about it:
1) No slowdown happens of Windows as far as I can tell. No matter how much I
move the mouse holding key and clicking madly, it shows same stable 15-16 ticks
latency in the testcase. I don't know what it does, but somehow it handles this
situation better than Wine.
2) Can this (broken) way of doing things be exposing some inefficiency in
message handling, maybe something that could use optimization? I tried to put
debug hacks into queue_hardware_message(), it seems that when slowdown is
already VERY bad in Forsaken (10fps), message queue in wine server has about 400
or maybe 600 messages. Is that kind of processing overhead per message
inevitable? (This is happening on AMD Athlon(tm) 3200+). Perhaps somebody who
knows that part of code well may be interested in looking into performance
issues in this case. Because, if 400-600 messages in the queue slow down the
application to a crawl, then who knows, perhaps it decreases performance of more
well-behaved but input-intensive apps as well, just less drastically (holding
one or several keys to move, all the while aiming with mouse and abusing mouse
buttons is a common thing in games, so there can be quite a few input messages
flooding the server).
The reason I decided to post it to wine-devel is because I'm not sure if this
kind of thing is expected and unavoidable or a bug that can be fixed, so better
to hear some comments first, then a bug entry can be opened if needed.
#include <windows.h>
HWND window;
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASS wc = {0};
MSG msg;
DWORD ticks, ticks2;
HHOOK kbd_hook, mouse_hook;
wc.lpfnWndProc = &DefWindowProc;
wc.lpszClassName = "testwc";
RegisterClass(&wc);
window = CreateWindow("testwc", "test", WS_OVERLAPPED | WS_VISIBLE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
ticks = GetTickCount();
for (;;) {
if (PeekMessage(&msg, NULL, WM_NULL, WM_KEYFIRST, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
DestroyWindow(window);
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//simulated work
ticks2 = GetTickCount();
for (;;) {
UINT i;
volatile int dummy = 1;
for (; i < 10000 && dummy; i++) ;
if (GetTickCount() - ticks2 >= 10) break;
}
printf("main loop %u tick latency\n", GetTickCount() - ticks);
ticks = GetTickCount();
}
}