Natural Performance Considerations: by Andreas Schütz Software AG August 2000 9th Natural User Conference Boston
Natural Performance Considerations: by Andreas Schütz Software AG August 2000 9th Natural User Conference Boston
Natural Performance
Considerations
By Andreas Schtz
Software AG
August 2000
Page 1 of 12
Status of August 1st, 2000
Formats
Best performance is achieved when you use the data formats "packed numeric" (P) and "integer" (I4) in
arithmetic operations. You should avoid converting data between the formats packed numeric (P), zoned
numeric (N), integer (I), and floating point (F), as this causes processing overhead even with optimized code.
Since there is no interpretation overhead with optimized code, the differences between the various data
formats become much more prominent: with optimized code the performance improvement gained by using
format P instead of N, for example, is even higher than with normal code.
Example
A = A + 1
With non-optimized code, the performance ratio between packed and unpacked formats when applied to the
statement above is only 1:1.15 approximately. With optimized code, however, the ratio between packed and
unpacked is 1:2.24 approximately. So the performance gain that would be achieved by applying the Natural
Optimizer Compiler to this simple statement is:
Normally it is recommended to use packed format fields on MF platforms. This is not true anymore when the
Optimizer Compiler is used. The direct translation into machine code eliminates the additional check for the
packed format, so here the integer operations are a lot faster.
Furthermore when applications are designed which are planned to run across multi platforms, especially c-
platforms, all zoned and packed format field operations have to be emulated. This means that there is a
substantial overhead in such calculations. So for performance reasons again it is recommended to use integer
variables.
Warning:
Intel CPUs, including the Pentium processors all have problems with floating point and integer calculations
up to processors with speed 120 MHZ. No such information has been published for AMD processors. So to
avoid calculation errors it is recommended to use packed field formats. The Natural emulation avoids all such
potential errors, but of course will cause some overhead.
All constant numeric values in Natural are allocated as packed fields. So the best performance can be
achieved by using that format (P) for all fields used in computation. The exception is when the Natural
Optimizer Compiler is being used. In this case, integer operations are much faster than zoned operations.
Another case where integer formats should be used is when the corresponding application should run in a
multi-platform environment. On C-platforms there is no format P available, so all processing based on that
format needs to be emulated. In this case again the integer format is much better.
Page 2 of 12
Status of August 1st, 2000
There is one exception to when the zoned format is better than either I or P: when numeric fields are used
which are not used in computations. When fields are only used for display purposes Natural can save quite
substantial time by not being required to convert from the internal (packed) format into the displayable zoned
format. This applies typically for fields containing information such as article number, user identifications,
county codes etc.
Index Variables
As the index variables always are used to calculate addresses, these variables should be in format I4. This is
basically the value of the address of an array element anyway, so Natural will not have to do any format
conversion.
Arrays
Array range operations such as the following:
are executed more efficiently than if the same function is programmed using a FOR statement processing
loop. This is also true for optimized code. When indexes are used, integer format I4 should be used to achieve
optimum performance.
Alpha Fields
When moving alpha literal values to alpha variables, or comparing alpha variables and alpha literal values, try
to make the length of the alpha literal the same as the variable if the difference in length is not large. This will
greatly speed up operation. For example:
A(A5):='XYZAB'
DECIDE ON
When using DECIDE ON with a system variable, array, or parameter operand1, move the value to a scalar
variable of the same type and length defined in the LOCAL storage section.
An example for this could be the check for the function key the user had used to enter his data.
DECIDE ON *PF-KEY
VALUE PF1 ----------
VALUE PF2 ----------
VALUE PF3 ----------
VALUE PF4 ----------
VALUE PF5 ----------
performs a lot worse than the following construction:
Page 3 of 12
Status of August 1st, 2000
DECIDE ON TEST
VALUE PF1 ----------
VALUE PF2 ----------
VALUE PF3 ----------
VALUE PF4 ----------
VALUE PF5 ----------
Numeric Values
When using numeric constants in assignments or arithmetic operations, try to force the constants to have the
same type as the variables.
Rules of Thumb
Any numeric constant with or without a decimal but without an exponent is compiled to a packed number
having the minimum length and precision to represent the value, unless the constant is an array index or sub-
string starting position or length in which case it becomes a four-byte integer (I4). This rule applies
irrespective of the variable types participating in the operation.
Operations containing floating point are executed in floating point. Add "E00" to numeric values to force
them to be floating point. For example:
Operations not containing floating point, but containing packed decimal, zoned decimal, or date or time
variables are executed in packed decimal. For ADD, SUBTRACT, and IF statements, force numeric constants
to have the same number of decimal places as the variable with the highest precision by adding a decimal
place and trailing zeros. For example:
To ease the optimization process, try to keep all scalar references at the front of the data section and all array
references at the end of the data section.
Typically this notation is used to indicate a non-database variable. In structured mode this does not have any
influence on the performance of the compiler (at runtime there is no performance relevance anyway). In
reporting mode the #-notation tells the compiler that in database loops it does not have to search the DDM for
a possible field with such a name.
STACK
For better performance reasons all commands which are stacked should be separated from their respective
data. All command entries are copied into the command input buffer, but the data part will be stacked back for
the subsequent input processing within the program. So it is quite a lot faster to program:
STACK TOP DATA p1 p2 p3 .
STACK TOP COMMAND 'CMND'
Page 4 of 12
Status of August 1st, 2000
Modularization
Of course every invocation of an external object requires overhead. Such calls require access to the system
files, to the buffer pool, the complete initialization process has to be done. This means before the object
actually starts a lot of CPU time and possibly database accesses have been performed.
On the other hand it is quite obvious that, the more an application is modularized the easier it will be
maintainable. So here we discuss the trade-off between performance and handling.
Typically all callable objects including maps can be coded as part of the main program. The performance
would increase dramatically. So the buffer pool manager or similar statistics should be used to identify objects
which could easily be returned into the calling program if required because of low performance.
Buffer Pool
Considerable performance gains can be achieved by tuning the buffer pool correctly. Some typical examples
of tuning features are listed below.
The buffer pool should be analyzed to find out if a smaller text block size would result in a dramatic increase
of objects fitting into the space allocated. Typically the default text size as delivered from Software AG is
4KB. This can result in a text size usage of 70 percent. This means that out of a 3MB buffer pool, only 2MB
are actually used to store objects. When the text block size is reduced to 2KB, the text size usage can increase
to up to 85 percent. In a 3MB buffer pool, this means that half a MB can be used additionally for program
storage. If this means that a given application can suddenly become resident in the buffer pool, a dramatic
decrease in the database calls to the system files can be experienced.
Search Logic
Another feature that can result in a dramatic reduction in accesses to the system files is the search logic in the
buffer pool versus the accesses to the system file.
If BPSFI is set to OFF, this means that for every access to an object not found in the current library a
corresponding lookup for this object is performed against the system file. Only when this is unsuccessful does
Natural check the buffer pool again with the library set to the current STEPLIB.
With BPSFI set to ON, Natural checks the buffer pool first through the complete STEPLIB chain without any
access to the system file. This can reduce the number of database calls dramatically. But keep in mind that this
logic can also cause wrong programs to be activated when object names are not unique across libraries. Please
check the chapter in this manual about the buffer pool for more information.
The sequence of the STEPLIBS is important as well. In case that a STEPLIB contains all the required
subprograms for many applications and therefore it is appended to the STEPLIB chain for all these
applications this means that all other libraries will be checked first before the correct library will be analyzed.
The rule is to place the STEPLIB with the most traffic as high as possible in the hierarchy of the STEPLIBS.
Whenever a LOGON is performed, the fast locate table is deleted. So try to avoid multiple LOGON to the
same library. In addition the number of the entries in the fast locate table is limited to 128 entries(Natural 2.3).
There is the special purpose zap NA34086 to increase the number of entries in that table.
Page 5 of 12
Status of August 1st, 2000
Work-file Processing
Some dramatic performance enhancements in Batch can be achieved when the work file statements are used
correctly. One is the VARIABLE feature that will reduce processing time dramatically, the other is the
RECORD clause, which again will save a lot of machine overhead.
All Natural programs compiled with the optimizer compiler run faster than without. But the resulting machine
code will be compiled into a special buffer, and this is stored in special records in the system file. This means
that the load into the buffer pool will mean at least one additional read access to the FUSER system file.
When the CPU gain does not cover this additional overhead, performance is lost. In addition, optimized code
is larger than not optimized code, which means again, that less objects can be loaded into the buffer pool. This
can result in a dramatic increase in the accesses to the system file.
In Natural 2.3 the generated code has been optimized even more. So the performance of a 2.3 optimized
program typically is faster then the equivalent 2.2 optimized code. But the generated code can be influenced
by a lot of options. Only fully tested application should be compiled with the optimizer compiler, and
typically only the most used 10-20 percent of the application.
As the symbol table is not used at execution time in a production environment, it should not be transferred to
the production system. These records use up only some space in the database, but will never be loaded from
Natural. This means that more programs will be able to be stored in the same physical data storage block of
the system file. Consecutive loading will then result in a lot faster load time. All Software AG INPLs are
being delivered without symbol table entries. There is a feature from Natural 2.3 onward in the SYSUNLD
utility to skip the download of the symbol table.
Database Access
Another area with great potential performance gains is optimal usage of database access statements.
In many performance studies it is recommended that the READ statement should be used instead of the FIND
statement. This is true only in a limited form. Typically when a large number of records are to be processed
identified by just one descriptor, the READ statement is better than the corresponding FIND statement. But
when the READ statement is used to retrieve only very few records, the FIND statement is better. Remember
that Natural always has to issue one more database call to find out if the next record still belongs to the
selected set of records. This additional statement can double the amounts of database accesses when the
descriptor values are unique and just one record is to be processed.
Another feature, which should not be forgotten, is the non-descriptor search in ADABAS. ADABAS allows
to use fields in the search buffer which are not defined as descriptors. This still means that every single record
will have top be read from the data file, but only the records which agree to the search criteria will be passed
to the calling system. I.e. Natural.
Page 6 of 12
Status of August 1st, 2000
When in applications the same set of records has to be processed with additional descriptor specifications, the
concept of retained lists should be used. This would mean that ADABAS will not have to rebuild the ISN-list
for the main descriptor all over again.
Descriptor Specification
One major performance issue is the use and specification of the right descriptor values. When quite a lot of
processing is done based on the sequence of one field in the database file, and the resulting record list is
always sorted according to its values, it may save substantial processing time making this field into a
descriptor. As soon as direct searches are being performed on a given field, it should be made a descriptor as
well. Conversely, existing descriptors should be released when they are not used anymore. Otherwise Adabas
needlessly updates the corresponding descriptor with every record modification.
FIND commands with complex search criteria may require some complex processing on the database side.
The following scenario demonstrates the requirements of a complex search:
This kind of a statement retrieves one ISN list for the region values and another one for the status values. The
first list may be quite small, but the second list could retrieve around 80 percent of the database. This means
that 100,000 ISNs have to be processed and matched against the other list.
means that no ISN list is produced, all records are read from region one, but only 20 percent will be rejected
because of the second descriptor value.
Another dangerous function is the WHERE clause in Natural. This option is evaluated before the statements
in the database access loop get control. This could result in the reading of the whole database file when the
WHERE condition is set wrong.
ADABAS offers the possibility to analyze the resulting data records based on further
values in fields, which are not necessarily descriptors. This means that the Natural
application can move the logic typically done based record selection with the
ACCEPT/REJECT or the IF condition can be processed on the ADABAS side and does not
require any physical data transfer between address spaces.
Reading Backward
Since ADABAS 5.3 the feature is offered that the logical read through a set of records based on an inverted
list can be processed backward. So when there is a requirement that data records have to be processed for
instance based on the newest date, this feature will be very helpful. In former versions an additional inverted
Page 7 of 12
Status of August 1st, 2000
list had to be build with the inverted date value and had to be maintained by the application.
It is obvious that the larger the view definition in the Natural program is, the more time ADABAS will spent
to do the corresponding format translation and the record retrieval. Therefore it is always recommended to use
only those fields which are really required in the current processing logic. Actually this is automatically
generated correctly in report mode programs (only the referred fields are used in the format buffer), in
structured mode it is the responsibility of the user to specify as many views as required with the respective
minimum number of fields.
Adabas FDT
All fields requested via the format buffer, i.e. via the Natural view definition, will have to be extracted from
the compressed data record. This means when fields are requested which are allocated at the far end of the
record, ADABAS will have to scan through the complete record to find these fields. The rule here is, place all
fields, which are most heavily used at the beginning of the record.
The Adabas record prefetch feature should be used especially in batch processing. Typically in batch many
records are processed. If several records can be passed to Natural in one call, a dramatic reduction in cross-
memory calls can be realized. Typically the activation of prefetch is valid for all files in the database, but
single files can be excluded from the prefetch processing.
One problem might be that in case of update transaction all records being read as part of the prefetch logic
will be put into the hold-queue as well. This is handled OK by ADABAS, even when some ET or BT
command will be issued before all records, which have been put into hold, have been processed. The
transaction command will re-establish the hold status for the remaining records again. On the other hand,
when the number of pre-read records is quite large, this might result in a hold queue overflow or decreased
performance on the ADABAS side.
When the record prefetch option is used for online processing, the buffers should be specified fairly small, as
online typically only 15-20 records will be processed at a time. In batch the number or records can be as large
as possible.
This value again has a direct impact on the performance of the database processing. The optimal performance
can be achieved when the blocks read by ADABAS contain all the records that will now be processed
anyway. When only a tiny records out of a set of one hundred records which ADABAS just loaded into his
buffer-pool is processed, a lot of time is wasted again.
As already mentioned, in a development environment the GFID generation should be deactivated. But for a
production environment the use of the GFID can save a huge amount of processing power by reusing identical
format buffers from many users within the same application.
Wait on Hold
Page 8 of 12
Status of August 1st, 2000
The parameter WH in Natural should be set according to the respective application requirements. In case that
users often have to wait for records just being processed by other users, this will block the thread during that
time, and the user of course will see a long response time, even when the system is absolutely not busy. So it
will be more efficient to use the RETRY clause in the ON ERROR block to inform the user that the record is
currently not available.
On the other hand the repeated access to finally get hold of the record is overhead again. So when the above
described situation is not too often, the WH parameter should be set to ON.
For RPC, asynchronous and batch processing this parameter should be set to ON in any case. There is no
possibility that any one user could be waiting on some records on his terminal.
Adabas always stores zoned numeric values in a packed format to save space in the database. This means that
all fields defined as numeric should be stored as packed values, so that this overhead can be saved as well.
Depending on the usage of the system files, the system file contents should be sorted according to some
descriptor values.
? In a development environment, where most accesses are done to Natural source objects, the files
should be sorted according the values in the LJ descriptor (which is used to identify the sources).
? In a production environment, the system files should be sorted according to the LL descriptor (which
is used to identify Natural objects). This optimizes the load process of Natural objects especially
when these objects are quite large, as the corresponding records are allocated physically one after
another in the database.
? The FNAT file should always be allocated in the sort sequence of the LL descriptor.
? For user files, the sort sequence should be based on the sequence of the most frequently used
descriptor.
All Natural objects processed by the Natural Optimizer Compiler execute faster. However, because of the
increased size of the optimized objects, the load time is longer. One or more additional records have to be read
from the system file. So when the performance gain generated by the machine code instructions does not
compensate for the additional load overhead, the general throughput of the system becomes slower.
Furthermore, because of the additional size that the optimized objects require, less objects may fit into the
buffer pool. This means that more objects have to be exchanged resulting in additional accesses to the system
file and subsequently decreased performance.
In general it is recommended to analyze only the 20 to 50 most accessed Natural programs and optimize them.
The additional load time will be compensated by the many executions of these objects, and the buffer pool
space will not be stressed too much.
Typically batch applications run quite a long time, which means that they may block programs in the buffer
pool. The administrator may not be able to find out if given programs with a use count greater than zero are
stuck in the buffer pool or are legally running from a batch task. In these situations it can be better to use a
Page 9 of 12
Status of August 1st, 2000
local buffer pool in batch. On the other hand, when SYSMAIN of similar tools are used to transfer application
to production environments, the global buffer pool should be used.
Another reason to use a global buffer pool in Batch is when multiple batch jobs are started with all the same
application. Instead of reinitializing a local buffer pool with all job initializations one global buffer pool
(which might not be used for the online applications) could save a lot overhead. This applies as well when
other buffer pools like the editor buffer pool or the sort buffer pool is used.
Again, when multiple batch jobs are started all over the day the use of the common Natural nucleus is
recommended. Remember, with every start of a batch job the load of a large batch Natural nucleus cost quite a
lot of load time whereas the use of the common nucleus just requires the connections to an already loaded
nucleus.
As a new feature Natural 2.3 and later the feature of sub-tasking in batch is available (see the example call in
library SYSEXTP). Instead of always submitting a new batch job the spawning of another subtask is much
more efficient than the activation of a new job.
Currently (with Natural 2.3) it is advisable to use GETMAINED threads. There is some
flaw in the processing of the shared threads, which will cause some performance
delays.
SAGSIS, SAGNET
There is always a lot of information available via SAGSIS (Software AG intern) or SAGNET (public) about
performance enhancements. Typically these are zaps which should be implemented to increase the speed of
certain Natural statements or functions. In SAGSIS there are several entries available listing all known zaps
and hints about such performance changes. Use keyword TCD (Technical Case Description) and specify the
keyword Performance for TRS. (Product Nat23-)
In case that some functions are heavily used in the application it is always worth
considering if such functions can be rewritten in COBOL or assembler. When these
routines are statically linked to the Natural nucleus the performance will of course be
Page 10 of 12
Status of August 1st, 2000
better than the Natural components. But keep in mind the maintainability of the
application.
One point, which is neglected in many companies, is the education of the employees. It
is quite obvious that experienced programmers will write better and faster code. So by
investing in training and keeping the experienced people as long as possible the
resulting applications they write will be much faster and perform better then otherwise.
PE/Multiple Fields
Some programs analyzed show that the programmer has clearly forgotten that the values C* exist in Natural
as well. These can be used to find the current maximum number of occurrences read. When this is used it will
not be required to read through the complete set of elements and process empty entries.
Whenever strings are analyzed it should be considered to use the EXAMINE feature of NATURAL instead
the array logic.
Just use the following program to see what the EXAMINE statement can do for you:
RESET A (A5/10) Page 1
FOR I 1 10
A(I) = I A
LOOP -----
DISPLAY A(*)
EXAMINE A(*) FOR '5' GIVING INDEX I 1
WRITE I 2
END 3
4
5
6
7
8
9
10
5
Already at the very early stage of the definition of the field structure of the new data file it should be kept in
mind that there might be additions later on. Just provide a few spare fields to be used for that purpose later.
Highly frequented files should be allocated on different disk packs to ensure that the data retrieval will not
reposition the disk with every access. Actually these files should even be allocated in the center of the disk to
reduce the time for accessing the data even more.
Page 11 of 12
Status of August 1st, 2000
When in nightly batch runs a complete set of records (or close to be complete) from one file have to be
processed, it can make sense to download these records to a work file. First of all, the download process is
much faster than accessing the data by the normal statements, and second, these data can be resorted even to
values which are not allocated as descriptors.
When specific data, typically table oriented data, will have to be processed permanently by an application, it
might make sense to download these data at the very beginning of the session into a 3GL program. This
program then can be called and will return the requested values much faster than a corresponding database
access.
Page 12 of 12