Welcome back to the third installment of a special multi-part edition of the App Note Spotlight, where we’ll continue highlighting an interesting app note that you may have overlooked—Simulation Performance Coding Guidelines for SystemVerilog. [link to app note here]. This app note overviews all sorts of coding guidelines and helpful tips to help optimize your SystemVerilog code’s performance. These strategies aren’t specific to just the Xcelium Parallel Simulator—in fact, they’ll help you no matter what simulator you’re using.
Today, we’ll talk about data structures, and how to make sure you’re using the best-optimized method for any use case.
1) Use static arrays instead of dynamic arrays when the size is relatively constant.
SystemVerilog has a couple of dynamic data structures, and static counterparts for each. The dynamic structures have overhead in that they are heap-managed objects, so there’s a certain amount of overhead that comes with that. Static data structures don’t suffer from this issue so, for cases where it is reasonable, static arrays will perform better than their dynamic counterparts.
2) Use associative arrays when you need to do lookup or random insertion/deletion
Associative arrays have more efficient lookup than other data structures. Often implemented using a tree, they have a complexity of O(log n). This is much, much faster than a queue or array, which has a linear lookup complexity, O(n).
It’s not all fun and games for associative arrays, though. Since they’re implemented as trees, adding or removing an element from the front or back isn’t as simple of a process; while queues and arrays have access to those areas in constant time, O(1), associative arrays are O(log n) to add or remove an element at any point.
So—if your use case requires a lot of random lookup, and you won’t be inserting or deleting things from the front or back specifically all that often, consider an associative array.
3) Choose queues when insertions and deletions are mostly at the front or back
Like the above tip, if you only care about adding to the front or back of your structure, a queue is for you. Not only does it access the front or back of the queue in constant time—it can also access an element at any index in constant time, too. This makes it the absolute fastest option for that use case.
4) Use built-in array functions when needed
This is a fairly simple one—don’t reinvent the wheel on your data structure’s functions. If you’re using a SystemVerilog standard data structure, there’s a good chance whatever operation you’re trying to perform can be done through a built-in function. This extends to querying functions, locator methods, ordering methods, and reduction methods.
5) Don’t use the wildcard (*) index type for associative arrays
You’re allowed to use the wildcard (*) to make your key a generic integral type; however, this isn’t a good idea if you’re looking for maximum efficiency. Since the wildcard allows you to use any key type, whenever an item is stored in the associative array, the simulator uses a dynamic key type to account for the uncertainty. This has quite a bit of overhead versus a statically sized key. Likewise, the simulator must dereference the dynamic keys to check against the input when you’re doing a lookup or search, and this adds overhead as well.
That’s all we have for today—check back soon for the next installment!