X = Y is most efficient when X and Y have identical type declarations, and it is least efficient when Y is a superior class of, or a more general value type, than X.
Use Local Variable Assignment Statements Wisely
In general, you should assign a local variable when you need to reference a value more than once because references to local variables are fast. Conversely, do not make a local variable assignment if you are referencing a value only once.
Use Stability Declarations
You can obtain significant increases in performance by using stability declarations, which allow you to designate key classes and procedures stable for dependent compilations. Stability declarations improve performance by:
You should only declare all items in a KB stable if your application provides a GUI front-end to all the items in your KB. If your application provides public items on public workspaces as part of the user-visible GUI, you should only declare private items to be stable. The reason for this has to do with upgrading text-stripped KBs, as the following note cautions.
To declare an item stable for dependent compilations:
Specify the Item-configuration of the item as follows:
declare properties as follows: stable-for-dependent-compilations
To declare an item unstable for dependent compilations:
Specify the Item-configuration of the item as follows:
declare properties as follows: not stable-for-dependent-compilations
For more information on using stability declarations, see the G2 Reference Manual.
For data that support this recommendation, see the references in this table:
Data Representation
Use Arrays for Fast Direct Access and Data Storage
Arrays are the best data structure for quick data access and storage under these conditions:
integer-array, symbol-array, and so on, instead of weakly typed arrays such as g2-array or value-array, if the type of value to be stored is known in advance.To maintain maximum efficiency, always declare the array subclass to be stable for dependent compilation.
For more information, see the references in this table:
Use List for Fast Manipulation of Elements
Lists are the most efficient data structure when the number of elements in a series is not known or might vary significantly at run-time, or when you need to insert or delete elements at run-time, when direct access to the list elements is not required.
| For information on... | See... |
|---|---|
|
Manipulating lists
|
Use Lists for Fast Insertion and Removal
|
|
Data that support this recommendation
|
Comparison of Various Types of References
|
Use Indexed Attributes when Referencing by Attribute Value
Define your classes with indexed attributes when you need to find objects by attribute value. Indexed attribute searches are much faster than explicit searches, such as looping over a class, or implicit searches, such as if there exists ... such that statements.
| For information on... | See... |
|---|---|
|
Indexed attributes
|
Using Indexed Attributes
|
|
Data that support this recommendation
|
Comparison of Various Types of References
|
Use Variables Only When Necessary
You should avoid using variables in your application unless you require one of these special features: data service, validity intervals, generic formulas, or backward chaining. Otherwise, use parameters or typed attributes. Variables introduce a significant performance overhead. Furthermore, obtaining the value of a variable by using a collect data statement is an asynchronous operation, which has implications on threading.
Try to Avoid Time-Based History Specifications
Always limit histories of variables and parameters. Whenever possible, limit histories by specifying the maximum number of data points as opposed to the maximum age of the history. History specifications based on time cause G2 to allocate memory at run-time, which can cause processing delays. Also, history references are slower than array references, so you might want to use arrays instead of histories in performance-critical applications.
Do Not Transfer to Workspace Unless Necessary
When you dynamically create objects, you should only transfer them to a workspace if the application requires it. If the objects are going to be deleted again or if they are only used internally, you will improve performance by not transferring them to a workspace. Procedural Processing
Use Inlining for Procedure Calls
If you practice good object-oriented design methodology by encapsulate knowledge, you will find that you will be creating a large number of methods and procedures. As a result, your application will also have a large number of procedure calls.
Caution: If you distribute a text-stripped KB that declares procedures to be inlineable and you distribute an upgraded KB, the user of the KB will not be able to run the KB. For this reason, we recommend that you declare only private procedures to be inlineable when you distribute a text-stripped KB.
To declare a procedure to be inlineable:
Specify the Item-configuration of the procedure definition as follows:
declare properties as follows: inlineable, stable for dependent compilations
Because you can declare only individual procedures to be inlineable, you should focus your inlining on a relatively few procedures that the KB calls repeatedly.
When you declare the class hierarchy to be stable, G2 automatically declares any methods associated with the classes in the hierarchy to be inlineable.
| For information on... | See... |
|---|---|
|
Stability declarations
|
Use Stability Declarations
|
|
data that support this recommendation
|
Comparing Method, Procedure, and Function Calls
|
Minimize "On Error" Statements
Each time you enter the scope of an on error statement, your application experiences a performance penalty. In code that has been well written, it should not be necessary to use on error statements frequently. on error statements to those errors that might occur when interacting with an external process, such as, writing to a file.
| For information on... | See... |
|---|---|
|
Error signalling
|
Validating Arguments and Signalling Errors
|
|
Data that support this recommendation
|
Effect of On Error Statements
|
Use "Do in Parallel" to Interact with External Processes
When you need to make multiple calls to get data from an external process via G2 Gateway, use do in parallel loops such as:
for X = each <... > do in parallel...
do in parallel statement allows G2 to group data requests, rather than completing independent "round trips" for each data request. This statement also allows the external process to work on fulfilling the data requests while G2 is simultaneously preparing further data requests or handling the information returned from earlier data requests.
wait statements, allow other processing statements, and other statements that introduce wait states. Although the statements themselves execute quickly, because of the action of other threads, objects that exists before such statements might not exist directly after these statements. Thus, you must re-validate your data after each such statement, which can result in a significant performance penalty. For more information, see Maintain Atomicity Whenever Possible.
Use System Procedures
G2 provides a utility module that contains numerous system procedures, which are built-in procedures and functions that implement common tasks. Some of the system procedures in sys-mod.kb are designed specifically to provide functionality that would be inefficient at the KB level, such as sorting and array operations. The efficiency gains are very significant, typically providing increased efficiency of a factor of ten. System procedures gain this advantage because they run as compiled code, rather than interpreted code.
Use Procedures Over Methods for Performance-Sensitive Code
Methods introduce approximately a 20% performance penalty over procedures when you invoke them by using a call statement. Thus, you might want to emphasize procedures over methods for performance-sensitive code. However, keep in mind that implementing behaviors as methods is a more object-oriented approach, which eases code development and maintenance. Knowledge Bases
Consider Issues of Scalability
Throughout the course of designing and implementing your application, you should consider how your application will perform when it is scaled up to large problems. You should be aware of the fact that the fastest algorithm for small problems is not necessarily the fastest algorithm for large problems. In particular, you need to be aware of scalability issues when designing and implementing algorithms based on searches, sorts, matrix operations, or any algorithm that involves iteration. In such cases, you need to consider not only which algorithm is fastest for the current problem, but also which algorithm will perform best when applied to a much larger problem.for loops, each with an iteration limit of n, the number of operations is proportional to n2, which is the number of times the algorithm processes the innermost statements. Separate Animation from Performance-Sensitive Code
Inside performance-sensitive code, do not cause the screen to redraw by moving objects, changing colors, charting or graphing, or placing attribute displays on objects whose attributes are being manipulated. Hide Tables and Attribute Displays
To improve performance significantly, hide all tables and attribute displays. Also, you should realize that even if the workspace on which an item exists is not visible, you still incur a performance penalty if an item has an attribute display showing.
Minimize the Use of Displays
Use displays such as charts, trend charts, readouts, and dynamic displays only when users require them. Hide displays when not necessary and avoid showing more than one trend chart, chart, or free form table at a time. Update displays only when necessary, make the update intervals as long as possible, and stagger update intervals when multiple displays are visible. Finally, avoid unnecessary color changes. All of these actions have significant performance implications. Avoid Scanned Rules and Polling Procedures
Avoid scanned rules and procedures that poll for events. Applications should be designed to be event driven.
Disable Rule Highlighting
As a diagnostic tool, G2 allows you to highlight rules when they execute. When this option is enabled, each rule that G2 invokes highlights for about 0.2 seconds, which is enough time to perceive the color change as a flash. During that time, no other activities take place within G2. Therefore, every rule that invokes when highlighting enabled takes up about 20% of the available CPU.
To control rule highlighting:
Choose Main Menu > Run Options > Highlight Invoked Rules or Disable Rule Highlighting
To use scheduled drawing:
Choose Main Menu > System Tables > Drawing Parameters and specify Allow-scheduled-drawing? to be yes.
conclude action is significantly slower than storing information in local variables. Try to use conclude only after the result of a calculation is determined and store intermediate results and working data in local variables and arrays. For data that support this recommendation, see Example of Comparing Operations: Change Versus Conclude.
Avoid "Change the Text of" Expressions
Changing the text of a rule, procedure, or system-defined attribute requires G2 to parse text, which is a slow operation. Furthermore, you can only dynamically change the text of items when you are running G2 by using a development license.
Avoid Existence and Type Checking
If possible, you should avoid statements that perform existence checking, whereby G2 checks whether a particular item exists in the KB, for example, if computer-1 exists... You should also try to avoid statements that perform type checking, whereby G2 verifies the data type of a particular value.
| For more information on... | See... |
|---|---|
|
Separating modules into layers
|
Designing Reusable Modules
|
|
Avoiding wait states
|
Maintain Atomicity Whenever Possible
|
Beware of Statements that Cause Implicit Iteration
Try to avoid statements that implicitly cause iterations, particularly statements such as if there exists a class such that (logical expression), which forces G2 to examine all members of the given class to see if any meet the criterion in the expression. The exception to this rule are searches over indexed attributes. Although indexed attribute references use the same syntax, they do not require iterative search. Also try to avoid expressions that cause iterations over all items on a workspace, such as the item nearest to.
Be Careful with List Iterations
The efficiency of list iteration can vary tremendously, depending on the technique that you use. We do not recommend iterating over lists by using indices. References like X[100] are many times slower than the equivalent array reference because G2 counts through the list element-by-element until it reaches the 100th element.
for I = 0 to N - 1 do
change Array[I] = List[I];
end;
for I = 0 to N - 1 do
J = List[0];
remove J from List;
change Array[I] = J;
insert J at the end of List;
end;
I= 0;
for J = each integer in List do
change Array[I] = J;
I = I + 1;
end;
Iterations for each item or value in a list are most efficient when the value or item type cited in the iteration exactly matches the declared type of the list. For example, this iteration is most efficient when you declare
MyList as an integer list:
for I = each integer in MyList
remove X[5] from X results in X = (0, 2, 3, 4, 1). Because of the pre-evaluation of the indexed reference, the statement is equivalent to remove 1 from X. You can use additional syntax to remove elements from lists; however, list references still require element-by-element traversal.
Use Referencing Based on Relations in Performance-Sensitive Code
In performance-sensitive code, you should avoid connection referencing and, instead, construct and cache relations between connected objects to allow rapid traversals via the relation. This recommendation is based on the fact that references based on relations are approximately twice as fast references based on directed connections.
Test Symbolic Equality with "=" Not "is"
Because is has many interpretations in G2 depending on the types of item and values involved, expressions involving is involve relatively high computational load. Do not use expressions like this:
the temperature of Tank is HOT
the temperature of Tank = the symbol HOT
the equipment is HOT
the temperature of the equipment is HOT