I've noticed that many programs, especially games, have some variation of this central loop. Windows is polled for messages and if there aren't any some application specific task is performed.
MSG msg = {0};
while(msg.message != WM_QUIT) {
if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
} else {
// do some processing for example render a graphics scene
}
}
Is this efficient? Doesn't it just unnecessarily drain the CPU under many circumstances, like say if you're drawing a simple graphics scene that changes infrequently? You get an extremely high frame-rate but it's far above the point where it matters anymore for the perceived image quality so it's essentially just a waste of processing power.
kirants
March 26th, 2008, 01:46 PM
It all depends on the specifics of:
// do some processing for example render a graphics scene
ahoodin
March 26th, 2008, 02:22 PM
You get an extremely high frame-rate but it's far above the point where it matters anymore for the perceived image quality so it's essentially just a waste of processing power.
Well actually you are processing windows messages. If you don't do that on a timely basis, there can be trouble.
One "alternative" is to calculate new graphic coordinates in a background thread, and then either flag the data as dirty and force a repaint or something similar. Multi-threading!!!
Alright you still have to handle the windows messages somewhere. So you have to Peek, Translate and Dispatch somewhere on some level. I suggest doing some reading. There are some books by Jeff Prosise that are pretty good.
_uj
March 27th, 2008, 01:49 AM
--- deleted by mistake :blush: ---
_uj
March 27th, 2008, 02:04 AM
Well actually you are processing windows messages. If you don't do that on a timely basis, there can be trouble.
One "alternative" is to calculate new graphic coordinates in a background thread, and then either flag the data as dirty and force a repaint or something similar. Multi-threading!!!
Alright you still have to handle the windows messages somewhere. So you have to Peek, Translate and Dispatch somewhere on some level. I suggest doing some reading. There are some books by Jeff Prosise that are pretty good.
I know a program must process windows messages but it doesn't have to do it by polling the message queue. It can use GetMessage instead of PeekMessage.
In your suggestion how do you "force" the repaint without the use of polling? One way is to start a timer and repaint on WM_TIMER messages. The drawback is that the repaint resolution then will be 1 microsecond at the most.
Or is it maybe possible for a background thread to insert a user-defined message into the windows message queue and then the program would repaint upon receiving this message? Would this be thread-safe?
I've read about PeekMessage polling in Petzold's Windows book (p. 199). The problem (to me) is that it's not discussed from a performance perspective. If this technique is not wasteful, although the increased CPU utilization indicates it indeed is, I have no problem using it.
olivthill
March 27th, 2008, 09:00 AM
Maybe the definition of messages is not clear. Here is a short list of different types of Windows messages:
WM_CHAR, WM_KEYDOWN, WM_KEYUP
They are generated when the user presses the keyboard.
WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_MOUSEWHEEL, etc.
They are generated when the user uses his mouse.
WM_COMMAND
When the user click on the menu, or on other objects
WM_PAINT, WM_SIZE, WM_NCPAINT, etc.
They are generated when the window is moved or resized, or another windows is moving above the window
WM_CREATE, WM_CLOSE, WM_DESTROY, WM_QUIT
When the widnow is created or closed
And there are many more messages.
Several messages are not associated with code written by the programmer, but by default routines via the return(DefWindowProc(hwnd, msg, wParam, lParam)); line, always present at the end of the dispatch message function.
Edit: I forgot to say that standard timers are managed through messages in Windows.
kirants
March 27th, 2008, 12:19 PM
Well, let's say it does nothing for discussion's sake. Then in principle you could stop polling windows for messages and replace PeekMessage with this instead,
if (::GetMessage(&msg, NULL, 0, 0)) {
This means that you're no longer polling and the CPU utilization goes down from like 100% to 0.
Sure.
To me it looks like polling makes a program always use up all its assigned processing time regardless of whether it has something useful to do or not. Isn't that a waste? [/QUOTE
Yes. IMO.
[QUOTE]
Are there ways to use polling without a 100% CPU utilization? Maybe sleep for a while in each loop, or maybe voluntarily give up the time slice when finished processing, or something.
Sure. That is why I asked for specifics. The answer , as you see, lies in WHAT and HOW exactly it is done.
Anyway the reason I'm asking this is that I want to avoid my program "hogging" the CPU, that is burning up cycles doing nothing.
Sure. So, do you know why you are using PeekMessage over GetMessage ?
kirants
March 27th, 2008, 12:21 PM
In your suggestion how do you "force" the repaint without the use of polling? One way is to start a timer and repaint on WM_TIMER messages. The drawback is that the repaint resolution then will be 1 microsecond at the most.
Would a human eye be receptive enough to this 1 micro second ?
Typical way ot refreshign UI is triggering a paint by invalidating a window and updating it ( InvalidateRect, UpdateWindow ). This causes Windows to queue up a WM_PAINT message
ahoodin
March 31st, 2008, 11:51 AM
Yeah gosh, a microsecond is even pretty good for a RTOS task latency...let alone the latency for a Windows screen repaint!
LOL:
A microsecond is the duration of exactly 9192.631770 periods of the radiation corresponding to the transition between two hyperfine levels of the ground state of the caesium-133 atom at a temperature of 0 K (13th CGPM (1967-1968) Resolution 1, CR 103).
S_M_A
March 31st, 2008, 01:03 PM
WM_TIMER has a resolution of 1 milli second, not 1 micro second. Also, even if you set a 1 ms timer your code wouldn't be executed that often. Think of SetTimer as a don't call me until at least this time has elapsed.
I think that the reason for that most games do it like you show is probably that very many games will be running at the machine performance peak. Most users want it that way, they run in full screen, tweaking screen resolution to max settings that give an acceptable frame rate.
_uj
April 3rd, 2008, 11:13 AM
So, do you know why you are using PeekMessage over GetMessage ?
I haven't decided yet because I still don't know whether there's a performance difference between these two?
MSG msg = {0};
while(msg.message != WM_QUIT) {
if (::GetMessage(&msg, NULL, 0, 0)) { // waiting for message to arrive
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
_uj
April 3rd, 2008, 11:34 AM
Maybe the definition of messages is not clear.
I understand that Windows puts different messages in the message queue to notify different events but that wasn't my question. Instead I was wondering which of the two main ways for an application to get at the messages, by polling or by waiting, is more efficient. Or rather my feeling is that polling is less efficient. I was hoping that someone could verify my hunch or otherwise clarify this issue.
MikeAThon
April 3rd, 2008, 11:42 AM
You are correct that gaming loops that use PeekMessage are wasteful of CPU resources. They are constantly polling for messages, and as a result, use 100% CPU availability doing essentially nothing.
A better gaming loop can be designed around MsgWaitForMultipleObjects (see http://msdn2.microsoft.com/en-us/library/ms684242(VS.85).aspx ). The function blocks (like GetMessage) until there is a message in the queue or a timeout is reached or a handle becomes signalled. That's perfect for your use. The message part is obviously useful. The timeout should be set before each and every call to the MsgWaitForMultipleObjects() function, so as to guarantee a desired minimum frame rate. If the function times out, then call your rendering routine. The handle should be used to trigger some sort of special event that needs out-of-order processing, before either a message arrives in the queue or the timeout elapses.
Mike
_uj
April 3rd, 2008, 11:43 AM
WM_TIMER has a resolution of 1 milli second, not 1 micro second. Also, even if you set a 1 ms timer your code wouldn't be executed that often. Think of SetTimer as a don't call me until at least this time has elapsed.
I think that the reason for that most games do it like you show is probably that very many games will be running at the machine performance peak. Most users want it that way, they run in full screen, tweaking screen resolution to max settings that give an acceptable frame rate.
Yes, sorry, I meant 1 millisecond. The WM_TIMER resolution is 1 millisecond at the most.
Well, my application isn't a game but I still want to display 3D graphics in DirectX windows. And the question remains - is PeekMessage a good idea from an efficiency standpoint or will my application unnecessarily burn cycles. I want it to be a good neighbour.
_uj
April 3rd, 2008, 11:51 AM
You are correct that gaming loops that use PeekMessage are wasteful of CPU resources. They are constantly polling for messages, and as a result, use 100% CPU availability doing essentially nothing.
A better gaming loop can be designed around MsgWaitForMultipleObjects (see http://msdn2.microsoft.com/en-us/library/ms684242(VS.85).aspx ). The function blocks (like GetMessage) until there is a message in the queue or a timeout is reached or a handle becomes signalled. That's perfect for your use. The message part is obviously useful. The timeout should be set before each and every call to the MsgWaitForMultipleObjects() function, so as to guarantee a desired minimum frame rate. If the function times out, then call your rendering routine. The handle should be used to trigger some sort of special event that needs out-of-order processing, before either a message arrives in the queue or the timeout elapses.
Mike
Thank you, :thumb: , I'll look into this function.
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.