03-20-2010 04:10 PM - edited 03-20-2010 04:12 PM
03-21-2010 04:15 AM - edited 03-21-2010 04:16 AM
Try to not use the callback for once and see if that makes a difference. The external component that you are calling may play tricks with the applications message loop while it is inside the callback. LabVIEW's UI thread does serve that application message loop and also does all the repainting. So if your component is somehow messing with the message loop it could severaly hamper the performance of LabVIEW.
This does not have to be done intentially by the component. For instance if it is based on an out of process ActiveX or COM component internally it may have to do something called marshalling. This happens usually automatically for properly created components but especially for the callback case this is a very tricky business and ActiveX does hook somehow into the applications message loop to implement out of process marshalling.
So disable the callback mechanisme and see if that has any significant influence on the sloppyness of your application. If it has I would guess that is a though cookie and otherwise look at your application and how you could improve its performance. There are several good guidelines and stylebooks out there that also give tips how to improve performance.
03-22-2010 11:00 AM
Thanks for the tips, I'll try it.
I'm not using ActiveX or COM. When in interrupt occurs on the card, the callback function in my wrapper DLL gets called by the firmware on the card. The firmware blocks on the callback function to prevent simultaneous memory access. The callback function posts a LabVIEW User Event using PostLVUserEvent, which is handled in a LabVIEW VI. The callback blocks on a semaphore. When the callback is finished doing whatever it needs to do, it calls a wrapper function whick posts the sempahore to release the callback function. When the callback function exits, the firmware unblocks.
The VI may need to use a CLFN to do it's work (for example, reading data from the card). However, I can probably push that work into the callback itself, eliminating the need for the CLFN. However, the VI must still use a CLFN to call the wrapper function to post the semaphore.
Can I use a LabVIEW semaphore as a regular C semaphore, or a C semaphore as a LabVIEW semaphore? This would eliminate the other CLFN.
03-22-2010 11:10 AM
You didn't answer the question if the sloppyness is only observed while the callback is active or also otherwise. If it is even when no callback is active, you most probably just have created a sloppy LabVIEW progam in general, by violating some of the styleguide and LabVIEW performance recomendations.
If it is only during the callback then you will have to investigate into that. Not having seen your driver DLL source code I can not really comment on what else could cause such a problem. I assume at least that when you use the term firmware you do mean your driver DLL. Because a firmware on the card itself could never possibly post an event to LabVIEW.
03-22-2010 11:19 AM
03-22-2010 04:14 PM
03-23-2010 12:20 PM
I cleaned my development VI code (and removed all CLFN calls) but could only get about 20 events/second. Then I created another small VI with too loops - one to generate events (producer) and one with an event structure which just counts them (consumer). Playing with the loop delays and a an interval divider I found I could get 500 events/second without too much trouble. This is with no CLFNs, no PostLVUserEvent, and no DLLs.
The big difference is that my little test VI presumably is running two threads in the same VI, while my development VI has an event loop to handle user input and a an event loop to handle the incoming events. The events are produced in my wrapper DLL using PostLVUserEvent. The thread that calls the function that calls PostLVUserEvent is actually in another "base" DLL.
Like this:
1. Base DLL runs a thread that waits for a local interrupt from the hardware
2. When the Base DLL senses an interrupt, it calls a "callback" function in the wrapper DLL
3. The "callback: function in the wrapper DLL calls PostLVUserEvent
4. The "WaitForEvents" VI uses an event structure in a loop to count the events.
local interrupt -> base DLL thread -> wrapper DLL callback function -> PostLVUserEvent -> LabVIEW event structure in while loop
So, there are some possible causes for the slow performance:
1. Overhead in PostLVUserEvent call?
2. Thread switching?
03-23-2010 01:50 PM
Did you use User events to post the producer events to the counter loop? Because if you just use a queue for instance it will certainly be faster. I'm not sure if native user events are handled synchronized, meaning inside the UI thread, but I'm pretty sure that PostLVUserEvent may actually be synchronized through the UI thread to prevent possible multithreading problems.
03-23-2010 02:17 PM
I made a test VI to see if there was a substantial problem in posting user events either natively or through the PostLVUserEvent function.
The result is that both methods work very similar resulting on my machine in about 110 events per ms.
03-23-2010 02:49 PM
I used a User Event in both cases, since that is what I need to use to post the event from my wrapper DLL. I'm not sure how I would use a queue (I've only been using LabVIEW for 2 months now).
I modified my simple test VI to use the same consumer loop, but turn on the hardware to generate the events. I'm getting 30 events/sec which is the correct rate. I think I'll keep adding the things I need and watch for the rate to drop, then I'll know when I've done something to cause the delay. To get full synchronization, I also need to be able to post a semaphore back to the wrapper DLL, so testing that will be my next step.
One thing is clear though - calling a VI after getting the event causes a significant delay and I can only handle ~10 events/sec.
I am building a SDK for LabVIEW developers to use our hardware, so I only need to know that a well-written VI will be able to handle the event rate, and that my chosen method for handling the events will work at that rate. Once I have proven that the wrapper DLL and any supplied VIs work, then I just I need to be able to give our customers some guidelines on what they can and can't do in their own application VI.