06-05-2019 04:05 PM
I am rebuilding the Basic Function Generator.vi to meet the needs of my generic and variable AO Voltage output module and came across this strange bit of code I thought I would throw out to the community and see what people think.
Several of the Waveform Generation VIs have a code segment like this one (clipped from the Basic Function Generator.vi):
Is there an advantage I don't see or understand to building a waveform using an "In Place Element Structure" and "Swap Values"? Anybody see any issue with just using the "Build Waveform"?
FYI, I compared the two methods of injecting the data into a waveform. When the number of samples in "Y" is 100k, the difference in execution time is 4 orders of magnitude in favor of just using the Build Waveform.
Solved! Go to Solution.
06-05-2019 05:07 PM
You raise a good point. I did my own test, and with LabVIEW 2018, the Swap method is only 50 times slower (not quite two orders of magnitude) with 100k samples, and with smaller sample sizes, the speeds become less than an order of magnitude (about 1.4 with 100 samples). Might have something to do with memory management, or else "clever" code that got overlooked ...
Bob Schor
06-06-2019 08:08 PM
Oh, dear, I'm ashamed to admit it, but when I timed the two methods of adding a large Array into a Cluster (Build Waveform vs In-Place Element Swap with an Empty Waveform), I labeled the two Time Indicators backwards! The (admittedly-weird-looking) "Swap" method is always faster than Build Array, a Trivial Amount for modest sized Arrays (less than an order of magnitude), but approaching two orders of magnitude when the Array is on the order of 100k elements!
Most of the time, it may not matter, but I guess the people who Program LabVIEW for NI's Living really do know what they are doing!! So the title of this Post should be "An Unusual Efficiency Hidden in the Waveform Generation VIs".
Bob Schor
06-06-2019 08:38 PM
Hi Bob,
Well now I am curious. I attached the VI I used to test the efficiency. I am using the same method used in the Waveform Generation VIs and calling it the swap time. Then I took the exact same inputs and fed them to a Build Waveform cluster. Each is nestled in a For loop for better averaging.
Note that I am not appending a waveform. I am only creating a waveform like the Basic Function Generator.vi.
...Ben
06-06-2019 10:20 PM
Here's my version, very similar (I think) to yours, except I do repeats (to try to get out of the "tick noise" of the clocks. My code is in LabVIEW 2018 -- I'm posting a "visible Snippet", and also the VI.
Bob Schor
06-06-2019 10:27 PM
Hmm -- our code looks suspiciously "the same", except I use a generated array of random numbers, while you use a fixed array of zeros. I wonder if the LabVIEW Compiler is "optimizing" your code in some way. I have found (to my chagrin) that designing a benchmark that measures what you want to measure (as opposed to what you told it to measure) can be a bit tricky ..
Bob Schor
06-07-2019 12:03 AM - edited 06-07-2019 12:10 AM
Hi Bob,
Logically your loops will create similar outputs. But, I think because the individual loop times are so short (on my computer swap 10^-5s, and build 10^-9s) on average, the OS will not provide you an accurate measure when only measuring a single iteration. Looping the same function multiple times and measuring the accumulated time will have less error.
Say the measurement of the function is "T" and the error in the High Resolution Relative seconds is "dt", where the value measured is T +/- 2*dt ("2*dt" because there are two High Res readings per measurement) . Your method adds up N(T +/- 2*dt) and then normalizes to remove N: N(Tswap +/- 2*dt)/N(Tbuild +/- 2*dt). However, your method assumes T to be much greater than 2*dt. Unfortunately, I doubt that is the case.
My method only reads the High Resolution Relative Seconds twice per N loops. My measured time is N*T +/- 2dt. Divide by the number of iterations and this method results in a timing error per loop of 2*dt/N. Given large N, the error will be much smaller than T.
I switched mine to use random numbers and still get the same results.
Cheers...
06-07-2019 12:37 AM
@hieyequeue @bobSchor
Hi Bob,
Switch the order of operations and see if your benchmarks change. I have seen this effect when I try to benchmark. Or make separate VIs.
mcduff
06-07-2019 10:53 AM - edited 06-07-2019 10:55 AM
Hi mcduff,
I have witnessed that too. I had originally swapped the order a couple times and not gotten any different results.
I tested one last time. This time creating a separate set of random number arrays each 100k samples in length for each loop iteration.
With only 16GB of memory I was a bit limited in the number of loops possible since the sample data set data was now so large. I then set the execution of this VI to match the Waveform Generation VIs and nested it in an external loop for even more iterations. Even though I saw a small, ~5%, faster performance with the build vs swap, it was not statistically significant irregardless of the order I performed the loops.
These results are far from the 4 orders of magnitude I saw initially using a single data array. It is possible that the auto indexing of the large arrays is the bottle neck here or there is some under the hood optimization when repeatedly building the waveform with the same data. It is apparent that it is difficult to isolate the build waveform functionality.
Since the single array performed much faster in the build method I am sticking with that for my solution.
06-07-2019 11:02 AM - edited 06-07-2019 11:03 AM
@hieyequeue wrote:
Hi mcduff,
I have witnessed that too. I had originally swapped the order a couple times and not gotten any different results.
I tested one last time. This time creating a separate set of random number arrays each 100k samples in length for each loop iteration.
With only 16GB of memory I was a bit limited in the number of loops possible since the sample data set data was now so large. I then set the execution of this VI to match the Waveform Generation VIs and nested it in an external loop for even more iterations. Even though I saw a small, ~5%, faster performance with the build vs swap, it was not statistically significant irregardless of the order I performed the loops.
These results are far from the 4 orders of magnitude I saw initially using a single data array. It is possible that the auto indexing of the large arrays is the bottle neck here or there is some under the hood optimization when repeatedly building the waveform with the same data. It is apparent that it is difficult to isolate the build waveform functionality.
Since the single array performed much faster in the build method I am sticking with that for my solution.
I have not installed 2019 yet to test, but can you try the following
Sometimes there are weird compiler optimizations if no wires connected.
mcduff
EDIT: Just saw this was 2018, we try some things.