I've done a rewrite of the AIX metrics file
(srclib/libmetrics/aix/metrics.c), using libperfstat already mentioned
by Richard Lefebvre. Since nearly every thing changed I don't provide a
patch, but the new file. The code is tested and works fine on  AIX 5.1
and 5.2 (32- and 64-Bit-Kernel).

bos.perf.libperfstat has to be installed, but pm_api is not needed any
more.

What's new:
- supports on 32- and 64-Bit-Kernel
- does not require root authority
- reporting cpu_wio and net stats (bytes_in/out, pkts_in/out)

libperfstat is proving easy access to a lot more of information, like
disk_io, swap_in and swap_out. But somebody has to write the code... So
everybody is welcome to add new features to the AIX metric!
More information on libperfstat can be found at:
http://publib16.boulder.ibm.com/pseries/en_US/aixbman/prftools/perfstat_api.htm


---------------------------------------------------------

Some necessary (?) changes in other parts of ganglia:
 - cpu_wio is not displayed in cpu report
 - cpu_wio is not treated like the other cpu_stats (t_max and reporting
block)
 - rpl_malloc should be defined some where
 - on AIX "IP_MULTICAST" has to be defined at compile time
 - srclib/confuse dose not compile on xlc


-----------------------------------------------------------------------------

Here is what I have done to get ganglia 3.0.1 work with the new metric:

1.) In srclib/libmetrics/unpifi.h:

#include <net/if.h>   should be replaced by:


#ifdef AIX
#ifndef IP_MULTICAST
  # define IP_MULTICAST
#endif
#endif
#include <net/if.h>
#ifdef AIX
#undef IP_MULTICAST
#endif
        
--------------------------------------------
2.) In srclib/libmetrics/libmetrics.h:

In Line 17 (before  #ifdef HAVE_CONFIG_H) the following code shoud be
inserted:


 void *malloc(size_t size);

 char *
 rpl_malloc(size_t n)
 {
     if (n == 0)
         n = 1;
     return malloc (n);
 }


----------------------------------------------------------------

3.) srclib/libmetrics/aix/metrics.c should be replaced by the attached
Version.

----------------------------------------------------------------

4.) use (install) gcc and set CFLAGS=-lperfstat before runing configure


Good luck
     Andreas Schoenfeld


-- 
               Andreas Schoenfeld | Andreas Schoenfeld
                                  |
Technische Universitaet Darmstadt | Darmstadt University of Technology
      Hochschulrechenzentrum (HRZ)| University Computing Centre
                                  |
               Petersenstrasse 30 | Petersenstrasse 30
                  64287 Darmstadt | 64287 Darmstadt
                                  | Germany
                                  |
              Tel.  06151-16 5608 | Tel. +49 (0) 6151-16 5608

             e-mail: [EMAIL PROTECTED]

/*
 *  Rewrite of AIX metrics using libperfstat API
 *
 *  Libperfstat can deal with a 32-bit and a 64-bit Kernel and does not require root authority.
 *
 *  The code is tested with AIX 5.2 (32Bit- and 64Bit-Kernel), but 5.1 and 5.3 shoud be OK too
 *
 *  by Andreas Schoenfeld, TU Darmstadt, Germany (4/2005) 
 *  E-Mail: [EMAIL PROTECTED]
 *
 *  Its based on the 
 *  First stab at support for metrics in AIX
 *  by Preston Smith <[EMAIL PROTECTED]>
 *  Wed Feb 27 14:55:33 EST 2002
 *
 *  AIX V5 support, bugfixes added by Davide Tacchella <[EMAIL PROTECTED]>
 *  May 10, 2002
 *
 *  you may still find some code (like "int bos_level(..)"  ) and the basic structure of this version. 
 *
 *  Some code fragments of the network statistics are "borowed" from  
 *  the Solaris Metrics   
 *
 */

#include "interface.h"
#include <stdlib.h>
#include <utmp.h>
#include <stdio.h>
#include <procinfo.h>
#include <strings.h>
#include <signal.h>
#include <odmi.h>
#include <cf.h>
#include <sys/utsname.h>

#include <libperfstat.h>

#include "libmetrics.h"




struct Class *My_CLASS;

struct product {
        char filler[12];
        char lpp_name[145];      /* offset: 0xc ( 12) */
        char comp_id[20];        /* offset: 0x9d ( 157) */
        short update;            /* offset: 0xb2 ( 178) */
        long cp_flag;            /* offset: 0xb4 ( 180) */
        char fesn[10];           /* offset: 0xb8 ( 184) */
        char *name;              /*[42] offset: 0xc4 ( 196) */
        short state;             /* offset: 0xc8 ( 200) */
        short ver;               /* offset: 0xca ( 202) */
        short rel;               /* offset: 0xcc ( 204) */
        short mod;               /* offset: 0xce ( 206) */
        short fix;               /* offset: 0xd0 ( 208) */
        char ptf[10];            /* offset: 0xd2 ( 210) */
        short media;             /* offset: 0xdc ( 220) */
        char sceded_by[10];      /* offset: 0xde ( 222) */
        char *fixinfo;           /* [1024] offset: 0xe8 ( 232) */
        char *prereq;            /* [1024] offset: 0xec ( 236) */
        char *description;       /* [1024] offset: 0xf0 ( 240) */
        char *supersedes;        /* [512] offset: 0xf4 ( 244) */
};



#define MAX_CPUS  64

#define INFO_TIMEOUT   10
#define CPU_INFO_TIMEOUT INFO_TIMEOUT

#define MEM_PAGESIZE 4096/1024


struct cpu_info {
  time_t timestamp;  
  u_longlong_t total_ticks;
  u_longlong_t user;        /*  raw total number of clock ticks spent in user mode */
  u_longlong_t sys;         /* raw total number of clock ticks spent in system mode */
  u_longlong_t idle;        /* raw total number of clock ticks spent idle */
  u_longlong_t wait;        /* raw total number of clock ticks spent waiting for I/O */
};

struct net_stat{
  double ipackets;
  double opackets;
  double ibytes;
  double obytes;
} cur_net_stat;






int ci_flag=0;
int ni_flag=0;

perfstat_cpu_total_t cpu_total_buffer;
perfstat_memory_total_t minfo;
perfstat_disk_total_t dinfo;
perfstat_netinterface_total_t ninfo[2],*last_ninfo, *cur_ninfo ;


struct cpu_info cpu_info[2], 
  *last_cpu_info,
  *cur_cpu_info;


  

int aixver, aixrel, aixlev, aixfix;
struct utsname unames;


/* Prototypes
 */
void  update_ifdata(void);
void get_cpuinfo(void);
int bos_level(int *aix_version, int *aix_release, int *aix_level, int *aix_fix);





/*
 * This function is called only once by the gmond.  Use to 
 * initialize data structures, etc or just return SYNAPSE_SUCCESS;
 */
g_val_t
metric_init(void)
{
   g_val_t val;


   last_cpu_info = &cpu_info[ci_flag];
   ci_flag^=1;
   cur_cpu_info  = &cpu_info[ci_flag];
   cur_cpu_info->total_ticks = 0;
   
   update_ifdata();
   uname(&unames);
   
   get_cpuinfo();
   sleep(CPU_INFO_TIMEOUT+1);
   get_cpuinfo();

   perfstat_memory_total(NULL, &minfo, sizeof(perfstat_memory_total_t), 1);  
   perfstat_disk_total(NULL, &dinfo, sizeof(perfstat_disk_total_t), 1);

   update_ifdata();

   bos_level(&aixver, &aixrel, &aixlev, &aixfix);

   val.int32 = SYNAPSE_SUCCESS;
   return val;
}



g_val_t
cpu_speed_func ( void )
{
   g_val_t val;

   perfstat_cpu_total(NULL,  &cpu_total_buffer, sizeof(perfstat_cpu_total_t), 1);
   val.uint32 = cpu_total_buffer.processorHZ/1000000;

   return val;
}


g_val_t
boottime_func ( void )
{
   g_val_t val;
   int boottime = 0;
   struct utmp buf;
   FILE *utmp = fopen(UTMP_FILE, "r");

   if (utmp == NULL) {
     /* Can't open utmp, use current time as boottime */
     boottime = time(NULL);
   } else {
     while (fread((char *) &buf, sizeof(buf), 1, utmp) == 1) {
        if (buf.ut_type == BOOT_TIME) {
            boottime = buf.ut_time;
            break;
        }
     }
   }
   val.uint32 = boottime;
   return val;
}

g_val_t
sys_clock_func ( void )
{
   g_val_t val;

   val.uint32 = time(NULL);
   return val;
}



g_val_t
machine_type_func ( void )
{
   g_val_t val;


   strncpy( val.str,cpu_total_buffer.description , MAX_G_STRING_SIZE );
   return val;
}


g_val_t
os_name_func ( void )
{
   g_val_t val;
   strncpy( val.str, unames.sysname, MAX_G_STRING_SIZE );
   return val;
}        


g_val_t
os_release_func ( void )
{
   g_val_t val;
   char oslevel[MAX_G_STRING_SIZE];

   sprintf(oslevel, "%d.%d.%d.%d", aixver, aixrel, aixlev, aixfix);
   strncpy( val.str, oslevel, MAX_G_STRING_SIZE );

   return val;
}        


/* AIX  defines
   CPU_IDLE, CPU_USER, CPU_SYS(CPU_KERNEL), CPU_WAIT
   so no metrics for cpu_nice, or cpu_aidle
*/


#define CALC_CPUINFO(type) ((100.0*(cur_cpu_info->type - last_cpu_info->type))/(1.0*(cur_cpu_info->total_ticks - last_cpu_info->total_ticks)))

g_val_t
cpu_user_func ( void )
{
   g_val_t val;
   
   
   get_cpuinfo();
   
   val.f = CALC_CPUINFO(user);

   if(val.f < 0) val.f = 0.0;
   return val;
}


/*
** AIX dosen't not that 
*/

g_val_t
cpu_nice_func ( void )
{
   g_val_t val;
   val.f = 0;
   return val;
}

g_val_t 
cpu_system_func ( void )
{
   g_val_t val;

   get_cpuinfo();
   val.f = CALC_CPUINFO(sys) ;
   if(val.f < 0) val.f = 0.0;
   return val;
}

g_val_t 
cpu_wio_func ( void )
{
   g_val_t val;
   
   get_cpuinfo();
   val.f = CALC_CPUINFO(wait);


   if(val.f < 0) val.f = 0.0;
   return val;
}

g_val_t 
cpu_idle_func ( void )
{
   g_val_t val;


   get_cpuinfo();
   val.f = CALC_CPUINFO(idle);


   if(val.f < 0) val.f = 0.0;
   return val;
}

/*
** AIX dosen't not that 
*/
g_val_t 
cpu_aidle_func ( void )
{
   g_val_t val;
   val.f = 0.0;
   return val;
}

/*
** Don't know what it is 
*/
g_val_t 
cpu_intr_func ( void )
{
   g_val_t val;
   val.f = 0.0;
   return val;
}

/* Don't know what it is 
** FIXME -- 
*/
g_val_t 
cpu_sintr_func ( void )
{
   g_val_t val;
   val.f = 0.0;
   return val;
}


g_val_t 
bytes_in_func ( void )
{
   g_val_t val;
   update_ifdata();
   val.f = cur_net_stat.ibytes;
   return val;
}


g_val_t 
bytes_out_func ( void )
{
   g_val_t val;

   update_ifdata();
   val.f = cur_net_stat.obytes;
   
   return val;
}


g_val_t 
pkts_in_func ( void )
{
   g_val_t val;

   update_ifdata();
   val.f = cur_net_stat.ipackets;

   return val;
}


g_val_t 
pkts_out_func ( void )
{
   g_val_t val;


   update_ifdata();
   val.f = cur_net_stat.opackets;

   return val;
}


g_val_t 
disk_free_func ( void )
{
   g_val_t val;
   
   perfstat_disk_total(NULL, &dinfo, sizeof(perfstat_disk_total_t), 1);
   val.d = dinfo.free;
   return val;
}


g_val_t 
disk_total_func ( void )
{
   g_val_t val;
   perfstat_disk_total(NULL, &dinfo, sizeof(perfstat_disk_total_t), 1);
   val.d =dinfo.size ;
   return val;
}

/* most used Partition dose not make sense to me 
** FIXME
*/
g_val_t 
part_max_used_func ( void )
{
   g_val_t val;
   val.f = 0.0;
   return val;
}



g_val_t
load_one_func ( void )
{
   g_val_t val;
   
   perfstat_cpu_total(NULL,  &cpu_total_buffer, sizeof(perfstat_cpu_total_t), 1);
   val.f =(1.0*cpu_total_buffer.loadavg[0])/(1<<SBITS) ;
   return val;
}

g_val_t
load_five_func ( void )
{  
   g_val_t val;

   perfstat_cpu_total(NULL,  &cpu_total_buffer, sizeof(perfstat_cpu_total_t), 1);
   val.f =(1.0*cpu_total_buffer.loadavg[1])/(1<<SBITS) ;
   return val;
}

g_val_t
load_fifteen_func ( void )
{
   g_val_t val;

   perfstat_cpu_total(NULL,  &cpu_total_buffer, sizeof(perfstat_cpu_total_t), 1);
   val.f =(1.0*cpu_total_buffer.loadavg[2])/(1<<SBITS)*1.0 ;

   return val;
}

g_val_t
cpu_num_func ( void )
{
   g_val_t val;

   val.uint16 =  cpu_total_buffer.ncpus;
   return val;
}



g_val_t
proc_total_func ( void )
{
  g_val_t foo;
 
  foo.uint32 = cpu_total_buffer.ncpus;
 
  return foo;
}


g_val_t
proc_run_func( void )
{
  g_val_t val;

  perfstat_cpu_total(NULL,  &cpu_total_buffer, sizeof(perfstat_cpu_total_t), 1);
  val.uint32 = cpu_total_buffer.ncpus_cfg;

 
  return val;
}



g_val_t
mem_total_func ( void )
{
   g_val_t val;
  
   perfstat_memory_total(NULL, &minfo, sizeof(perfstat_memory_total_t), 1);

   val.uint32 = minfo.real_total*MEM_PAGESIZE;
   
   return val;
}

g_val_t
mem_free_func ( void )
{
   g_val_t val;
  
   perfstat_memory_total(NULL, &minfo, sizeof(perfstat_memory_total_t), 1);
   
   val.uint32 = minfo.real_free*MEM_PAGESIZE; 
   return val;
}

g_val_t
mem_shared_func ( void )
{
   g_val_t val;
   val.uint32 = 0;

   return val;
}

g_val_t
mem_buffers_func ( void )
{
   g_val_t val;
   val.uint32 = 0;
   return val;
}

g_val_t
mem_cached_func ( void )
{
   g_val_t val;
   val.uint32 = 0;
   return val;
}

g_val_t
swap_total_func ( void )
{
   g_val_t val;

   perfstat_memory_total(NULL, &minfo, sizeof(perfstat_memory_total_t), 1);
   
   val.uint32 =minfo.pgsp_total ;
   return val;
   
}

g_val_t
swap_free_func ( void )
{
   g_val_t val;
   perfstat_memory_total(NULL, &minfo, sizeof(perfstat_memory_total_t), 1);
   
   val.uint32 =minfo.pgsp_free;

   return val;
}


g_val_t
mtu_func ( void )
{
   /* We want to find the minimum MTU (Max packet size) over all UP interfaces.
*/
   unsigned int min=0;
   g_val_t val;
   val.uint32 = get_min_mtu();
   /* A val of 0 means there are no UP interfaces. Shouldn't happen. */
   return val;
}








void get_cpuinfo() 
{
  u_longlong_t cpu_total;
  time_t new_time;


  new_time = time(NULL);

  if (new_time - CPU_INFO_TIMEOUT > cur_cpu_info->timestamp ) 
    {

      perfstat_cpu_total(NULL,  &cpu_total_buffer, sizeof(perfstat_cpu_total_t), 1);


      cpu_total = cpu_total_buffer.user +  cpu_total_buffer.sys  
	+  cpu_total_buffer.idle +  cpu_total_buffer.wait;

  
      last_cpu_info=&cpu_info[ci_flag];
      ci_flag^=1; 
      cur_cpu_info=&cpu_info[ci_flag];

      cur_cpu_info->timestamp   = new_time;
      cur_cpu_info->total_ticks = cpu_total;
      cur_cpu_info->user        = cpu_total_buffer.user;
      cur_cpu_info->sys         = cpu_total_buffer.sys;
      cur_cpu_info->idle        = cpu_total_buffer.idle;
      cur_cpu_info->wait        = cpu_total_buffer.wait;
    }
} /*      get_cpuinfo  */
  


/* int bos_level(int *aix_version, int *aix_release, int *aix_level, int *aix_fix)
 *  is copied form 
 *
 *  First stab at support for metrics in AIX
 *  by Preston Smith <[EMAIL PROTECTED]>
 *  Wed Feb 27 14:55:33 EST 2002
 *
 *  AIX V5 support, bugfixes added by Davide Tacchella <[EMAIL PROTECTED]>
 *  May 10, 2002
 *
 */

int bos_level(int *aix_version, int *aix_release, int *aix_level, int *aix_fix)
{
    struct Class *my_cl;   /* customized devices class ptr */
    struct product  productobj;     /* customized device object storage */
    int rc, getit, found = 0;
    char *path;

    /*
     * start up odm
     */
    if (odm_initialize() == -1)
        return E_ODMINIT; 

    /*
     * Make sure we take the right database
     */
    if ((path = odm_set_path("/usr/lib/objrepos")) == (char *) -1)
        return odmerrno;
 
    /*
     * Mount the lpp class
     */
    if ((My_CLASS = odm_mount_class("product")) == (CLASS_SYMBOL) -1)
        return odmerrno;

    /*
     * open customized devices object class
     */
    if ((int)(my_cl = odm_open_class(My_CLASS)) == -1)
        return E_ODMOPEN;

    /*
     * Loop trough all entries for the lpp name, ASSUMING the last
     * one denotes the up to date number!!!
     */
    /*
     * AIX > 4.2 uses bos.mp or bos.up
     */
    getit = ODM_FIRST;
    while ((rc = (int)odm_get_obj(my_cl, "name like bos.?p",
                                  &productobj, getit)) != 0) {
        getit = ODM_NEXT;
        if (rc == -1) {
            /* ODM failure */
            break;
        }
        else {
            *aix_version = productobj.ver;
            *aix_release = productobj.rel;
            *aix_level   = productobj.mod;
            *aix_fix     = productobj.fix;
            found++;
        }
    }
    /*
     * AIX < 4.2 uses bos.mp or bos.up
     */
    if (!found) {
        getit = ODM_FIRST;
        while ((rc = (int)odm_get_obj(my_cl, "name like bos.rte.?p",
                                      &productobj, getit)) != 0) {
            getit = ODM_NEXT;
            if (rc == -1) {
                /* ODM failure */
                break;
            }
            else {
                *aix_version = productobj.ver;
                *aix_release = productobj.rel;
                *aix_level   = productobj.mod;
                *aix_fix     = productobj.fix;
                found++;
            }
        }
    }



    /*
     * close lpp object class
     */
    odm_close_class(my_cl);

    odm_terminate();

    free(path);
    return (found ? 0 : -1);

} /* bos_level */



#define CALC_NETSTAT(type) (double) ( (cur_ninfo->type - last_ninfo->type)/timediff)

void 
update_ifdata(void){

   static int init_done = 0;
   static struct timeval lasttime={0,0};
   struct timeval thistime;
   double timediff;
   

   /*
   ** Compute time between calls
   */
   gettimeofday (&thistime, NULL);
   if (lasttime.tv_sec)
     timediff = ((double) thistime.tv_sec * 1.0e6 +
                 (double) thistime.tv_usec -
                 (double) lasttime.tv_sec * 1.0e6 -
                 (double) lasttime.tv_usec) / 1.0e6;
   else
     timediff = 1.0;

   /*
   ** Do nothing if we are called to soon after the last call
   */
   if (init_done && (timediff < INFO_TIMEOUT)) return;
   
   lasttime = thistime;

   last_ninfo = &ninfo[ni_flag];

   ni_flag^=1;

   cur_ninfo = &ninfo[ni_flag];

   perfstat_netinterface_total(NULL, cur_ninfo, sizeof(perfstat_netinterface_total_t), 1);

   if (init_done) {
      cur_net_stat.ipackets = CALC_NETSTAT(ipackets);
      cur_net_stat.opackets = CALC_NETSTAT(opackets);
      cur_net_stat.ibytes   = CALC_NETSTAT(ibytes);
      cur_net_stat.obytes   = CALC_NETSTAT(obytes);
   }
   else
     {
       init_done = 1;
       cur_net_stat.ipackets = 0;
       cur_net_stat.opackets = 0;
       cur_net_stat.ibytes   = 0;
       cur_net_stat.obytes   = 0;
     }

}  /* update_ifdata */

Reply via email to