The perfstat application programming interface (API) is a collection of C programming language subroutines that execute in user space and uses the perfstat kernel extension to extract various AIX performance metrics. System component information is also retrieved from the Object Data Manager (ODM) and returned with the performance metrics.
The perfstat API is both a 32-bit and a 64-bit API, is thread-safe, and does not require root authority.
The API supports extensions so binary compatibility is maintained across all releases. This is accomplished by using one of the parameters in all the API calls to specify the size of the data structure to be returned. This allows the library to easily determine which version is in use, as long as the structures are only growing, which is guaranteed. This releases the user from version dependencies. For the list of extensions made in earlier versions of AIX, see the Change History section.
The perfstat API subroutines reside in the libperfstat.a library and are part of the bos.perf.libperfstat fileset, which is installable from the AIX base installation media and requires that the bos.perf.perfstat fileset is installed. The later contains the kernel extension and is automatically installed with AIX.
The /usr/include/libperfstat.h file contains the interface declarations and type definitions of the data structures to use when calling the interfaces. This include file is also part of the bos.perf.libperfstat fileset. Sample source code is provided with bos.perf.libperfstat and resides in the /usr/samples/libperfstat directory. Detailed information for the individual interfaces and the data structures used can be found in the libperfstat.h file in the AIX 5L Version 5.2 Files Reference.
Two types of APIs are available. Global types return global metrics related to a set of components, while the individual types return metrics related to individual components. Both types of interfaces have similar signatures, but slightly different behavior.
All the interfaces return raw data; that is, values of running counters. Multiple calls must be made at regular intervals to calculate rates.
Several interfaces return data retrieved from the ODM (object data manager) database. This information is automatically cached into a dictionary that is assumed to be "frozen" after it is loaded. The perfstat_reset subroutine must be called to clear the dictionary whenever the machine configuration has changed.
Most types returned are unsigned long long; that is, unsigned 64-bit data. This provides complete kernel independence. Some kernel internal metrics are in fact 32-bit wide in the 32-bit kernel, and 64-bit wide in the 64-bit kernel. The corresponding libperfstat APIs data type is always unsigned 64-bit.
All of the examples presented in this chapter can be compiled in AIX 5.2 using cc with -lperfstat.
Global interfaces report metrics related to a set of components on a system (such as processors, disks, memory).
All of the following AIX 5.2 interfaces use the naming convention perfstat_subsystem_total, and use a common signature:
perfstat_cpu_total | Retrieves global CPU usage metrics |
perfstat_memory_total | Retrieves global memory usage metrics |
perfstat_disk_total | Retrieves global disk usage metrics |
perfstat_netinterface_total | Retrieves global network interfaces metrics |
The common signature used by all of the global interfaces is as follows:
int perfstat_subsystem_total(perfstat_id_t *name, perfstat_subsystem_total_t *userbuff, int sizeof_struct, int desired_number);
The usage of the parameters for all of the interfaces is as follows:
perfstat_id_t *name | Reserved for future use, should be NULL |
perfstat_subsystem_total_t *userbuff | A pointer to a memory area with enough space for the returned structure |
int sizeof_struct | Should be set to sizeof(perfstat_subsystem_t) |
int desired_number | Reserved for future use, must be set to 0 or 1 |
The return value will be -1 in case of errors. Otherwise, the number of structures copied is returned. This is always 1.
An exception to this scheme is: when name=NULL, userbuff=NULL and desired_number=0, the total number of structures available is returned. This is always 1.
The following sections provide examples of the type of data returned and code using each of the interfaces.
The perfstat_cpu_total function returns a perfstat_cpu_total_t structure, which is defined in the libperfstat.h file. Selected fields from the perfstat_cpu_total_t structure include:
processorHz | Processor speed in Hertz (from ODM) |
description | Processor type (from ODM) |
ncpus | Current number of active CPUs |
ncpus_cfg | Number of configured CPUs; that is, the maximum number of processors that this copy of AIX can handle simultaneously |
ncpus_high | Maximum number of active CPUs; that is, the maximum number of active processors since the last reboot |
user | Total number of clock ticks spent in user mode |
sys | Total number of clock ticks spent in system (kernel) mode |
idle | Total number of clock ticks spent idle with no I/O pending |
wait | Total number of clock ticks spent idle with I/O pending |
Several other processor-related counters (such as number of system calls, number of reads, write, forks, execs, and load average) are also returned. For a complete list, see the perfstat_cpu_total_t section of the libperfstat.h header file in AIX 5L Version 5.2 Files Reference.
The following code shows an example of how perfstat_cpu_total is used:
#include <stdio.h> #include <sys/time.h> #include <libperfstat.h> unsigned long long last_tot, last_user, last_sys, last_idle, last_wait; int main(int argc, char *argv[]) { perfstat_cpu_total_t cpu_total_buffer; unsigned long long cur_tot; unsigned long long delt_tot, delt_user, delt_sys, delt_idle, delt_wait; /* get initial set of data */ perfstat_cpu_total(NULL, &cpu_total_buffer, sizeof(perfstat_cpu_total_t), 1); /* print general processor information */ printf("Processors: (%d:%d) %s running at %llu MHz\n", cpu_total_buffer.ncpus, cpu_total_buffer.ncpus_cfg, cpu_total_buffer.description, cpu_total_buffer.processorHZ/1000000); /* save values for delta calculations */ last_tot = cpu_total_buffer.user + cpu_total_buffer.sys + cpu_total_buffer.idle + cpu_total_buffer.wait; last_user = cpu_total_buffer.user; last_sys = cpu_total_buffer.sys; last_idle = cpu_total_buffer.idle; last_wait = cpu_total_buffer.wait; printf("\n User Sys Idle Wait Total Rate\n"); while(1 == 1) { sleep(1); /* get new values after one second */ perfstat_cpu_total(NULL, &cpu_total_buffer, sizeof(perfstat_cpu_total_t), 1); /* calculate current total number of ticks */ cur_tot = cpu_total_buffer.user + cpu_total_buffer.sys + cpu_total_buffer.idle + cpu_total_buffer.wait; delt_user = cpu_total_buffer.user - last_user; delt_sys = cpu_total_buffer.sys - last_sys; delt_idle = cpu_total_buffer.idle - last_idle; delt_wait = cpu_total_buffer.wait - last_wait; delt_tot = cur_tot - last_tot; /* print percentages, total delta ticks and tick rate per cpu per sec */ printf("%#5.1f %#5.1f %#5.1f %#5.1f %-5llu %llu\n", 100.0 * (double) delt_user / (double) delt_tot, 100.0 * (double) delt_sys / (double) delt_tot, 100.0 * (double) delt_idle / (double) delt_tot, 100.0 * (double) delt_wait / (double) delt_tot, delt_tot, delt_tot/cpu_total_buffer.ncpus); /* save current value for next time */ last_tot = cur_tot; last_user = cpu_total_buffer.user; last_sys = cpu_total_buffer.sys; last_idle = cpu_total_buffer.idle; last_wait = cpu_total_buffer.wait; } }
The preceding program produces (on a single PowerPc 604e microprocessor-based machine) output similar to the following:
Processors: (1:1) PowerPC_604e running at 375 MHz User Sys Idle Wait Total Rate 19.0 31.0 1.0 49.0 100 100 20.8 34.7 0.0 44.6 101 101 35.0 30.0 0.0 35.0 100 100 12.0 20.0 0.0 68.0 100 100 19.0 33.0 0.0 48.0 100 100 29.0 43.0 11.0 17.0 100 100 23.0 30.0 25.0 22.0 100 100 24.0 25.0 15.0 36.0 100 100 26.0 27.0 25.0 22.0 100 100 20.0 32.0 37.0 11.0 100 100 16.0 22.0 49.0 13.0 100 100 16.0 33.0 18.0 33.0 100 100
The perfstat_memory_total function returns a perfstat_memory_total_t structure, which is defined in the libperfstat.h file. Selected fields from the perfstat_memory_total_t structure include:
virt_total | Amount of virtual memory (in units of 4 KB pages) |
real_total | Amount of real memory (in units of 4 KB pages) |
real_free | Amount of free real memory (in units of 4 KB pages) |
real_pinned | Amount of pinned memory (in units of 4 KB pages) |
pgins | Number of pages paged in |
pgouts | Number of pages paged out |
pgsp_total | Total amount of paging space (in units of 4 KB pages) |
pgsp_free | Amount of free paging space (in units of 4 KB pages) |
pgsp_rsvd | Amount of reserved paging space (in units of 4 KB pages) |
Several other memory related metrics (such as number of paging space paged in and out, and amount of system memory) are also returned. For a complete list, see the perfstat_memory_total_t section in libperfstat.h.
The following code shows an example of how perfstat_memory_total is used:
#include <stdio.h> #include <libperfstat.h> int main(int argc, char* argv[]) { perfstat_memory_total_t minfo; perfstat_memory_total(NULL, &minfo, sizeof(perfstat_memory_total_t), 1); printf("Memory statistics\n"); printf("-----------------\n"); printf("real memory size : %llu MB\n", minfo.real_total*4096/1024/1024); printf("reserved paging space : %llu MB\n",minfo.pgsp_rsvd); printf("virtual memory size : %llu MB\n", minfo.virt_total*4096/1024/1024); printf("number of free pages : %llu\n",minfo.real_free); printf("number of pinned pages : %llu\n",minfo.real_pinned); printf("number of pages in file cache : %llu\n",minfo.numperm); printf("total paging space pages : %llu\n",minfo.pgsp_total); printf("free paging space pages : %llu\n", minfo.pgsp_free); printf("used paging space : %3.2f%%\n", (float)(minfo.pgsp_total-minfo.pgsp_free)*100.0/ (float)minfo.pgsp_total); printf("number of paging space page ins : %llu\n",minfo.pgspins); printf("number of paging space page outs : %llu\n",minfo.pgspouts); printf("number of page ins : %llu\n",minfo.pgins); printf("number of page outs : %llu\n",minfo.pgouts); }
The preceding program produces output similar to the following:
Memory statistics ----------------- real memory size : 256 MB reserved paging space : 512 MB virtual memory size : 768 MB number of free pages : 32304 number of pinned pages : 6546 number of pages in file cache : 12881 total paging space pages : 131072 free paging space pages : 129932 used paging space : 0.87% number of paging space page ins : 0 number of paging space page outs : 0 number of page ins : 20574 number of page outs : 92508
The perfstat_disk_total function returns a perfstat_disk_total_t structure, which is defined in the libperfstat.h file. Selected fields from the perfstat_disk_total_t structure include:
number | Number of disks |
size | Total disk size (in MB) |
free | Total free disk space (in MB) |
xfers | Total transfers to/from disk (in KB) |
Several other disk-related metrics, such as number of blocks read from and written to disk, are also returned. For a complete list, see the perfstat_disk_total_t section in libperfstat.h.
The following code shows an example of how perfstat_disk_total is used:
#include <stdio.h> #include <libperfstat.h> int main(int argc, char* argv[]) { perfstat_disk_total_t dinfo; perfstat_disk_total(NULL, &dinfo, sizeof(perfstat_disk_total_t), 1); printf("Total disk statistics\n"); printf("---------------------\n"); printf("number of disks : %d\n", dinfo.number); printf("total disk space : %llu\n", dinfo.size); printf("total free space : %llu\n", dinfo.free); printf("number of transfers : %llu\n", dinfo.xfers); printf("number of blocks written : %llu\n", dinfo.wblks); printf("number of blocks read : %llu\n", dinfo.rblks); }
This program produces output similar to the following:
Total disk statistics --------------------- number of disks : 3 total disk space : 4296 total free space : 2912 number of transfers : 77759 number of blocks written : 738016 number of blocks read : 363120
The perfstat_netinterface_total function returns a perfstat_netinterface_total_t structure, which is defined in the libperfstat.h file. Selected fields from the perfstat_netinterface_total_t structure include:
number | Number of network interfaces |
ipackets | Total number of input packets received on all network interfaces |
opackets | Total number of output packets sent on all network interfaces |
ierror | Total number of input errors on all network interfaces |
oerror | Total number of output errors on all network interfaces |
Several other network interface related metrics (such as number of bytes sent and received). For a complete list, see the perfstat_netinterface_total_t section in libperfstat.h .
The following code shows an example of how perfstat_netinterface_total is used:
#include <stdio.h> #include <libperfstat.h> int main(int argc, char* argv[]) { perfstat_netinterface_total_t ninfo; perfstat_netinterface_total(NULL, &ninfo, sizeof(perfstat_netinterface_total_t), 1); printf("Network interfaces statistics\n"); printf("-----------------------------\n"); printf("number of interfaces : %d\n", ninfo.number); printf("\ninput statistics:\n"); printf("number of packets : %llu\n", ninfo.ipackets); printf("number of errors : %llu\n", ninfo.ierrors); printf("number of bytes : %llu\n", ninfo.ibytes); printf("\noutput statistics:\n"); printf("number of packets : %llu\n", ninfo.opackets); printf("number of bytes : %llu\n", ninfo.obytes); printf("number of errors : %llu\n", ninfo.oerrors); }
The program above produces output similar to this:
Network interfaces statistics ----------------------------- number of interfaces : 2 input statistics: number of packets : 306688 number of errors : 0 number of bytes : 24852688 output statistics: number of packets : 63005 number of bytes : 11518591 number of errors : 0
Component-specific interfaces report metrics related to individual components on a system (such as a processor, disk, network interface, or paging space).
All of the following interfaces use the naming convention perfstat_subsystem, and use a common signature:
perfstat_cpu | Retrieves individual CPU usage metrics |
perfstat_disk | Retrieves individual disk usage metrics |
perfstat_diskadapter | Retrieves individual disk adapter metrics |
perfstat_netinterface | Retrieves individual network interfaces metrics |
perfstat_protocol | Retrieves individual network protocol related metrics |
perfstat_netbuffer | Retrieves individual network buffer allocation metrics |
perfstat_pagingspace | Retrieves individual paging space metrics |
The common signature used by all the component interfaces is as follows:
int perfstat_subsystem(perfstat_id *name, perfstat_subsystem_t * userbuff, int sizeof_struct, int desired_number);
The usage of the parameters for all of the interfaces is as follows:
perfstat_id_t *name | The name of the first component (for example hdisk2 for perfstat_disk()) for which statistics are desired. A structure containing a char * field is used instead of directly passing a char * argument to the function to avoid allocation errors and to prevent the user from giving a constant string as parameter. To start from the first component of a subsystem, set the char* field of the name parameter to "" (empty string). You can also use the macros such as FIRST_SUBSYSTEM (for example,FIRST_CPU) defined in the libperfstat.h file. |
perfstat_subsystem_total_t *userbuff | A pointer to a memory area with enough space for the returned structure(s). |
int sizeof_struct | Should be set to sizeof(perfstat_subsystem_t). |
int desired_number | The number of structures of type perfstat_subsystem_t to return in userbuff. |
The return value will be -1 in case of error. Otherwise, the number of structures copied is returned. The field name is either set to NULL or to the name of the next structure available.
An exception to this scheme is when name=NULL, userbuff=NULL and desired_number=0, the total number of structures available is returned.
To retrieve all structures of a given type, either ask first for their number, allocate enough memory to hold them all at once, then call the appropriate API to retrieve them all in one call. Otherwise, allocate a fixed set of structures and repeatedly call the API to get the next such number of structures, each time passing the name returned by the previous call. Start the process with the name set to "" or FIRST_SUBSYSTEM, and repeat the process until the name returned is equal to "".
Minimizing the number of API calls, and therefore the number of system calls, will always lead to more efficient code, so the two-call approach should be preferred. Some of the examples shown in the following sections illustrate the API usage using the two-call approach. Because the two-call approach can lead to a lot of memory being allocated, the multiple-call approach must sometime be used and is illustrated in the following examples.
The following sections provide examples of the type of data returned and code using each of the interfaces.
The perfstat_cpu function returns a set of structures of type perfstat_cpu_t, which is defined in the libperfstat.h file. Selected fields from the perfstat_cpu_t structure include:
name | Logical CPU name (cpu0, cpu1, ...) |
user | Number of clock ticks spent in user mode |
sys | Number of clock ticks spent in system (kernel) mode |
idle | Number of clock ticks spent idle with no I/O pending |
wait | Number of clock ticks spent idle with I/O pending |
syscall | Number of system call executed |
Several other CPU related metrics (such as number of forks, read, write, and execs) are also returned. For a complete list, see the perfstat_cpu_t section in the libperfstat.h file.
The following code shows an example of how perfstat_cpu is used:
#include <stdio.h> #include <stdlib.h> #include <libperfstat.h> int main(int argc, char *argv[]) { int i, retcode, cputotal; perfstat_id_t firstcpu; perfstat_cpu_t *statp; /* check how many perfstat_cpu_t structures are available */ cputotal = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0); printf("number of perfstat_cpu_t available : %d\n", cputotal); /* allocate enough memory for all the structures */ statp = calloc(cputotal,sizeof(perfstat_cpu_t)); /* set name to first cpu */ strcpy(firstcpu.name, FIRST_CPU); /* ask to get all the structures available in one call */ retcode = perfstat_cpu(&firstcpu, statp, sizeof(perfstat_cpu_t), cputotal); /* return code is number of structures returned */ printf("number of perfstat_cpu_t returned : %d\n", retcode); for (i = 0; i < retcode; i++) { printf("\nStatistics for CPU : %s\n", statp[i].name); printf("------------------\n"); printf("CPU user time (raw ticks) : %llu\n", statp[i].user); printf("CPU sys time (raw ticks) : %llu\n", statp[i].sys); printf("CPU idle time (raw ticks) : %llu\n", statp[i].idle); printf("CPU wait time (raw ticks) : %llu\n", statp[i].wait); printf("number of syscalls : %llu\n", statp[i].syscall); printf("number of readings : %llu\n", statp[i].sysread); printf("number of writings : %llu\n", statp[i].syswrite); printf("number of forks : %llu\n", statp[i].sysfork); printf("number of execs : %llu\n", statp[i].sysexec); printf("number of char read : %llu\n", statp[i].readch); printf("number of char written : %llu\n", statp[i].writech); } }
On a single processor machine, the preceding program produces output similar to the following:
number of perfstat_cpu_t available : 1 number of perfstat_cpu_t returned : 1 Statistics for CPU : cpu0 ------------------ CPU user time (raw ticks) : 1336297 CPU sys time (raw ticks) : 111958 CPU idle time (raw ticks) : 57069585 CPU wait time (raw ticks) : 19545 number of syscalls : 4734311 number of readings : 562121 number of writings : 323367 number of forks : 6839 number of execs : 7257 number of char read : 753568874 number of char written : 132494990
In an environment where dynamic logical partitioning is used, the number of perfstat_cpu_t structures available will always be equal to the ncpus_high field in the perfstat_cpu_total_t. This number represents the highest index of any active processor since the last reboot. Kernel data structures holding performance metrics for processors are not deallocated when processors are turned offline or moved to a different partition. They simply stop being updated. The ncpus field of the perfstat_cpu_total_t structure always represents the number of active processors, but the perfstat_cpu interface will always return ncpus_high structures.
Applications can detect offline or moved processors by checking clock-tick increments. If the sum of the user, sys, idle and wait fields is identical for a given processor between two perfstat_cpu calls, that processor has been offline for the complete interval. If the sum multiplied by 10 ms (the value of a clock tick) does not match the time interval, the processor has not been online for the complete interval.
The perfstat_disk function returns a set of structures of type perfstat_disk_t, which is defined in the libperfstat.h file. Selected fields from the perfstat_disk_t structure include:
name | Disk name (from ODM) |
description | Disk description (from ODM) |
vgname | Volume group name (from ODM) |
size | Disk size (in MB) |
free | Free space (in MB) |
xfers | Transfers to/from disk (in KB) |
Several other disk related metrics (such as number of blocks read from and written to disk, and adapter names) are also returned. For a complete list, see the perfstat_disk_t section in the libperfstat.h header file.
The following code shows an example of how perfstat_disk is used:
#include <stdio.h> #include <stdlib.h> #include <libperfstat.h> int main(int argc, char* argv[]) { int i, ret, tot; perfstat_disk_t *statp; perfstat_id_t first; /* check how many perfstat_disk_t structures are available */ tot = perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0); /* allocate enough memory for all the structures */ statp = calloc(tot, sizeof(perfstat_disk_t)); /* set name to first interface */ strcpy(first.name, FIRST_DISK); /* ask to get all the structures available in one call */ /* return code is number of structures returned */ ret = perfstat_disk(&first, statp, sizeof(perfstat_disk_t), tot); /* print statistics for each of the disks */ for (i = 0; i < ret; i++) { printf("\nStatistics for disk : %s\n", statp[i].name); printf("-------------------\n"); printf("description : %s\n", statp[i].description); printf("volume group name : %s\n", statp[i].vgname); printf("adapter name : %s\n", statp[i].adapter); printf("size : %llu MB\n", statp[i].size); printf("free space : %llu MB\n", statp[i].free); printf("number of blocks read : %llu\n", statp[i].rblks); printf("number of blocks written : %llu\n", statp[i].wblks); } }
The preceding program produces output similar to the following:
Statistics for disk : hdisk1 ------------------- description : 16 Bit SCSI Disk Drive volume group name : rootvg adapter name : scsi0 size : 4296 MB free space : 2912 MB number of blocks read : 403946 number of blocks written : 768176 Statistics for disk : hdisk0 ------------------- description : 16 Bit SCSI Disk Drive volume group name : None adapter name : scsi0 size : 0 MB free space : 0 MB number of blocks read : 0 number of blocks written : 0 Statistics for disk : cd0 ------------------- description : SCSI Multimedia CD-ROM Drive volume group name : not available adapter name : scsi0 size : 0 MB free space : 0 MB number of blocks read : 3128 number of blocks written : 0
The perfstat_diskadapter function returns a set of structures of type perfstat_diskadapter_t, which is defined in the libperfstat.h file. Selected fields from the perfstat_diskadapter_t structure include:
name | Adapter name (from ODM) |
description | Adapter description (from ODM) |
size | Total disk size connected to this adapter (in MB) |
free | Total free space on disks connected to this adapter (in MB) |
xfers | Total transfers to/from this adapter (in KB) |
Several other disk adapter related metrics (such as the number of blocks read from and written to the adapter) are also returned. For a complete list, see the perfstat_diskadapter_t section in libperfstat.h.
The following code shows an example of how perfstat_diskadapter is used:
#include <stdio.h> #include <stdlib.h> #include <libperfstat.h> int main(int argc, char* argv[]) { int i, ret, tot; perfstat_diskadapter_t *statp; perfstat_id_t first; /* check how many perfstat_diskadapter_t structures are available */ tot = perfstat_diskadapter(NULL, NULL, sizeof(perfstat_diskadapter_t), 0); /* allocate enough memory for all the structures */ statp = calloc(tot, sizeof(perfstat_diskadapter_t)); /* set name to first interface */ strcpy(first.name, FIRST_DISK); /* ask to get all the structures available in one call */ /* return code is number of structures returned */ ret = perfstat_diskadapter(&first, statp, sizeof(perfstat_diskadapter_t), tot); /* print statistics for each of the disk adapters */ for (i = 0; i < ret; i++) { printf("\nStatistics for adapter : %s\n", statp[i].name); printf("----------------------\n"); printf("description : %s\n", statp[i].description); printf("number of disks connected : %d\n", statp[i].number); printf("total disk size : %llu MB\n", statp[i].size); printf("total disk free space : %llu MB\n", statp[i].free); printf("number of blocks read : %llu\n", statp[i].rblks); printf("number of blocks written : %llu\n", statp[i].wblks); } }
The preceding program produces output similar to the following:
Statistics for adapter : scsi0 ---------------------- description : Wide/Fast-20 SCSI I/O Controller number of disks connected : 3 total disk size : 4296 MB total disk free space : 2912 MB number of blocks read : 411284 number of blocks written : 768256
The perfstat_netinterface function returns a set of structures of type perfstat_netinterface_t, which is defined in the libperfstat.h file. Selected fields from the perfstat_netinterface_t structure include:
name | Interface name (from ODM) |
description | Interface description (from ODM) |
ipackets | Total number of input packets received on this network interface |
opackets | Total number of output packets sent on this network interface |
ierror | Total number of input errors on this network interface |
oerror | Total number of output errors on this network interface |
Several other network interface related metrics (such as number of bytes sent and received, type, and bitrate) are also returned. For a complete list, see the perfstat_netinterface_t section in the libperfstat.h file.
The following code shows an example of how perfstat_netinterfaceis used:
#include <stdio.h> #include <stdlib.h> #include <libperfstat.h> #include <net/if_types.h> char * decode(uchar type) { switch(type) { case IFT_LOOP: return("loopback"); case IFT_ISO88025: return("token-ring"); case IFT_ETHER: return("ethernet"); } return("other"); } int main(int argc, char* argv[]) { int i, ret, tot; perfstat_netinterface_t *statp; perfstat_id_t first; /* check how many perfstat_netinterface_t structures are available */ tot = perfstat_netinterface(NULL, NULL, sizeof(perfstat_netinterface_t), 0); /* allocate enough memory for all the structures */ statp = calloc(tot, sizeof(perfstat_netinterface_t)); /* set name to first interface */ strcpy(first.name, FIRST_NETINTERFACE); /* ask to get all the structures available in one call */ /* return code is number of structures returned */ ret = perfstat_netinterface(&first, statp, sizeof(perfstat_netinterface_t), tot); /* print statistics for each of the interfaces */ for (i = 0; i < ret; i++) { printf("\nStatistics for interface : %s\n", statp[i].name); printf("------------------------\n"); printf("type : %s\n", decode(statp[i].type)); printf("\ninput statistics:\n"); printf("number of packets : %llu\n", statp[i].ipackets); printf("number of errors : %llu\n", statp[i].ierrors); printf("number of bytes : %llu\n", statp[i].ibytes); printf("\noutput statistics:\n"); printf("number of packets : %llu\n", statp[i].opackets); printf("number of bytes : %llu\n", statp[i].obytes); printf("number of errors : %llu\n", statp[i].oerrors); } }
The preceding program produces output similar to the following:
Statistics for interface : tr0 ------------------------ type : token-ring input statistics: number of packets : 306352 number of errors : 0 number of bytes : 24831776 output statistics: number of packets : 62669 number of bytes : 11497679 number of errors : 0 Statistics for interface : lo0 ------------------------ type : loopback input statistics: number of packets : 336 number of errors : 0 number of bytes : 20912 output statistics: number of packets : 336 number of bytes : 20912 number of errors : 0
The perfstat_protocol function returns a set of structures of type perfstat_protocol_t, which consists of a set of unions to accommodate the different sets of fields needed for each protocol, as defined in the libperfstat.h file. Selected fields from the perfstat_protocol_t structure include:
name | protocol name: ip, ip6, icmp, icmp6, udp, tcp, rpc, nfs, nfsv2 or nfsv3. |
ipackets | Number of input packets received using this protocol. This field exists only for protocols ip, ipv6, udp, and tcp. |
opackets | Number of output packets sent using this protocol. This field exists only for protocols ip, ipv6, udp, and tcp. |
received | Number of packets received using this protocol. This field exists only for protocols icmp and icmpv6. |
calls | Number of calls made to this protocol. This field exists only for protocols rpc, nfs, nfsv2, and nfsv3. |
Many other network protocol related metrics are also returned. The complete set of metrics printed by nfsstat is returned for instance. For a complete list, see the perfstat_protocol_t section in the libperfstat.h file.
The following code shows an example of how perfstat_protocol is used:
#include <stdio.h> #include <string.h> #include <libperfstat.h> int main(int argc, char* argv[]) { int ret, tot, retrieved = 0; perfstat_protocol_t pinfo; perfstat_id_t protid; /* check how many perfstat_protocol_t structures are available */ tot = perfstat_protocol(NULL, NULL, sizeof(perfstat_protocol_t), 0); printf("number of protocol usage structures available : %d\n", tot); /* set name to first protocol */ strcpy(protid.name, FIRST_PROTOCOL); /* retrieve first protocol usage information */ ret = perfstat_protocol(&protid, &pinfo, sizeof(perfstat_protocol_t), 1); retrieved += ret; do { printf("\nStatistics for protocol : %s\n", pinfo.name); printf("-----------------------\n"); if (!strcmp(pinfo.name,"ip")) { printf("number of input packets : %llu\n", pinfo.ip.ipackets); printf("number of input errors : %llu\n", pinfo.ip.ierrors); printf("number of output packets : %llu\n", pinfo.ip.opackets); printf("number of output errors : %llu\n", pinfo.ip.oerrors); } else if (!strcmp(pinfo.name,"ipv6")) { printf("number of input packets : %llu\n", pinfo.ipv6.ipackets); printf("number of input errors : %llu\n", pinfo.ipv6.ierrors); printf("number of output packets : %llu\n", pinfo.ipv6.opackets); printf("number of output errors : %llu\n", pinfo.ipv6.oerrors); } else if (!strcmp(pinfo.name,"icmp")) { printf("number of packets received : %llu\n", pinfo.icmp.received); printf("number of packets sent : %llu\n", pinfo.icmp.sent); printf("number of errors : %llu\n", pinfo.icmp.errors); } else if (!strcmp(pinfo.name,"icmpv6")) { printf("number of packets received : %llu\n", pinfo.icmpv6.received); printf("number of packets sent : %llu\n", pinfo.icmpv6.sent); printf("number of errors : %llu\n", pinfo.icmpv6.errors); } else if (!strcmp(pinfo.name,"udp")) { printf("number of input packets : %llu\n", pinfo.udp.ipackets); printf("number of input errors : %llu\n", pinfo.udp.ierrors); printf("number of output packets : %llu\n", pinfo.udp.opackets); } else if (!strcmp(pinfo.name,"tcp")) { printf("number of input packets : %llu\n", pinfo.tcp.ipackets); printf("number of input errors : %llu\n", pinfo.tcp.ierrors); printf("number of output packets : %llu\n", pinfo.tcp.opackets); } else if (!strcmp(pinfo.name,"rpc")) { printf("client statistics:\n"); printf("number of connection-oriented RPC requests : %llu\n", pinfo.rpc.client.stream.calls); printf("number of rejected connection-oriented RPCs : %llu\n", pinfo.rpc.client.stream.badcalls); printf("number of connectionless RPC requests : %llu\n", pinfo.rpc.client.dgram.calls); printf("number of rejected connectionless RPCs : %llu\n", pinfo.rpc.client.dgram.badcalls); printf("\nserver statistics:\n"); printf("number of connection-oriented RPC requests : %llu\n", pinfo.rpc.server.stream.calls); printf("number of rejected connection-oriented RPCs : %llu\n", pinfo.rpc.server.stream.badcalls); printf("number of connectionless RPC requests : %llu\n", pinfo.rpc.server.dgram.calls); printf("number of rejected connectionless RPCs : %llu\n", pinfo.rpc.server.dgram.badcalls); } else if (!strcmp(pinfo.name,"nfs")) { printf("total number of NFS client requests : %llu\n", pinfo.nfs.client.calls); printf("total number of NFS client failed calls : %llu\n", pinfo.nfs.client.badcalls); printf("total number of NFS server requests : %llu\n", pinfo.nfs.server.calls); printf("total number of NFS server failed calls : %llu\n", pinfo.nfs.server.badcalls); printf("total number of NFS version 2 server calls : %llu\n", pinfo.nfs.server.public_v2); printf("total number of NFS version 3 server calls : %llu\n", pinfo.nfs.server.public_v3); } else if (!strcmp(pinfo.name,"nfsv2")) { printf("number of NFS V2 client requests : %llu\n", pinfo.nfsv2.client.calls); printf("number of NFS V2 server requests : %llu\n", pinfo.nfsv2.server.calls); } else if (!strcmp(pinfo.name,"nfsv3")) { printf("number of NFS V3 client requests : %llu\n", pinfo.nfsv3.client.calls); printf("number of NFS V3 server requests : %llu\n", pinfo.nfsv3.server.calls); } /* make sure we stop after the last protocol */ if (ret = strcmp(protid.name, "")) { printf("\nnext protocol name : %s\n", protid.name); /* retrieve information for next protocol */ ret = perfstat_protocol(&protid, &pinfo, sizeof(perfstat_protocol_t), 1); retrieved += ret; } } while (ret == 1); printf("\nnumber of protocol usage structures retrieved : %d\n", retrieved); }
The preceding program produces output similar to the following:
number of protocol usage structures available : 10 Statistics for protocol : ip ----------------------- number of input packets : 142839 number of input errors : 54665 number of output packets : 63974 number of output errors : 55878 next protocol name : ipv6 Statistics for protocol : ipv6 ----------------------- number of input packets : 0 number of input errors : 0 number of output packets : 0 number of output errors : 0 next protocol name : icmp Statistics for protocol : icmp ----------------------- number of packets received : 35 number of packets sent : 1217 number of errors : 0 next protocol name : icmpv6 Statistics for protocol : icmpv6 ----------------------- number of packets received : 0 number of packets sent : 0 number of errors : 0 next protocol name : udp Statistics for protocol : udp ----------------------- number of input packets : 4316 number of input errors : 0 number of output packets : 308 next protocol name : tcp Statistics for protocol : tcp ----------------------- number of input packets : 82604 number of input errors : 0 number of output packets : 62250 next protocol name : rpc Statistics for protocol : rpc ----------------------- client statistics: number of connection-oriented RPC requests : 375 number of rejected connection-oriented RPCs : 0 number of connectionless RPC requests : 20 number of rejected connectionless RPCs : 0 server statistics: number of connection-oriented RPC requests : 32 number of rejected connection-oriented RPCs : 0 number of connectionless RPC requests : 0 number of rejected connectionless RPCs : 0 next protocol name : nfs Statistics for protocol : nfs ----------------------- total number of NFS client requests : 375 total number of NFS client failed calls : 0 total number of NFS server requests : 32 total number of NFS server failed calls : 0 total number of NFS version 2 server calls : 0 total number of NFS version 3 server calls : 0 next protocol name : nfsv2 Statistics for protocol : nfsv2 ----------------------- number of NFS V2 client requests : 0 number of NFS V2 server requests : 0 next protocol name : nfsv3 Statistics for protocol : nfsv3 ----------------------- number of NFS V3 client requests : 375 number of NFS V3 server requests : 32 number of protocol usage structures retrieved : 10
The perfstat_netbuffer function returns a set of structures of type perfstat_netbuffer_t, which is defined in the libperfstat.hfile. Selected fields from the perfstat_netbuffer_t structure include:
size | Size of the allocation (string expressing size in bytes) |
inuse | Current allocation of this size |
failed | Failed allocation of this size |
free | Free list for this size |
Several other allocation related metrics (such as high-water mark and freed) are also returned. For a complete list, see the perfstat_netbuffer_t section in the libperfstat.h file.
The following code shows an example of how perfstat_netbuffer is used:
#include <stdio.h> #include <stdlib.h> #include <libperfstat.h> int main(int argc, char* argv[]) { int i, ret, tot; perfstat_netbuffer_t *statp; perfstat_id_t first; /* check how many perfstat_netbuffer_t structures are available */ tot = perfstat_netbuffer(NULL, NULL, sizeof(perfstat_netbuffer_t), 0); /* allocate enough memory for all the structures */ statp = calloc(tot, sizeof(perfstat_netbuffer_t)); /* set name to first interface */ strcpy(first.name, FIRST_NETBUFFER); /* ask to get all the structures available in one call */ /* return code is number of structures returned */ ret = perfstat_netbuffer(&first, statp, sizeof(perfstat_netbuffer_t), tot); /* print info in netstat -m format */ printf("%-12s %10s %9s %6s %9s %7s %7s %7s\n", "By size", "inuse", "calls", "failed", "delayed", "free", "hiwat", "freed"); for (i = 0; i < ret; i++) { printf("%-12s %10llu %9llu %6llu %9llu %7llu %7llu %7llu\n", statp[i].name, statp[i].inuse, statp[i].calls, statp[i].delayed, statp[i].free, statp[i].failed, statp[i].highwatermark, statp[i].freed); } }
The preceding program produces output similar to the following:
By size inuse calls failed delayed free hiwat freed 32 199 4798 0 57 0 826 0 64 96 8121 0 32 0 413 0 128 110 50156 0 146 0 206 2 256 279 20313587 0 361 0 496 0 512 156 5298 0 12 0 51 0 1024 38 1038 0 6 0 129 0 2048 1 6946 0 129 0 129 1024 4096 67 276102 0 132 0 155 0 8192 4 123 0 4 0 12 0 16384 1 1 0 15 0 31 0 65536 1 1 0 0 0 512 0
The perfstat_pagingspace function returns a set of structures of type perfstat_pagingspace_t, which is defined in the libperfstat.h file. Selected fields from the perfstat_pagingspace_t structure include:
mb_size | Size of the paging space in MB |
lp_size | Size of the paging space in logical partitions |
mb_used | Portion of the paging space used in MB |
Several other paging space related metrics (such as name, type, and active) are also returned. For a complete list, see the perfstat_pagingspace_t section in the libperfstat.h file.
The following code shows an example of how perfstat_pagingspace is used:
#include <stdio.h> #include <stdlib.h> #include <libperfstat.h> int main(int argc, char agrv[]) { int i, ret, tot; perfstat_id_t first; perfstat_pagingspace_t *pinfo; tot = perfstat_pagingspace(NULL, NULL, sizeof(perfstat_pagingspace_t), 0); pinfo = calloc(tot,sizeof(perfstat_pagingspace_t)); strcpy(first.name, FIRST_PAGINGSPACE); ret = perfstat_pagingspace(&first, pinfo, sizeof(perfstat_pagingspace_t), tot); for (i = 0; i < ret; i++) { printf("\nStatistics for paging space : %s\n", pinfo[i].name); printf("---------------------------\n"); printf("type : %s\n", pinfo[i].type == LV_PAGING ? "logical volume" : "NFS file"); if (pinfo[i].type == LV_PAGING) { printf("volume group : %s\n", pinfo[i].lv_paging.vgname); } else { printf("hostname : %s\n", pinfo[i].nfs_paging.hostname); printf("filename : %s\n", pinfo[i].nfs_paging.filename); } printf("size (in LP) : %llu\n", pinfo[i].lp_size); printf("size (in MB) : %llu\n", pinfo[i].mb_size); printf("used (in MB) : %llu\n", pinfo[i].mb_used); } }
The preceding program produces output similar to the following:
Statistics for paging space : hd6 --------------------------- type : logical volume volume group : rootvg size (in LP) : 64 size (in MB) : 512 used (in MB) : 4
The following additions have been made to the perfstat tool:
The following interfaces were added in AIX 5.2:
The following additions have been made to the specified AIX release.
The following fields were added to perfstat_cpu_total_t:
u_longlong_t bread u_longlong_t bwrite u_longlong_t lread u_longlong_t lwrite u_longlong_t phread u_longlong_t phwrite
Support for C++ was added in this AIX level.
Note that the AIX 4.3.3 version of libperfstat is synchronized with this level. No binary or source compatibility is provided between the AIX 4.3.3 version and any AIX 5.1 version prior to 5.1.0.15.
The following fields were added to perfstat_cpu_t:
u_longlong_t bread u_longlong_t bwrite u_longlong_t lread u_longlong_t lwrite u_longlong_t phread u_longlong_t phwrite
The following fields were added to perfstat_cpu_t:
u_longlong_t iget u_longlong_t namei u_longlong_t dirblk u_longlong_t msg u_longlong_t sema
The name field which returns the logical processor name is now of the form cpu0, cpu1, ... instead of proc0, proc1, ... as it was in previous releases.
The following fields were added to perfstat_cpu_total_t:
u_longlong_t runocc u_longlong_t swpocc u_longlong_t iget u_longlong_t namei u_longlong_t dirblk u_longlong_t msg u_longlong_t sema u_longlong_t rcvint u_longlong_t xmtint u_longlong_t mdmint u_longlong_t tty_rawinch u_longlong_t tty_caninch u_longlong_t tty_rawoutch u_longlong_t ksched u_longlong_t koverf u_longlong_t kexit u_longlong_t rbread u_longlong_t rcread u_longlong_t rbwrt u_longlong_t rcwrt u_longlong_t traps int ncpus_high
The following field was added to perfstat_disk_t:
char adapter[IDENTIFIER_LENGTH]
The following field was added to perfstat_netinterface_t:
u_longlong_t bitrate
The following fields were added to perfstat_memory_total_t:
u_longlong_t real_system u_longlong_t real_user u_longlong_t real_process
The following defines were added to libperfstat.h:
#define FIRST_CPU "" #define FIRST_DISK "" #define FIRST_DISKADAPTER "" #define FIRST_NETINTERFACE "" #define FIRST_PAGINGSPACE "" #define FIRST_PROTOCOL "" #define FIRST_ALLOC ""
The libperfstat.h file