Node interfaces

Node interfaces report metrics related to a set of components or individual components of a remote node in the cluster. The components include processors or memory, and individual components include a processor, network interface, or memory page of the remote node in the cluster.

The remote node must belong to one of the clusters of the current node, which uses the perfstat API.

The following node interfaces use theperfstat_subsystem_node as the naming convention and a common signature:
Item Descriptor
perfstat_cpu_node Retrieves the usage metrics of an individual processor on a remote node.
perfstat_disk_node Retrieves the usage metrics of an individual disk on a remote node.
perfstat_diskadapter_node Retrieves the adapter metrics of a disk on a remote node.
perfstat_diskpath_node Retrieves the path metrics of a disk on a remote node.
perfstat_logicalvolume_node Retrieves the usage metrics of a logical volume on a remote node.
perfstat_memory_page_node Retrieves the usage metrics of a memory page size on a remote node.
perfstat_netbuffer_node Retrieves the buffer allocation metrics of a network on a remote node.
perfstat_netinterface_node Retrieves the interface metrics of a network on a remote size node.
perfstat_pagingspace_node Retrieves the space metrics of a page on a remote node.
perfstat_protocol_node Retrieves the protocol-related metrics of a network on a remote node.
perfstat_tape_node Retrieves the usage metrics of a tape on a remote node.
perfstat_volumegroup_node Retrieves the usage metrics of a volume group on a remote node.
perfstat_cpu_total_node Retrieves the summary on the usage metrics of a processor on a remote node.
perfstat_partition_total_node Retrieves the partition metrics on a remote node.
perfstat_tape_total_node Retrieves the summary on the usage metrics of a tape on a remote node.
perfstat_memory_total_node Retrieves the summary on the usage metrics of a memory on a remote node.
perfstat_netinterface_total_node Retrieves the summary on the usage metrics of a network interface on a remote node.
perfstat_disk_total_node Retrieves the summary on the usage metrics of a disk on a remote node.
The following common signature is used by the perfstat_subsystem_node interface except the perfstat_memory_page_node interface:
int perfstat_subsystem_node(perfstat_id_node_t *name,
perfstat_subsystem_t *userbuff,
int sizeof_struct,
int desired_number);
The following signature is used by the perfstat_memory_page_node interface:
int perfstat_memory_page_node(perfstat_id_node_t *name,
perfstat_psize_t *psize;
perfstat_subsystem_t *userbuff,
int sizeof_struct,
int desired_number);
The following table describes the usage of the parameters of the perfstat_subsystem_node interface:
Item Descriptor
perfstat_id_node_t *name Specify the name of the node in name->u.nodenameformat. The name must contain the name of the first component. For example, hdisk2 for perfstat_disk_node(), where hdisk 2 is the name of the disk for which you require the statistics.
Note: When you specify a nodename, it must be initialized as NODENAME.
perfstat_subsystem_t *userbuff Points to a memory area that has enough space for the returned structure.
int sizeof_struct Sets this parameter to the size of perfstat_subsystem_t.
int desired_number Specifies the number of structures of type perfstat_subsystem_t to return to a userbuff field.

The perfstat_subsystem_node interface return -1 value for error. Otherwise it returns the number of structures copied. The field namename is set to the name of the next available structure, and an exceptional case when userbuff equals NULL and desired_number equals 0, the total number of structures available is returned.

The following example shows the usage of the perfstat_disk_node interface:
#include <stdio.h>
#include <stdlib.h>
#include <libperfstat.h>

#define INTERVAL_DEFAULT 2
#define COUNT_DEFAULT 10

int main(int argc, char* argv[])
{
    int i, ret, tot;
    int interval = INTERVAL_DEFAULT, count = COUNT_DEFAULT;
    int collect_remote_node_stats = 0;
    char nodename[MAXHOSTNAMELEN];
    perfstat_disk_t *statp;
    perfstat_id_t first;
    perfstat_id_node_t nodeid;

    /* Process the arguments */
    while ((i = getopt(argc, argv, "i:c:n:")) != EOF)
    {
       switch(i)
       {
           case 'i':/* Interval */
                    interval = atoi(optarg);
                    if( interval <= 0 )
                        interval = INTERVAL_DEFAULT;
                    break;
           case 'c':/* Number of interations */
                    count = atoi(optarg);
                    if( count <= 0 )
                        count = COUNT_DEFAULT;
                    break;
           case 'n':/* Node name in a cluster environment */
                    strncpy(nodename, optarg, MAXHOSTNAMELEN);
                    nodename[MAXHOSTNAMELEN-1] = '\0';
                    collect_remote_node_stats = 1;
                    break;
           default:
                    /* Invalid arguments. Print the usage and terminate */
                    fprintf (stderr, "usage: %s [-i <interval in seconds>] [-c <number of iterations>] [-n <node name in the cluster>]\n", argv[0]); 
       }
    }

    if(collect_remote_node_stats)
    {
        /* perfstat_config needs to be called to enable cluster statistics collection */
        ret = perfstat_config(PERFSTAT_ENABLE|PERFSTAT_CLUSTER_STATS, NULL);
        if (ret == -1)
        {
           perror("cluster statistics collection is not available");
           exit(-1);
        }
    }

    /* check how many perfstat_disk_t structures are available */
    if(collect_remote_node_stats)
    {
        strncpy(nodeid.u.nodename, nodename, MAXHOSTNAMELEN);
        nodeid.spec = NODENAME;
        tot =  perfstat_disk_node(&nodeid, NULL, sizeof(perfstat_disk_t), 0);
    }
    else
    {
        tot =  perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0);
    }

    
    /* check for error */
    if (tot < 0)
    {
        perror("perfstat_disk");
        exit(-1);
    }
    if (tot == 0)
    {
        printf("No disks found\n");
        exit(-1);
    }

    /* allocate enough memory for all the structures */
    statp = calloc(tot, sizeof(perfstat_disk_t));
    if(statp==NULL){
	printf("No sufficient memory\n");
	exit(-1);
    }
    
    if(collect_remote_node_stats)
    {
        /* Remember nodename is already set */
        /* Now set name to first interface */
        strcpy(nodeid.name, FIRST_DISK);
        
        /* ask to get all the structures available in one call */
        /* return code is number of structures returned */
        ret = perfstat_disk_node(&nodeid, statp,
                            sizeof(perfstat_disk_t), tot);
    }
    else
    {
        /* 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);
    }

    /* check for error */
    if (ret <= 0)
    {
        perror("perfstat_disk");
        exit(-1);
    }

    /* 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 blocks of %llu bytes\n", statp[i].rblks, statp[i].bsize);
        printf("number of blocks written : %llu blocks of %llu bytes\n", statp[i].wblks, statp[i].bsize);
    }

   if(collect_remote_node_stats) {
     /* Now disable cluster statistics by calling perfstat_config */
     perfstat_config(PERFSTAT_DISABLE|PERFSTAT_CLUSTER_STATS, NULL);
   }
}
The program displays an output that is similar to the following example output:
Statistics for disk : hdisk0
----------------------------
description              : Virtual SCSI Disk Drive
volume group name        : rootvg
adapter name             : vscsi0
size                     : 25568 MB
free space               : 19616 MB
number of blocks read    : 315130 blocks of 512 bytes
number of blocks written : 228352 blocks of 512 bytes
The following program shows the usage of the vmstat command and an example of using the perfstat_memory_total_node interface to retrieve the virtual memory details of the remote node:
#include <stdio.h>
#include <libperfstat.h>

#define INTERVAL_DEFAULT 2
#define COUNT_DEFAULT 10

int main(int argc, char* argv[])
{
    perfstat_memory_total_t minfo;
    perfstat_id_node_t nodeid;
    char nodename[MAXHOSTNAMELEN];
    int interval = INTERVAL_DEFAULT, count = COUNT_DEFAULT;
    int collect_remote_node_stats = 0;
    int i, rc;

    /* Process the arguments */
    while ((i = getopt(argc, argv, "i:c:n:")) != EOF)
    {
       switch(i)
       {
           case 'i': /* Interval */
                    interval = atoi(optarg);
                    if( interval <= 0 )
                        interval = INTERVAL_DEFAULT;
                    break;
           case 'c': /* Number of iterations */
                    count = atoi(optarg);
                    if( count <= 0 )
                        count = COUNT_DEFAULT;
                    break;
           case 'n': /* Node name in a cluster environment */
                    strncpy(nodename, optarg, MAXHOSTNAMELEN);
                    nodename[MAXHOSTNAMELEN-1] = '\0';
                    collect_remote_node_stats = 1;
                    break;
           default:
                   /* Invalid arguments. Print the usage and end */
                   fprintf (stderr, "usage: %s [-i <interval in seconds>] [-c <number of iterations>] [-n <node name in the cluster>]\n", argv[0]);
       }
    }

    if(collect_remote_node_stats)
    {
        /* perfstat_config needs to be called to enable cluster statistics collection */
        rc = perfstat_config(PERFSTAT_ENABLE|PERFSTAT_CLUSTER_STATS, NULL);
        if (rc == -1)
        {
           perror("cluster statistics collection is not available");
           exit(-1);
        }
    }

    if(collect_remote_node_stats)
    {
        strncpy(nodeid.u.nodename, nodename, MAXHOSTNAMELEN);
        nodeid.spec = NODENAME;
        rc = perfstat_memory_total_node(&nodeid, &minfo, sizeof(perfstat_memory_total_t), 1);
    }
    else
    {
        rc = perfstat_memory_total(NULL, &minfo, sizeof(perfstat_memory_total_t), 1);
    }

    if (rc != 1) {
        perror("perfstat_memory_total");
        exit(-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);

    if(collect_remote_node_stats) {
     /* Now disable cluster statistics by calling perfstat_config */
     perfstat_config(PERFSTAT_DISABLE|PERFSTAT_CLUSTER_STATS, NULL);
   }
}
The program displays an output that is similar to the following example output:
Memory statistics
-----------------
real memory size                 : 4096 MB
reserved paging space            : 512 MB
virtual memory size              : 4608 MB
number of free pages             : 768401
number of pinned pages           : 237429
number of pages in file cache    : 21473
total paging space pages         : 131072
free paging space pages          : 128821
used paging space                : 1.72%
number of paging space page ins  : 0
number of paging space page outs : 0
number of page ins               : 37301
number of page outs              : 9692
The perfstat_cluster_total interface is used to retrieve cluster statistics from the perfstat_cluster_total_t structure, which is defined in the libperfstat.h file. The following selected fields are from the perfstat_cpu_total_t structure:
Item Descriptor
name Specifies the name of the cluster.
Type Specifies the set of bits that describes the cluster.
num_nodes Specifies the number of nodes in the cluster.
node_data Points to a memory area that describes the details of all the nodes.
num_disks Specifies the number of disks in the cluster.
disk_data Points to a memory area that describes the details of all the disks.

For a complete list of parameters related to the perfstat_cluster_total_t structure, see the libperfstat.h header file.

The following code example shows the usage of the perfstat_cluster_total interface:
#include <stdio.h>
#include <libperfstat.h>

typedef enum {
	DISPLAY_DEFAULT = 0,
	DISPLAY_NODE_DATA = 1,
	DISPLAY_DISK_DATA = 2
} display_t;

int main(int argc, char* argv[])
{
    perfstat_cluster_total_t cstats;
    perfstat_node_data_t *node_details;
    perfstat_disk_data_t *disk_details;
    perfstat_id_node_t nodeid;
    display_t display = DISPLAY_DEFAULT;
    int num_nodes;
    int i, rc;

    /* Process the arguments */
    while ((i = getopt(argc, argv, "lnd")) != EOF)
    {
       switch(i)
       {
           case 'n': /* Request to display node data */
                    display |= DISPLAY_NODE_DATA;
                    break;
           case 'd': /* Request to diplay disk data */
                    display |= DISPLAY_DISK_DATA;
                    break;
           case 'h': /* Print help message */
           default:
                   /* Print the usage and end */
                   fprintf (stderr, "usage: %s [-n] [-d]\n", argv[0]);
                   exit(-1);
       }
    }

    /* perfstat_config needs to be called to enable cluster statistics collection */
    rc = perfstat_config(PERFSTAT_ENABLE|PERFSTAT_CLUSTER_STATS, NULL);
    if (rc == -1)
    {
        perror("cluster statistics collection is not available");
        exit(-1);
    }

    /* Collect cluster statistics */
    strncpy(nodeid.u.nodename, FIRST_CLUSTERNAME, MAXHOSTNAMELEN);
    nodeid.spec = CLUSTERNAME;
    cstats.node_data = NULL;  /* To indicate no interest in node details */
    cstats.disk_data = NULL;  /* To indicate no interest in disk details */
    rc = perfstat_cluster_total(&nodeid, &cstats, sizeof(perfstat_cluster_total_t), 1);
    if (rc == -1)
    {
        perror("perfstat_cluster_total failed");
        exit(-1);
    }
    fprintf(stdout, "Cluster statistics\n");
    fprintf(stdout, "------------------\n");
    fprintf(stdout, "Cluster Name : %s\n", cstats.name);
    fprintf(stdout, "Cluster type : ");
    if (cstats.type.b.is_local)
        fprintf(stdout, "LOCAL\n");
    else if (cstats.type.b.is_zone)
        fprintf(stdout, "ZONE\n");
    else if (cstats.type.b.is_link)
        fprintf(stdout, "LINK\n");
    fprintf(stdout, "Number of nodes : %u\n", cstats.num_nodes);
    fprintf(stdout, "Number of disks : %u\n", cstats.num_disks);

    /* check if the user requested node data */
    if(((display & DISPLAY_NODE_DATA) && (cstats.num_nodes > 0)) ||
       ((display & DISPLAY_DISK_DATA) && (cstats.num_disks > 0)))
    {
        if(display & DISPLAY_NODE_DATA)
        {
            cstats.sizeof_node_data = sizeof(perfstat_node_data_t);
            /* Make sure you allocate at least cstats.num_nodes */
            /* Otherwise, perfstat_cluster_total() fails with ENOSPC */
            cstats.node_data = (perfstat_node_data_t *) malloc(cstats.sizeof_node_data * cstats.num_nodes);
            if(cstats.node_data == NULL)
            {
                perror("malloc failed for node_data");
                exit(-1);
            }
        }
        if(display & DISPLAY_DISK_DATA)
        {
            cstats.sizeof_disk_data = sizeof(perfstat_disk_data_t);
            /* Make sure you allocate at least cstats.num_disks */
            /* Otherwise, perfstat_cluster_total() fails with ENOSPC */
            cstats.disk_data = (perfstat_disk_data_t *) malloc(cstats.sizeof_disk_data * cstats.num_disks);
            if(cstats.disk_data == NULL)
            {
                perror("malloc failed for disk_data");
                exit(-1);
            }
        }

        rc = perfstat_cluster_total(&nodeid, &cstats, sizeof(perfstat_cluster_total_t), 1);
        if (rc == -1)
        {
            perror("perfstat_cluster_total failed");
            exit(-1);
        }
        if(display & DISPLAY_NODE_DATA)
        {
            fprintf(stdout, "\nNode details:\n");
            fprintf(stdout, "-------------\n");
            node_details = cstats.node_data;
            for (i = 0; i < cstats.num_nodes; i++, node_details++)
            {
                fprintf(stdout, "Node name : %s\n", node_details->name);
                fprintf(stdout, "Node shorthand id : %llu\n",
                        node_details->shorthand_id);
                fprintf(stdout, "Status of the node : ");
                if (node_details->status.b.is_up)
                    fprintf(stdout, "UP\n");
                else if (node_details->status.b.is_down)
                    fprintf(stdout, "DOWN\n");
                fprintf(stdout, "Number of clusters the node is participating : %u\n", node_details->num_clusters);
                fprintf(stdout, "Number of zones the node is participating    : %u\n", node_details->num_zones);
                fprintf(stdout, "Number of points of contact to the node      :%u\n", node_details->num_points_of_contact); 
                fprintf(stdout, "\n");
            }
        }

        if(display & DISPLAY_DISK_DATA)
        {
            fprintf(stdout, "\nDisk details:\n");
            fprintf(stdout, "-------------\n");
            disk_details = cstats.disk_data;
            for (i = 0; i < cstats.num_disks; i++, disk_details++)
            {
                fprintf(stdout, "Disk name : %s\n", disk_details->name);
                fprintf(stdout, "Status of the disk :");
                if (disk_details->status.b.is_found)
                {
                    fprintf(stdout, " FOUND");
                    if (disk_details->status.b.is_ready)
                        fprintf(stdout, " | READY");
                    else
                        fprintf(stdout, " | NOT READY");
                }
                else
                    fprintf(stdout, " NOT FOUND");
                fprintf(stdout, "\n");
                fprintf(stdout, "\n");
            }
        }
    }

     /* Now disable cluster statistics by calling perfstat_config */
     perfstat_config(PERFSTAT_DISABLE|PERFSTAT_CLUSTER_STATS, NULL);
}
The perfstat_node_list interface is used to retrieve the list of nodes in the perfstat_node_t structure, which is defined in the libperfstat.h file. The following selected fields are from the perfstat_node_t structure:
Item Descriptor
nodeid Specifies the identifier of the node.
nodename Specifies the name of the node.
The following code example shows the usage of theperfstat_node_list interface:
#include <stdio.h>
#include <libperfstat.h>

int main(int argc, char* argv[])
{
    perfstat_id_node_t nodeid;
    perfstat_node_t *node_list;
    int num_nodes;
    int i, rc;

    /* perfstat_config needs to be called to enable cluster statistics collection */
    rc = perfstat_config(PERFSTAT_ENABLE|PERFSTAT_CLUSTER_STATS, NULL);
    if (rc == -1)
    {
        perror("cluster statistics collection is not available");
        exit(-1);
    }

    strncpy(nodeid.u.nodename, FIRST_CLUSTERNAME, MAXHOSTNAMELEN);
    nodeid.spec = CLUSTERNAME;
    num_nodes = perfstat_node_list(&nodeid, NULL, sizeof(perfstat_node_t), 0);
    if (num_nodes == -1)
    {
        perror("perfstat_node_list failed");
        exit(-1);
    }
    if (num_nodes == 0)
    {   /* This cannot happen */
        fprintf(stdout, "No nodes in the cluster.\n");
        exit(-1);
    }
    node_list = (perfstat_node_t *) malloc(sizeof(perfstat_node_t) * num_nodes);
    num_nodes = perfstat_node_list(&nodeid, node_list, sizeof(perfstat_node_t), num_nodes);
    if (num_nodes == -1)
    {
        perror("perfstat_node_list failed");
        exit(-1);
    }
    fprintf(stdout, "Number of nodes : %d\n\n", num_nodes);
    for (i = 0; i < num_nodes; i++)
    {
        fprintf(stdout, "Node name : %s\n", node_list[i].nodename);
        fprintf(stdout, "Node id : %llu\n", node_list[i].nodeid);
        fprintf(stdout, "\n");
    }

    /* Now disable cluster statistics by calling perfstat_config */
    perfstat_config(PERFSTAT_DISABLE|PERFSTAT_CLUSTER_STATS, NULL);

     return (0);
}

The perfstat_cluster_disk interface is used to retrieve the list of disks in the perfstat_disk_data_t structure. The perfstat_cluster_disk interface is defined in the libperfstat.h file.

The following example code shows the usage of the perfstat_cluster_disk subroutine:


#include <stdio.h>
#include <libperfstat.h>

typedef enum {
	DISPLAY_NODE_DATA = 1,
	DISPLAY_DISK_DATA = 2,
} display_t;

int main(int argc, char* argv[])
{
	perfstat_node_data_t *node_details;
	perfstat_disk_data_t *disk_details;
	perfstat_id_node_t nodeid;
	char nodename[MAXHOSTNAMELEN];
    display_t display = DISPLAY_DISK_DATA;
	int num_nodes;
	int i, rc, num_of_disks = 0;

	/* Process the arguments */
	while ((i = getopt(argc, argv, "n:d")) != EOF)
	{
		switch(i)
		{
			case 'n':               /* Request to display node data */
				display |= DISPLAY_NODE_DATA;
				strncpy(nodename,optarg,MAXHOSTNAMELEN);
				break;
			case 'd':               /* Request to diplay disk data */
				display |= DISPLAY_DISK_DATA;
				break;

			case 'h':               /* Print help message */
			default:
				/* Print the usage and terminate */
				fprintf (stderr, "usage: %s [-n <nodename>] [-d]\n", argv[0]);
				exit(-1);
		}
	}

	/* perfstat_config needs to be called to enable cluster statistics collection */
	rc = perfstat_config(PERFSTAT_ENABLE|PERFSTAT_CLUSTER_STATS, NULL);
	if (rc == -1)
	{
		perror("cluster statistics collection is not available");
		exit(-1);
	}
	/*If Node details are specified pass that data as input to get the disk details
	  for that node . Else pass FIRST_NODENAME */
	if (display & DISPLAY_NODE_DATA)
	{
		strncpy(nodeid.u.nodename,nodename,MAXHOSTNAMELEN);
	}
	else
		strncpy(nodeid.u.nodename, FIRST_NODENAME, MAXHOSTNAMELEN);

	nodeid.spec = NODENAME;
	/*Get the number of disks for that node */
	num_of_disks = perfstat_cluster_disk(&nodeid,NULL, sizeof(perfstat_disk_data_t), 0);    
	if (num_of_disks == -1)
	{
		perror("perfstat_cluster_disk failed");
		exit(-1);
	}

	disk_details = (perfstat_disk_data_t *)calloc(num_of_disks,sizeof(perfstat_disk_data_t));
	/* collect all the disk data for the node */
	if(!disk_details){
		perror("calloc");
	exit(-1);
	}
	num_of_disks = perfstat_cluster_disk(&nodeid,disk_details,sizeof(perfstat_disk_data_t),num_of_disks);
	fprintf(stdout, "Disk Details\n");
	fprintf(stdout, "------------------\n");
	for(i = 0; i < num_of_disks; i++)
	{
		fprintf(stdout,"Disk Name:%s\t UDID:%s\n",disk_details[i].name,disk_details[i].uuid);

	}

	/* Now disable cluster statistics by calling perfstat_config */
	perfstat_config(PERFSTAT_DISABLE|PERFSTAT_CLUSTER_STATS, NULL);
	free(disk_details);
	disk_details = NULL;
}