Jump to content

Templates?


Recommended Posts

One drawback with OOP i the loss of execution speed. In C++ templates can often be used instead of inheretence, offering the same/similar functionality in most cases, and with no loss of speed. Could this be something for LVOOP? Or will this simply be the same as a polymorphic vi? Can this be done with LVOOP classes?

Link to comment

QUOTE (bsvingen @ Feb 10 2009, 06:37 PM)

One drawback with OOP i the loss of execution speed. In C++ templates can often be used instead of inheretence, offering the same/similar functionality in most cases, and with no loss of speed. Could this be something for LVOOP? Or will this simply be the same as a polymorphic vi? Can this be done with LVOOP classes?
I've never heard of such a situation in C++, but templates is an area where my knowledge is admittedly weak. So let me ask a couple questions... it might help me say whether the same problem even exists in LV and whether the same (or similar) solution might help.

A) What is the performance problem that you are attempting to ameliorate? Is it the overhead of dynamic dispatching?

B) What is an example from C++ where you would use templates instead of inheritance to improve performance?

Link to comment

It was mainly just something I was wondering about. You can get some info here. In the early 90s there were alot of development in mathematical packages using C++ due to the OOP functionality, but lots of it simply died due to performance penalty, ranging from 20% at best, to a factor of 10 compared with FORTRAN (or sometimes C programmed in "FORTRAN fashion"). Templates even the table a bit (lots actually) while maintaining most of the flexibility of OOP.

Link to comment
  • 1 month later...

QUOTE (bsvingen @ Feb 11 2009, 02:39 PM)

It was mainly just something I was wondering about. You can get some info here. In the early 90s there were alot of development in mathematical packages using C++ due to the OOP functionality, but lots of it simply died due to performance penalty, ranging from 20% at best, to a factor of 10 compared with FORTRAN (or sometimes C programmed in "FORTRAN fashion"). Templates even the table a bit (lots actually) while maintaining most of the flexibility of OOP.

Having putzed with C++ templates in the 90s AND been in a scripting-ish world since the late 90s...

The benchmarks from the 90's are virtually meaningless today. A modern Intel chip does SO much voodoo that the cost of using a dynamic language (as opposed to a compiled language like C/C++) has become less of an issue. If you are a real geek and love to understand what makes a modern CPU so magical (as well as what the practical limits are), check out Computer Architecture, Fourth Edition: A Quantitative Approach.

LabVIEW (and hopefully recent textual scripting languages) are all about programmer productivity which is usually worth far more than a faster CPU these days. I spent over a year working with C++ templates and the Standard Template Library. It's a year of my life I want back! Use the tools LabVIEW gives you. Only then if you find the code is too slow, examine your algorithm and perhaps spend time making your code utilize multiple cores or machines efficiently.

Link to comment

QUOTE (Matthew Zaleski @ Mar 21 2009, 07:28 PM)

Use the tools LabVIEW gives you. Only then if you find the code is too slow, examine your algorithm and perhaps spend time making your code utilize multiple cores or machines efficiently.

:thumbup:

I learned the framework of every bit and every clock cycle counts. Whilst it helps me occasionally, I used to really get hung up on it. Now, I prefer to be productive.

Link to comment

I remember when I worked with a computer hardware engineer designing measurement equipment for the oil industry. He needed to hire software engineers to help program the embedded systems we used (simple stuff according to him). He found it impossible, because all engineers freshly out of universities had tons of knowledge about Windows and how to make GUIs using OO and inheretence, and I bet they could do it very efficiently, but not a single one had any idea how to program simple embedded chips. This was 12 years ago.

QUOTE

Use the tools LabVIEW gives you. Only then if you find the code is too slow, examine your algorithm and perhaps spend time making your code utilize multiple cores or machines efficiently.

I fail to see how spending time making my code utilize multiple cores or machines efficiently would do anything but kill coding efficiency. Especially when the code can be coded within minutes in C/C++ and run at highest execution speed possible. Over-generalizations and complex solutions is very seldom a good substitute for proper knowledge of how to solve simple problems.

Link to comment

QUOTE (bsvingen @ Mar 22 2009, 01:26 PM)

Your original post nor my reply was not about making multiple cores run efficiently. You stated a loss of speed due to OOP (not arguing that, but stated that programmer time is valuable these days). Then you asked about C++ templates and if they could be a solution to LabVIEW's OOP speed penalty. I worked with them a LOT for about 2 years after already having 5+ years of heavy C++ coding/designing under my belt. I think I can say, without lying, that I was proficient in C++ templates. C++ templates are primarily a COMPILED language solution to a single class not working efficiently for all data types. They cause a massive explosion in object code size (which kills processor caches btw). They are also notoriously difficult to code properly; and the resulting code looks even more tortured than C++ is. Mind you, at the time, I thought all "good" code had to be that cryptic.

Years of working in newer non-compiled languages (Python, Matlab, and now LabVIEW being the major part of my experience) gave me an appreciation of "developer productivity". Blazingly fast code delivered 2 years late and also prone to all the issues C++ can cause (pointer violations, weird memory leaks) is not always the best use of a programmer's time. I agree with you that "yes, sometimes it is." Users generally want reliable code that is "fast enough" (not fastest) and preferably delivered to them yesterday.

Applying C++ templates to LabVIEW would not necessarily gain you speed. I think you are sort of corrrect that it would be like asking for a polymorphic VI. It is still a scripted dataflow language (graphical prettiness notwithstanding). Your VI, whether part of a class or not, still has to run through an engine designed by NI, optimized by NI, enhanced by NI before it executes on a CPU (ignoring FPGA for the moment as an unusual beast). Any optimization along the lines of C++ templates is likely best handled by the wizards at NI optimizing the G execution engine and delivered in a new version of LabVIEW without us changing a single VI.

Can C++ code run faster than LabVIEW for certain tasks? Yes because it is effectively object oriented assembly language. I challenge you to quickly write C++ code that is reentrant and threadsafe (like most of G) and still runs fast and, more importantly, not likely to crash hard when encountering an unexpected error. Oh, and design your UI quickly in C++ as well. Gawd I hated UI work in C++ even with a framework library!

Implied questions in my original response: Are you currently not achieving performance demanded in an application spec document due to using LVOOP? Is it due to poor algorithm design/choice (which can sometimes be covered up by a compiled language if the end result is "fast enough")? It could very well be that LabVIEW isn't the correct implementation solution for your project today.

Playing devil's advocate:

Python is slower than C++, right? Then why is Google built on a massive system of Python backends? Java is slower than C++, right? Then why are more enterprise-class systems built on Java than C++ today? LabVIEW is slower than C++, right? Then why are large numbers of solutions being delivered via LabVIEW today? I feel that a lot of the answer boils down to programmer productivity: delivering a functioning solution sooner with fewer gotchas. This is all assuming proper development methodologies were used regardless of what language used for the solution.

In short, use the tools you got to deliver a maintainable solution quickly. In my experience, the result executes fast enough.

Now, I see that you related an embedded programming anecdote. The programmer productivity curve/payback is different. You are amortizing a programmer's time over thousands or millions of units sold and need super-low variable costs. I think most LabVIEW projects are amortized to a handful of (or one) built system. In the latter case, doubling the CPU horsepower purchased from Intel is cheap compared to 6 months' salary for example.

QUOTE (bsvingen @ Mar 22 2009, 01:26 PM)

Over-generalizations and complex solutions is very seldom a good substitute for proper knowledge of how to solve simple problems.

I don't get paid to solve simple problems; anybody can do that in a lot of different langages. I'm employed to solve the tough ones. Solving the tough ones usually results in complex solutions where I strive to make it still easy to maintain.

Link to comment

QUOTE (Matthew Zaleski @ Mar 23 2009, 10:00 PM)

It is still a scripted dataflow language (graphical prettiness notwithstanding).
No, it isn't. LabVIEW is a compiled assembly language. The engine simply exists to schedule blocks of code to run. There is not a JIT compiler or a script interpreter underlying LabVIEW. Some of the optimizations that C++ can do LV cannot because those optimizations would cross clump boundaries (clump == chunk of nodes that are scheduled to be run as a block before offering the thread a chance to go pick a different clump, possibly on a different VI running in parallel). But you'd be surprised I think just how many of C++ optimizations are possible within LV, and we have a few tricks of our own that C++ can only dream about. When the next version of LV comes out, we'll have some new surprises in that arena.

Sometimes we can piggyback on C++. There are some nodes on a VI that are compiled into assembly that calls back into the LV engine -- essentially precompiled chunks that are written in C++ that the VI does a call and return to access. Those are exposed in the runtime engine lvrt.dll.

The PDA and FPGA targets go even further, not relying upon the lvrt.dll at all and generating the entire code structure of the VI hierarchy in their code. We could do the same thing on the desktop, but it is more efficient for VIs to share those large blocks of common code than to have every VI generating the assembly necessary for every operation. But an Add node turns into an "add ax bx" assembly instruction.

Link to comment

QUOTE (Aristos Queue @ Mar 24 2009, 01:24 AM)

I would not have expected that based on the IDE interface. When are the compile steps happening then? I'm in the middle of writing G, then hit the run button. Was it compiling chunks as I wired or when I saved? Or when I build an application in the project? The debugger's visualizations of wire flow and retaining values is not something I'd expect from fully compiled code.

QUOTE (Aristos Queue @ Mar 24 2009, 01:24 AM)

But you'd be surprised I think just how many of C++ optimizations are possible within
LV
, and we have a few tricks of our own that C++ can only dream about. When the next version of
LV
comes out, we'll have some new surprises in that arena.

That would not surprise me. Abstracting to a higher level than pure C++ gives new avenues for optimization.

QUOTE (Aristos Queue @ Mar 24 2009, 01:24 AM)

Sometimes we can piggyback on C++. There are some nodes on a VI that are compiled into assembly that calls back into the
LV
engine -- essentially precompiled chunks that are written in C++ that the VI does a call and return to access. Those are exposed in the runtime engine lvrt.dll.

The PDA and FPGA targets go even further, not relying upon the lvrt.dll at all and generating the entire code structure of the VI hierarchy in their code. We could do the same thing on the desktop, but it is more efficient for VIs to share those large blocks of common code than to have every VI generating the assembly necessary for every operation. But an Add node turns into an "add ax bx" assembly instruction.

Out of curiosity, are you treating the VI akin to a .c file with a pile of functions (1 function per chunk) or are these chunks handled in a more raw form (pointer arrays to code snippets)?

I still feel that the main points of my argument stand (since you can compile Python, Matlab and Java to native code). The value proposition from LabVIEW (since it isn't "free") is enhancing my productivity and allowing me to ignore the gritty details of C++/assembly most of the time.

Link to comment

QUOTE (Matthew Zaleski @ Mar 24 2009, 09:30 AM)

From my understanding the answer is yes, LabVIEW compiles the code as you wire it. It is constantly compiling the code. Someone from NI can correct me if I am wrong but I believe they are smart enough to only require recompiling the affects pieces of code and not every clump. This is how they can achieve the constant and effectively real-time time compiling of code.

QUOTE (Matthew Zaleski @ Mar 24 2009, 09:30 AM)

That would not surprise me. Abstracting to a higher level than pure C++ gives new avenues for optimization.

Out of curiosity, are you treating the VI akin to a .c file with a pile of functions (1 function per chunk) or are these chunks handled in a more raw form (pointer arrays to code snippets)?

I still feel that the main points of my argument stand (since you can compile Python, Matlab and Java to native code). The value proposition from LabVIEW (since it isn't "free") is enhancing my productivity and allowing me to ignore the gritty details of C++/assembly most of the time.

I would surmise that the performances issues that LabVIEW has are due to the higher level abstractions the language provides over C++. Remember, with LabVIEW you have built-in parallel processing as well as data flow execution. If you were to write the same execution engine entirely in C++ you would probably encounter the same performance hits. There is a lot of stuff going on under the hood that LabVIEW provides that isn't happening in C++ programs. In most cases the hit on performance is not that significant because like you say most applications are "fast enough" and the increase in programmer productivity more than makes up for the loss in performance. In the cases where the performance is an issue that other solutions need to be investigated such as the over design and architecture of the application, the alogorthm implementations, etc. And in some cases parts or possibly all of the solution will need to be written in another language.

I have worked with embedded systems for over 20 years and it never ceases to amaze me how easy it is to implement parallel tasks in LabVIEW as opposed to other languages. And most embedded developers I work with who first encounter LabVIEW are amazed as well. (Note: the embedded solutions I have worked on cannot be developed in LabVIEW since NI has not provided a general purpose programming environment for LabVIEW running on custom hardware. They are starting to get there with their current RT support but I don't think we are quite at the point where you can throw an NI solution as a possible candidate for custom hardware development projects.)

Link to comment

QUOTE (Mark Yedinak @ Mar 24 2009, 11:34 AM)

I have worked with embedded systems for over 20 years and it never ceases to amaze me how easy it is to implement parallel tasks in LabVIEW as opposed to other languages. And most embedded developers I work with who first encounter LabVIEW are amazed as well. (Note: the embedded solutions I have worked on cannot be developed in LabVIEW since NI has not provided a general purpose programming environment for LabVIEW running on custom hardware. They are starting to get there with their current RT support but I don't think we are quite at the point where you can throw an NI solution as a possible candidate for custom hardware development projects.)

I haven't had a need for embedded beyond cRIO at this point. Is the LabVIEW ARM or Microprocessor SDK of any value or are you further down the chain (i.e. cheaper end) in the embedded space? Not knowing a lot about the embedded space, I had thought the new ARM microcontroller package was specifically targetted at folks like you.

Link to comment

QUOTE (Matthew Zaleski @ Mar 24 2009, 12:37 PM)

I haven't had a need for embedded beyond cRIO at this point. Is the LabVIEW ARM or Microprocessor SDK of any value or are you further down the chain (i.e. cheaper end) in the embedded space? Not knowing a lot about the embedded space, I had thought the new ARM microcontroller package was specifically targetted at folks like you.

We are talking to NI about it now and haven't investigated it far enough to know if this will work or not. But until this there was no option for even considering LabVIEW for actual product development. This may be changing though. I doubt we will do our entire development in LabVIEW at this point but were are certainly looking at for rapid prototyping. I could see the day though when it would be possible to design an entire system using LabVIEW.

Link to comment

QUOTE (Mark Yedinak @ Mar 24 2009, 07:34 AM)

From my understanding the answer is yes, LabVIEW compiles the code as you wire it. It is constantly compiling the code. Someone from NI can correct me if I am wrong but I believe they are smart enough to only require recompiling the affects pieces of code and not every clump. This is how they can achieve the constant and effectively real-time time compiling of code.

If you get a slow enough machine running, you can see the recompiles as you work. The Run Arrow flashes to a glyph of 1's and 0's while compiling. You can also force recompiling by holding down the ctrl key while pressing run, but it's still too fast on my unexceptional laptop to see the glyph (or maybe they got rid of it). You can also do ctrl-shift-Run to recompile the entire hierarchy, but I still don't see the glyph, even though my mouse turns into an hourglass for a short while.

Link to comment

QUOTE (Matthew Zaleski @ Mar 24 2009, 09:30 AM)

Partially, yes. Enough so that when you hit the run button, we can do the last bits right then and then run it. Try this ... have a big hierarchy of VIs, 100 or more. Then hit ctrl+shift+left click on the Run arrow. This is a backdoor trick to force LV to recompile every user VI in memory. You'll spend a noticable amount of time. That gives you some idea of just how much compilation is going on behind the scenes while you're working.

From a CS standpoint, LabVIEW has two cool aspects:

1) Dataflow

2) Graphical

The dataflow we talk about a lot -- magic parallelism and automatic memory allocation without a garbage collector. But its the graphical that gives us a real leg up in the compilation time. We have no parser. Our graphics tree is our parse tree. That's 1/3 of the compile time of C++ sliced off right there. The other two parts are code gen and linking. Codegen we do pretty quick from our parse tree. Linking is taken care of when we load the subVIs. When you recompile a VI after an edit (something that is usually only done when you Save or when you hit the Run arrow), it is compiled by itself, and the only linking that needs to be done is to copy the call proc addresses of the subVI into the caller VI.

Optimizations across VIs are only applied when going through AppBuilder or to one of the non-RT targets, such as FPGA or PDA.

QUOTE

If you go to VI Properties dialog, in the Execution tab, there's a checkbox for "Allow Debugging". A VI will run faster if you turn that off because we will actually compile in less code. Our debug hooks are compiled into the VI. Notice that the "after probes" is an option that you have to turn on on a block diagram, not something that is available by default, since we have to recompile the VI to remove all of our memory optimizations in order to be able to preserve the value of every wire.

QUOTE

(I'm going to gloss a few details here, but the structure is generally correct... at least through LV8.6.) The block diagram is divided into clumps of nodes. The clumping algorithm considers any structure node or any node that can "go to sleep" as a reason to start a new clump (Wait for Notifier, Dequeue Element, Wait Milliseconds). It may also break large functional blocks into separate clumps, though I don't know all the rules for those decisions. Each clump is a chunk that can run completely in parallel with every other chunk, so if a node Alpha has two outputs that go to two parallel branches and then come back together at another downstream node Beta, you'll end up with at least four clumps -- the code before and including Alpha, the top branch after Alpha, the bottom branch after Alpha, and Beta and downstream.

In your head you can think of these clumps as meganodes. A node runs when its inputs are all available. Same for a clump. The number of inputs to a clump is called the "fire count."

Each clump is optimized as tight as it can be (register spilling, loop unrolling, etc). The call address for any clump with a fire count of zero is put into an execution queue.

When you hit the Run arrow, a bunch of threads each dequeue from that execution queue and start running their clump. When they're finished, the clump has instructions that say "decrement the fire count for these N clumps." Any of those clumps that hits a fire count of zero is put into the execution queue. The thread then grabs the next clump at the front of the queue. That clump may not be a part of the same VI -- it may not even be the same VI hierarchy. Whatever clump comes out next gets executed. When the execution queue is empty, the threads go to sleep waiting for more clumps to be enqueued.

Clearly, since clumps never know how long it will be between when they finish and when the next clump in line will start running, each clump writes the registers back to memory when it finishes running, at memory addresses that the next clump will know to pick them up. Thus LV tries to build large clumps when possible, and we take advantage of every cache trick for modern CPUs so that the hardware takes care of optimizing the cases of "write to mem then read right back to the same registers" that can occur when successive clumps actually do run back-to-back.

The actual execution engine of LV is pretty small -- small enough that it was reproduced for the LEGO Mindstorms NXT brick. Most of the size of the lvrt.dll is not the execution engine but is the library of functions for all the hardware, graphics and toolkits that NI supports.

All of the above is true through LV 8.6. The next version of LV this will all be mostly true, but we're making some architecture changes... they will be mildly beneficial to performance in the next LV version... and they open sooooo many intriguing doors...

QUOTE

Oh, most definitely. :yes: I just know that many programmers have a nose-in-the-air opinion that "scripting is for kiddies." Those are the folks who say, "Well, it might work for some people, but I write real code, so there's no way it could work for me." Thus I prefer everyone to be aware that LV really is a compiler, not an interpreter. :ninja:

QUOTE (jdunham @ Mar 26 2009, 05:31 PM)

If you get a slow enough machine running, you can see the recompiles as you work. The Run Arrow flashes to a glyph of 1's and 0's while compiling. You can also force recompiling by holding down the ctrl key while pressing run, but it's still too fast on my unexceptional laptop to see the glyph (or maybe they got rid of it). You can also do ctrl-shift-Run to recompile the entire hierarchy, but I still don't see the glyph, even though my mouse turns into an hourglass for a short while.

You only see the glyph while that particular VI is recompiling. These days you'd need either a reaallllly old machine or a HUGE block diagram.

Link to comment

QUOTE (Aristos Queue @ Mar 26 2009, 07:20 PM)

Partially, yes. Enough so that when you hit the run button, we can do the last bits right then and then run it. Try this ... have a big hierarchy of VIs, 100 or more. Then hit ctrl+shift+left click on the Run arrow. This is a backdoor trick to force LV to recompile every user VI in memory. You'll spend a noticable amount of time. That gives you some idea of just how much compilation is going on behind the scenes while you're working.

From a CS standpoint, LabVIEW has two cool aspects:

1) Dataflow

2) Graphical

...tons of cool details snipped...

I just know that many programmers have a nose-in-the-air opinion that "scripting is for kiddies." Those are the folks who say, "Well, it might work for some people, but I write real code, so there's no way it could work for me." Thus I prefer everyone to be aware that LV really is a compiler, not an interpreter.

Thanks AQ for all those details! The geek side of me loves to know how programs tick (and would have to to get all the way through the Computer Architecture book I linked earlier). I do hold my nose-in-the-air, but not for scripting; I reserve that righteous attitude for Visual Basic :thumbdown: .

I do think LabVIEW suffers from an unusual stigma from the traditional CS crowd. I'm a programmer turned engineer rather than the typical "engineer needs an easy language to program a test measurement system". I was introduced to a LabVIEW/E-series based data-acquisition system 13 years ago (just now being phased out). At the time I thought LabVIEW was not for "real programmers". This was biased by the other graphical development systems I had seen in the 90's, including Visual Basic and competitors to LabVIEW whom I can't even remember the names. The interface for LabVIEW is quite foreign to traditional text programmers.

Eighteen months after my boss told me point-blank that I would learn LabVIEW, I've come full circle. The range of hardware supported and the power of a good dataflow language is dazzling to this old CS fart. For our team, the rock-solid experience of working with NI hardware (and then seeing the power of the cRIO system) convinced us to learn more about the NI software solution. I don't know how many CS degrees include exposure to LabVIEW, but I think NI should be pushing hard in that direction at the university level; engineers shouldn't be allowed to have all this fun by themselves.

Link to comment

QUOTE (Aristos Queue @ Mar 26 2009, 04:20 PM)

All of the above is true through LV 8.6. The next version of LV this will all be mostly true, but we're making some architecture changes... they will be mildly beneficial to performance in the next LV version... and they open sooooo many intriguing doors...

Would that be the DFIR (Data Flow Intermediary Representation) stuff that Jeff K. talk about in last year NIWeek keynote presentation? Anything you could share with us?

PJM

Link to comment
QUOTE (Matthew Zaleski @ Mar 27 2009, 02:43 PM)
but I think NI should be pushing hard in that direction at the university level; engineers shouldn't be allowed to have all this fun by themselves.
Good idea. We agree, and that's why NI has an entire department dedicated to nothing but this. :-)

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.