When writing OPS/REXX programs, there are usually multiple ways of achieving the same objective. However, some coding techniques may have unintended side effects that can seriously impact the overall performance of the code. This article describes how the misuse of Static Variables might create an undesired impact in CPU utilization
OPS/MVS-Event Management & Automation-for JES2
Description:
The following two AOF MSG rules perform similar functions:
Example rule 1 | )MSG ADASTATICS )INIT GLVTEMPM.L1.L2.A = 1 GLVTEMPM.L1.L2.B = 1 GLVTEMPM.L1.L2.C = 1 GLVTEMPM.L1.L2.D = 1 GLVTEMPM.L1.L2.E = 1 GLVTEMPM.L1.L2.F = 1 GLVTEMPM.L1.L2.G = 1 GLVTEMPM.L1.L2.H = 1 GLVTEMPM.L1.L2.I = 1 GLVTEMPM.L1.L2.J = 1 GLVTEMPM.L1.L2.K = 1 GLVTEMPM.L1.L2.L = 1 GLVTEMPM.L1.L2.M = 1 GLVTEMPM.L1.L2.N = 1 GLVTEMPM.L1.L2.O = 1 GLVTEMPM.L1.L2.P = 1 GLVTEMPM.L1.L2.Q = 1 GLVTEMPM.L1.L2.R = 1 GLVTEMPM.L1.L2.S = 1 GLVTEMPM.L1.L2.T = 1 GLVTEMPM.L1.L2.U = 1 GLVTEMPM.L1.L2.V = 1 GLVTEMPM.L1.L2.W = 1 GLVTEMPM.L1.L2.X = 1 GLVTEMPM.L1.L2.Y = 1 GLVTEMPM.L1.L2.Z = 1 )PROC if GLVTEMPM.L1.L2.A > 0 then GLVTEMPM.L1.L2.A = GLVTEMPM.L1.L2.A + 1 if GLVTEMPM.L1.L2.B > 0 then GLVTEMPM.L1.L2.B = GLVTEMPM.L1.L2.B + 1 if GLVTEMPM.L1.L2.C > 0 then |
Example rule 2 | )MSG ADASTATICS )INIT itemp = OPSVALUE('GLVTEMPM.L1.L2.A','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.B','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.C','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.D','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.E','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.F','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.G','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.H','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.I','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.J','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.K','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.L','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.M','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.N','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.O','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.P','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.Q','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.R','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.S','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.T','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.U','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.V','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.W','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.X','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.Y','U',1) itemp = OPSVALUE('GLVTEMPM.L1.L2.Z','U',1) )PROC if OPSVALUE('GLVTEMPM.L1.L2.A','V') > 1 then temp = OPSVALUE('GLVTEMPM.L1.L2.A','A',1) if OPSVALUE('GLVTEMPM.L1.L2.B','V') > 1 then temp = OPSVALUE('GLVTEMPM.L1.L2.B','A',1) if OPSVALUE('GLVTEMPM.L1.L2.C','V') > 1 then temp = OPSVALUE('GLVTEMPM.L1.L2.C','A',1) |
When looking at the PROC sections of each rule, which are both fairly small, it appears as if there are no significant differences between the two in terms of performance. However, example rule 1 consumes more than twice as many CPU resources as example rule 2 for each event processed in the PROC section. This occurs because the code in the INIT section is connected to the performance of the PROC section. The OPS/REXX statement GLVTEMPM.L1.L2.A = 1 in the INIT section has the unintended side effect of creating three uninitialized simple variables (L1, L2, and A), which, because they are used in the INIT section, are treated as Static Variables.
Now let us take a look at the code in the PROC section of the example rule 1:
if GLVTEMPM.L1.L2.A > 0 then
GLVTEMPM.L1.L2.A = GLVTEMPM.L1.L2.A + 1
The code references each of the Static Variables (as part of the standard OPS/REXX compound variable name resolution), as well as the temporary global variable three times. Since the overhead of evaluating Static Variables is fairly high, this coding style results in significantly higher CPU consumption than the optimal coding in example rule 2, which specifies the temporary global variable names as character strings.
Also, notice that in example rule 2 different temporary variables (itemp and temp) are used to avoid using the Static Variable (itemp) in the PROC section.
Finally, the OPSVALUE ADD function used in example rule 2 not only provides a serialized add function, but it also reduces the number of accesses to the temporary global variables by two thirds, which further reduces the overhead.
While the above examples may be contrived examples used to illustrate a point, we have seen the former technique used in a MSG * rule, and the result was an inefficient rule that consumed significantly more CPU resources than it should have.
Static and Global Variables are fully documented in the Using Automated Operations Facility AOF Rules section of the OPS/MVS User Guide.