Wednesday, June 29, 2005

Writing Parallel Programs in LabVIEW - Part 1

In my post about how the CPU business is going to multi-core processors, I talked about how LabVIEW can help things. Here's the first in an occasional series of things I can think of that help LabVIEW applications run in parallel on multi-CPU machines.

1) Read the paper about Hyperthreading and LabVIEW. That shows you all about the LabVIEW threading model, clumps, and how to write some basic applications that do run in parallel.

2) Learn about re-entrant SubVIs. Normally, a VI that is called from two places in parallel will not actually execute in parallel. Otherwise, the data from one iteration would stomp on the data running in the other. Therefore, you need to mark the VI as re-entrant.

There's a hard way and an easy way to do this. The easy way is to go to the VI properties and mark the VI as re-entrant, then drop down the VI in all of the places you want to use it. This was shown in the Hyperthreading and LabVIEW paper.

But what if you don't know how much parallelism you want when you write the program? What if you don't know how many channels you are going to run in parallel?

One application note on this is Multi-Tachometer Processing with the Order Analysis Toolkit. Order Analysis is accomplished through a long computation (FFT). If you have multiple channels, you can compute multiple channels in parallel on a multiprocessor machine. Add more processors, compute more channels in the same amount of time. This appnote shows you how to dynamically add more parallelism based on the number of channels you are processing.

3) Make sure you don't get serialized in Call Library Nodes either. If a Call Library node isn't marked as threadsafe, LabVIEW will serialize calls to the DLL. However, unlike a VI, just changing the Call Library Node to reentrant is NOT a good idea unless you are positive the code is really threadsafe. If it is threadsafe, then it's always a good idea to mark the Call Library Node as reentrant. There is no downside (and there's a big performance boost to marking a Call Library Node reentrant).

4) Be judicious in your use of re-entrant SubVIs. If your VI that you want called in parallel calls other VIs, you may need to make those SubVIs you call re-entrant also. However, it's a bad move to mark absolutely everything as re-entrant. When you do that, it causes extra copies of every single VI's dataspace to be created. That can result in a HUGE memory footprint and you won't realize it. Therefore, be selective. Use the profiler to help determine which VIs should be marked as re-entrant. The VIs that execute for a long time (or have children that execute for a while) should be marked as re-entrant if there is any chance they will be called in parallel. The short quick VIs can be left as normal since they won't typically get called simultaneously or, even if they do, they won't block for very long.

There are some other tricks but I'll save those for another time.

4 Comments:

At 2:35 PM, Anonymous wouter termote said...

Hi,

Using dual pentium, second pentium as a RT target.

I don't know how clever you all are, but could it be possible to use the second cpu in a dual core as a real-time target.
....
What I ment was using two programs side by side.
I tried with Matlab/simulink, when running it took 100% of both cpu's,
Now by giving Matlab only one cpu as prefered cpu, doing so leaves one free cpu to Labview to do its job.
Maybe we could do the same with two Labview programs, one given one entire cpu (the time critical part) the second cpu just do its interface to the user and Windows OS.
So only one cpu will talk to the NI hardware, the other to the rest of the OS.

I will try if I find some time at work.

 
At 8:42 AM, Blogger Joel said...

Yes, you could use processor affinity (in the Windows Task Manager) to assign a LabVIEW process to just one processor. You could write a second LabVIEW app and run it in a second instance of LabVIEW, or as a built application, and set the processor affinity for that process to the second processor.
Note, when you say "real-time", I assume you are talking about the relatively soft realtimeness of MS Windows. Our systems and drivers, such as NI-DAQmx, allow you to get relatively good performance even though Windows is not actually a "real time" or "deterministic" OS.

If your application really needs hard real-time performance and Windows isn't up to the task, I recommend LabVIEW RT for RTX. This allows you to run a hard real-time process underneath Windows to get a truly tens of microseconds-level determinism while still running MS Windows for your operator interface.

 
At 8:24 PM, Anonymous NI folk said...

Hi Joel,

You say in your blog "There's a hard way and an easy way to do this. The easy way is to go to the VI properties and mark the VI as re-entrant, then drop down the VI in all of the places you want to use it.".

I couldn't find what's the hard way you refer to. Did you just miss it, am I miss-reading it, or is it that painful that you rather not discuss it?

Thanks.

 
At 9:30 AM, Blogger Joel said...

There are a couple of "hard ways".

1) Instead of calling the VI statically, use Open VI Reference and call the VI dynamically. One of the optional inputs to Open VI Reference is to "prepare for reentrant run". See the online help for this. According to the online help, there is an example at examples\viserver\runvi.llb.

2) Turn the VI into a ".vit" file (VI Template). Do an open VI Reference on the template file. The default behavior of opening a template by reference is to spawn a new instance. It achives the same effect as making the VI reentrant though template VIs have other consquences.

3) If you are calling the VI from 3 places, duplicate it 3 times on disk, give the duplicates unique names, and drop them independently.

I think I used method #2 once so I could spawn an arbitrary number of state machines.

 

Post a Comment

Links to this post:

Create a Link

<< Home

FREE hit counter and Internet traffic statistics from freestats.com