when using the Tick Count millisecond timer with a .dll I've written in C, I'm getting some odd timing issues.
When I code the function I want (I'll explain it below in case it helps) in LV and run it as a subVI, feeding it the Tick count as an argument, the function runs quickly, but not quite as quickly as I would like. When I feed this same subVI just an integer constant rather than the Tick Count, it takes about the same amount of time, maybe a tiny bit more on average.
When I bring in my function from a .dll, however, I start to run into problems. When I feed my function an integer constant, it is much faster than my subVI written in LV. When I feel my .dll the Tick Count, however, it slows down tremendously. I'm including a table with the times below:
This is running the function 100,000 times. The function basically shifts the contents of a 2-dimensional array one place. For this function, it probably won't be a huge deal for me, but I plan on moving some of my other code out of LV and into C to speed it up, so I'd really like to figure this out.
This sounds like an interesting issue. The difference in execution times for the subvi with the constant or the tick timer is so close, it's hard to say that anything significantly different is happening there. The difference with the DLL, however, is very significant!
I have tried playing around with this a little myself. I wrote a very simple DLL (using CVI) that just adds two numbers together. Using the tick count or integer constants as inputs to the call library function node, I could not reproduce the difference you describe (using LabVIEW 8.0.1). Thus, I have some questions for you:
1. What version of LabVIEW are you using?
2. What operating system?
3. Are you running the CLFN in the UI Thread or is it set to Reentrant?
4. Can you post your code and your DLL so that others can give it a try? (or at least something that reproduces the problem?)
I am interested to help you figure this one out. Let me know what you find out!
1) LabView 8.0 (not sure about .0 or .1) 2) WinXP Pro 3) Running the functions in the UI thread 4) The attached .zip file contains everything needed to test this. The VI "MSTick Bad Behavior.vi" should reproduce the problems I've been talking about. Change the third argument of the CLFN from 123456789 to the Tick Count and my problem should show up. Or, you can just place the tick count inside the loop without even wiring it to anything and it will slow down. The attached "MSTick fine behavior.vi" is the same function being implemented purely in LabView. Finally, the attached "olfactometer_functions.dll" has the required function in it. The calling procedure is (C calling convention):
unsigned int shift_2d_and_average_2nd(unsigned int *array_start, int loa, unsigned int new_entry, int average)
where array_start is a pointer to the (0,0) entry in an array with 2 columns, loa is the total length of the space required by that array (2xlength), new_entry is the entry you want placed at the end of the first column, and average is just a flag indicating whether or not to compute the average of the 2nd column. What the function does can be seen quite easily in "MSTick fine behavior.vi".
If this is something really easy to correct that I have just overlooked, my apologies as I'm quite inexperienced with LabView. Also, if there is a better way (most likely is!) to do what I'm doing in "MSTick fine behavior.vi" then by all means let me know.
Thanks for posting the code -- that made things a lot clearer for me. I believe I know what's going on here, and the good news is that it's easy to correct! (You shouldn't apologize for this though, as even an experienced LabVIEW programmer could run into a similar situation.) Let me explain...
When you set your Call Library Function Node to run in the UI Thread you're telling LabVIEW that your DLL is not Thread-safe -- this means that under no circumstances should the DLL be called from more than one place at a time. Since LabVIEW itself is inherently multithreaded the way to work with a "thread-unsafe" DLL is to run it in a dedicated thread -- in this case, the UI thread. This safety comes at a price, however, as your program will have to constantly thread-swap to call the DLL and then execute block diagram code. This thread-swapping can come with a performance hit, which is what you're seeing in your application.
The reason your "MSTick fine behavior.vi" works is that it isn't swapping threads with each iteration of the for loop -- same with the "MSTick bad behavior.vi" without the Tick Count function. When you introduce the Tick Count Function in the for loop, LabVIEW now has to swap threads every single iteration -- this is where your performance issues originate. In fact, you could reproduce the same behavior with any function (not just TIck Count) or any DLL. You could even make your "MSTick fine behavior.vi" misbehave by placing a control property node in the for loop. (Property nodes are also executed in the UI thread).
So what's the solution? If your DLL is thread-safe, configure the call library function node to be "reentrant." You should see a pretty drastic reduction in the amount of time it takes your code to execute. In general, you can tell if your DLL is thread-safe when:
The code is thread safe when it does not store any global data, such as global variables, files on disk, and so on.
The code is thread safe when it does not access any hardware. In other words, the code does not contain register-level programming.
The code is thread safe when it does not make any calls to any functions, shared libraries, or drivers that are not thread safe.
The code is thread safe when it uses semaphores or mutexes to protect access to global resources.
The code is thread safe when it is called by only one non-reentrant VI.
There are also a few documents on the website that you may want to take a look at, if you want some more details on this: