To download NI software, including the products shown below, visit ni.com/downloads.
Overview
The following example introduce some of the basic concepts of improving code performance and demonstrate a good benchmarking to estimate the execution time of program. The results indicate that memory allocation for arrays can play a significant role in the performance of application.
Description
If we’re looking to improve the performance of our code in some way, we must first know how it’s currently performing. There are several tools and techniques to do this, and the tool or technique we should use depends on what we want to look at and to what level of detail. We can choose to implement some basic techniques within our code, or use more powerful and feature-rich tools such as the profiling tools that come with LabVIEW. In our case, we are going to look at improving the performance of execution time. One of the simplest methods we benchmark this is to take a timestamp before execution (T1) and another afterwards (T2). T2-T1 will give us a good estimate of the time taken.
Something to note is that the time taken to execute the benchmarking itself has not been considered here – improvements can be made to this template, and these vary among platforms. For simplicity, we’ll stick with this example for the time being as it is sufficient for our needs. Unfortunately, on some targets (such as a Windows PC) we’re more limited with the accuracy we can get from our timestamps (tick counts). As such, if our code is only taking, let’s say, 1ms to execute, we’re not going to get accurate results because we can only measure accurate to 1ms using Windows. To compensate for this, we can perform the code multiple times and divide the result by the iteration count (N), giving us the following formula: (T2-T1)/N = Execution Time.
The code below is a good starting point for benchmarking:
Each time we have to allocate more memory we have to call the LabVIEW memory manager, which will have an additional overhead. As such, we want to keep the number of calls to this to a minimum.
One such example of allocating memory which can easily cause performance issues is the ‘Build Array’ function. This function can take an existing array and either append, or prepend data to it. This function is great for its intended purpose, but due to the way in which it operates, we should generally avoid using it inside loops.
Let’s take the example where we want to generate one random number per loop iteration (simulated by a random number here) and stop after 100000 elements have been acquired. We have two main options here:
As we previously mentioned, we want to avoid having to repeatedly call the LabVIEW memory manager and as such, it is better to assign all memory required for the array in advance. This can simply be an array constant initialized with the number of elements required (if known).
Another factor which may affect the performance of this demonstration is the need for array elements to be contiguous in memory. If we do not allocate memory in advance, LabVIEW does not know how many elements the array will eventually hold. As such, it may start placing elements in a free block of contiguous memory which has the capacity to hold, for example 100 elements as shown below:
What happens when we want to add element 101? LabVIEW cannot place this new element in memory at a different location and keep the original memory at this location, because it must be contiguous. As such, the entire array must be moved in memory to a location with more available space, which will in turn introduce a delay in our program execution.
An option we have not yet discussed is to prepend data to the array in the loop rather than append. At first glance, we may expect the performance to be comparable to that of appending data in a loop, but in fact, the execution time increases significantly. This comes back to the need for Arrays to be contiguous in memory. If we have an existing array and want to add an element at the start, LabVIEW will need to move the entire array in memory each time as the used memory will always be at the start of our block of memory. This means we have no free space at the start of the array, whereas before, we were adding to the end of the array where free space may have been available, please note that this may take around 5 seconds to execute due to the number of iterations.
Requirements
Steps to Implement or Execute Code
Additional Information or References
VI Block Diagram
**This document has been updated to meet the current required format for the NI Code Exchange.**
Example code from the Example Code Exchange in the NI Community is licensed with the MIT license.