Appendix G. VM/ESA REXX Performance Guidelines.

The text in this chapter is an extract of the Washington Systems Center Technical Bulletin VM/ESA Release 1.2.1 Performance Report (GC24-5673)

As you will see, it confirms what we have stressed throughout this course.  The document however misses some useful information, such as comparison with CMS Pipelines solutions.

REXX performance suggestions are consolidated and quantified in this section.  The majority of REXX applications may not need to be scrutinized with respect to performance, but selecting the best REXX environment and using a coding style that reduces the cost of REXX scanning and execution may optimize a performance-sensitive REXX application.  Execs, such as those on shared disks, which are commonly run by many users on a system, are good candidates for performance tuning.

Although not quantified here, a REXX application's performance may be improved by loading the REXX program into memory with EXECLOAD to save the cost of loading the exec in future executions or saving the exec in a shared segment to reduce overall system virtual storage requirements.  Also, if the REXX compiler is installed on the system, the REXX program may be compiled to reduce run time.  These suggestions and most of those that are provided later in this section apply to CMS Pipelines stages written in REXX as well.


REXX Environments

The system under which REXX programs run includes a default environment for processing commands.  Selecting the optimum REXX environment within your REXX program will reduce the amount of searching required for issuing commands.

When it begins scanning and executing a file, the REXX interpreter establishes, by default, the XEDIT environment for XEDIT macros and the CMS environment for CMS execs.  For example, if you issued the CP command SP READER NOHOLD from an XEDIT macro, the default search path would be as follows:

  1. The REXX interpreter determines if it is a REXX instruction.  If not, it passes it to XEDIT.
  2. XEDIT determines if it is an XEDIT instruction.  If not, it passes it to CMS.
  3. CMS determines if it is a CMS instruction.  If not it passes it to CP.
  4. CP runs the instruction.

Within your program, selecting the optimum REXX environment can reduce the amount of searching.  (Issuing the command SAY ADDRESS() will tell you which environment is active).  The following are three environments that REXX understands along with the order in which the command search is performed when all defaults apply:

The REXX environment can be changed temporarily or permanently to reduce the amount of searching.  For example, you can temporarily change to the command environment for the ACCESS command by issuing

  address 'COMMAND' 'ACCESS ...'

then for subsequent commands use the current default environment.  The REXX environment can be changed permanently by setting a new default, so subsequent commands are sent to the new environment as follows:

  address 'COMMAND' /* sets new default environment */
  ...
  'ACCESS ...' /* uses new default environment */

We will describe the performance characteristics both for changing the environment for one command and for setting a new default later in this document.

Upon entry to a function or subroutine, the environment of the caller is used and upon return, the environment of the caller is restored.

XEDIT search order

XEDIT goes through the following steps to determine if an instruction is an XEDIT instruction(footnote).

  1. If invoked as
      COMMAND subcommand
    

    then only try steps 4, 5, 6.1, and 7.  (This is the editor command COMMAND, not the REXX environment COMMAND).

  2. If invoked as
      MACRO macro
    

    then only try step 6.2.

  3. Look for a synonym and substitute (unless SET SYNONYM OFF).
  4. If command is "=" then rerun last command.
  5. Look for an implicit locate (for example ":2" is an implicit form of LOCATE :2).
  6. The default for SET MACRO ON or OFF is OFF.  (If SET MACRO ON has been specified, check step 6.2 before 6.1):
    1. Look for an XEDIT subcommand.  If none, check for implicit editor SET subcommand.  (For example VERIFY ON 1 80 is really SET VERIFY ON 1 80).
    2. Look for an XEDIT macro.
  7. If XEDIT SET IMPCMSCP ON, then pass to CMS.

Note: Setting the default to MACRO ON is not functionally equivalent to prefixing with MACRO.  This is because fewer areas are searched when looking for the command when it is prefixed with MACRO.


REXX Scanning and Executing.

Scanning involves combining the separate characters of the file into higher constructs.  For example, the DO construct would be formed from the letter D followed by the letter O during scanning.  The scanning virtual path length applies just once per invocation of the REXX program.  The execution virtual path length applies each time an instruction is executed.  Total virtual path length represents the sum of scanning and execution path length.

REXX scans and executes a program as follows:


Summary of REXX Performance Tips

The measurements and conclusions summarized in the following tables were based on

VM/ESA Version 1, Release 2.0
Changes in VM/ESA internals could change the results.  However, the recommendations should be fairly stable.
virtual machine configuration
For example, the cost of searching all accessed minidisks or directories for an exec varies with the number of accessed mini-disks and (to some extent) the number of files on each minidisk.
small test programs
For example, saving a variable lookup could be more of a benefit to programs that contain more variables.
CMS path lengths
The tips assume that CP path lengths would not change the recommendations.
Execution from FILELIST
The data supplied were gathered by running the test cases from FILELIST.  The path lengths will be different if run by other means, but the relative positioning of the various cases will be the same.

System defaults were used for the measurements unless otherwise specified.  For example, when measuring the path length of an XEDIT macro, the XEDIT environment was used.  (This is the default REXX environment for XEDIT macros).

Alternative REXX coding techniques are compared in this section.  The method having the smallest total path length is considered the best and is flagged with a þ.  Sometimes a second method is worth consideration.  If so, it will also be flagged with the þ.  The second method may, for example, have a shorter execution path length, which would be a benefit when the code is in a loop.

Alternate methods are presented for three reasons:

Data were collected using the CP TRACE facility.  The collection method is described in detail at the end of this document.  This method can be used to measure alternatives in your environment.

In the following tables, column headings are as follows:
Total Total virtual path length (scanning plus execution path lengths combined).
Exec Execution virtual path length.
Scan Scanning virtual path length.
Example REXX code examples for which data is supplied.

A þ highlights the best performing solution.

Invoking commands from an exec

The following shows various ways of invoking CP commands, CMS commands, and execs from a procedure (with the default REXX environment of CMS).

To invoke a CP Command

The best method has the form:

   address 'COMMAND' 'CP cpcmd':

and saved 8522 total path length when compared to the slowest.

Total Exec Scan
Example
13556 13095 461
SPOOL READER NOHOLD
12753 12500 253
'SPOOL READER NOHOLD'
8689 8410 279
'CP SPOOL READER NOHOLD'
9005 8442 563
address 'CMS' 'CP SPOOL READER NOHOLD'
13457 12532 925
address 'CMS' 'SPOOL READER NOHOLD'
5034 4451 583 þ address 'COMMAND' 'CP SPOOL READER NOHOLD'
5406 4789 617
call 'DIAG' '08','SPOOL READER NOHOLD'
5813 5140 673
address 'COMMAND' 'EXECIO 0 CP (STRING SPOOL READER NOHOLD'

Our additional comments:

To invoke a CMS command

The fastest method is:

   address 'COMMAND' 'cmscmd'

and saved 4104 total path length when compared to the slowest.

Total Exec Scan
Example
8365 8114 251
MAKEBUF
8156 8028 128
'MAKEBUF'
8472 8060 412
address 'CMS' 'MAKEBUF'
4368 3936 432 þ address 'COMMAND' 'MAKEBUF'

To invoke an Exec

The fastest method is:

   address 'COMMAND' 'EXEC exec'

and saved 21475 total path length when compared to the slowest.  NULLEXEC EXEC only contained the following two lines:

  /* */
  exit

Total Exec Scan
Example
29344 28704 640
address 'CMS' 'EXEC NULLEXEC'
46969 46463 506
CALL 'NULLEXEC'
29094 28666 428
'EXEC NULLEXEC'
26492 26041 451
NULLEXEC
26284 25951 333
'NULLEXEC'
26503 25978 525
address 'CMS' 'NULLEXEC'
25494 24945 549 þ address 'COMMAND' 'EXEC NULLEXEC'

Our additional comments:

It is clear now that address 'COMMAND' is the best.  All commands in the next examples were coded using address 'COMMAND' but we replaced these by address '', as it saves some space in the tables.

Additional CMS short cuts

Abbreviate CMS Command Parameters (but not CMS commands)

Abbreviating the parameter (but not the command) saved 4229 total path length.

Total Exec Scan
Example
8775 8308 467
address '' 'QUERY LANGUAGE'
12860 12418 442
address '' 'Q LANGUAGE'
12716 12294 422
address '' 'Q LANG'
8631 8184 447 þ address '' 'QUERY LANG'

Use variable record format files (RECFM=V)

Scan path length for this one statement was reduced by 312 instructions by using RECFM=V.  In this section a ø represents the space character in the example column.
Total Exec Scan
Example
904 391 513
x=1 øøøø ... øøøø (total of 80 characters)
This file was RECFM=F LRECL=80
592 391 201 þ x=1
this file was RECFM=V

Use the STEM option of EXECIO

To read in an entire file, a single EXECIO DISKR with STEM option is better than multiple EXECIOs.  The stem option requires more storage than holding one line at a time in memory (the VAR option).  The STEM option is also available for writing (EXECIO DISKW).

Total Exec Scan
Example
64766 62809 1957
do i = 1 to 5
   address '' 'EXECIO 1 DISKR LINES ASSEMBLE B (VAR X'
end
address '' 'FINIS LINES05 ASSEMBLE B'
30046 28805 1241
address '' 'EXECIO * DISKR LINES ASSEMBLE B (STEM Y.'
address '' 'FINIS LINES05 ASSEMBLE B'
27342 26626 716 þ address '' 'EXECIO * DISKR LINES ASSEMBLE B (FINIS STEM Y.'

Using this tip saved 37424 total path length:

With EXECIO loop, use single FINIS

When multiple EXECIOs are done to same file, it is faster to keep the file open and do a single FINIS at end.  Using the single FINIS saved 68421 total path length.  For both examples, the two lines beginning with address were actually one long line in the test files.

Total Exec Scan
Example
124439 122796 1643
do i = 1 to 5
   address '' 'EXECIO 1 DISKW LINES ASSEMBLE B (FINIS STRING TEXT'
end
56018 53973 2045 þ do i = 1 to 5
   address '' 'EXECIO 1 DISKW LINES ASSEMBLE B (STRING TEXT'
end
address '' 'FINIS LINES ASSEMBLE B'

Use MAKEBUF, DROPBUF only when needed

You can see that they each cost about 4500 total path length.  If you issue a MAKEBUF, put entries on the stack, always remove all those entries from the stack, and issue a DROPBUF, then you can remove the MAKEBUF/DROPBUF as it serves no useful purpose.

Total Exec Scan
Example
4496 4065 431
address '' 'MAKEBUF'
4486 4055 431
address '' 'DROPBUF'

VALUE is faster than GLOBALV for one variable

Using the REXX VALUE() function saved 3613 total path length (7160-3547) when putting a global variable, and saved 4547 total path length (7142-2595) when getting a global variable.  However, GLOBALV has the advantage when more than one variable is to be saved/retrieved because GLOBALV supports a list of variables.

Total Exec Scan
Example
7160 6593 567
address '' 'GLOBALV SELECT TESTGRP PUT GLOBVAR'
7142 6575 567
address '' 'GLOBALV SELECT TESTGRP GET GLOBVAR'
3547 2692 855 þ prevvar = 'VALUE'('VALUVAR',valuvar,'GLOBAL TESTGRP') /* PUT */
2595 1932 663 þ newvar = 'VALUE'('VALUVAR',,'GLOBAL TESTGRP') /* GET */

Minimize wildcards

By specifying the file mode, 19560 total path length was saved because CMS did not have to search all file modes.

Total Exec Scan
Example
28151 27634 517
address '' 'LISTFILE WILDCARD EXEC *'
8591 8069 522 þ address '' 'LISTFILE WILDCARD EXEC B1'

Invoking commands from XEDIT macros

The following shows various ways of invoking CP and CMS commands, execs, XEDIT macros, and editor subcommands from XEDIT macros (with the default REXX environment of XEDIT).

To invoke CP command

The fastest method is:

   'CP cpcmd'

and saved 15337 total path length when compared to the slowest.

Total Exec Scan
Example
17691 17255 436
SPOOL READER NOHOLD
16870 16642 228
'SPOOL READER NOHOLD'
2354 2075 279 þ 'CP SPOOL READER NOHOLD'
7296 6733 563
address 'CMS' 'CP SPOOL READER NOHOLD'
11708 10805 903
address 'CMS' 'SPOOL READER NOHOLD'
3497 2914 583
address '' 'CP SPOOL READER NOHOLD'
4008 3391 617
call 'DIAG' '08','SPOOL READER NOHOLD'
4320 3647 673
address '' 'EXECIO 0 CP (STRING SPOOL READER NOHOLD'

To invoke CMS command

The fastest method format is:

   address '' 'cmscmd'

and saved 10977 total path length when compared to the slowest.

Total Exec Scan
Example
13914 13683 231
MAKEBUF
13699 13591 108
'MAKEBUF'
8950 8812 138
'CMS MAKEBUF'
7040 6638 402
address 'CMS' 'MAKEBUF'
2937 2505 432 þ address '' 'MAKEBUF'
8984 8806 178
'COMMAND CMS MAKEBUF'

To invoke an exec

The fastest method has the form:

   address '' 'EXEC exec'

and saved 21306 total path length when compared to the slowest.  NULLEXEC EXEC only contained the following two lines:

  /* */
  exit

Total Exec Scan
Example
30812 30419 393
NULLEXEC
30604 30329 275
'NULLEXEC'
26161 25860 301
'CMS NULLEXEC'
23833 22964 869
address 'CMS' 'NULLEXEC'
22460 21922 538 þ address '' 'EXEC NULLEXEC'
26292 25708 584
address 'CMS' 'EXEC NULLEXEC'
43766 43318 448
call 'NULLEXEC'
33265 32893 372
'EXEC NULLEXEC'

To invoke a macro

The best format is:

   'MACRO macro'

With the default setting of SET MACRO OFF, using the MACRO prefix saved 835 total path length.  Similar tests also showed that the MACRO prefix helped, but not by as much, when SET MACRO ON was active.

A functional difference between using the MACRO prefix and not using the prefix is that using the prefix avoids separating of nonalphabetic characters.  For example :

  N2

sends parameter 2 to routine N ; however,

  MACRO N2

invokes routine N2.

Total Exec Scan
Example
8218 8084 134
'NULLMACR'
7383 7219 164 þ 'MACRO NULLMACR'

To invoke an editor subcommand

Both techniques below are very similar (total path length).  If 'COMMAND EXTRACT /FNAME/' were in a loop it would have the advantage because its execution path length was slightly less.  Also, if SET MACRO ON had been in effect, 'COMMAND EXTRACT /FNAME/' would have had a definite advantage because it would save searching for an XEDIT macro named EXTRACT.  We will see that there is an extra advantage in abbreviating XEDIT subcommands.

Total Exec Scan
Example
3429 3258 171
'EXTRACT /FNAME/'
3438 3227 211 þ 'COMMAND EXTRACT /FNAME/'

Additional editor short cuts

Use EXTRACT instead of CMS stack

This example gets the logical record length of the file being edited.  Use of EXTRACT saved 10684 total path length.

Total Exec Scan
Example
11029 9713 1316
address '' 'LISTFILE USEEXTR XEDIT B (FIFO DATE NOH'
parse pull p1 p2 p3 p4 lrecln .
3457 3254 203 þ 'COMMAND EXTRACT /LRECL'

SET SYNONYM OFF

Each avoidance of synonym checking saved 172 total path length (3256-3084).  So, after 15 avoidances (2612/172), the new default began to help.

Total Exec Scan
Example
3256 3066 190
'SET PF1 111'
2612 3084 2404
'COMMAND SET SYNONYM OFF'
2856 208 228 þ 'SET PF1 111'

Combine commands, macros sent to the editor

The last 4 commands in the second method averaged a savings of 760 total path length (15596-12558)/4.

Total Exec Scan
Example
15596 14359 1237
'COMMAND SET PF1 111'
'COMMAND SET PF1 111'
'COMMAND SET PF1 111'
'COMMAND SET PF1 111'
'COMMAND SET PF1 111'
12558 11165 1393 þ 'COMMAND SET PF1 111#',
'COMMAND SET PF1 111#',
'COMMAND SET PF1 111#',
'COMMAND SET PF1 111#',
'COMMAND SET PF1 111'

Use implicit SET for SET editor command

Each avoidance saved 32 total path length.

Total Exec Scan
Example
3260 3101 159
'COMMAND SET PF1 111'
3228 3051 177 þ 'COMMAND PF1 111'

Abbreviate XEDIT subcommands and parameters

Saved about 17 total path length per character removed: (3503-3384)/7

Total Exec Scan
Example
3503 3305 198
'COMMAND EXTRACT /FNAME/'
3452 3269 183
'COMMAND EXTRACT /FN/'
3384 3221 163 þ 'COMMAND EXT /FN/'

Accept XEDIT command defaults

Removing the 1 saved 65 total path length.

Total Exec Scan
Example
1817 1678 139
'COMMAND N 1'
1752 1623 129 þ 'COMMAND N'

Minimize space

In these sections a ø represents the space character in the example column.

Remove blank lines

Removing blank lines saved execution path length=37 and scan path length=59.

Total Exec Scan
Example
96 37 59
blank line
0 0 0 þ no line

Minimize spaces before code on line

Moving code to the left saved 3 scan path length per character: (216-201)/5.

Total Exec Scan
Example
663 447 216
øøøøø x=1
648 447 201 þ x=1

Do not space before the continuation character

Saved 3 scan path length per character (282-267)/5.

Total Exec Scan
Example
729 447 282
x= øøøøø,
1
714 447 267 þ x=,
1

Working with comments

In this discussion "line comments" refers to lines that have just a comment (no executable code):

  /* this is a line comment */

"Code comments" refers to comments that are along side the code:

  x = 1 /* this is a code comment */

"Comments" refers to line comments and code comments.

Minimize characters in comments

Each character removed from a comment saves 5 scan path length (118-103)/3.

Total Exec Scan
Example
250 147 103 þ /**/
255 147 108
/*.*/
260 147 113
/*..*/
265 147 118
/*...*/

Execution path length = 0 for code comments

Code comments do not cause any additional execution path length (they do, however, cause additional scan path length).

Total Exec Scan
Example
722 447 275
x=1 /*.....*/
648 447 201 þ x=1

Minimize the number of consecutive line comments

Each additional line comment cost 160 total path length ((590-270)/2) and 37 execution path length ((221-147)/2).

Total Exec Scan
Example
270 147 123 þ /*....*/
430 184 246
/*....*/
/*....*/
590 221 369
/*....*/
/*....*/
/*....*/

Use multiline comments

Switching from three consecutive line comments to a single multiline comment (with three lines) saved 196 total path length (590-394).

Also, notice that execution path length for the multiline comment (147) is the same as for a single line comment.

Total Exec Scan
Example
270 147 123
/*....*/
590 221 369
/*....*/
/*....*/
/*....*/
394 147 247 þ /*....
  ....
  ....*/

Locate line comments before labels

It costs 37 execution path length to execute a line comment.

Keep line comments out of hot paths

It costs 37 execution path length to execute a line comment.

Working with IF and SELECT statements

ELSE path is faster for IF-THEN-ELSE

Total Exec Scan
Example
2804 1386 1418
(with g=0, THEN path taken)
2766 1348 1418 þ (with g=1, ELSE path taken)
    if go=0 then do
                 end
            else do
                 end

Order of OR expressions for THEN path is irrelevant

It is not faster to put the most frequent true condition first because all three conditions are evaluated anyway.
However, this may influence the way you code.

Total Exec Scan
Example
4529 2709 1820
(when a=1 b=0 c=0)
4529 2709 1820
(when a=0 b=1 c=0)
4532 2712 1820
(when a=0 b=0 c=1)
    if a=1 | b=1 | c=1
           then do
                end
           else do
                end

Use SELECT for OR-THEN path

From previous section, we know that it does not help to put the most frequent true condition first (when ORing the conditions).  If one of the conditions (say a=1) is much more likely and the code is in a loop, then switching to a SELECT statement costs 157 total path length (4399-4556) for the first use, but saves 872 execution path length (2579-1707) for each subsequent use.

Total Exec Scan
Example
4399 2579 1820
(when a=1, b=0, c=0)
    if a=1 | b=1 | c=1
           then do
                end
           else do
                end
4450 1759 2691
(when a=1, b=0, c=0)
    if a=1
       then do
            end
       else if b=1 | c=1
            then do
                 end
            else do
                 end
4556 1707 2849 þ (when a=1, b=0, c=0)
    select
       when a=1 then
            do
            end
       when b=1 | c=1 then
            do
            end
       otherwise
    end

Order of AND expressions for ELSE path is irrelevant

It is not faster to put the most frequent false condition first because all three conditions are evaluated anyway.  However, this may influence the way you code.

Total Exec Scan
Example
4486 2666 1820
(when a=0, b=1, c=1)
    if a=1 & b=1 & c=1
       then do
            end
       else do
            end
4486 2666 1820
(when a=1, b=0, c=1)
    if a=1 & b=1 & c=1
       then do
            end
       else do
            end
4483 2663 1820
(when a=1, b=1, c=0)
    if a=1 & b=1 & c=1
       then do
            end
       else do
            end

Use SELECT for AND-ELSE path

From previous section, we know that it does not help to put the most frequent false condition first (when ANDing the conditions).  If one of the conditions (say a=0) is much more likely and the code is in a loop, then switching to a SELECT statement costs 47 total path length (4458-4505) for the first use, but saves 982 execution path length (2638-1656) for each subsequent use.

Total Exec Scan
Example
4458 2638 1820
   if a=1 & b=1 & c=1
         then do
              end
         else do
              end
4399 1708 2691
    if a=0
         then do
              end
         else if b=1 & c=1
         then do
              end
         else do
              end
4505 1656 2849 þ
    select
         when a=0 then do
                       end
         when b=1 & c=1 then do
                             end
         otherwise
    end

Use nested IFs In place of SELECT

By using the nested IF, it saved 350 total path length (5296-4946) when the a=1 path was taken.  Savings was similar when the b=1 path was taken and when the c=1 path was taken.

Total Exec Scan
Example
4946 1914 3032 þ (when a=1 path taken)
5473 2441 3032
(when b=1 path taken)
6011 2979 3032
(when c=1 path taken)
    if a=1
       then do
            end
       else if b=1
          then do
               end
          else if c=1
             then do
                  end
5296 1944 3352
(when a=1 path taken)
5834 2482 3352
(when b=1 path taken)
6383 3031 3352
(when c=1 path taken)
    select
       when a=1 then
          do
          end
       when b=1 then
          do
          end
       when c=1 then
          do
          end
    end

Use IF flag THEN ... ELSE

If you have a flag that is set to 1 for TRUE and 0 for FALSE, then using the second method saved 505 total path length.  See next section, Use 'DO flag' in place of 'IF flag THEN'" when the IF statement only has a THEN path.

Total Exec Scan
Example
2737 1321 1416
    if a=1 /* given a=1 */
         then do
              end
         else do
              end
2232 906 1326 þ
    if a /* given a=1 */
         then do
              end
         else do
              end

Use 'DO flag' in place of 'IF flag THEN'

If you have a flag that is set to 1 for TRUE and 0 for FALSE, then the using the second method saved 388 total path length.  See previous section, Use IF flag THEN ... ELSE when the IF statement has both THEN path and an ELSE path.

Total Exec Scan
Example
1615 644 971
if a /* given a=1 */
         then do
              end
1227 697 530 þ
do a /* given a=1 */
end

SELECT: Put most likely WHENs higher

Each lower path costs 660 total path length (6634-5301)/2.

Total Exec Scan
Example
5302 1999 3303 þ (when a=1 path is taken)
5968 2665 3303
(when a=2 path is taken)
6634 3331 3303
(when a=3 path is taken)
    select
      when a=1 then
         do
         end
      when a=2 then
         do
         end
      when a=3 then
         do
         end
    end

Working with variables

To Initialize All Compound Variables, aaaa. = 5:  Initializing just the stem saved 14342 total path length.

Total Exec Scan
Example
15236 14175 1061
do i = 1 to 10
    aaaa.i = 5
end
894 570 324 þ aaaa. = 5

Use PARSE to initialize variables

Using PARSE to initialize the variables saved 871 total path length.

Total Exec Scan
Example
2978 1835 1143
aaa = 1
bbb = 2
ccc = 3
ddd = 4
eee = 5
2107 1265 842 þ
parse value '1 2 3 4 5' with aaa bbb ccc ddd eee

Use short variable names

Using the short variable name saved 48 total path length.

Total Exec Scan
Example
657 417 240
aaaaaa=1
609 409 200 þ a=1

Start parts of compound name tail with a digit

In vara.aaaa.bbbb, vara. is the stem, and aaaa and bbbb might be variables, so REXX must do a variable look-up for aaaa and bbbb.

If aaaa and bbbb are not really variables, it was faster to use vara.1aaa.1bbb because the digit 1 caused REXX to suppress the variable lookup.  The example saved 19 total path length.

Total Exec Scan
Example
871 549 322
vara.aaaa.bbbb = 'data'
852 530 322 þ vara.1aaa.1bbb = 'data'

Use PARSE VAR to process words in a variable

Using PARSE VAR saved 3708 total path length.

Total Exec Scan
Example
14700 13235 1465
    a = 'WORD1 WORD2 WORD3 WORD4 WORD5'
    do i = 1 to 'WORDS'(a)
       x = 'WORD'(a,i)
    end
10992 9560 1432 þ
    a = 'WORD1 WORD2 WORD3 WORD4 WORD5'
    do i = 1 to 'WORDS'(a)
       parse var a x a
    end

Other tips

Set default REXX environment: address ''

It may pay to set a new default REXX environment (as in the second example) rather than to keep overriding an existing REXX environment (as in the first example).

Setting a new default environment cost 482 total path length, and each time the new default was used saved 336 (4383-4047).  The savings started with the second use.

Total Exec Scan
Example
4383 4071 312
address '' 'MAKEBUF'
482 217 265
address ''
4047 4039 8 þ 'MAKEBUF'

Built-in functions are generally more efficient.

Using the built in function saved 7631 total path length.

Total Exec Scan
Example
9448 8299 1149
    n=10
    text = ''
    do n
       text = text'*'
    end
1817 1232 585 þ
    n=10
    text = 'COPIES'('*',n)

Remove loops when possible

Removing the loop saved 8797 total path length.

Total Exec Scan
Example
12413 10961 1452
    sumi = 0
    do i = 1 to 5
       sumi = sumi + a.i
    end
3616 2821 795 þ sumi = a.1 + a.2 + a.3 + a.4 + a.5

Combine statements where logic permits

This example sets b to a 4 digit number with leading zeros (with a=23, b will be set to 0023).  Combining statements saved 665 total path length. See next section for an even better way of performing the function.

Total Exec Scan
Example
3532 2484 1048
b='RIGHT'(a,4)
b='TRANSLATE'(b,'0',' ')
2867 2019 848 þ b='TRANSLATE'('RIGHT'(a,4),'0',' ')

Understand available REXX capabilities

This is a refinement of "Combine Statements Where Logic Permits." The second example below takes advantage of a third parameter of the RIGHT() function (the TRANSLATE() was no longer needed).  The savings was 868 total path length.

Total Exec Scan
Example
2867 2019 848
b='TRANSLATE'('RIGHT'(a,4),'0',' ')
1999 1427 572 þ b='RIGHT'(a,4,'0')

...=... versus ...==...

The two comparison operators function as follows:

The net of the above is that they are different.  In the example below the exact value of the operand was known so the strictly equal operand, '==', saved 4 total path length.

Total Exec Scan
Example
1667 835 832
if answer = 'YES' then nop /* with answer='YES' */
1663 794 869 þ if answer == 'YES' then nop /* with answer='YES' */

Use the concatenation operator only when necessary

When concatenation without an intervening blank is desired, removing the concatenation operator saved 93 total path length.

Total Exec Scan
Example
1040 644 396
a = 'pre'||line
947 625 322 þ a = 'pre'line

When concatenation with intervening blank is desired, removing the concatenation operator saved 410 total path length.

Total Exec Scan
Example
1326 808 518
a = 'pre'||' '||line
916 601 315 þ a = 'pre' line

Minimize scanning of unexecuted code

Scanning of unexecuted code can cause significant unnecessary overhead. If your REXX program has code that is infrequently executed (but scanned), the infrequently executed code could be made into a routine and either externalized or moved to the bottom (this could require the practice of quoted function/subroutine calls).

When the less likely event does occur (the code is executed) the path length would be longer, but with infrequent use this could be an excellent trade-off.

To get a feel for the cost of the scanning, look at the scan path length column in the measurement tables.  You will notice that it is a fairly small percentage of the cost of commands that REXX passes to other environments (CMS for example).

However, for REXX instructions, scan path length can be a significant percentage.  The largest percentage improvement would be for programs that are heavy with REXX instructions and do not have many loops.

Quoted function, subroutine trade-off

Use of the quoted function/subroutine suppresses a cache of the location of the function.  Not using the quotes cost 49 execution path length (630-581) for the first invocation, but saved 34 execution path length (581-547) on subsequent invocations.  Results will vary greatly with the functions used and sequence of execution.  This comparison relates to execution path length so scan path length and total path length are not presented.

Total Exec Scan
Example

581

x='QUEUED'()
looks external to the program

630

x=queued()
- sets lookaside
- causes scan to end of program
  (if not already scanned)

547
þ x=queued()
uses lookaside

Enclose nonvariable data in quotes

Adding the quotes saved 138 total path length (4879-4741).  The quotes tell REXX that it is looking at a literal string, so there is no need for REXX to search to see if a variable (MAKEBUF for example) exists.  The more variables used in the REXX program, the more significant the savings would be.  The test exec had just 2 variables.

Here is another example:

  address COMMAND LISTFILE fn ft fm /* O.K. */
  address '' 'LISTFILE' fn ft fm /* better */

You may not enclose REXX keywords in quotes.  REXX keywords are in upper case in the REXX syntax diagrams:

  'do' i = 1 'to' 3 /* does not work */
  do i = 1 to 3 /* works */

Total Exec Scan
Example
4879 4427 452
address COMMAND MAKEBUF
4749 4316 433
address COMMAND 'MAKEBUF'
4741 4318 423 þ address 'COMMAND' 'MAKEBUF'

Reduce arithmetic precision (set by NUMERIC DIGITS)

It took 1018 total path length to set NUMERIC DIGITS.  For arithmetic in which numbers and results are low precision, dropping the precision to 5 made no difference.  However, for calculations resulting in more significant digits (for example, calculating 1/3), decreasing the precision from 9 (the default) to 5 decreased total path length by 480 (2514-2034) for just this one calculation.

Total Exec Scan
Example
1018 592 426 þ NUMERIC DIGITS n
1250 959 291
x=1+1 /* given precision=5 */
1250 959 291
x=1+1 /* given precision=7 */
1250 959 291
x=1+1 /* given precision=9 */
2034 1739 295 þ x=1/3 /* given precision=5 */
2274 1979 295
x=1/3 /* given precision=7 */
2514 2219 295
x=1/3 /* given precision=9 */

Remove the semicolon at the end of the line

Removing the semicolon at end of the line saved 23 scan path length.

Total Exec Scan
Example
671 447 224
x=1;
648 447 201 þ x=1

Exit a loop via LEAVE instead of SIGNAL

Using LEAVE saved 1201 total path length.

Total Exec Scan
Example
11542 8651 2891
    do i = 1 to 5
       if i=3 then signal done
    end
    done: say i
10341 8414 1927 þ
    do i = 1 to 5
       if i=3 then leave
    end
    say i

Use ITERATE to alter the flow in a loop

Using ITERATE saved 1500 total path length.

Total Exec Scan
Example
13392 11107 2285
    do i = 1 to 5
       if i^=3 then do
            ...
         end
    end
11892 10121 1771 þ
    do i = 1 to 5
       if i=3 then iterate
       ...
    end

Invoke code: inline, routine, procedure, external EXEC

Total Exec Scan
Example
1122 819 303 þ y=y+1 /* inline code */
5267 2665 2602
y=bump(y) /* internal routine */
the routine was: bump:return y+1
6171 3068 3103
y=bump(y) /* internal procedure */
- the procedure was:
  bump:procedure expose y
     return y+1
- One of the reasons that the internal procedure
  had a longer path length than the internal routine
  was that a new variable tree was set up for the
  internal procedure. This could provide the
  internal procedure with an advantage if the
  calling routine had lot of variables (because REXX
  would not have to search through all the calling
  routine variables when doing a variable lookup).
73050 70431 2619
y=bump(y) /* external exec */
Where the external exec was:
  /* */
  exit arg(1)+1

Use EXPOSE to pass parameter

When you are using a PROCEDURE, using EXPOSE to pass a parameter saved 823 total path length.

Total Exec Scan
Example
5810 2393 3417
  stext = 'StringOfText'
  call sub stext
the procedure was:
  sub: procedure
       parse arg stext
       return
4987 1866 3121 þ   stext = 'StringOfText'
  call sub
the procedure was:
  sub: procedure expose stext
       return

Abbreviate CP commands and parameters

Overall savings is 240 total path length (5028-4788).

Total Exec Scan
Example
5028 4531 497
address '' 'CP SPOOL READER HOLD'
4956 4474 482
address '' 'CP SP READER HOLD'
4836 4379 457
address '' 'CP SP R HOLD'
4788 4341 447 þ address '' 'CP SP R HO'

Try alternate approaches


Obtaining the path lengths

Using CP TRACE to get CMS path length.

CMS path lengths can be obtained by placing the following instructions with the code being measured:

  address '' 'CP TRACE I NOTERM' /* start counting */
  address '' 'CP TRACE COUNT' /* reset count */
  (test A)
  address '' 'CP TRACE COUNT' /* display then reset */
  (test B)
  address '' 'CP TRACE COUNT' /* display then reset */
  (test C)
  address '' 'CP TRACE COUNT' /* display then reset */
  address '' 'CP TRACE END ALL' /* display and end */

This tracing causes your virtual machine to run much slower because of the processing required to count the CMS instructions.

When the above example is run, the first two CP TRACE instructions do not generate any output.  The first three measurements displayed "Trace count is nnnn" are for the three test cases respectively.  The last displayed measurement can be ignored.

The output is something like:

  (test case A running here)
  Trace count is 7697
  (test case B running here)
  Trace count is 7463
  (test case C running here)
  Trace count is 7413
  Trace count is 4860
  Trace ended

The measurements above include path length associated with scanning and executing the instruction:

  address '' 'CP TRACE COUNT' /* display then reset */

Successive instructions of this type were tested from both EXECs and XEDIT macros to obtain the following trace overhead chart:

Total Exec Scan
Example
4892 4289 603
(from an EXEC)
3331 2728 603
(from an XEDIT macro)

The path lengths are then obtained by subtracting the appropriate trace overhead from the measured results.

It is possible for the REXX application to fail during tracing.  If instructions are being counted and the REXX program terminates without getting to

   address '' 'CP TRACE END ALL' /* display and end */

your virtual machine will seem to be running very slowly because instructions are still being counted.  To get your virtual machine back to normal, try

  1. Pressing your virtual machine's break key (PA1 by default)
  2. Enter
      TRACE END ALL
    
  3. Enter
      BEGIN
    

Scanning versus Execution path length

To obtain the breakout in virtual path length between scanning and execution, the following line of code was placed at the beginning of the file (after the initial REXX comment, /* */):

  arg inparm; if inparm = 'EX' then x=queued()

Footnotes:

  In this discussion, XEDIT macro is an editor command that is implemented in an exec file with a file type of XEDIT.  XEDIT subcommands are the other commands that XEDIT understands, but are not in a file with file type XEDIT.
Back to text