Midrange News for the IBM i Community

Posted by: Bob Cozzi
Rogue Programmer
Cozzi Productions, Inc.
has no ratings.
Published: 01 Feb 2013
Revised: 01 Feb 2013 - 1517 days ago
Last viewed on: 29 Mar 2017 (3848 views) 

Using IBM i? Need to create Excel, CSV, HTML, JSON, PDF, SPOOL reports? Learn more about the fastest and least expensive tool for the job: SQL iQuery.

Things You Should Know About the RTNPARM Keyword Published by: Bob Cozzi on 01 Feb 2013 view comments

RPG IV at v7r1 RTNPARM Definition Spec Keyword Considerations

With v7r1, IBM improved the performance of RPG IV Subprocedures calls when the subprocedure includes a so called "return value". To leverage this performance improvement the RTNPARM keyword must be added to the prototype and procedure interface definition line. The prototype or procedure interface definition statement is normally where the "PR" and "PI" definition type is coded.

Basically numeric return values are fine and don't need to be considered as candidates for this keyword. However, large return values (greater than 16 bytes) can benefit from this keyword. Rather than use the extremely performance burdened STACK to return the value, the compiler simply converts the return value to a hidden first parameter, passed by reference. By doing this the overhead of the return value is completely eliminated.

For example, if you have a simple function named TOLOWER() that accepts a 64k input parameter and returns a 64k VARYING return value, the performance can be very poor. Obviously if you're calling TOLOWER() once, who cares? But let's look at the prototype and procedure for a TOLOWER function:

 RPG IV V6R1 and Earlier

     D toLower         PR         65535A   ExtProc('RPG_Convert_To_LowerCase')      
     D                                     Varying      
     D  szInput                   65535A   Const Varying

     P tolower         B                   EXPORT       
     D toLower         PI         65535A   Varying      
     D  szInput                   65535A   Const Varying
     D low             C                   'abcdefghijklmnopqrstuvwxyz'
     D up              C                   'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
          return %xlate(UP:low : szInput);              
     P tolower         E

 When the TOLOWER function is used, you convert an input value to upper case and return it to the caller. The way the return value is set up (above) the returned value is placed on the stack. This causes a slow down as the system reformats the data for storage on the stack, then when it copies the value from the stack, it takes more time to reassemble it back into proper form, and then finally, copies it to the target variable. Here's a simple example:

     D myName          S             50A   Inz('NEIL ARMSTRONG')
           myName = toLower( myName );

When you're calling the procedure multiple times, the constant pushing onto the stack and removing the value from the stack can be time consuming. Since the stack is 16 bytes wide (or less) the returned value is broken up into piece and placed into 16-byte chunks on the Stack. Then the value is popped off the stack (in 16-byte chunks) and re-assembled into a temp/work variable, then finally it is copied to the target value.

By adding the RTNPARM keyword you completely remove the interaction with the stack. The value is instead passed as a hidden 1st parameter by the compiler; shifting the remaining parameters down. Improved performance is accomplished by avoiding the stack and hiding the return value as the first parameter of the call. Here's what the modified code look like:

 RPG IV V7R1 and Later

     D toLower         PI         65535A   ExtProc('RPG_Convert_To_LowerCase')      
     D                                     Varying RTNPARM
     D  szInput                   65535A   Const Varying

     P tolower         B                   EXPORT       
     D toLower         PI         65535A   Varying RTNPARM      
     D  szInput                   65535A   Const Varying
     D low             C                   'abcdefghijklmnopqrstuvwxyz'
     D up              C                   'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
          return %xlate(UP : low : szInput);              
     P tolower         E

Now when the TOLOWER function is used, performance is substantially improved over the previous method.

Because RTNPARM causes the returned value to be passed as a hidden parameter, your function has to be aware of this. For example, if you have parameter numbers in your function body, for example used with %PARMS() or one of the CEE APIs such as CEEDOD or CEESTA, you will need to adjust that number when RTNPARM is used. While the parameter is hidden, IBM did not adjust other portions of the compiler to accommodate RTNPARM. Therefore YOU HAVE TO UP THE PARAMETER NUMBERS by 1 when RTNPARM is used. If you avoid doing this you'll certainly have a learning experience.

Here's a summary of the RTNPARM gotcha's

  • The return value is actually passed as the first parameter of the call. 
  • The %PARMS and %PARMNUM built-in functions include the additional parameter in the parameter count.
    • When the RTNPARM keyword is specified, the value returned by %PARMNUM is one higher than the parameter count.
  • When calling APIs that require a parameter number, such as CEEDOD or CEETSTA, you should use %PARMNUM. But if you already have hard-coded digits (parameter numbers) specified, change them to %PARMNUM or increase them by 1.
  • Only RPG IV to RPG IV procedures support this keyword. When calling procedures in other languages, do not use RTNPARM as not return value will be returned and the parameter list is altered.
    • When RTNPARM is used, no return value is actually passed therefore other programming languages such as C, C++ and CL will not play nice with RTNPARM.

Return to midrangenews.com home page.
Sort Ascend | Descend