Link to home
Start Free TrialLog in
Avatar of steenpat
steenpat

asked on

Windows Message Queue Saturation

I am trying to add support for custom features to a piece of software. The code for these features is using a sdk from a third party driver (wacom driver for tablet devices). The software I am working on is very large, and I have noticed the previous programmers have chosen to send a lot of windows messages back in forth, instead say using a function call instead. So there are periods in the software where a lot of processing is going where the windows message queue is getting extremely backed up.

Now, the way the hardware works is that it sends packets whenever an event occurs (pen touched screen, button was pressed, etc). The hardware will also send a windows message upon packet arrival (this is how my code will know when to process packets and then flush them from the queue). So as you can guess, what is happening is a buffer overflow sitation in which packets are being sent, but are not properly flushed from the queue because the windows message associated with them is backed up in the windows message queue and is not reaching the code in time. I have already increased the packet buffer size to its limit.

So, this code is large, redesign is not possible. That leaves other options on the table. I have considered in the past making the class responsible for packet handling a user interface thread and setting up a separate message queue for handling packets but this did not work real well. I am open for advice at this point on what to do.
Avatar of wayside
wayside

Put the code that interfaces with the hardware into a separate exe, and have that exe fire the windows events to the main program. In essense, move the packet buffer from the driver into your program where you can have an unlimited buffer size.

You might also be able to condense out some of the events, for example if there are multiple pointer moves in a row, skip them. This will lower the message traffic to the main program as well.
Avatar of steenpat

ASKER

"Put the code that interfaces with the hardware into a separate exe, and have that exe fire the windows events to the main program. In essense, move the packet buffer from the driver into your program where you can have an unlimited buffer size."

Making a separate exe is an option, even though I'm not crazy about it. Wouldnt it be possible to somehow handle packets on a separate thread instead of making a new exe?
> Wouldnt it be possible to somehow handle packets on a separate thread instead of making a new exe?

Well, you indicated that you tried this and it didn't work satisfactorily. What happened when you tried it?

You could try running the thread at an elevated priority, that would give it more cpu cycles.
>>>> Making a separate exe is an option,

Really? Why should the overhead of an additional process and the need of interprocess communication help to make performance issues smaller?

>>>> Well, you indicated that you tried this and it didn't work satisfactorily.
If somewhat doesn't work at the first approach, try somewhat completely different? Is that the message?

>>>> So as you can guess, what is happening is a buffer overflow sitation
No. A buffer overflow is when you write beyond buffer boundaries, not when a queue can't be processed in time.

You need to find out what is the bottle-neck. I actually doubt that your message queue can't respond in time but guess that you have some handlers (handler functions) which make some lengthy jobs (or even have waits) when being called from the message queue. Of course, the driver should use *new* memory for each packet. If the driver would use the same piece of memory for every write, you would need a realtime operation system to make that work. If using new memory, the only limitation is the (virtual) memory available and I really can't think that this can be a  issue in these days. The only important thing is that you keep your message pump fast. That implies that any handler function must return nearly at once and none does any lengthy operations, e. g. database queries or network communications. These parts either must be splitted into small pieces where the pieces were processed with a message queue timer or must be moved to threads.
>>>> You could try running the thread at an elevated priority
I don't agree again. Normaly the bottle-neck is the queue and not the threads. By giving (worker) threads a higher priority you would slow down the message pump.
> No. A buffer overflow is when you write beyond buffer boundaries, not when a queue can't be processed in time.

My interpretation of the OP's post is that the packets are buffered in the *driver* until a Windows message is received and the packet then removed, and the driver (not being the OP's code) can only be configured to hold so many packets.

> Why should the overhead of an additional process and the need of interprocess communication help to make performance issues smaller?

Thus, by moving the handling of the driver messages to a separate exe that can respond to the driver in a timely way, the packets can be moved out of the driver and buffered in the exe, which can be virtually unlimited in size.

Besides, process overhead is not very large once the process has started.

> The only important thing is that you keep your message pump fast. That implies that any handler function must return nearly at once and none does any lengthy operations, e. g. database queries or network communications. These parts either must be splitted into small pieces where the pieces were processed with a message queue timer or must be moved to threads.

OK, I think this violates the "redesign is not possible" statement of the original poster.

> If somewhat doesn't work at the first approach, try somewhat completely different? Is that the message?

How does this contribute to helping the poster? I'm not trying to send any "message", I merely suggested an alternative, I didn't claim it was the only, or even the best, solution. What is your point?
Can you poll the driver to see if there are any packets available?

If so you could set up a thread to poll for and retrieve the packets and put them in a buffer, and then have another thread which will process them. If you don't poll too often, the performance hit should be very small.
"Can you poll the driver to see if there are any packets available?"

That's actually another alternative. As I read in the documentation you can either poll for packets or wait for 'packet events' i.e. a WT_PACKET message.

"If so you could set up a thread to poll for and retrieve the packets and put them in a buffer, and then have another thread which will process them. If you don't poll too often, the performance hit should be very small."

I guess that is the catch because I would need to poll often for something as simple as setting the cursor on the screen based on where the pen is touching. I will definitely look into it though as it may be the only feasible alternative right now.

"My interpretation of the OP's post is that the packets are buffered in the *driver* until a Windows message is received and the packet then removed, and the driver (not being the OP's code) can only be configured to hold so many packets."

That's exactly right.
"You need to find out what is the bottle-neck. I actually doubt that your message queue can't respond in time but guess that you have some handlers (handler functions) which make some lengthy jobs (or even have waits) when being called from the message queue"

I think you might actually have a point here too. I was thinking about it the other day, and it doesn't seem possible that the windows message queue is getting saturated; it seems possible though that the handler responsible for processing the WT_PACKET message is not being called in time to process the packets.

"That implies that any handler function must return nearly at once and none does any lengthy operations, e. g. database queries or network communications. These parts either must be splitted into small pieces where the pieces were processed with a message queue timer or must be moved to threads. "

Like wayside said redesign is not a feasible option. Although that would have a been a better idea from the start.
>>>> "My interpretation of the OP's post is that the packets are buffered in the *driver* until a Windows message is received and the packet then removed, and the driver (not being the OP's code) can only be configured to hold so many packets."
>>>> That's exactly right.

I recommended to make the message queue faster. Then, the time between sending the message (from the driver) and receiving (by queue) and retrieving (by your handler) would be smaller what should solve the problem.

>>>> Thus, by moving the handling of the driver messages to a separate exe that can respond to the driver in a timely way, the packets can be moved out of the driver and buffered in the exe, which can be virtually unlimited in size.

What are the advantages of a new exe over a thread which does the same?

>>>> How does this contribute to helping the poster?
Hmm. The poster asked you why to have a new exe instead of a new thread. You answered "you indicated that you tried this and it didn't work satisfactorily". I don't think that experts should answer a valid question like that. I think you better should have admitted here that the exe wasn't a good idea.

>>>> OK, I think this violates the "redesign is not possible" statement of the original poster.

If you go from message handling to callback or go from message handling to polling, it is a redesign, right?

If you move lengthy handling from the main thread to a worker thread to make the queue faster, it is a change in one handler function, but not a redesign.

I still think you first should find out why the queue is so slow and then remove the bottle-necks.
>>>> OK, I think this violates the "redesign is not possible" statement of the original poster.

>>>> If you go from message handling to callback or go from message handling to polling, it is a redesign, right?

What wayside said by that is in reference to this:
>>>> That implies that any handler function must return nearly at once and none does any lengthy operations, e. g. database queries or network communications. These parts either must be splitted into small pieces where the pieces were processed with a message queue timer or must be moved to threads.

Of which he is right because there are sections in the software where a lot of processing is occuring and causing the bottleneck. For me to do what you ask not realistic in terms of the scope of this software.

>>>> I actually doubt that your message queue can't respond in time but guess that you have some handlers (handler functions) which make some lengthy jobs (or even have waits) when being called from the message queue.

Ok again on this point saying that is the case, as far as I know because it seems to me now that is what's happening, there are a million of these functions taking their time and for me to redesign so that each gets its own slice is just not a feasible choice, what is left?

>>>>> If you move lengthy handling from the main thread to a worker thread to make the queue faster, it is a change in one handler function, but not a redesign.

Ok, so by this you are saying to move the packet handler to its own thread or to move every lengthy operation to one worker thread?
> What are the advantages of a new exe over a thread which does the same?

The new exe will not lose events because its access to messages will not be impeded by other message handlers in the program which are getting in the way.

Ultimately, this may not help the overall user experience that much, because the original program still needs to handle the events at some point, and if it is very busy handling other events then handling the new events might be (will be) delayed. But at least the events won't be dropped.

> If you move lengthy handling from the main thread to a worker thread to make the queue faster, it is a change in one handler function, but not a redesign.

For this to work, there would have to be no dependencies on the completion of the handler and the start of another handler, which is unlikely or the original designers would have used threads, or a lot of complicated synchronization would need to be added to make sure the dependencies were preserved. The switch from single-threaded to multi-threaded is a non-trivial change in architecture, and is unlikely to be as simple as moving a block of code into a thread.
>>>> The new exe will not lose events
But why should the thread loose events? If the message queue was too slow because of too much messages (or lengthy handling), the thread could peek the queue and pick the one and only message of interest. Or, if once a thread was invoked, the main thread could ignore further messages and the thread  uses any of the other ways to get packets from the driver.  

>>>> and is unlikely to be as simple as moving a block of code into a thread.
Though that is true, there is no alternative if lengthy things must be done. A Windows program must be responsive, and it can't block message processing in favor of some network communications or database queries, especially if there are messages with higher priority.

Another idea is to let the thread have its own (pseudo) window where it can run a separate message loop. Then, the driver could be forced to use that window for its notifications (though normally I am not a friend to let a worker thread make its own messaging).

But, again, first find out out what is wrong and then make a new concept based on the new insights. I often experienced that a wrong behavior was caused by a simple to change code I added in a hurry.

ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial