One of the many additions to the last release and Technology Refresh, IBM i 7.5 and 7.4 TR6, was a SQL View that returns one row of results of the usage of the CPU.
To most people it may not sound the most interesting information, but I have been asked if there was a way to get to this information so it could be written to an outfile, by a couple of people. Previously the only way I knew how to show the information was the Work with System Activity command, WRKSYSACT.
Work with System Activity DEV750 DD/DD/DD TT:TT:TT Automatic refresh in seconds . . . . . . . . . . . . . . . . . . . 5 Job/Task CPU filter . . . . . . . . . . . . . . . . . . . . . . . . .10 Elapsed time . . . . . . : 00:00:02 Overall CPU util . . . . : 80.1 Overall SQL CPU util . . . : 30.4 Average CPU rate . . . . . : 101.2 Current processing capacity: 1.00 |
The View, SYSTEM_ACTIVITY_INFO, allows me to get to the needed information. It has a single optional parameter:
DELAY_SECONDS: The number of seconds that separates the collection of the results. If not given it uses a default value of 1.
In this first example I am not going to give a number of seconds to delay, therefore, a delay of one second is used:
SELECT * FROM TABLE(QSYS2.SYSTEM_ACTIVITY_INFO()) |
The View returns four columns:
AVERAGE_ AVERAGE_CPU_ MINIMUM_CPU_ MAXIMUM_CPU_ CPU_RATE UTILIZATION UTILIZATION UTILIZATION -------- ------------ ------------ ------------ 100.00 4.36 4.36 4.36 |
- AVERAGE_CPU_RATE: Average CPU rate shown as a percentage of its nominal frequency, which would be shown as 100%. If a value is greater than 100%, for example 120%, then the processor is running at (120% – 100%) 20% faster than its nominal speed
- AVERAGE_CPU_UTILIZATION: Average CPU utilization for all of the active processors
- MINIMUM_CPU_UTILIZATION: CPU utilization of the CPU that reported the minimum amount of CPU utilization
- MAXIMUM_CPU_UTILIZATION: CPU utilization of the CPU that reported the maximum amount of CPU utilization
If I wanted to use the delay seconds I could include the parameter name:
SELECT * FROM TABLE(QSYS2.SYSTEM_ACTIVITY_INFO(DELAY_SECONDS => 30)) |
Or just the number of seconds:
SELECT * FROM TABLE(QSYS2.SYSTEM_ACTIVITY_INFO(30)) |
The results for the above statement are:
AVERAGE_ AVERAGE_CPU_ MINIMUM_CPU_ MAXIMUM_CPU_ CPU_RATE UTILIZATION UTILIZATION UTILIZATION -------- ------------ ------------ ------------ 98.80 11.54 11.54 11.54 |
As I am not the only person using this partition are the differences in results caused by the delay seconds or the fluctuations of demands made by other users and jobs? I tried to test this with the following statement:
SELECT * FROM TABLE(QSYS2.SYSTEM_ACTIVITY_INFO()) UNION SELECT * FROM TABLE(QSYS2.SYSTEM_ACTIVITY_INFO(30)) |
I am using a UNION clause to combine the results from the two statements into one set of results. I know it is not perfect, but it was best way I could think to test if there were really any difference in the results they return. I ran this four times over an hour and the results were:
AVERAGE_ AVERAGE_CPU_ MINIMUM_CPU_ MAXIMUM_CPU_ CPU_RATE UTILIZATION UTILIZATION UTILIZATION -------- ------------ ------------ ------------ 100.00 1.79 1.79 1.79 98.73 2.85 2.85 2.85 98.86 6.11 6.11 6.11 98.85 42.03 42.03 42.03 98.79 31.74 31.74 31.74 98.75 3.43 3.43 3.43 98.86 4.65 4.65 4.65 100.00 5.81 5.81 5.81 |
Just with this small sample of results it would appear that there is not much of a difference between the two. From this point forward I am going to use this statement with the default, one second.
If I am going to capture this information into an "outfile" I am going to need a table into which to insert the data.
01 CREATE TABLE MYLIB.TESTTABLE 02 (PARTITION,TIMESTAMP,CPU_RATE,AVERAGE_CPU) 03 AS 04 (SELECT CHAR(CURRENT_SERVER,10), 05 CURRENT_TIMESTAMP, 06 DEC(AVERAGE_CPU_RATE,5,2), 07 DEC(AVERAGE_CPU_UTILIZATION,5,2) 08 FROM TABLE(QSYS2.SYSTEM_ACTIVITY_INFO())) 09 DEFINITION ONLY ; |
Line 1: The table will be created in my library.
Line 2: These are the names of the Table's columns:
- PARTITION: Name of the partition
- TIMESTAMP: Timestamp of when the row was inserted into the Table
- CPU_RATE: Average CPU rate
- AVERAGE_CPU: Average CPU utilization
Line 4 - 8: I am creating the Table "on the fly" using a SQL Statement.
I have redefined several of the columns to make them a more suitable size for what I want.
- CURRENT_SERVER by using the CHAR scalar function I convert it from VARCHAR(28) to CHAR(10)
- AVERAGE_CPU_RATE and AVERAGE_CPU_UTILIZATION by using the DEC scalar function I converted them from DEC(20,2) to DEC(5,2)
Line 9: DEFINITION ONLY means that the Table will be created, but not populated with data.
I can insert a row of data with the following statement:
01 INSERT INTO TESTTABLE 02 SELECT CURRENT_SERVER, 03 CURRENT_TIMESTAMP, 04 AVERAGE_CPU_RATE, 05 AVERAGE_CPU_UTILIZATION 06 FROM TABLE(QSYS2.SYSTEM_ACTIVITY_INFO()) |
As I have already "resized" those columns in the Table I do not have to do so again in the Insert statement. The result from this insert looks like:
SELECT * FROM TESTTABLE ; CPU_ AVERAGE PARTITION TIMESTAMP RATE _CPU --------- -------------------------- ------ ------- DEV750 YYYY-MM-DD 10:47:32.416071 98.74 4.17 |
To update this "outfile" I am going to use a RPG program:
01 **free 02 ctl-opt option(*srcstmt:*nodebugio) dftactgrp(*no) ; 03 dcl-pr sleep extproc('sleep') ; 04 *n uns(10) value ; 05 end-pr ; 06 dcl-s Seconds uns(10) ; 07 exec sql SET OPTION COMMIT = *NONE ; 08 Seconds = 5 * 60 ; // 5 minutes in seconds 09 dow (*on) ; 10 exec sql INSERT INTO TESTTABLE SELECT CURRENT_SERVER, CURRENT_TIMESTAMP, AVERAGE_CPU_RATE, AVERAGE_CPU_UTILIZATION FROM TABLE(QSYS2.SYSTEM_ACTIVITY_INFO()) ; 11 sleep(Seconds) ; 12 enddo ; 13 *inlr = *on ; |
Line 1`: Why would anyone in 2022 not use totally free RPG.
Line 2: My favorite control options, and I need the DFTACTGRP as I am going to call an external procedure.
Lines 3 - 5: I am going to call the sleep C function to pause the program by the number of seconds I want. This is the prototype definition for the function.
Line 6: Variable to contain the number of seconds to "sleep" this program.
Line 7: I do not want to commit the data from the Insert, therefore, I make sure that commitment control is turned off with this statement.
Line 8: I am just being lazy here. I am calculating the number of second five minutes is, 300. Why did I do this? If I need to change the number of minutes to 75 or 13 or 123 I don't have to do the calculation to translate that number of minutes to seconds. This calculation does it for me.
Line 9 – 12: This is a never-ending loop.
Line 10: The SQL Insert statement into the "outfile" Table.
Line 11: Now I sleep for the period I desire.
And after its sleep the program loops again.
After compiling the program, I submitted to batch and left it run for 25 minutes. These were the results in the "outfile" Table:
CPU_ AVERAGE PARTITION TIMESTAMP RATE _CPU --------- -------------------------- ------ ------- DEV750 YYYY-MM-DD 11:39:40.932170 100.00 2.54 DEV750 YYYY-MM-DD 11:44:42.003215 98.63 28.61 DEV750 YYYY-MM-DD 11:49:43.170619 100.00 1.35 DEV750 YYYY-MM-DD 11:54:44.266721 98.86 50.48 DEV750 YYYY-MM-DD 11:59:45.337086 98.73 53.00 |
A simple View and a simple RPG program to capture this information.
You can learn more about the SYSTEM_ACTIVITY_INFO SQL View from the IBM website here.
This article was written for IBM i 7.5 and 7.4 TR6.
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.