APIs by Example: Workload Capping Groups – Save License Fees (?) and Manage Workload Capacity

I had come across the term Workload Capping Groups (WLC) a couple of times before I actually found out what it was about – and exactly how workload capping groups could be taken advantage of. I had noticed a new Workload Capping Group (WLCGRP) attribute on the Change Job (CHGJOB command) at one point. The attribute text was written in all capital letters, revealing that the attribute had been PTF added mid-release.

This discovery didn’t prompt any further research on my part, until my eyes sometime later caught a discussion on midrange.com about the ability to restrict the processor capacity assigned to a DR/HA-product called MIMIX, which is marketed by Vision Solutions. The requirement was to use only a subset of the processor cores available on a multi core server by means of configuring a workload capping group.

The intention of this maneuver was to limit the product to only the number of processor cores needed to run the system mirroring process, rather than having to pay license fees for the processor cores required by the workload introduced by other software products, system components and business applications. Upon opening a ticket with Vision Solutions’ technical support, the customer however received the laconic reply to either purchase a license that covers all cores running on the server, or reduce the (total) number of cores.

The conclusion on this discussion points to a dilemma many vendors apparently face these days, with the current license model based on number of processor cores and CPW. The continuous improvements in the areas of processor cores in particular and server technology in general, drive towards consolidating server workloads to reduce total costs, inevitable increases the number of processor cores per server. While the processor capacity needed to run the individual vendor’s product does not increase, the customer is still in many cases forced to pay excessive license fees, due to the increase in total number of processor cores on the server.

I assume IBM by introducing the workload capping group concept was trying to accommodate this concern, allowing on one hand their customers to take advantage of technological improvements and consolidate workloads onto fewer servers, yet on the other hand still allow vendors to be competitive based on the actual workload footprint required by their product – as originally expressed and intended to be reflected in the common license fee model.

It appears however that many vendors have rather seen this development as an opportunity to increase their license fee profits – possible due to the lack of competition being the result of many product and vendor mergers in recent years. Given the reality that their customers are facing – server consolidation and virtualization is a fact of life – these vendors, sooner rather than later in my humble opinion, need to decide whether they want to become part of the solution, or remain part of the problem.

Thankfully though, IBM for one is taking its own medicine. If you for example have installed the IBM MQ or the DB2 Web Query product, both will actually honor any workload capping configured in terms of licenses required. My company has for many years with great success relied on the IBM MQ product, but it comes with a quite substantial price tag. Our use of the product however only impacts the server performance by a fraction, so using workload capping groups, we have been able to reduce our license costs significantly for this very useful and platform independent application integration product.

The Workload Capping Group Concept and Configuration

In the following section I will now try to explain the workload capping group concept in a little more detail. Basically, workload capping groups are divided into two separate aspects. The primary aspect is the capability to do the actual workload capping, tied to either individual jobs or all jobs running in a specific subsystem. Both options are in turn managed through the association of a Workload Capping Group (WLG). To give you an example – the following command will create a workload capping group named MQPROD:

ADDWLCGRP WLCGRP(MQPROD) PRCLMT(2)     

The workload capping group MQPROD will limit the number of processor cores available to 2, for any job or subsystem that it is assigned to. If you want to assign MQPROD to a job directly, you do it by issuing the following command:

CHGJOB … WLCGRP(MQPROD)         

When you run the above command, the specified job will be limited to two processor cores. To associate a workload capping group to a subsystem, you use a special data area named QWTWLCGRP in library QSYS for release 7.2 and earlier. To assign workload capping group MQPROD to subsystem QMQM I specify a value pair of two 10 byte names in the data area, subsystem name and workload capping group, respectively:

            Value                                                
Offset      *...+....1....+....2....+....3....+....4....+....5  
    0      'QMQM      MQPROD    '

Up to 100 name pairs can be stored in the data area if you create it with the maximum character data area length of 2000 bytes. A PTF has also been issued to add the ability to specify generic subsystem names, in case your subsystem naming convention allows you to take advantage of this improvement.

At release 7.3 and later, a workload capping group attribute has been added directly to the subsystem description, and this attribute is accessible using either the Create Subsystem Description (CRTSBSD) or the Change Subsystem Description (CHGSBSD) command. Anyway, once a workload capping group is assigned to a subsystem, all jobs running in that subsystem will be limited to the number of processor cores specified for that workload group.

You can verify the change the next time the subsystem starts (or immediately following the CHGSBSD command at release 7.3 or later) as message CPI146C, indicating that the subsystem processor access is limited by the workload group will be issued to the subsystem monitor job log:

Subsystem QMQM is using workload capping group MQPROD.

At this point, you have achieved the ability to control the number of processor cores assigned to a given job or subsystem. From a workload management perspective this is very useful in its own right – it allows you to individually prioritize workloads on a job or subsystem basis.

Note, that for auditing purposes the following journal entries are deposited to the system audit journal QAUDJRN:

  • Workload groups operations result in a ZC (Object Change) journal entry
  • Security audit records for the JS (Job Start/Change) journal entry includes the workload group name

The next part of the equation allows you to also financially benefit from this capacity, as you have the ability to associate the specific product license to the workload capping group. To continue our IBM MQ example, you achieve that by means of the Add WLC Product Entry (ADDWLCPRDE) command:

ADDWLCPRDE WLCGRP(MQPROD)
           PRDID(5724H72)
           LICTRM(V7R1M0)
           FEATURE(5050)

This final configuration step enables the IBM license manager component to include the workload capping group in the assessment of product license limit compliance. This also eliminates the warning messages otherwise sent to message queue QSYSOPR, if a license agreement is exceeded and thereby violated.

For products that are not actually loaded into the product license repository, the above command will mainly serve as an indication that workload capping is in effect for the product, as the license manager is not involved in license validation or usage compliance for such products. You can use the command Work with License Information (WRKLICINF) to verify if the product has been loaded into the product license repository.

Workload Capping Group Commands

I have already mentioned a couple of native CL commands available to manage workload capping groups and their associated product entries, and here’s the complete list of IBM’s offering on WLC CL commands:

ADDWLCGRP     Add Workload Capping Group    
ADDWLCPRDE    Add WLC Product Entry         
CHGWLCGRP     Change Workload Capping Group 
DSPWLCGRP     Display Workload Capping Group
RMVWLCGRP     Remove Workload Capping Group 
RMVWLCPRDE    Remove WLC Product Entry      

As you might notice there are no Work with-commands, or specialized commands to manipulate the QWTWLCGRP data area for releases prior to 7.3. But – and how lucky is that 🙂 – IBM does offer a Retrieve Workload Groups Information (QLZRTVWC) API to enable you to programmatically access all information pertaining to workload capping groups and associated WLC product entries. In addition to that IBM has also added a job attribute for Workload Group to the return information for the Retrieve Thread Attribute (QWTRTVTA) API.

Armed with that knowledge, and since I find that Workload Capping Groups are a very interesting and valuable enhancement to an already brilliant operating system, I decided to make up for some of IBMs most obvious omissions in order to make WLC management a little easier. Here’s what I came up with:

DSPJOBWLG     Display Job Workload Group
WRKWLCGRP     Work with Workload Capping Groups
WRKWLCPRDE    Work with WLC Product Entries
ADDWLCSBS     Add Workload Capping Subsystem
RMVWLCSBS     Remove Workload Capping Subsystem
WRKWLCSBS     Work with Workload Capping Subsystem 

To collect the full range of WLC commands in one place I also ended up creating a UIM menu:

CMDWLC        Workload Capping Group Commands Menu

But before going further down that road, let me briefly explain the Retrieve Workload Groups Information (QLZRTVWC) API and its parameters.

The Retrieve Workload Groups Information (QLZRTVWC) API

The Retrieve Workload Groups Information (QLZRTVWC) API is not that complicated, but might look a bit confusing at first, due to the fact that it is capable of returning one of two different sets of information based on one of three different request specifications. Here’s the QLZRTVWC API parameter list:
Required Parameter Group:

  1  Receiver variable                         Output    Char(*)
  2  Length of receiver variable               Input     Binary(4)
  3  Workload groups information format name   Input     Char(8)
  4  Workload groups query value               Input     Char(*)
  5  Workload groups query format name         Input     Char(8)
  6  Error code                                I/O       Char(*)

The information returned by the QLZRTVWC API is defined by parameters 1, 2 and 3: The receiver variable where the API output information is returned, the length of the receiver variable defining the space available, and the format defining the receiver variable content, respectively. As for the latter the following two format names apply, as documented in the API manual:

WLCR0100   Capacity and software product information for a given
           workload group is retrieved.
WLCR0200   The list of all workload groups on the partition which
           match the query value is retrieved.

The WLCR0100 format returns processor limit and all product entries for a given, single workload group name.

The WLCR0200 format returns a list of one or more workload groups and their associated capacity, depending on whether a single workload group name or the special value *ALL was specified for the workload group name input parameter.

For QLZRTVWC API parameters 4 and 5, all in all three query value formats are available to define the workload groups for which to return information. Parameter 4 specifies the query value(s), and parameter 5 names the format:

WLCQ0100   The workload groups query value is the product information
           for a given licensed program. 
WLCQ0200   The workload group query value is a fully qualified product
           directory path name. 
WLCQ0300   The workload groups query value is a specific workload 
           group name or is special value *ALL. 

To expand a little on the above excerpt from the API manual: The WLCQ0100 query value format allows you to identify a specific workload group based on a specified product ID, license term, feature and product option.

The WLCQ0200 query value format specifies the fully qualified product directory path name – registered with the licensed product when it was loaded – to identify a specific workload group.

The WLCQ0300 query value format specifies either a single workload group name or the special value *ALL to identify either a specific workload group or all workload groups on the system, respectively.

Typically you would use the WLCQ0100 and WLCQ0200 query value formats to retrieve capacity and software product entries in return format WLCR0100, while using query format WLCQ0300 allows you to employ either return format, depending on the actual query value being either a workload group name or the special value *ALL.

The sixth and final API parameter is the standard API error data structure. At the end of this article, I have included links to both IBM documentation of the API error data structure concept, as well as a couple of articles explaining this concept in more practical details.

Turning API documentation into RPG/IV code

Based on the above API documentation here’s how I define the QLZRTVWC API prototype:

**-- Retrieve workload groups information:                       
D RtvWlgInf       Pr                  ExtPgm( 'QLZRTVWC' )       
D  RcvVar                    65535a   Const  Options( *VarSize ) 
D  RcvVarLen                    10i 0 Const                      
D  RcvFmtNam                     8a   Const                      
D  QryVal                    65535a   Const  Options( *VarSize ) 
D  QryFmtNam                     8a   Const                      
D  Error                     32767a          Options( *VarSize )

And here are RPG/IV data structures implementing the two return information formats as well as the three query value formats:

**-- API return information data structures:                      
D WLCR0100        Ds         65535    Qualified                   
D  BytRtn                       10i 0                             
D  BytAvl                       10i 0                             
D  WlcGrp                       10a                               
D                                2a                               
D  WlgPrcCap                    10i 0                             
D  OfsWlgLst                    10i 0                             
D  NbrWlgLstE                   10i 0                             
D  LenWlgLstE                   10i 0                             
**                                                                
D WlgProd         Ds                  Qualified  Based( pWlgProd )
D  PrdId                         7a                               
D  LicTerm                       6a                               
D  Feature                       4a                               
**                                                                
D WLCR0200        Ds         65535    Qualified                   
D  BytRtn                       10i 0                             
D  BytAvl                       10i 0                             
D  OfsWlgLst                    10i 0                             
D  NbrWlgLstE                   10i 0                            
D  LenWlgLstE                   10i 0                            
**                                                               
D WlgLst          Ds                  Qualified  Based( pWlgLst )
D  WlcGrp                       10a                              
D  MaxPrcLmt                    10i 0                            
                                                                 
**-- API query value data structures:                                  
D WLCQ0100        Ds                  Qualified                  
D  PrdId                         7a                              
D  LicTerm                       6a                              
D  Feature                       4a                              
D  Option                        4a                              
**                                                               
D WLCQ0200        Ds                  Qualified                  
D  PrdDirNamLen                 10i 0                            
D  DirNamCcsId                  10i 0                            
D  PrdDirNam                  1024a                              
**                                                               
D WLCQ0300        Ds                  Qualified                  
D  WlcGrp                       10a

In the following code snippets I show an example of how to call the QLZRTVWC API and subsequently process the API output information:

                                              
(1) WLCQ0300.WlcGrp = PxWlcGrp;             
                                              
(2) RtvWlgInf( WLCR0200                     
               : %Size( WLCR0200 )            
               : 'WLCR0200'                   
               : WLCQ0300                     
               : 'WLCQ0300'                   
               : ERRC0100                     
               );                             
                                              
    If  ERRC0100.BytAvl > *Zero;            
      ExSr  EscApiErr;                      
                                              
    Else;                                   
(3)   ExSr  PrcWlcLst;                      
    EndIf; 


   BegSr  PrcWlcLst;                                    
                                                        
(4)  pWlgLst = %Addr( WLCR0200 ) + WLCR0200.OfsWlgLst;  
(5)  For  Idx = 1  to  WLCR0200.NbrWlgLstE;             

       LstEnt.Option = *Zero;                           
                                                        
(6)    LstEnt.WlcGrp    = WlgLst.WlcGrp;               
       LstEnt.MaxPrcLmt = WlgLst.MaxPrcLmt;            
       LstEnt.NbrPrdEnt = GetPrdCnt( WlgLst.WlcGrp );    
       
       ...        
(7)    If  Idx < WLCR0200.NbrWlgLstE;   
         pWlgLst += WLCR0200.LenWlgLstE;
       EndIf;                           
     EndFor;                            
P GetPrdCnt       B                   
D                 Pi            10i 0   
D  PxWlcGrp                     10a   Const
                                   
 /Free                  
                  
(8)  WLCQ0300.WlcGrp = PxWlcGrp;
                                           
(9)  RtvWlgInf( WLCR0100          
              : %Size( WLCR0100 )
              : 'WLCR0100'    
              : WLCQ0300  
              : 'WLCQ0300' 
              : ERRC0100     
              );      
                        
     If  ERRC0100.BytAvl > *Zero; 
       Return  *Zero; 
            
     Else;    
       Return  WLCR0100.NbrWlgLstE;
     EndIf;        
                                  
 /End-Free
                      
P GetPrdCnt       E 

At call-out (1) the Workload group name query value is populated with an input parameter value being either a specific workload group name or the special value *ALL. Both variants are supported by the WLCQ0300 query value format.

At call-out (2) the QLZRTVWC API call is executed, specifying the workload group list return format WLCR0200 as the API output, in order to receive a list of workload groups.

At call-out (3) a subroutine is executed to process the API output in the event of a successful API call.

Call-out 4-7 details the programming logic that enables you to retrieve and process each list entry one-by-one:

(4) Set list entry basing pointer pWlgLst to the address of the
    beginning of list (first list entry)
(5) For each returned list entry (if any)
(6) Process list entry data as defined by WlgLst data structure
(7) If more entries available add entry length to list entry 
    basing pointer pWlgLst (next list entry) 

Call-out 8 and 9 shows an example of calling the QLZRTVWC API with a specific workload group name and specifying the WLCR0100 return format to obtain the number of product entries registered for the workload group. In this example I do not actually retrieve each product entry also returned by return format WLCR0100, but that could easily be done by implementing the same logic as shown in call-outs 4-7.

New Workload Capping Group CL commands

In the following section, I briefly introduce each of the new Workload Capping Group commands that I mentioned at the beginning of this article. For more details please refer to the commands’ and display panels’ online help text.

The Display Job Workload Group (DSPJOBWLG) command displays in the form of a completion message the workload capping group associated with the job specified.

DSPJOBWLG     Display Job Workload Group

To check if the MQ server job AMQALMPX is running in a workload capping group, run the following command for the specific job:

DSPJOBWLG JOB(319406/QMQM/AMQALMPX)

The completion message will tell you:

Job 319406/QMQM/AMQALMPX workload capping group is MQPROD.

The Work with Workload Capping Groups (WRKWLCGRP) command allows you to work with one or all workload capping groups defined on your system. The indented list below shows all commands accessible from the work with-display, either as a list option (LO) or command function key (CF).

WRKWLCGRP     Work with Workload Capping Groups
  ADDWLCGRP   Add Workload Capping Group            (CF)    
  CHGWLCGRP   Change Workload Capping Group         (LO)  
  DSPWLCGRP   Display Workload Capping Group        (LO)
  RMVWLCGRP   Remove Workload Capping Group         (LO)
  WRKWLCPRDE  Work with WLC Product Entries         (CF)
  WRKWLCSBS   Work with Workload Capping Subsystem  (CF) 6.1+
  WRKSBSD     Work with Subsystem Description       (CF) 7.3+ 

The Work with WLC Product Entries (WRKWLCPRDE) command allows you to work with all WLC product entries defined for the specified workload capping group. The indented list below shows all commands accessible from the work with-display, either as a list option (LO) or command function key (CF).

WRKWLCPRDE    Work with WLC Product Entries        
  ADDWLCPRDE  Add WLC Product Entry                 (CF)
  RMVWLCPRDE  Remove WLC Product Entry              (LO)
  WRKLICINF   Work with License Information         (LO) 
  WRKWLCSBS   Work with Workload Capping Subsystem  (CF) 6.1+
  WRKSBSD     Work with Subsystem Description       (CF) 7.3+

The Work with WLC Subsystem (WRKWLCSBS) command allows you to work with the association between workload capping groups and subsystemsat release 7.2 and earlier. Note that as of release 7.3 and later workload groups are
associated directly to subsystems using the Create Subsystem Description (CRTSBSD) or Change Subsystem Description (CHGSBSD) commands, at which point the WLCSBS commands and the QWTWLCGRP data area become obsolete.

The WRKWLCSBS, ADDWLCSBS and RMVWLCSBS commands use APIs to retrieve and update the data area QWTWLCGRP in library QSYS. The indented list below shows all commands accessible from the work with-display, either as a list option (LO) or command function key (CF).

                                                      
WRKWLCSBS     Work with Workload Capping Subsystem  
  ADDWLCSBS   Add Workload Capping Subsystem        (CF)
  RMVWLCSBS   Remove Workload Capping Subsystem     (LO)
  WRKWLCGRP   Work with Workload Capping Groups     (LO)
  WRKSBSD     Work with Subsystem Descriptions      (LO)

As mentioned earlier I have also created a menu named CMDWLC to make it easier to find and access all the commands related to workload capping groups – have a look

CMDWLC            Workload Capping Group Commands                    
                                                      System:  WYNDHAMW
Select one of the following:                                      
                                                                   
  Workload Capping Group commands                                   
    10. Add Workload Capping Group                           ADDWLCGRP
    11. Change Workload Capping Group                        CHGWLCGRP
    12. Display Workload Capping Group                       DSPWLCGRP
    13. Remove Workload Capping Group                        RMVWLCGRP
    14. Work with Workload Capping Groups                    WRKWLCGRP
                                                                      
  Workload Capping Product Entry commands                              
    20. Add WLC Product Entry                                ADDWLCPRDE
    21. Remove WLC Product Entry                             RMVWLCPRDE
    22. Work with WLC Product Entries                        WRKWLCPRDE
                                                                     
  Workload Capping Job commands                                     
    30. Display Job Workload Group                           DSPJOBWLG
  
  Workload Capping Subsystem commands                               
    40. Add Workload Capping Subsystem                       ADDWLCSBS
    41. Remove Workload Capping Subsystem                    RMVWLCSBS
    42. Work with Workload Capping Subsystem                 WRKWLCSBS
                                                    
  Service options                                    
    90. Sign off                                             SIGNOFF
                                                 
                                                                 Bottom
Selection or command                                                  
===>                                                                   
F3=Exit   F4=Prompt   F9=Retrieve   F12=Cancel

The following source members are included in the zip-file containing all the Workload Capping Group CL commands:

CBX301U   UIM     Workload Capping Group Commands Menu

CBX301    RPGLE   Display Job Workload Group                 
CBX301H   PNLGRP  Display Job Workload Group - Help          
CBX301X   CMD     Display Job Workload Group                 
CBX301M   CLP     Display Job Workload Group - Build command 

CBX3021   RPGLE   Work with Workload Capping Groups - CCP          
CBX3021C  RPGLE   Work with Workload Capping Groups - UIM Cond Pgm 
CBX3021E  RPGLE   Work with Workload Capping Groups - UIM Exit Pgm 
CBX3021H  PNLGRP  Work with Workload Capping Groups - Help         
CBX3021P  PNLGRP  Work with Workload Capping Groups - Panel Group  
CBX3021V  RPGLE   Work with Workload Capping Groups - VCP          
CBX3021X  CMD     Work with Workload Capping Groups                
CBX3021M  CLP     Work with Workload Capping Groups - Build command

CBX3022   RPGLE   Work with WLC Product Entries - CCP             
CBX3022C  RPGLE   Work with WLC Product Entries - UIM Cond Program
CBX3022E  RPGLE   Work with WLC Product Entries - UIM Exit Program
CBX3022H  PNLGRP  Work with WLC Product Entries - Help            
CBX3022P  PNLGRP  Work with WLC Product Entries - Panel Group     
CBX3022V  RPGLE   Work with WLC Product Entries - VCP             
CBX3022X  CMD     Work with WLC Product Entries    
CBX3022M  CLP     Work with WLC Product Entries - Build command   

CBX3031   RPGLE   Add Workload Capping Subsystem - CPP           
CBX3031H  PNLGRP  Add Workload Capping Subsystem - Help          
CBX3031V  RPGLE   Add Workload Capping Subsystem - VCP           
CBX3031X  CMD     Add Workload Capping Subsystem                 
CBX3031M  CLP     Add Workload Capping Subsystem - Build Command 

CBX3032   RPGLE   Remove Workload Capping Subsystem - CPP           
CBX3032H  PNLGRP  Remove Workload Capping Subsystem - Help          
CBX3032V  RPGLE   Remove Workload Capping Subsystem - VCP           
CBX3032X  CMD     Remove Workload Capping Subsystem                 

CBX3033   RPGLE   Work with Workload Capping Subsystem - CPP        
CBX3033E  RPGLE   Work with Workload Capping Subsystem - UIM Exit Pgm
CBX3033H  PNLGRP  Work with Workload Capping Subsystem - Help       
CBX3033P  PNLGRP  Work with Workload Capping Subsystem - Panel Group
CBX3033V  RPGLE   Work with Workload Capping Subsystem - VCP        
CBX3033X  CMD     Work with Workload Capping Subsystem              

To create all the above objects, compile and run the CBX301M, CBX3021M, CBX3022M and CBX3031M CL programs, following the instructions in each of the four source headers.

You’ll also find compilation instructions in the respective source headers of the individual sources.

Download the WlcGrpSrc zip file containing the source code.

Download the WlcGrpDoc zip file containing documentation.

More information

Workload capping groups were introduced by PTFs for release 6.1 and 7.1 and have been part of the base OS since release 7.2. I have included links below to more articles discussing the WLC concept and setup quite thoroughly – in case you’d like to dive deeper into the topic.

Setting up workload groups – 7.2 and earlier

Setting up workload groups – 7.3 and later

Manage Workloads Better with IBM i 7.1

Workload Group Configuration with IBM i 7.3

Workload Groups and Performance Considerations

Manage Work Better with Better Work Management Version 7.1 TR8

IBM i Work Management – Best Kept Secrets

Software Pricing With IBM i Virtualization

Limiting WebSphere MQ Licensing and Processing Capacity with Workload Groups

The workload capping portion of the DB2 Web Query product limits the CPU resources that the product can use

Workload groups V7R3 – the QSYS/QWTWLCGRP data area is obsolete

Leverage Workload Groups (presentation)

Workload capping – reducing license costs on IBMi

Sub-capacity (Virtualization) License Counting Rules

Steve Will: IBM i “Workload Groups” Qualify for Virtualization Technologies’ Subcapacity Pricing

Retrieve Workload Groups Information (QLZRTVWC) API

Retrieve Thread Attribute (QWTRTVTA) API

Know Your Errors: Use the API Error Parameter in RPG (by Craig Rutledge)

APIs by Example: Using the ERRC0200 Data Structure

API error code parameter format

OSP-Workload Capping function V6R1

OSP-Workload Capping function V7R1

OSP QWTWLCGRP Allow use of wildcard (*) in subsystem name V7R1 and V7R2

SE65646 – OSP-INCORROUT QLZRTVWC API FIX

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s