Question:

 

Concerning your article "Procedures and Performance" (Article Id. 54505) in SystemiNetwork, maybe you could improve the performance by using the keyword "STATIC" at the local variable declaration?

 

Answer:

 

Good question. I had the question on my finger tip, but at the time I wrote this article my target was not to optimize the code, it was to show how painfully was the error I did. Done. And now, it's time to show how to use correctly STATIC.

 

I've try STATIC on my test case, it improves dramatically performance.

And there is nothing linked to recursivity, as I supposed when reading ILE RPG Reference, just reusability.

 

Excerpt from SC09-2508-05 :

 

For a local variable of a subprocedure, the STATIC keyword specifies that the data item is to be stored in static storage, and thereby hold its value across calls to the procedure in which it is defined. The keyword can only be used within a subprocedure. All global fields are static.

The data item is initialized when the program or service program it is contained in is first activated. It is not reinitialized again, even if reinitialization occurs for global definitions as part of normal cycle processing.

If STATIC is not specified, then any locally defined data item is stored in automatic storage. Data stored in automatic storage is initialized at the beginning of every call. When a procedure is called recursively, each invocation gets its own copy of the storage.

 

The most important part of this excerpt is It is not reinitialized again.

 

with STATIC, all procs have approx the same duration :

 

Inline CPU time in nanoseconds

Inline elapsed time in nanoseconds

Procedure name

without static

 

706,162

60,980,882

PR1

174,489,762

1,113,089,427

PR3

with static

 

832,095

85,185,077

PR1

686,321

69,075,643

PR3

 

with static, there's only one variable, no matter how many instances (level of recursivity) of the procedure there are. So if you call the procedure recursively and change the variable, it'll still be changed when you return to your caller. A static variable IS a global variable,  except that it's not available outside of the procedure it's declared in.

 

This is also why it improves performance. 

AS explained in the RPG Reference, The data item is initialized when the program or service program it is contained in is first activated.

That is to say, most of the work has be done at compilation time, to have the program loader to do as less as possible. Nothing has to be allocated or initialized when the procedure starts. The variable is already there.

 

However, in many cases (though, not always) people want their variables to be "fresh" (i.e. start with blanks or zeroes) at the start of their subprocedure.  If you use STATIC, it will maintain it's value from the last call, so you'd have to manually move *blanks or *zeros to it to clear it.  If you do that, do you still get better performance?  If so, by how much?

 

Another good question, but before starting to show if it's better to initialize yourself or let the system do the work, meditate a moment on "How many times do you need to get the value of a variable before having loaded it ?" because it's what the initialization step do.

 

To measure this way of initialization, I've updated my test case to add a CLEAR of each static variable at the beginning of each procedure :

 

Sample :

Basic case:

P pr3             b                               

D pr3             pi                              

D  data                      65535    const varying

D  wrk1           s          65535          varying

D  wrk2           s          65535                

                                                  

 /free                                            

        i=i;                                      

 /end-free                                        

P                 e                               

Static case:

P pr3             b                                      

D pr3             pi                                     

D  data                      65535    const varying      

D  wrk1           s          65535          varying static

D  wrk2           s          65535                  static

                                                         

 /free                                                   

        i=i;                                              

 /end-free                                               

P                 e                                      

Static and clear case

P pr3             b                                      

D pr3             pi                                      

D  data                      65535    const varying      

D  wrk1           s          65535          varying static

D  wrk2           s          65535                  static

                                                         

 /free                                                   

        clear wrk1;                                      

        clear wrk2;                                      

        i=i;                                             

 /end-free                                                

P                 e                                      

 

Here is the raw data pick from PEX querying

 

 

 

basic

static

static clear

PR1

0

647,374

857,800

797,558

PR2

0

726,615

724,994

719,779

PR4

20

711,349

637,665

965,562

PR14

120

961,893

579,518

909,964

PR13

250

1,012,788

599,375

1,979,497

PR12

500

1,991,179

557,065

1,723,770

PR11

1,000

2,414,745

556,393

2,647,059

PR10

2,000

3,681,011

503,616

3,830,128

PR9

4,000

6,238,758

622,569

6,153,956

PR8

8,000

11,777,871

537,384

11,746,635

PR7

16,000

32,614,964

580,419

42,885,212

PR6

32,000

65,810,440

547,675

86,496,278

PR5

64,000

165,727,434

1,213,270

137,154,020

PR3

128,000

210,528,671

960,006

139,650,891

PR15

128,000

79,396,397

887,121

1,049,137

PR16

128,000

303,216,710

559,160

276,187,999

 

PR15 and PR16 are a variant of PR3 : PR3 has a 64k fix and a 64k varying field

 

There is an erratic measure  for the PR13 (255 bytes), but globally, static plus clear is equal to basic. IE it's not a good idea to do ourselves the initialisation.

 

On the other hand, it's a good idea to declare STATIC for each variable that don't participate to a recursive call. Because I never need to get the value of a variable before having loaded it. And I think it's the same for you.

 

You can find in attached material