Wednesday, July 22, 2026

Program to alert when elapsed CPU percentage becomes too high

When I published my article about Program to alert when jobs' CPU percentage becomes too high someone messaged me asking could I think of something that would do the same when the total CPU exceeded a certain percentage. The answer is, of course, "Yes".

Before I create a program we need to consider the whether the partition that the program will be run on is "capped" or "uncapped". What does that mean?

When a partition is capped it cannot use more than its allocated processing units, in other words it can never exceed 100% CPU usage.

While an uncapped partition has its base entitlement of the processing units, but can borrow unused processing power from the other partitions if available. This means that its CPU usage can exceed 100% of the partition's resources.

This means that 90% CPU utilization could be more concerning on a capped than an uncapped. Keep this in mind when you look at my example program.

I always use ACS's Run SQL Scripts, RSS, to develop the SQL statements I will be including in a RPG program. I can get the elapsed CPU percentage from the SYSTEM_STATUS SQL table function:

01  SELECT ELAPSED_CPU_USED 
02    FROM TABLE(QSYS2.SYSTEM_STATUS(
03                 DETAILED_INFO => 'BASIC')
04  ) 

Line 1: ELAPSED_CPU_USED is the average of the elapsed time during which the processing units were in use.

Line 3: If I use the basic information not all the columns in the table function are returned, this means that the results are returned to me faster and takes less CPU to calculate the results.

The results returned that the CPU usage is running at 32.90%.

ELAPSED_CPU_USED
----------------
           32.90

I can take that SQL statement and build a RPG program around it:

01  **free
02  ctl-opt main(Main) option(*srcstmt) dftactgrp(*no) actgrp(*caller) ;

03  dcl-s Threshold packed(5 : 2) inz(80.00) const ;
04  dcl-s SleepSeconds int(10) inz(60) const ;

05  dcl-pr sleep int(10) extproc('sleep') ;
06    *n uns(10) value ;
07  end-pr ;

08  dcl-proc Main ;
09    dcl-s CpuUsed packed(5 : 2) ;
10    dcl-s Text varchar(1000) ;

11    dow (*on) ;
12      exec sql SELECT ELAPSED_CPU_USED INTO :CpuUsed      
13                 FROM TABLE(QSYS2.SYSTEM_STATUS(          
14                              DETAILED_INFO => 'BASIC')) ;

15      if (CpuUsed > Threshold) ;
16        Text = 'SNDMSG MSG('''+
17               'Elapsed CPU Usage is ' + %trimr(%char(CpuUsed)) +
18               ' which is greater than the threshold ' +
19               %trimr(%char(Threshold)) + ''') ' +
20               'TOMSGQ(QSYSOPR) ' ;

21        exec sql CALL QCMDEXC(:Text) ;
22      endif ;

23      sleep(SleepSeconds) ;
24    enddo ;

25  on-exit ;
26  end-proc ;

Line 2: I have used the MAIN keyword so that this program will use the Main procedure, and will not include all of rubbish for the RPG cycle that is included in a program that does not have a Main procedure. I want debug to use the source member sequence numbers, rather than generate its own. And as a C procedure will be called this program cannot be run in the default activation group.

Lines 3 and 4: I have defined these two variables as "global variables", as they are the ones you might want to change the values of. Line 3, Threshold, is value I will be using to compare the elapsed CPU percentage to. Line 4, SleepSeconds, contains the number of seconds this program will be "slept" after each time I fetch the results. I have also included the CONST keyword for both variables, this will prevent these values from being changed elsewhere within the program.

Lines 5 – 7: This is the procedure definition for the C procedure sleep. I will be using this as the method the pause the program between fetches.

Line 8: Start of the Main procedure.

Lines 9 and 10: Definition of the two variables I will be using just within this procedure. CpuUsed will contain the elapsed percentage of CPU used. Text will contain the message text.

Line 11: Start of a "never ending" Do loop.

Lines 12 – 14: The SQL statement I showed before, but this time the value of the elapsed CPU percentage is placed in the RPG variable CpuText, which is why it is prefixed with a colon ( : ).

Line 15: If the elapsed CPU percentage retrieved from the SQL statement is greater than the value in the variable Threshold this If group is performed.

Lines 16 – 20: The message text for the message to be sent to the System Operator message queue is created.

Line 21: I am using the SQL QCMDEXC procedure to execute the SNDMSG command.

Line 23: This is the call to the sleep procedure to pause the program.

Line 25: I have included an ON-EXIT group that I can use to perform any kind of clean up when the program is ended.

When this program was run I was fortunate that the elapsed CPU percentage exceeded the threshold, which meant the text for the SNDMSG command was generated:

SNDMSG MSG('Elapsed CPU Usage is 85.20% which is greater than the threshold 80.00%') TOMSGQ(QSYSOPR)

And when I looked in the System Operator messages I saw:

From  . . . :   SIMON          06/18/26   04:15:11
Elapsed CPU Usage is 82.50% which is greater than the threshold 80.00%

If you are going to use this program remember to change the Threshold value to suit the percentage you want to alert for your environment. 80% maybe too little or great for your situation.

 

This article was written for IBM i 7.6, and should work for some earlier releases too.

No comments:

Post a Comment

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.