Version 3 of the Current Value Table (CVT) introduced some significant changes in the library. This document provides a summary of these changes as well as some comparative performance benchmarks.
The Current Value Table is implemented in a two layer hierarchy consisting of core VIs and API VIs. The core contains all of the functionality of the CVT, including the data storage mechanism and additional service functions. The API VIs provide access to the CVT functionality in a simple interface. There are a few sets of API functions that provide slightly different access to the CVT and vary in flexibility and performance, as well as easy-of-use.
The core data structure consists of two VIs which support tag management for the entire CVT, and an additional data storage VI for each data type supported.
The Memory Block polymorphic function stores all data for the system, and consists of a single VI for every data type supported. This functional global variable allows you to clear memory, read or write a single value in memory, and read or write a set of values in a single call.
The Tag List and Group List functions store all information necessary for the access and management of that data. The tag list stores the name, type, description, and memory location of each tag. The group list stores information about any groups formed in the table. Both of these functions store information by name in the form of variant attributes. Variant attribute "get" and "set" functions provide an extremely fast lookup which is superior to a linear array search for data sets larger than approximately 40 tags.
The CVT contains a number of API function sets to provide different interfaces that can be chosen according to the needs of an individual application. The basic API provides simple write and read functionality. The additional APIs provide a higher performance interface to the CVT, but place some restrictions on the application when using the CVT. All three APIs share the same common core VIs and can be used in conjunction with one another, so you can choose the appropriate function for each individual access to the CVT.
Before the CVT can be used to store and retrieve data it needs to be initialized. Initialization allocates memory for contained tags, forms any groups specified, and stores any user-defined metadata. The initialization of the CVT is defined using a cluster array that contains the attributes of all variables used by an application. Version 3 of the CVT introduces a new cluster which allows the system to handle new features like groups. This cluster is incompatible with the cluster used in prior versions of the library, but a conversion VI is provided for backwards compatibility. This cluster can be created as a constant on the diagram or loaded from a file. Version 3 of the CVT also adds the ability to create new tags as needed during runtime, without overwriting existing tags. The initialize VI allows the user to select whether or not they wish to clear the CVT.
The standard API contains functions to read and write data items in the CVT using the variable name as an identifier. Using the basic API the variable name can be a static string or can be created at runtime using the LabVIEW string functions. In the API call, the variable name is used to lookup the index of the variable and then the value is accessed in the using the index. To improve performance, version 3 of the CVT only performs the lookup on the first call, if the lookup previously failed, or if the tag name input changed from the previous iteration. This API uses polymorphic VIs to switch between data types. For writes, this data type is selected automatically based on the wire type. Reads can be selected by providing a default value or by manually selecting a type. The appearance of the VI will change based on the instance selected.
The Static API is very similar to the standard API. However it requires that you use a static name (constant string) in your application when accessing a variable. This restriction allows each instance of the Static API to only perform the variable index lookup operation once on the first call to each instance. It then buffers the index for subsequent accesses providing a significant performance advantage when repeatedly reading or writing the same variable in the CVT. Version 3 of the CVT also allows the static API to perform the lookup again if an error occurred, rather than relying on the "first call?" primitive. This API can be distinguished by the inclusion of a small glyph which indicates that the lookup value is stored internally.
The Advanced API provides even better performance with the tradeoff of requiring the application-level code to perform the lookup. Using the Advanced API you use two VIs to access a value in the CVT. The first VI is used to retrieve the index and type of a variable in the CVT. This step is only performed once for each variable used. Then the index is used to access the variable value. This provides the thinnest possible API to repeatedly access the same value in the CVT.
For sets of tags which share the same data type, the Advanced API can be used to further boost performance by eliminating the sub-VI overhead of each lookup in memory. Performance will vary, but a rule of thumb is to use set of indices any time you wish to access three or more tags of the same type. Because tag names themselves are untyped, the Advanced API look-up function returns the tag type along with the references in order to provide a type confirmation to the application code.
Sometimes, it can be beneficial to attach a name to a set of tags of varying data types rather than referencing each tag individually. Version 3 of the CVT adds a group API which allows the user to read or write a set of tags simultaneously. One method for forming a group is to create the group during initialization.
Groups can also be formed at run-time. Once a group has been formed, it can be accessed by the group name rather than the individual tags. Similarly to the Basic API, a look-up will only be performed if the group name changes or if an error occurs. Users cannot modify an already formed group, but groups can be deleted and reformed using this API. Care should be taken to ensure that tags are looked up after a group has been deleted or reformed. Once the lookup has been performed, the group can be read as a whole, in the order specified.
In addition to the VIs that access the stored variable values, the CVT also provides utility VIs to access additional properties or attributes of each variable or group.
Read Tag Description.vi provides a tool for retrieving the stored description of a tag.
List Grouped Tags.vi and List Grouped Tags By Type.vi provide a utility for retrieving the members of a group. The first function returns the full list as entered. The second returns a list which is organized by type, with a type descriptor for each set.
Finally, Save CVT to Disk.vi and Save Grouped Tags to Disk.vi provide tools for storing the currently loaded CVT data to disk. Save CVT to disk will initiate a lookup of every tag in the system on first call, and will use that information to perform an extremely efficient index read on the data on subsequent calls. Save Grouped Tags to Disk will perform a lookup in the same fashion as the Basic API. Both functions will then pack the data into an XML file and save it in the location specified.
A series of performance tests were generated and run using the Unit Test Framework in order to compare the performance of any change to the performance of the CVT v2.0.1. The results of these tests, when run on a Quad-core laptop, are shown below. All tests consist of 1000 reads. For individual access APIs, a single value is read. For bulk access APIs, 1000 values are read. The only exception is for the 4x Parallel Static Reads and Writes tests shown in Figure A, where 400,000 accesses are performed across 4 parallel loops.
Figure A: Performance results for the higher-speed CVT APIs. This demonstrates the improvements offerred by the modified memory function. Note: Since CVT 2.0.1 can only read items by index, I have used that as the result for Reference Read, Reference Write, Group Read, and Group Write.
Figure B: Performance results for static access and for named access. These tests demonstrate the improvements made to the tag management functions. Even across 1000 reads, the single lookup performed by the static reads function is enough to slow the entire test down for CVT 2.0.1, as compared to the more direct comparison offered through the tests in Figure A. The Named Read and Write tests use the basic API to read 1000 tags in sequence, performing the lookup every time.
Figure C: Performance results for tag management functions. Because run-time performance was the goal, some slight sacrafices were made to init-time performance. This test also demonstrates the time taken to save 2000 tags to disk and to form a group of 2000 tags. Note: For CVT 2.0.1, the "Load CVT1 Tags" test is equivalent to the "Init" test. Init uses the native tag type for each API. As such, the "Load CVT1 Tags" does not include groups, but does include the code required to convert from CVT1 tags to CVT3 tags.