A Conditional For Loop (or some other form of 'break') has been something various people have wanted in LabVIEW for a long time, but NI was always resistant. What changed?
I'm not sure what resistance you've heard. There might have been some people in the past who felt that it wasn't a priority, since it didn't make the impossible possible (i.e. it doesn't do anything you can't do with a while loop). But we frequently review customer requests, and this feature "made the cut" for this release.
It has always been my understanding that a For loop was more efficient than a While loop in LabVIEW. If I had to guess why it would be related to lack of overhead related to things like a conditional stop... have I been mislead all this time or has the For loop just gotten demoted to the while loops equal?
The For Loop was more efficient than the While Loop, and still is. WITHOUT the Conditional Terminal showing, the generated code is unchanged from pre-8.5 LabVIEW. WITH the Conditional Terminal showing, LabVIEW has to evaluate that boolean value and decide whether to break out or keep looping. Thus, there is a VERY SLIGHT performance hit. The takeaway here is that if you don't need to break out of a For Loop, don't show the Conditional Terminal.
Now, comparing the For Loop w/Conditional Terminal to an equivalent While Loop, the For Loop can be considerably faster. First, the same code is generated to evaluate the Conditional Terminal, so that's a wash. However, you won't need to be comparing the index to the array size, so that's faster. But probably more noticeable will be the performance gain if you are building any arrays using the Auto-index output terminal. With a while loop, we don't know how big an array that auto-index terminal is going to create. So, we allocate memory over and over again (in chunks, but still possibly many times) until the while loop stops. With the For Loop, we at least know the maximum size that array will be, so we only have to do one large data allocation, and then resize downward if we terminated the loop early.
To summarize, the For Loop w/Conditional Terminal is still going to be the most efficient loop.
I see your point, however... What if I don't wire N on the for loop? I can send a dynamically sized array, meaning that the compiler doesn't know the size, as the input of the for loop. Is there overhead related to this? or would the for loop, behind the scenes, do an array size on the input and set the size of the output accordingly? I think I may have to build up a few VIs with the different configurations and time test them... just out of curiousity.
Okay... Here is a description of what I just did. All 4 VIs have a flat sequence to get time before and after a loop structure. All VIs are searching a set of 100k integers that are sorted in an array. Each iteration searches this array for the current iterator value (roughly a very dirty index array function). I ran each VI two times and close LabVIEW between running each VI to force deallocation of ALL memory. No other non-critical processes are running on the computer
1. While loop: Compare iterator to input size of array calculated outside the loop. 1st run 19.2657s, 2nd run 19.25s 2. Conditional For loop: replaced while loop exactly with conditional terminal enabled. 1st run: 19.2811, 2nd run 19.2499s. 3. Autoindex for loop: Number of iterations based on a static input array. 1st run 19.3124s, 2nd run 19.2499s. 4. For loop with array size wired to N. 1st run 19.2655, 2nd run 19.2499.
Based on this information the order of efficiency based on this simple sample in order from best to worst is: 1. Wired N based for loop. 2. While loop. 3. Conditional For loop. 4. Auto indexed for loop.
I have the VIs all ready for review if anyone want to test them again. Leave a comment with your email address.
OK, I may overstated the performance benefit of the For Loop over the While Loop. I think we're splitting hairs here, to some degree. It will likely be measurable in milliseconds, not seconds, and so unless you're dealing with MASSIVE quantities of data, it probably won't be noticeable.
The problem with your tests, Matt, is that you're not really testing the loop's performance. In those VIs, more than 99% of the time is spent in the Search 1D Array function, so you're not testing the loop cycle time, but rather the Search 1D Array performance in different contexts. Granted, it's very odd that there's a difference and I honestly can't explain. In fact, on my machine, the difference is more pronounced with the For Loop versions clustered around 16sec. and the While Loop version taking only 13sec! I've asked someone else on the team with more knowledge of our code generation if he can explain it. Either he'll post, or I'll let you know what he tells me.
So, I think if you make the loop bodies in your tests faster, you'll see that what I said in my original post is true. I took your VIs and replaced the Search 1D Array function with an Increment function. I also had to make the array a million elements to get a measurable difference. And I replaced the Get Data/Time functions with the Tick Count function (because it's faster).
With those as my test VIs, I get the following results: 1. While loop: Compare iterator to input size of array calculated outside the loop. 33ms 2. Conditional For loop: replaced while loop exactly with conditional terminal enabled. 22ms 3. Autoindex for loop: Number of iterations based on a static input array. 16ms 4. For loop with array size wired to N. 16ms
So, as you can see, we're only talking about 17ms between the best and the worst times, and that's iterating over a million elements. You might be tempted to say that it's a factor of 2 difference, but don't forget that the loop cycle time is going to be such a small percentage of your application. Even if the loop body takes a whole 1ms to execute, the difference is still going to be about 17ms, out of 1,000,033ms.
Robbie and Christina: I certainly wasn't trying to disprove you by any means... an unfortunate side effect to removing "person to person" communication and replacing it with text. When I find something like this, something that seems to be an anomaly, I can't help but learn all I can about it. I am always trying to learn best practices from the best people. I look forward to future responses on this topic.
Out of curiosity I wrote the same code up in 8.2.1... obviously without the "conditional for" test.
In this test, the For loop wins by a matter of seconds in both the N wired and not wired case. The while loop takes longer even after multiple runs than the For loop takes on the first run.
Matt, I don't think either of us thought you were trying to disprove us, nor would we mind if you were. We may develop some of the coolest software in the world, but we're far from perfect! So, you have to question us. Best case scenario, we both end up learning something.
As for your 8.2.1 test, when you say "the same code", which code do you mean, your original code (with Search 1D Array), or my modifications to it (with Increment)? If you mean your original code, I tried the same thing when I was investigating your original performance tests, and I actually saw pretty much the same results as in 8.5 (with While Loop being faster than For Loop). I just tried it again, and still see the For Loop being slower. While Loop ~13sec, For Loop ~16sec. This still remains a mystery to me.
I ran the original nasty search on my box and saw a performance increase with the For loop. I didn't back save, I recoded it fresh... I guess there is always the possibility that the "in-placeness" algorithm is messing with us? Either way, if you are baffled I won't concern myself with it any longer. I don't think that in reality this will effect any of us. Thanks for the great discussion though.
12 Comments:
A Conditional For Loop (or some other form of 'break') has been something various people have wanted in LabVIEW for a long time, but NI was always resistant. What changed?
I'm not sure what resistance you've heard. There might have been some people in the past who felt that it wasn't a priority, since it didn't make the impossible possible (i.e. it doesn't do anything you can't do with a while loop). But we frequently review customer requests, and this feature "made the cut" for this release.
It has always been my understanding that a For loop was more efficient than a While loop in LabVIEW. If I had to guess why it would be related to lack of overhead related to things like a conditional stop... have I been mislead all this time or has the For loop just gotten demoted to the while loops equal?
The For Loop was more efficient than the While Loop, and still is. WITHOUT the Conditional Terminal showing, the generated code is unchanged from pre-8.5 LabVIEW. WITH the Conditional Terminal showing, LabVIEW has to evaluate that boolean value and decide whether to break out or keep looping. Thus, there is a VERY SLIGHT performance hit. The takeaway here is that if you don't need to break out of a For Loop, don't show the Conditional Terminal.
Now, comparing the For Loop w/Conditional Terminal to an equivalent While Loop, the For Loop can be considerably faster. First, the same code is generated to evaluate the Conditional Terminal, so that's a wash. However, you won't need to be comparing the index to the array size, so that's faster. But probably more noticeable will be the performance gain if you are building any arrays using the Auto-index output terminal. With a while loop, we don't know how big an array that auto-index terminal is going to create. So, we allocate memory over and over again (in chunks, but still possibly many times) until the while loop stops. With the For Loop, we at least know the maximum size that array will be, so we only have to do one large data allocation, and then resize downward if we terminated the loop early.
To summarize, the For Loop w/Conditional Terminal is still going to be the most efficient loop.
I see your point, however... What if I don't wire N on the for loop? I can send a dynamically sized array, meaning that the compiler doesn't know the size, as the input of the for loop. Is there overhead related to this? or would the for loop, behind the scenes, do an array size on the input and set the size of the output accordingly? I think I may have to build up a few VIs with the different configurations and time test them... just out of curiousity.
Okay... Here is a description of what I just did.
All 4 VIs have a flat sequence to get time before and after a loop structure. All VIs are searching a set of 100k integers that are sorted in an array. Each iteration searches this array for the current iterator value (roughly a very dirty index array function).
I ran each VI two times and close LabVIEW between running each VI to force deallocation of ALL memory. No other non-critical processes are running on the computer
1. While loop: Compare iterator to input size of array calculated outside the loop. 1st run 19.2657s, 2nd run 19.25s
2. Conditional For loop: replaced while loop exactly with conditional terminal enabled. 1st run: 19.2811, 2nd run 19.2499s.
3. Autoindex for loop: Number of iterations based on a static input array. 1st run 19.3124s, 2nd run 19.2499s.
4. For loop with array size wired to N. 1st run 19.2655, 2nd run 19.2499.
Based on this information the order of efficiency based on this simple sample in order from best to worst is:
1. Wired N based for loop.
2. While loop.
3. Conditional For loop.
4. Auto indexed for loop.
I have the VIs all ready for review if anyone want to test them again. Leave a comment with your email address.
Matt,
Robbie and I would like to see your VIs. Please e-mail them to me (eyesonvis at gmail.com).
Thanks!
OK, I may overstated the performance benefit of the For Loop over the While Loop. I think we're splitting hairs here, to some degree. It will likely be measurable in milliseconds, not seconds, and so unless you're dealing with MASSIVE quantities of data, it probably won't be noticeable.
The problem with your tests, Matt, is that you're not really testing the loop's performance. In those VIs, more than 99% of the time is spent in the Search 1D Array function, so you're not testing the loop cycle time, but rather the Search 1D Array performance in different contexts. Granted, it's very odd that there's a difference and I honestly can't explain. In fact, on my machine, the difference is more pronounced with the For Loop versions clustered around 16sec. and the While Loop version taking only 13sec! I've asked someone else on the team with more knowledge of our code generation if he can explain it. Either he'll post, or I'll let you know what he tells me.
So, I think if you make the loop bodies in your tests faster, you'll see that what I said in my original post is true. I took your VIs and replaced the Search 1D Array function with an Increment function. I also had to make the array a million elements to get a measurable difference. And I replaced the Get Data/Time functions with the Tick Count function (because it's faster).
With those as my test VIs, I get the following results:
1. While loop: Compare iterator to input size of array calculated outside the loop. 33ms
2. Conditional For loop: replaced while loop exactly with conditional terminal enabled. 22ms
3. Autoindex for loop: Number of iterations based on a static input array. 16ms
4. For loop with array size wired to N. 16ms
So, as you can see, we're only talking about 17ms between the best and the worst times, and that's iterating over a million elements. You might be tempted to say that it's a factor of 2 difference, but don't forget that the loop cycle time is going to be such a small percentage of your application. Even if the loop body takes a whole 1ms to execute, the difference is still going to be about 17ms, out of 1,000,033ms.
Robbie and Christina:
I certainly wasn't trying to disprove you by any means... an unfortunate side effect to removing "person to person" communication and replacing it with text.
When I find something like this, something that seems to be an anomaly, I can't help but learn all I can about it. I am always trying to learn best practices from the best people.
I look forward to future responses on this topic.
Out of curiosity I wrote the same code up in 8.2.1... obviously without the "conditional for" test.
In this test, the For loop wins by a matter of seconds in both the N wired and not wired case. The while loop takes longer even after multiple runs than the For loop takes on the first run.
Matt,
I don't think either of us thought you were trying to disprove us, nor would we mind if you were. We may develop some of the coolest software in the world, but we're far from perfect! So, you have to question us. Best case scenario, we both end up learning something.
As for your 8.2.1 test, when you say "the same code", which code do you mean, your original code (with Search 1D Array), or my modifications to it (with Increment)? If you mean your original code, I tried the same thing when I was investigating your original performance tests, and I actually saw pretty much the same results as in 8.5 (with While Loop being faster than For Loop). I just tried it again, and still see the For Loop being slower. While Loop ~13sec, For Loop ~16sec. This still remains a mystery to me.
Robbie:
I ran the original nasty search on my box and saw a performance increase with the For loop. I didn't back save, I recoded it fresh... I guess there is always the possibility that the "in-placeness" algorithm is messing with us? Either way, if you are baffled I won't concern myself with it any longer. I don't think that in reality this will effect any of us. Thanks for the great discussion though.
Post a Comment
<< Home