Performance Metrics

System Requirements

Performance metrics are available in KCML 07.16.00.23055 or later for AIX 7 and Linux 2.6 (or later) and are depedent on the KCML Message Queue Support library, kmsgq.so.


Introduction

KCML has been instrumented to produce statistics on the performance of the application code. Statistics include processor utilization, memory usage and disk I/O, see List of Performance Metrics.

The statistics are sent, via kmsgq.so to a RabbitMQ server cluster where they can be processed, for example by populating an InfluxDB database. To reduce the impact of performance metrics it is advisable to have a fast network connection between the application server and the RabbitMQ server.

Each performance metric can be individually enabled by calling 'KCML_PerfMetric_Set() passing in one of the built-in KCML_PERFMETRIC_ flags. In KCML 7.16, or later, these flags are members of a KCML_PERFMETRICS enumeration. A performance metric can either be enabled for an individual partition or globally, for all partitions, by passing in a partition number of zero. A performance metric will be sent if its flag has been set either at a partition or global level. These flags are stored in same shared memory area as $PSTAT which must have been created by a KCML, or its utilities, that support performance metrics and with an extended $PSTAT configured.

REM Enable kcml.kdb.open on this partition
'KCML_PerfMetric_Set(_KCML_PERFMETRIC_KCML_KDB_OPEN, #PART, sToken$)
REM Enable kcml.session.start on all partitions
'KCML_PerfMetric_Set(_KCML_PERFMETRIC_KCML_SESSION_START, 0, sToken$)

Calling 'KCML_PerfMetric_Clear() will unset the flag, either for the specified partition or for all partitions.

The optional sToken$ parameter is intended for use on customer systems where only certain processes are expected to change the state of performance metrics.
See: Access Control

Applications can check what performance metrics are enabled by calling 'KCML_PerfMetric_Get(). This will return an array of KCML_PerfMetricRec records which contains the performance metrics name, its flag value and its state, ie enabled or disabled.

00010 REM Display global performance metrics
    : DIM a$(0)_kcml_perfmetricrec
    : DIM rc AS bool
    : DIM nCount AS Integer
    : DIM i AS Integer
    : DIM state$8
    : rc = 'kcml_perfmetric_get(BYREF a$(),0)
    : IF (rc)
    :     nCount = DIM(a$(),1)
    :     FOR i = 1 TO nCount
    :         state$ = (FLD(a$(i).kcml_perfmetric_enabled) ? "on" : "off")
    :         PRINT FLD(a$(i).kcml_perfmetric_name$);" = ";FLD(a$(i).kcml_perfmetric_flag);" = ";state$
    :     NEXT i
    : ELSE
    :     REM $PSTAT not large enough. Most likely created by an older version of KCML.
    :     PRINT "Performance metrics not available"
    : END IF
    : $END

Running the above example should display the state of each performance metric.


Configuration

By default the collection of performance metrics is disabled. To enable performance metrics the location, and credentials, to the RabbitMQ server and a named queue must be specified in /etc/kcml/msgq.conf. Systems that have been executed as a Connection Manager Service may also define their own configuration in /etc/kcml/msgq.$SERVICE.conf. If /etc/kcml/msgq.$SERVICE.conf does not exist then the configuration will be loaded from /etc/kcml/msgq.conf.

See KCML Message Queue Support library: Configuration.

Next configure KCML to use that queue for performance metrics by adding the following to msgq.conf

[perfmetric]
queue=myQueue

The [perfmetric] section can also have the following optional settings:-

mem=1024
logperiod=30
iotimerfreq=1000
decltimerfreq=50
maxdupidx=20000
lockwaitalert=5
maxtranstime=4
x509warndays=100

The mem setting will cause kcml.mem.delta to be reported for every allocation that exceeds the specified size, in kilobytes.
The logperiod value specifies the frequency, in seconds, that periodically logged metrics such as kcml.kdb.io & kcml.declare.total are reported.
Increasing the following key values of the [perfmetric] section can be used to reduce the overhead of determining how long ago the last periodic metrics were sent.

MetricKeyDefault valueDescription
kcml.kdb.ioiotimerfreq100Number of I/O operations between checking the last time kcml.kdb.io was sent
kcml.declare.totaldecltimerfreq25Number of $DECLARE calls executed between checking the last time kcml.declare.total was sent

For example the above configuration will only check every 1000 read/write operations and every 50th $DECLARE call.
The maxdupidx value controls the sensitivity of the kcml.kdb.dupidxio metric. By default KCML will report this metric if 100000 index blocks are scanned when searching a table with duplicate indices. The above example lowers this limit to 20000 index blocks.
The lockwaitalert value sets the timeout, in seconds, for kcml.native.lock - if $OPEN takes longer than that time to obtain the lock then the kcml.native.lock metric will be sent. The default, if no lockwaitalert value is set, is 2 seconds. The maxtranstime value set the threshold, in seconds, over which the life-time of a transaction will be reported by the kcml.kdb.transtime & kcml.sql.opttranstime metrics. The default value is 2 seconds.

The x509warndays setting sets the number of days before certificate expiry that the kcml.x509.expiry metric will be sent. The default is 30.

By default all performance metrics are not enabled. However performance metrics can be enabled, for all partitions, when $PSTAT is created by specifying them in the [perfmetric] section of msgq.conf:-

# Send performance metrics to myQueue and always enable kcml.session.start and kcml.session.lic
[perfmetric]
queue=myQueue
kcml.session.start=1
kcml.session.lic=1

Access Control

Changing the state of performance metrics can be restricted on customer systems by passing in a security token to the 'KCML_PerfMetric_Set() & 'KCML_PerfMetric_Clear() functions. The format of the token is a text string ending with a | followed by an UTC timestamp in ISO-8601 format followed by carriage-return + line-feed characters.

Text-string|YYYY-MM-DDThh:mm:ssZ<crlf>

A SHA-256 message digest signature is then calculated, using a private key, and then appended after being base-64 encoded:-

Text-string|YYYY-MM-DD hh:mm:ss<crlf>
signature=xxxxx...

Where xxxxx... is the base-64 encoded signature.

The public key is then extracted from the private key and then added to the [perfmetric] section of /etc/kcml/msgq.conf:-

# Enforce security for 'KCML_PerfMetric_Set() and 'KCML_PerfMetric_Clear()
[perfmetric]
queue=myQueue
pubkey=zzzzz...

Where zzzzz... is the base-64 encoded public key.
When 'KCML_PerfMetric_Set() & 'KCML_PerfMetric_Clear() are called they inspect the timestamp and check that it is within 5 minutes of the current time. If the timestamp is outside of that margin the functions will fail and return a value of _KCML_PERFMETRIC_TOKENEXPIRED. The default margin can be changed by specifying the tokentimestampmargin value, in seconds, in the [perfmetric] section on /etc/kcml/msgq.conf

# Enforce security for 'KCML_PerfMetric_Set() and 'KCML_PerfMetric_Clear()
# Increase timestamp margin to 10 minutes.
[perfmetric]
queue=myQueue
pubkey=zzzzz...
tokentimestampmargin=600

The signature will then be verified using the public key that was added to /etc/kcml/msgq.conf, if no pubkey value was added to /etc/kcml/msgq.conf then _KCML_PERFMETRIC_NOPUBKEY will be returned. If the signature is valid then the state of the perfmance metric will be changed, othwise a value of _KCML_PERFMETRIC_VERIFYFAILURE will be returned.

The KCML process that calls 'KCML_PerfMetric_Set() & 'KCML_PerfMetric_Clear() should not have access to the private key, ie to avoid the possibility bypassing the security by using self-signed tokens. Typically the token, and its signature, would be constructed on a different machine and then passed to a SOAP server, that verifies the signature using the public key, when it calls 'KCML_PerfMetric_Set() & 'KCML_PerfMetric_Clear().

However on internal development systems such security may not be required and can be disabled by adding the suppressverify key to the [perfmetric] section of /etc/kcml/msgq.conf :-

# Disable security for 'KCML_PerfMetric_Set() and 'KCML_PerfMetric_Clear()
[perfmetric]
queue=myQueue
suppressverify=1

In this case the sToken$ parameter can be omitted or passed an empty string.


Message Format

Messages are plain text and begin with a name of the form kcml.perf.metric. Then a common set of comma-separated key=value pair identifiers are included.

ExampleDescription
host="MachineName"The application server's node name
user="UserName"Owner of the process
pid=12345Process ID
uuid="...."Univerally unique identifier
ts=1484752401428527Timestamp. Number of microseconds since epoch
exe="kcml"Executable program name. Typically kcml but can be kiodbc or kwebserv.
service="AppName"Application's service name in kconf.xml
part=345Partition number, #PART.

This set of values is also included with application performance metrics sent using 'KCML_PerfMetric_Send().

Each performance metric then appends one or more, comma separated, key=value pairs.
For example, kcml.load.prog

kcml.load.prog,host="centos6.kcml.com",user="fred",pid=6481,uuid="884a1fc0-65f9-4a53-9d8e-875172abf5b6",ts=1488216010824575,exe="kcml",service="MyApp",part=1015,file="/user1/src/myapp/sw/progs/main.src",loadtime=2545

List of Performance Metrics

Below is a list of performance metrics with the common set of key=value pairs omitted for clarity. All time values are in micro-seconds, unless otherwise stated. Hover the mouse pointer over each statistic for a description.
Note that not all constants have unique value as some metrics are enabled in pairs, for example kcml.session.start & kcml.session.end.

MetricConstant NameConstant ValueDescriptionSend ConditionExample
kcml.clnt.roundtriptime_KCML_PERFMETRIC_KCML_CLNT_ROUNDTRIPTIME1A measure of network latency. Round-trip time, in microseconds, from the server to the client and back.Form.Open()kcml.clnt.roundtriptime,rtt=usec
kcml.clnt.payload_KCML_PERFMETRIC_KCML_CLNT_PAYLOAD2Client network payload required to display a form. It is a total of all the data sent up until the form's Show() event.Form.Terminate()kcml.clnt.payload,prog=string,form=string,cached=bool,shown=bool,size=count
kcml.cpu.usage_KCML_PERFMETRIC_KCML_CPU_USAGE3Total amount of processor time the partition has usedProgram LOAD, SOAP server method calls & $END. Periodically from KDB/KISAM I/O operations, form events, $BREAK, $IF & 'KCML_poll()kcml.cpu.usage,usertime=usec,systime=usec
kcml.declare.call_KCML_PERFMETRIC_KCML_DECLARE_CALL4Record of a $DECLARE call. The number of bytes sent and received is only applicable to client-side $DECLARE calls, where svr is 0$DECLAREkcml.declare.call,lib=string,fn=string,svr=bool,time=usec,writebytes=count,readbytes=count
kcml.declare.total_KCML_PERFMETRIC_KCML_DECLARE_TOTAL39Summary of $DECLARE callsProgram LOAD, $END & periodically from $DECLAREkcml.declare.total,count=num,writebytes=num,readbytes=num,server=num,client=num
kcml.env.get_KCML_PERFMETRIC_KCML_ENV_GET5Get environment valueval$=ENV(varName$)kcml.env.get,name=string,time=usec,stack=string
kcml.env.set_KCML_PERFMETRIC_KCML_ENV_SET6Set environment valueENV(varName$)=newValue$kcml.env.set,name=string,time=usec,stack=string
kcml.env.total_KCML_PERFMETRIC_KCML_ENV_TOTAL53Total number of ENV() statementsProgram LOAD, SOAP server method calls & $END. Periodically from KDB/KISAM I/O operations, form events, $BREAK, $IF & 'KCML_poll()kcml.env.total,set=count,get=count
kcml.form.open_KCML_PERFMETRIC_KCML_FORM_OPEN7Form openForm.Open()kcml.form.open,prog=string,form=string
kcml.form.idle_KCML_PERFMETRIC_KCML_FORM_IDLE8Record of a form's Idle() event executingForm.Idle()kcml.form.idle,prog=string,form=string,timer=msec
kcml.kdb.open_KCML_PERFMETRIC_KCML_KDB_OPEN9Database open tableKI_OPEN & KI_CREATEkcml.kdb.open,table=string,handle=num,chandle=num,mode=string,time=usec
kcml.kdb.close_KCML_PERFMETRIC_KCML_KDB_CLOSE9Database close tableKI_CLOSEkcml.kdb.close,table=string,handle=num,chandle=num
kcml.kdb.connect_KCML_PERFMETRIC_KCML_KDB_CONNECT12Database connectKI_CONNECTkcml.kdb.connect,time=usec,type=string,handle=num,dsn=string
kcml.kdb.disconnect_KCML_PERFMETRIC_KCML_KDB_DISCONNECT12Database disconnectKI_DISCONNECTkcml.kdb.disconnect,handle=num
kcml.kdb.io_KCML_PERFMETRIC_KCML_KDB_IO11Database I/OSent periodically during any read/write operation on KISAM/KDB tables & KI_CLOSEkcml.kdb.io,table=string,handle=num,chandle=num,nread=count,readbytes=count,readtime=usec,nwrite=count,writebytes=count,writetime=usec,nreadidx=count,readbytesidx=count,readtimeidx=usec,nwriteidx=count,writebytesidx=count,writetimeidx=usec,nreaddata=count,readbytesdata=count,readtimedata=usec,nwritedata=count,writebytesdata=count,writetimedata=usec,mode=char
kcml.kdb.error_KCML_PERFMETRIC_KCML_KDB_ERROR34Last database errorKI_ERROR_TEXT on a handle where a database call has failedkcml.kdb.error,handle=num,chandle=num,errtext=string
kcml.kdb.dupidxio_KCML_PERFMETRIC_KCML_KDB_DUPIDXIO47Duplicate index I/OSent during database I/O when the maxdupidx threshold in /etc/kcml/msgq.conf has been exceededkcml.kdb.dupidxio,table=string,handle=num,chandle=num,keyval=hex,add=bool,reccnt=count,reclen=num,idxblocks=count,idxbytes=count
kcml.kdb.transtime_KCML_PERFMETRIC_KCML_KDB_TRANSTIME54Time taken to perform a transactionTransaction commitkcml.kdb.transtime,chandle=num,time=usec,retries=count,status=string,stack=string
kcml.kdb.prepare_KCML_PERFMETRIC_KCML_KDB_PREPARE58Preparation of SQL planSent when an SQL plan is prepared using CALL KI_PREPARE or KI_SQLkcml.kdb.prepare,plan=num,handle=num,chandle=num,errtext=string,sql=string,time=usec,columns=count,kfn=string
kcml.kdb.execute_KCML_PERFMETRIC_KCML_KDB_EXECUTE58Execution of SQL planSent when an SQL plan is executed using CALL KI_EXECUTE or KI_SQLkcml.kdb.execute,plan=num,handle=num,chandle=num,time=usec,reclen=num,errtext=string
kcml.kdb.fetch_KCML_PERFMETRIC_KCML_KDB_FETCH59Result-set fetch from a databaseSent in KI_CLOSE or periodically during CALL KI_FETCH or when kiodbc queries an Oracle/PostgreSQL databasekcml.kdb.fetch,plan=num,rows=count,time=usec
kcml.kdb.wsopen_KCML_PERFMETRIC_KCML_KDB_WSOPEN64Open or create a word search indexKI_WS_OPEN & KI_WS_CREATEkcml.kdb.wsopen,table=string,mode=string,chandle=num,exhandle=num,idxhandle=num,noisefile=string,noisesize=num,time=usec,major=num,minor=num
kcml.kdb.startio_KCML_PERFMETRIC_KCML_KDB_STARTIO70KI_START ioKI_STARTkcml.kdb.startio,table=string,handle=num,chandle=num,keyval=hex,reccnt=count,idxblocks=count,idxbytes=count
kcml.mem.used_KCML_PERFMETRIC_KCML_MEM_USED14Amount of memory usedProgram LOAD & SOAP server method calls. Periodically from KDB/KISAM I/O operations, form events, $BREAK, $IF & 'KCML_poll()kcml.mem.used,mem=kb
kcml.mem.delta_KCML_PERFMETRIC_KCML_MEM_DELTA15Change in memory used, sent when the change exceeds threshold as defined in msgq.confDIM, REDIM & NEWkcml.mem.delta,mem=kb,stack=string
kcml.mem.sym_KCML_PERFMETRIC_KCML_MEM_SYM56Foreground symbol table statisticsProgram LOAD, COM CLEAR & SOAP server method calls. Periodically from KDB/KISAM I/O operations, form events, $BREAK, $IF & 'KCML_poll()kcml.mem.sym,size=num,total=num,com=num,const=num,defsub=num,obj=num
kcml.mem.redim_KCML_PERFMETRIC_KCML_MEM_REDIM63Number of times an array or string as been REDIMensionedMAT REDIMkcml.mem.redim,newsize=bytes,dim1=num,dim2=num,redimcnt=count,stack=string
kcml.native.open_KCML_PERFMETRIC_KCML_NATIVE_OPEN18Opening native filesOPEN #, $DEVICE, DATALOAD DC OPEN, DATASAVE DC OPENkcml.native.open,file=string,handle=num,mode=string,time=usec,device=string
kcml.native.close_KCML_PERFMETRIC_KCML_NATIVE_CLOSE18Close native fileCLOSE #, $CLOSE, $REWINDkcml.native.close,file=string,handle=num,device=string
kcml.native.io_KCML_PERFMETRIC_KCML_NATIVE_IO16Native I/OCLOSE # & periodically during READ #, WRITE #, PRINT, DATALOAD BA/BU and DATASAVE BA/BUkcml.native.io,file=string,nread=count,readbytes=count,readtime=usec,nwrite=count,writebytes=count,writetime=usec,handle=num,device=string
kcml.native.dir_KCML_PERFMETRIC_KCML_NATIVE_DIR17Directory enumerationKI_DIR, KI_DIR_LIST & 'KCML_Dir_List()kcml.native.dir,path=string,files=count,dirs=count,readtime=usec
kcml.native.lock_KCML_PERFMETRIC_KCML_NATIVE_LOCK45Native file lock$OPENkcml.native.lock,file=string,handle=num,device=string,waittime=num,locked=num,ownerpid=num,ownerpart=num,owneruuid=string
kcml.session.start_KCML_PERFMETRIC_KCML_SESSION_START22Start of a KCML sessionSession startup and $RELEASEkcml.session.start,client=string,ip=string,term=num,peerip=string,peerport=num,mac=string,rel=num,termtype=char,version=string,puuid=string,time=usec
kcml.session.end_KCML_PERFMETRIC_KCML_SESSION_END22End of a sessionEnd of a session, $ENDkcml.session.end,client=string,ip=string,term=num,peerip=string,peerport=num,mac=string,rel=num,termtype=char,status=num
kcml.session.lic_KCML_PERFMETRIC_KCML_SESSION_LIC30Session licence usageStart and end of a foreground sessionkcml.session.lic,total=num,used=num
kcml.shell.cmd_KCML_PERFMETRIC_KCML_SHELL_CMD21Shell commandSHELLkcml.shell.cmd,result=num,exectime=usec,systime=usec,usertime=usec,ptty=bool,cmd=string
kcml.tcp.open_KCML_PERFMETRIC_KCML_TCP_OPEN19TCP/IP Socket openOPEN #hSock ... "@" & SOAP clientkcml.tcp.open,address=string,port=num,time=usec,dnstime=usec,ssl=bool,tls_ver=string,error=string,handle=num,server=bool
kcml.tcp.close_KCML_PERFMETRIC_KCML_TCP_CLOSE19TCP Socket closeCLOSE #hSockkcml.tcp.close,address=string,port=num,handle=num
kcml.tcp.io_KCML_PERFMETRIC_KCML_TCP_IO20TCP Socket transfersSOAP client & server. Periodically sent during READ #hSock & WRITE #hSockkcml.tcp.io,address=string,port=num,nrecv=count,recvbytes=count,recvtime=usec,nsend=count,sendbytes=count,sendtime=usec,handle=num
kcml.udp.open_KCML_PERFMETRIC_KCML_UDP_OPEN50UDP Socket openOPEN #hSock ... "@"kcml.udp.open,handle=num
kcml.udp.close_KCML_PERFMETRIC_KCML_UDP_CLOSE50UDP Socket closeCLOSE #hSockkcml.udp.close,handle=num
kcml.udp.recv_KCML_PERFMETRIC_KCML_UDP_RECV51UDP Socket ReadREAD #hSockkcml.udp.recv,handle=num,address=string,port=num,recvbytes=count,recvtime=usec,nrecv=count
kcml.udp.send_KCML_PERFMETRIC_KCML_UDP_SEND51UDP Socket WriteWRITE #hSockkcml.udp.send,handle=num,address=string,port=num,sendbytes=count,sendtime=usec,nsend=count
kcml.soap.start_KCML_PERFMETRIC_KCML_SOAP_START28SOAP server startup timeStart of a SOAP server when generating WSDLkcml.soap.start,interface=string,wsdltime=usec,version=string,endpoint=string
kcml.soap.call_KCML_PERFMETRIC_KCML_SOAP_CALL29Detail of the execution of a SOAP server methodAfter execution of a SOAP server methodkcml.soap.call,interface=string,method=string,time=usec
kcml.soap.lic_KCML_PERFMETRIC_KCML_SOAP_LIC30SOAP licence usageStart and end of SOAP serverkcml.soap.lic,total=num,used=num
kcml.httpd.request_KCML_PERFMETRIC_KCML_HTTPD_REQUEST46HTTP requestAfter a request to a HTTP serverkcml.httpd.request,interface=string,method=string,endpoint=string,time=usec,reqsize=count,respsize=count,status=string
kcml.total.io_KCML_PERFMETRIC_KCML_TOTAL_IO23Total file & network I/OProgram LOAD, SOAP server method calls & $END. Periodically from KDB/KISAM or native file I/O operations, form events, $BREAK, $IF & 'KCML_poll()kcml.total.io,nread=count,readbytes=count,nwrite=count,writebytes=count,nreadkdb=count,readbyteskdb=count,nwritekdb=count,writebyteskdb=count,nreadnative=count,readbytesnative=count,nwritenative=count,writebytesnative=count,nreadtcp=count,readbytestcp=count,nwritetcp=count,writebytestcp=count,nreadudp=count,readbytesudp=count,nwriteudp=count,writebytesudp=count,readbyteskclient=count,writebyteskclient=count,cachedrows=count,nativehdlcnt=count,dbhdlcnt=count
kcml.load.lib_KCML_PERFMETRIC_KCML_LOAD_LIB26Library load I/OLIBRARY ADD / MODULE ADDkcml.load.lib,file=string,kar=string,size=count,loadtime=usec
kcml.load.prog_KCML_PERFMETRIC_KCML_LOAD_PROG27Program load I/OLOAD programkcml.load.prog,file=string,loadtime=usec
kcml.global.load_KCML_PERFMETRIC_KCML_GLOBAL_LOAD48Loading process global librarySELECT @PARTkcml.global.load,lib=string,size=num,globpart=num,globuuid=string
kcml.global.lock_KCML_PERFMETRIC_KCML_GLOBAL_LOCK49Locking of the global shared@LOCK / @UNLOCKkcml.global.lock,lock=bool,time=usec
kcml.xml.open_KCML_PERFMETRIC_KCML_XML_OPEN24XML_OPENXML_OPENkcml.xml.open,file=string,handle=num,size=bytes
kcml.xml.parsebuffer_KCML_PERFMETRIC_KCML_XML_PARSEBUFFER24Load XML via XML_PARSE_BUFFERXML_PARSE_BUFFERkcml.xml.parsebuffer,handle=num,size=bytes
kcml.xml.next_KCML_PERFMETRIC_KCML_XML_NEXT25Parse XMLFirst XML_NEXT callkcml.xml.next,handle=num,mem=bytes,time=usec
kcml.xml.close_KCML_PERFMETRIC_KCML_XML_CLOSE24XML_CLOSE callXML_CLOSEkcml.xml.close,handle=num
kcml.odbc.lic_KCML_PERFMETRIC_KCML_ODBC_LIC43ODBC licence usageStart up of kiodbckcml.odbc.lic,total=num,used=num,version=string
kcml.odbc.start_KCML_PERFMETRIC_KCML_ODBC_START22Start of an instance of the ODBC serverStart of an instance of the ODBC serverkcml.odbc.start,client=string
kcml.odbc.end_KCML_PERFMETRIC_KCML_ODBC_END22End of an instance of the ODBC serverEnd of an instance of the ODBC serverkcml.odbc.end,client=string,fetched=count,rows=count,status=num
kcml.odbc.prepare_KCML_PERFMETRIC_KCML_ODBC_PREPARE60Preparation of SQL planSent when an SQL plan is prepared by kiodbckcml.odbc.prepare,plan=num,handle=num,chandle=num,err=num,sql=string,time=usec,columns=count
kcml.odbc.execute_KCML_PERFMETRIC_KCML_ODBC_EXECUTE60Execution of SQL planSent when an SQL plan is executed by kiodbckcml.odbc.execute,plan=num,handle=num,chandle=num,time=usec,reclen=num,err=num
kcml.odbc.error_KCML_PERFMETRIC_KCML_ODBC_ERROR60Database errorSent when kiodbc sends an error back to the driverkcml.odbc.error,plan=num,errtext=string
kcml.odbc.fetch_KCML_PERFMETRIC_KCML_ODBC_FETCH61Result-set fetchSent periodically when the kiodbc server is sending a result set to the ODBC driverkcml.odbc.fetch,plan=num,rows=count,fetched=count,time=usec
kcml.sql.open_KCML_PERFMETRIC_KCML_SQL_OPEN31Database open tableKI_OPENkcml.sql.open,table=string,handle=num,chandle=num,mode=string,time=usec
kcml.sql.close_KCML_PERFMETRIC_KCML_SQL_CLOSE31Database close tableKI_CLOSEkcml.sql.close,table=string,handle=num,chandle=num
kcml.sql.prepare_KCML_PERFMETRIC_KCML_SQL_PREPARE32Preparation of SQL planSent when an SQL plan is prepared on an Oracle databasekcml.sql.prepare,sthandle=num,handle=num,chandle=num,sql=string,time=usec,kfn=string,err=num,plan=num
kcml.sql.execute_KCML_PERFMETRIC_KCML_SQL_EXECUTE32Execution of SQL planSent when an SQL plan is executed on an Oracle databasekcml.sql.execute,schandle=num,sthandle=num,handle=num,chandle=num,time=usec,err=num,plan=num
kcml.sql.fetch_KCML_PERFMETRIC_KCML_SQL_FETCH33Result-set fetchSent periodically during any read/write operation on an Oracle database table & KI_END or KI_CLOSEkcml.sql.fetch,sthandle=num,handle=num,chandle=num,rows=count,time=usec,plan=num
kcml.sql.lobread_KCML_PERFMETRIC_KCML_SQL_LOBREAD33LOB readSent periodically during any read/write operation on an Oracle database tablekcml.sql.lobread,handle=num,chandle=num,schandle=num,size=num,time=usec
kcml.sql.bindin_KCML_PERFMETRIC_KCML_SQL_BINDIN38Binding of input parametersSent during & after the execution of the SQL plan on an Oracle databasekcml.sql.bindin,sthandle=num,handle=num,chandle=num,name=string,size=num,type=string,ind=num,fmt=string,value=string
kcml.sql.transstart_KCML_PERFMETRIC_KCML_SQL_TRANSSTART41Transaction startStart of a transaction. Oracle databases onlykcml.sql.transstart,chandle=num,schandle=num,flags=num,err=num
kcml.sql.transrollback_KCML_PERFMETRIC_KCML_SQL_TRANSROLLBACK41Transaction rollbackTransaction rollback. Oracle databases onlykcml.sql.transrollback,chandle=num,schandle=num,time=usec,err=num
kcml.sql.transcommit_KCML_PERFMETRIC_KCML_SQL_TRANSCOMMIT41Transaction commitTransaction commit. Oracle database onlykcml.sql.transcommit,chandle=num,schandle=num,time=usec,err=num
kcml.sql.transdetach_KCML_PERFMETRIC_KCML_SQL_TRANSDETACH41Transaction detachStart of an autonomous transaction. Oracle databases onlykcml.sql.transdetach,chandle=num,schandle=num,flags=num,err=num
kcml.sql.total_KCML_PERFMETRIC_KCML_SQL_TOTAL35Total remote database loadProgram LOAD, SOAP server method calls, form events & $END. Periodically from database or native file I/O operations, $BREAK, $IF & 'KCML_poll()kcml.sql.total,prepcnt=num,execcnt=num,fetchcnt=num,lobrds=num,ptime=usec,etime=usec,ftime=usec,ltime=usec,hdlcnt=num,curscnt=num
kcml.sql.error_KCML_PERFMETRIC_KCML_SQL_ERROR40Database errorLookup of an error caused by the failure of a database function callkcml.sql.error,handle=num,chandle=num,err=num
kcml.sql.handlealloc_KCML_PERFMETRIC_KCML_SQL_HANDLEALLOC44Allocate handleKI_OPEN, KI_PREPAREkcml.sql.handlealloc,handle=num,chandle=num,sthandle=num
kcml.sql.handlefree_KCML_PERFMETRIC_KCML_SQL_HANDLEFREE44Free handleKI_END, KI_CLOSE, LOAD & $SPACEkcml.sql.handlefree,handle=num,chandle=num,sthandle=num
kcml.sql.opttranstime_KCML_PERFMETRIC_KCML_SQL_OPTTRANSTIME62Time taken to commit an optimistic transactionUser input, LOAD, $BREAK, $IF, KI_CLOSEkcml.sql.opttranstime,chandle=num,time=usec,stack=string
kcml.sql.ddl_KCML_PERFMETRIC_KCML_SQL_DDL66DDL executed in DBAny DDL executed in DBkcml.sql.ddl,handle=num,chandle=num,sql=string,stack=string
kcml.sql.tableddl_KCML_PERFMETRIC_KCML_SQL_TABLEDDL67DDL executed in DBAny table DDL executed in DB, CREATE TABLE, DROP TABLE, RENAME, ALTER TABLEkcml.sql.tableddl,handle=num,chandle=num,sql=string,stack=string
kcml.databridge.socketwrite_KCML_PERFMETRIC_KCML_DATABRIDGE_SOCKETWRITE68Time taken to write to socket (milli-seconds)Message written to kdatadaemonkcml.databridge.socketwrite,time=num
kcml.databridge.daemonmessage_KCML_PERFMETRIC_KCML_DATABRIDGE_DAEMONMESSAGE69Message from DataBridge daemonError in kdatadaemon processingkcml.databridge.daemonmessage,message=string
kcml.cache.open_KCML_PERFMETRIC_KCML_CACHE_OPEN9Table cache openOpening of a cached tablekcml.cache.open,table=string,handle=num,chandle=num,size=num,time=usec
kcml.cache.close_KCML_PERFMETRIC_KCML_CACHE_CLOSE9Table cache closeClose of a cached tablekcml.cache.close,table=string,handle=num,chandle=num,time=usec,rows=count
kcml.cache.refresh_KCML_PERFMETRIC_KCML_CACHE_REFRESH36Database table cachingCache file is rebuiltkcml.cache.refresh,file=string,handle=num,chandle=num,size=num,time=usec
kcml.cache.reject_KCML_PERFMETRIC_KCML_CACHE_REJECT36Table cache rejectionAttempting to cache a table that is too largekcml.cache.reject,table=string,handle=num,chandle=num
kcml.cache.read_KCML_PERFMETRIC_KCML_CACHE_READ55Table cache readSent periodically while reading from a cached tablekcml.cache.read,table=string,handle=num,chandle=num,rows=count
kcml.lic.open_KCML_PERFMETRIC_KCML_LIC_OPEN37Lookup of a [Section] and key=value from the application server's licence file$LIC()kcml.lic.open,file=string,section=string,key=string,value=string,time=usec,found=bool
kcml.lic.client_KCML_PERFMETRIC_KCML_LIC_CLIENT37Lookup of a [Section] and key=value from the client's licence file$LIC()kcml.lic.client,section=string,key=string,value=string,time=usec,found=bool
kcml.proc.stacktrace_KCML_PERFMETRIC_KCML_PROC_STACKTRACE42Program stack trace. The flag is temporary and is unset when the perfmetric metric is sent.After execution of a statement that has been signalled with bkstat -K<part>:SIGUSR2:Stacktracekcml.proc.stacktrace,stack=string
kcml.jclient.req_KCML_PERFMETRIC_KCML_JCLIENT_REQ52Browser client request timesSent periodically while processing requests from the browser clientkcml.jclient.req,network=usec,render=usec,wcm=usec,event=usec,resp=usec,sent=count,recv=count
kcml.translate.form_KCML_PERFMETRIC_KCML_TRANSLATE_FORM57Warning of missing translations in a DEFFORMForm.Terminate()kcml.translate.form,lang=num,form=string,prog=string,count=count
kcml.translate.missing_KCML_PERFMETRIC_KCML_TRANSLATE_MISSING57Warning of a missing translation in a chevron stringLOAD program & $ENDkcml.translate.missing,lang=num,prog=string,line=num,stat=num,count=num
kcml.translate.clipped_KCML_PERFMETRIC_KCML_TRANSLATE_CLIPPED57Translated strings clipped on rendering in the clientForm.Open()kcml.translate.clipped,form=string,ctrl=string,context=string,label=string,text=string,dpi=num,screenw=num,screenh=num,formw=num,formh=num,ctrlw=num,textw=num,extra=string
kcml.x509.expiry_KCML_PERFMETRIC_KCML_X509_EXPIRY65Warn of SSL certificate expirykcml.x509.expiry,type=string,validto=string,subject=string,san=string,issuer=string,path=string,daysremaining=num,selfsigned=num,peer=num

The [perfmetric] section supports the following settings:-

MetricKeyDefault ValueRequiredDescription
kcml.declare.totaldecltimerfreq25 Optional Number of $DECLARE calls between checking time of last send of kcml.declare.total
kcml.kdb.dupidxiomaxdupidx100000 Optional Max number of index blocks we read while scanning for a dup idx, if we exceed that limit issue a kcml.kdb.dupidxio
kcml.kdb.transtimemaxtranstime2 Optional If a transaction takes longer than this timeout (in seconds) then issue a kcml.kdb.transtime
kcml.kdb.startiomaxstartio5000 Optional Max KI_START io
kcml.mem.deltamem65536 Optional Default threshold, in kilobytes, for kcml.mem.delta
kcml.mem.redimmaxredim50 Optional Threshold of number of REDIMs on an array/string
kcml.native.locklockwaitalert2 Optional If a lock takes longer than this timeout (in seconds) then issue a kcml.native.lock
kcml.translate.missingmaxtranslatemissing2 Optional Max number of kcml.translate.missing metrics to report
kcml.x509.expiryx509warndays30 Optional How many days before we warn of X509 cert expiry
pubkey"" Optional Public key used to verify the security token
tokentimestampmargin300 Optional Maximum difference of the timestamp in the security token and the current time.
perfopenfileFALSE Optional Flag to allow 'KCML_PerfMetric_OpenFile() to work with signatures
iotimerfreq100 Optional Number of I/O operations between checking the time between periodic metrics
logperiod600 Optional Number of seconds between reporting periodic metrics, such as kcml.kdb.io
suppressverifyFALSE Optional Flag to disable token verification on internal development systems
queue"" Required Queue name for performance metrics

Application Performance Metrics

Application code may also be instrumented. As all KCML internal performance metrics use microseconds it is also recommended to do the same. An application's metric name may be any string value except that is must not begin with "kcml".

The example below uses 'KCML_PerfTimer_Start() and 'KCML_PerfTimer_Stop() to measure how long a subroutime took to execute and then sends the statistics to the RabbitMQ server using 'KCML_PerfMetric_Send().

00010 'main()
    : $END
    : DEFSUB 'main()
    : LOCAL DIM rTimes$_kcml_perftimerrec
    : LOCAL DIM nTimerId AS integer
    : 
    : REM Start a performance timer
    : ntimerid = 'KCML_PerfTimer_Start()
    : 
    : REM call the code to be monitored
    : 'doSomeThing()
    : 
    : REM Stop the performance timer
    : 'KCML_PerfTimer_Stop(ntimerid,BYREF rTimes$)
    : REM Report the statistic
    : 'KCML_PerfMetric_Send("","my.app.metric",$PRINTF("elapsed=%d,exectime=%d,usertime=%d,kerneltime=%d",FLD(rTimes$.KCML_PerfTimer_Elapsed),FLD(rTimes$.KCML_PerfTimer_Exec),FLD(rTimes$.KCML_PerfTimer_User),FLD(rTimes$.KCML_PerfTimer_Kernel)))
    : END SUB
    : 
    : REM Fake up application processor and idle time
    : DEFSUB 'doSomeThing()
    : LOCAL DIM i AS integer
    : LOCAL DIM j AS integer
    : LOCAL DIM rc
    : LOCAL DIM a$0
    : 
    : FOR i = 1 TO 1000
    :     REM Fake up execution time
    :     FOR j = 1 TO 1000
    :         REDIM a$ = $UPPER("quick brown fox")
    :     NEXT j
    :     REM Fake up idle time by pausing for 1 millisecond
    :     rc = $IF,1
    : NEXT i
    : END SUB

The final message sent via 'KCML_PerfMetric_Send() is the application's metric name followed by the common set of identifiers and then finally the list of statistics the application has measured.
For example, the above program may report the following to the message queue:-

my.app.metric,host="myserver",user="fred",pid=29583,uuid="e8bf5cba-183f-40c8-9e30-cf5674c9ee3f",ts=1490374670046022,exe="kcml",part=2048,elapsed=2372010,exectime=160416,usertime=163000,kerneltime=19000

ODBC Performance Metrics

The 07.22 version of kiodbc will also produce performance metrics in the same way as KCML. As kiodbc processes tend to be short-lived & they are not interactive there is little opportunity to enable additional metrics on a running process. It may also be desireable to only have kiodbc report certain database metrics such as kcml.kdb.io, as a KCML process may produce too many messages. Additional metrics for kiodbc can be configured by listing them in the [odbc] section of /etc/kcml/msgq.conf :-

# Additional default metrics for kiodbc only
[odbc]
kcml.kdb.io=1
kcml.kdb.fetch=1
kcml.odbc.fetch=1
kcml.odbc.prepare=1